/*
Packed:
*/


/*
Non-packed:
jquery.js
jquery.tabs.js
jquery.tablesorter.js
jquery.corner.js
jquery.color.js
jquery.ui.base.js
jquery.ui.sortable.js
jquery.simpleColor.js
jquery.lightbox.js
jquery.simplemodal.js
jquery.tooltip.js
jquery.tooglePathways.js
jquery.lightBoxDelete.js
jquery.lightBoxEdit.js
jquery.editInPlace.js
jquery.lightBoxDownload.js
jquery.associateQualifications.js
jquery.dimensions.js
jquery.cwmodal.js
jquery.qtip.js
jquery.associateProvider.js
jquery.fixedheadertable.js
ConfirmationOfOffer.js
LearningPathwaysCourses.js
ProviderPartnershipCourses.js
MessagingAdmin.js
OptionBlockFitzalan.js
ProfLearningPathwayPlan.js
jquery.associateCourses.js
FaqAdmin.js
RelatedMedia.js
MyLearners.js
ProviderAdmin.js
CourseBrowser.js
UserManager.js
OptionBlockAdmin.js
AssignProsToLearners.js
AssignLearnersToProgs.js
FreeChoicePollAdmin.js
OptionBlock.js
UserAccount.js
FreeChoicePoll.js
LearningPathwayPlan.js
jqform.js
CalenderPopup.js
jAutocomplete.js
common.js
ConProviderCourse.js
CertificatesAndCourses.js
WorkExperience.js
AchievementsAndExperience.js
Research.js
Qualifications.js
SupportTeam.js
LearningPathways.js
RelatedEClipsLeaflets.js
ConMediaFile.js
MySiteAdmin.js
EClipsSearch.js
ProviderCourseAdmin.js
Messaging.js
ConEClipsLeafletDisplay.js
ContentTools.js
Employment.js
DataTransfer.js
WorkRelatedEducation.js
AboutMeMyDetails.js
Interests.js
TodoList.js
RateMySkills.js
TagCloud.js
MySkillsOutput.js
AMSInformation.js
AMSVacancies.js
AMSProfile.js
AboutMeMyPersonalProfile.js
GoalsAndAspirations.js
UserProvider.js
ManageMyDocuments.js
VenueDetails.js
SavedContent.js
Ideas.js
CreateYourCV.js
ExistingCVs.js
BuildYourCV.js
Commenting.js
SSRS.js
CollaborativeProgrammeOptions.js
NetworkCourseSearch.js
OptionTextSearchFields.js
OptionSearchContent.js
WblCourseSearch.js
ProviderPartnershipAdmin.js
CollaborativeOfferAdmin.js
SwanseaGuaranteeChoices.js
SwanseaGuarantee.js
WBLCourseSearchCourse.js
CourseSearchCourse.js
PersonalLearningRecord.js
PersonalLearningRecordAdmin.js
*/
/* jquery.js (105) */
/***
 * jQuery JavaScript Library v1.3.2
 * http://jquery.com/
 *
 * Copyright (c) 2009 John Resig
 * Dual licensed under the MIT and GPL licenses.
 * http://docs.jquery.com/License
 *
 * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009)
 * Revision: 6246
 */
(function(){

var
	// Will speed up references to window, and allows munging its name.
	window = this,
	// Will speed up references to undefined, and allows munging its name.
	undefined,
	// Map over jQuery in case of overwrite
	_jQuery = window.jQuery,
	// Map over the $ in case of overwrite
	_$ = window.$,

	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)
	quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,
	// Is it a simple selector
	isSimple = /^.[^:#\[\.,]*$/;

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;
			this.context = selector;
			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] );

					// Handle the case where IE and Opera return items
					// by name instead of ID
					if ( elem && elem.id != match[3] )
						return jQuery().find( selector );

					// Otherwise, we inject the element directly into the jQuery object
					var ret = jQuery( elem || [] );
					ret.context = document;
					ret.selector = selector;
					return ret;
				}

			// 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 ).ready( selector );

		// Make sure that old selector state is passed along
		if ( selector.selector && selector.context ) {
			this.selector = selector.selector;
			this.context = selector.context;
		}

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

	// Start with an empty selector
	selector: "",

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

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

	// 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
			Array.prototype.slice.call( 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, name, selector ) {
		// Build a new jQuery matched element set
		var ret = jQuery( elems );

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

		ret.context = this.context;

		if ( name === "find" )
			ret.selector = this.selector + (this.selector ? " " : "") + selector;
		else if ( name )
			ret.selector = this.selector + "." + name + "(" + selector + ")";

		// 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 ) {
		// 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 ( typeof name === "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
			var wrap = jQuery( html, this[0].ownerDocument ).clone();

			if ( this[0].parentNode )
				wrap.insertBefore( this[0] );

			wrap.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, function(elem){
			if (this.nodeType == 1)
				this.appendChild( elem );
		});
	},

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

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

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

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

	// For internal use only.
	// Behaves like an Array's method, not like a jQuery method.
	push: [].push,
	sort: [].sort,
	splice: [].splice,

	find: function( selector ) {
		if ( this.length === 1 ) {
			var ret = this.pushStack( [], "find", selector );
			ret.length = 0;
			jQuery.find( selector, this[0], ret );
			return ret;
		} else {
			return this.pushStack( jQuery.unique(jQuery.map(this, function(elem){
				return jQuery.find( selector, elem );
			})), "find", selector );
		}
	},

	clone: function( events ) {
		// Do the clone
		var ret = this.map(function(){
			if ( !jQuery.support.noCloneEvent && !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 html = this.outerHTML;
				if ( !html ) {
					var div = this.ownerDocument.createElement("div");
					div.appendChild( this.cloneNode(true) );
					html = div.innerHTML;
				}

				return jQuery.clean([html.replace(/ jQuery\d+="(?:\d+|null)"/g, "").replace(/^\s*/, "")])[0];
			} else
				return this.cloneNode(true);
		});

		// Copy the events from the original to the clone
		if ( events === true ) {
			var orig = this.find("*").andSelf(), i = 0;

			ret.find("*").andSelf().each(function(){
				if ( this.nodeName !== orig[i].nodeName )
					return;

				var events = jQuery.data( orig[i], "events" );

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

				i++;
			});
		}

		// 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, jQuery.grep(this, function(elem){
				return elem.nodeType === 1;
			}) ), "filter", selector );
	},

	closest: function( selector ) {
		var pos = jQuery.expr.match.POS.test( selector ) ? jQuery(selector) : null,
			closer = 0;

		return this.map(function(){
			var cur = this;
			while ( cur && cur.ownerDocument ) {
				if ( pos ? pos.index(cur) > -1 : jQuery(cur).is(selector) ) {
					jQuery.data(cur, "closest", closer);
					return cur;
				}
				cur = cur.parentNode;
				closer++;
			}
		});
	},

	not: function( selector ) {
		if ( typeof selector === "string" )
			// test special case where just one selector is passed in
			if ( isSimple.test( selector ) )
				return this.pushStack( jQuery.multiFilter( selector, this, true ), "not", selector );
			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 !!selector && this.is( "." + selector );
	},

	val: function( value ) {
		if ( value === undefined ) {
			var elem = this[0];

			if ( elem ) {
				if( jQuery.nodeName( elem, 'option' ) )
					return (elem.attributes.value || {}).specified ? elem.value : elem.text;

				// 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(option).val();

							// 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
				return (elem.value || "").replace(/\r/g, "");

			}

			return undefined;
		}

		if ( typeof value === "number" )
			value += '';

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

			if ( jQuery.isArray(value) && /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.replace(/ jQuery\d+="(?:\d+|null)"/g, "") :
				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 ),
			"slice", Array.prototype.slice.call(arguments).join(",") );
	},

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

	domManip: function( args, table, callback ) {
		if ( this[0] ) {
			var fragment = (this[0].ownerDocument || this[0]).createDocumentFragment(),
				scripts = jQuery.clean( args, (this[0].ownerDocument || this[0]), fragment ),
				first = fragment.firstChild;

			if ( first )
				for ( var i = 0, l = this.length; i < l; i++ )
					callback.call( root(this[i], first), this.length > 1 || i > 0 ?
							fragment.cloneNode(true) : fragment );

			if ( scripts )
				jQuery.each( scripts, evalScript );
		}

		return this;

		function root( elem, cur ) {
			return table && jQuery.nodeName(elem, "table") && jQuery.nodeName(cur, "tr") ?
				(elem.getElementsByTagName("tbody")[0] ||
				elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
				elem;
		}
	}
};

// 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 ( typeof target === "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" && !jQuery.isFunction(target) )
		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;
};

// exclude the following css properties to add px
var	exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i,
	// cache defaultView
	defaultView = document.defaultView || {},
	toString = Object.prototype.toString;

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

		if ( deep )
			window.jQuery = _jQuery;

		return jQuery;
	},

	// See test/unit/core.js for details concerning isFunction.
	// Since version 1.3, DOM methods and functions like alert
	// aren't supported. They return false on IE (#2968).
	isFunction: function( obj ) {
		return toString.call(obj) === "[object Function]";
	},

	isArray: function( obj ) {
		return toString.call(obj) === "[object Array]";
	},

	// check if an element is in a (or is an) XML document
	isXMLDoc: function( elem ) {
		return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" ||
			!!elem.ownerDocument && jQuery.isXMLDoc( elem.ownerDocument );
	},

	// Evalulates a script in a global context
	globalEval: function( data ) {
		if ( data && /\S/.test(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.support.scriptEval )
				script.appendChild( document.createTextNode( data ) );
			else
				script.text = 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();
	},

	// 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 typeof value === "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 elem && 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, extra ) {
		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;

				if ( extra === "border" )
					return;

				jQuery.each( which, function() {
					if ( !extra )
						val -= parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0;
					if ( extra === "margin" )
						val += parseFloat(jQuery.curCSS( elem, "margin" + this, true)) || 0;
					else
						val -= parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0;
				});
			}

			if ( elem.offsetWidth !== 0 )
				getWH();
			else
				jQuery.swap( elem, props, getWH );

			return Math.max(0, Math.round(val));
		}

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

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

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

			return ret == "" ?
				"1" :
				ret;
		}

		// 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 )
				ret = computedStyle.getPropertyValue( name );

			// 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, fragment ) {
		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;

		// If a single string is passed in and it's a single tag
		// just do a createElement and skip the rest
		if ( !fragment && elems.length === 1 && typeof elems[0] === "string" ) {
			var match = /^<(\w+)\s*\/?>$/.exec(elems[0]);
			if ( match )
				return [ context.createElement( match[1] ) ];
		}

		var ret = [], scripts = [], div = context.createElement("div");

		jQuery.each(elems, function(i, elem){
			if ( typeof elem === "number" )
				elem += '';

			if ( !elem )
				return;

			// 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 = elem.replace(/^\s+/, "").substring(0, 10).toLowerCase();

				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.support.htmlSerialize &&
					[ 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.support.tbody ) {

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

						// String was a bare <thead> or <tfoot>
						wrap[1] == "<table>" && !hasBody ?
							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 ( !jQuery.support.leadingWhitespace && /^\s/.test( elem ) )
					div.insertBefore( context.createTextNode( elem.match(/^\s*/)[0] ), div.firstChild );

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

			if ( elem.nodeType )
				ret.push( elem );
			else
				ret = jQuery.merge( ret, elem );

		});

		if ( fragment ) {
			for ( var i = 0; ret[i]; i++ ) {
				if ( jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) {
					scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] );
				} else {
					if ( ret[i].nodeType === 1 )
						ret.splice.apply( ret, [i + 1, 0].concat(jQuery.makeArray(ret[i].getElementsByTagName("script"))) );
					fragment.appendChild( ret[i] );
				}
			}

			return scripts;
		}

		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;

		// 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" && elem.parentNode )
				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;

				// elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
				// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
				if ( name == "tabIndex" ) {
					var attributeNode = elem.getAttributeNode( "tabIndex" );
					return attributeNode && attributeNode.specified
						? attributeNode.value
						: elem.nodeName.match(/(button|input|object|select|textarea)/i)
							? 0
							: elem.nodeName.match(/^(a|area)$/i) && elem.href
								? 0
								: undefined;
				}

				return elem[ name ];
			}

			if ( !jQuery.support.style && 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 = !jQuery.support.hrefNormalized && 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 ( !jQuery.support.opacity && 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 || typeof array === "string" || jQuery.isFunction(array) || array.setInterval )
				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.support.getAll ) {
			while ( (elem = second[ i++ ]) != null )
				if ( elem.nodeType != 8 )
					first[ pos++ ] = elem;

		} else
			while ( (elem = second[ i++ ]) != null )
				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 );
	}
});

// Use of jQuery.browser is deprecated.
// It's included for backwards compatibility and plugins,
// although they should work to migrate away.

var userAgent = navigator.userAgent.toLowerCase();

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

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

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

		for ( var i = 0, l = insert.length; i < l; i++ ) {
			var elems = (i > 0 ? this.clone(true) : this).get();
			jQuery.fn[ original ].apply( jQuery(insert[i]), elems );
			ret = ret.concat( elems );
		}

		return this.pushStack( ret, name, selector );
	};
});

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, state ) {
		if( typeof state !== "boolean" )
			state = !jQuery.className.has( this, classNames );
		jQuery.className[ state ? "add" : "remove" ]( this, classNames );
	},

	remove: function( selector ) {
		if ( !selector || jQuery.filter( selector, [ this ] ).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).children().remove();

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

// 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 expando = "jQuery" + now(), uuid = 0, windowData = {};

jQuery.extend({
	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 ];
		}
	},
	queue: function( elem, type, data ) {
		if ( elem ){

			type = (type || "fx") + "queue";

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

			if ( !q || jQuery.isArray(data) )
				q = jQuery.data( elem, type, jQuery.makeArray(data) );
			else if( data )
				q.push( data );

		}
		return q;
	},

	dequeue: function( elem, type ){
		var queue = jQuery.queue( elem, type ),
			fn = queue.shift();

		if( !type || type === "fx" )
			fn = queue[0];

		if( fn !== undefined )
			fn.call(elem);
	}
});

jQuery.fn.extend({
	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 );
		});
	},
	queue: function(type, data){
		if ( typeof type !== "string" ) {
			data = type;
			type = "fx";
		}

		if ( data === undefined )
			return jQuery.queue( this[0], type );

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

			 if( type == "fx" && queue.length == 1 )
				queue[0].call(this);
		});
	},
	dequeue: function(type){
		return this.each(function(){
			jQuery.dequeue( this, type );
		});
	}
});/*!
 * Sizzle CSS Selector Engine - v0.9.3
 *  Copyright 2009, The Dojo Foundation
 *  Released under the MIT, BSD, and GPL Licenses.
 *  More information: http://sizzlejs.com/
 */
(function(){

var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,
	done = 0,
	toString = Object.prototype.toString;

var Sizzle = function(selector, context, results, seed) {
	results = results || [];
	context = context || document;

	if ( context.nodeType !== 1 && context.nodeType !== 9 )
		return [];

	if ( !selector || typeof selector !== "string" ) {
		return results;
	}

	var parts = [], m, set, checkSet, check, mode, extra, prune = true;

	// Reset the position of the chunker regexp (start from head)
	chunker.lastIndex = 0;

	while ( (m = chunker.exec(selector)) !== null ) {
		parts.push( m[1] );

		if ( m[2] ) {
			extra = RegExp.rightContext;
			break;
		}
	}

	if ( parts.length > 1 && origPOS.exec( selector ) ) {
		if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
			set = posProcess( parts[0] + parts[1], context );
		} else {
			set = Expr.relative[ parts[0] ] ?
				[ context ] :
				Sizzle( parts.shift(), context );

			while ( parts.length ) {
				selector = parts.shift();

				if ( Expr.relative[ selector ] )
					selector += parts.shift();

				set = posProcess( selector, set );
			}
		}
	} else {
		var ret = seed ?
			{ expr: parts.pop(), set: makeArray(seed) } :
			Sizzle.find( parts.pop(), parts.length === 1 && context.parentNode ? context.parentNode : context, isXML(context) );
		set = Sizzle.filter( ret.expr, ret.set );

		if ( parts.length > 0 ) {
			checkSet = makeArray(set);
		} else {
			prune = false;
		}

		while ( parts.length ) {
			var cur = parts.pop(), pop = cur;

			if ( !Expr.relative[ cur ] ) {
				cur = "";
			} else {
				pop = parts.pop();
			}

			if ( pop == null ) {
				pop = context;
			}

			Expr.relative[ cur ]( checkSet, pop, isXML(context) );
		}
	}

	if ( !checkSet ) {
		checkSet = set;
	}

	if ( !checkSet ) {
		throw "Syntax error, unrecognized expression: " + (cur || selector);
	}

	if ( toString.call(checkSet) === "[object Array]" ) {
		if ( !prune ) {
			results.push.apply( results, checkSet );
		} else if ( context.nodeType === 1 ) {
			for ( var i = 0; checkSet[i] != null; i++ ) {
				if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) {
					results.push( set[i] );
				}
			}
		} else {
			for ( var i = 0; checkSet[i] != null; i++ ) {
				if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
					results.push( set[i] );
				}
			}
		}
	} else {
		makeArray( checkSet, results );
	}

	if ( extra ) {
		Sizzle( extra, context, results, seed );

		if ( sortOrder ) {
			hasDuplicate = false;
			results.sort(sortOrder);

			if ( hasDuplicate ) {
				for ( var i = 1; i < results.length; i++ ) {
					if ( results[i] === results[i-1] ) {
						results.splice(i--, 1);
					}
				}
			}
		}
	}

	return results;
};

Sizzle.matches = function(expr, set){
	return Sizzle(expr, null, null, set);
};

Sizzle.find = function(expr, context, isXML){
	var set, match;

	if ( !expr ) {
		return [];
	}

	for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
		var type = Expr.order[i], match;

		if ( (match = Expr.match[ type ].exec( expr )) ) {
			var left = RegExp.leftContext;

			if ( left.substr( left.length - 1 ) !== "\\" ) {
				match[1] = (match[1] || "").replace(/\\/g, "");
				set = Expr.find[ type ]( match, context, isXML );
				if ( set != null ) {
					expr = expr.replace( Expr.match[ type ], "" );
					break;
				}
			}
		}
	}

	if ( !set ) {
		set = context.getElementsByTagName("*");
	}

	return {set: set, expr: expr};
};

Sizzle.filter = function(expr, set, inplace, not){
	var old = expr, result = [], curLoop = set, match, anyFound,
		isXMLFilter = set && set[0] && isXML(set[0]);

	while ( expr && set.length ) {
		for ( var type in Expr.filter ) {
			if ( (match = Expr.match[ type ].exec( expr )) != null ) {
				var filter = Expr.filter[ type ], found, item;
				anyFound = false;

				if ( curLoop == result ) {
					result = [];
				}

				if ( Expr.preFilter[ type ] ) {
					match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );

					if ( !match ) {
						anyFound = found = true;
					} else if ( match === true ) {
						continue;
					}
				}

				if ( match ) {
					for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
						if ( item ) {
							found = filter( item, match, i, curLoop );
							var pass = not ^ !!found;

							if ( inplace && found != null ) {
								if ( pass ) {
									anyFound = true;
								} else {
									curLoop[i] = false;
								}
							} else if ( pass ) {
								result.push( item );
								anyFound = true;
							}
						}
					}
				}

				if ( found !== undefined ) {
					if ( !inplace ) {
						curLoop = result;
					}

					expr = expr.replace( Expr.match[ type ], "" );

					if ( !anyFound ) {
						return [];
					}

					break;
				}
			}
		}

		// Improper expression
		if ( expr == old ) {
			if ( anyFound == null ) {
				throw "Syntax error, unrecognized expression: " + expr;
			} else {
				break;
			}
		}

		old = expr;
	}

	return curLoop;
};

var Expr = Sizzle.selectors = {
	order: [ "ID", "NAME", "TAG" ],
	match: {
		ID: /#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,
		CLASS: /\.((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,
		NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF_-]|\\.)+)['"]*\]/,
		ATTR: /\[\s*((?:[\w\u00c0-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
		TAG: /^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/,
		CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,
		POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,
		PSEUDO: /:((?:[\w\u00c0-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/
	},
	attrMap: {
		"class": "className",
		"for": "htmlFor"
	},
	attrHandle: {
		href: function(elem){
			return elem.getAttribute("href");
		}
	},
	relative: {
		"+": function(checkSet, part, isXML){
			var isPartStr = typeof part === "string",
				isTag = isPartStr && !/\W/.test(part),
				isPartStrNotTag = isPartStr && !isTag;

			if ( isTag && !isXML ) {
				part = part.toUpperCase();
			}

			for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
				if ( (elem = checkSet[i]) ) {
					while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}

					checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ?
						elem || false :
						elem === part;
				}
			}

			if ( isPartStrNotTag ) {
				Sizzle.filter( part, checkSet, true );
			}
		},
		">": function(checkSet, part, isXML){
			var isPartStr = typeof part === "string";

			if ( isPartStr && !/\W/.test(part) ) {
				part = isXML ? part : part.toUpperCase();

				for ( var i = 0, l = checkSet.length; i < l; i++ ) {
					var elem = checkSet[i];
					if ( elem ) {
						var parent = elem.parentNode;
						checkSet[i] = parent.nodeName === part ? parent : false;
					}
				}
			} else {
				for ( var i = 0, l = checkSet.length; i < l; i++ ) {
					var elem = checkSet[i];
					if ( elem ) {
						checkSet[i] = isPartStr ?
							elem.parentNode :
							elem.parentNode === part;
					}
				}

				if ( isPartStr ) {
					Sizzle.filter( part, checkSet, true );
				}
			}
		},
		"": function(checkSet, part, isXML){
			var doneName = done++, checkFn = dirCheck;

			if ( !part.match(/\W/) ) {
				var nodeCheck = part = isXML ? part : part.toUpperCase();
				checkFn = dirNodeCheck;
			}

			checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);
		},
		"~": function(checkSet, part, isXML){
			var doneName = done++, checkFn = dirCheck;

			if ( typeof part === "string" && !part.match(/\W/) ) {
				var nodeCheck = part = isXML ? part : part.toUpperCase();
				checkFn = dirNodeCheck;
			}

			checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML);
		}
	},
	find: {
		ID: function(match, context, isXML){
			if ( typeof context.getElementById !== "undefined" && !isXML ) {
				var m = context.getElementById(match[1]);
				return m ? [m] : [];
			}
		},
		NAME: function(match, context, isXML){
			if ( typeof context.getElementsByName !== "undefined" ) {
				var ret = [], results = context.getElementsByName(match[1]);

				for ( var i = 0, l = results.length; i < l; i++ ) {
					if ( results[i].getAttribute("name") === match[1] ) {
						ret.push( results[i] );
					}
				}

				return ret.length === 0 ? null : ret;
			}
		},
		TAG: function(match, context){
			return context.getElementsByTagName(match[1]);
		}
	},
	preFilter: {
		CLASS: function(match, curLoop, inplace, result, not, isXML){
			match = " " + match[1].replace(/\\/g, "") + " ";

			if ( isXML ) {
				return match;
			}

			for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
				if ( elem ) {
					if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) {
						if ( !inplace )
							result.push( elem );
					} else if ( inplace ) {
						curLoop[i] = false;
					}
				}
			}

			return false;
		},
		ID: function(match){
			return match[1].replace(/\\/g, "");
		},
		TAG: function(match, curLoop){
			for ( var i = 0; curLoop[i] === false; i++ ){}
			return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase();
		},
		CHILD: function(match){
			if ( match[1] == "nth" ) {
				// parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
				var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
					match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" ||
					!/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);

				// calculate the numbers (first)n+(last) including if they are negative
				match[2] = (test[1] + (test[2] || 1)) - 0;
				match[3] = test[3] - 0;
			}

			// TODO: Move to normal caching system
			match[0] = done++;

			return match;
		},
		ATTR: function(match, curLoop, inplace, result, not, isXML){
			var name = match[1].replace(/\\/g, "");

			if ( !isXML && Expr.attrMap[name] ) {
				match[1] = Expr.attrMap[name];
			}

			if ( match[2] === "~=" ) {
				match[4] = " " + match[4] + " ";
			}

			return match;
		},
		PSEUDO: function(match, curLoop, inplace, result, not){
			if ( match[1] === "not" ) {
				// If we're dealing with a complex expression, or a simple one
				if ( match[3].match(chunker).length > 1 || /^\w/.test(match[3]) ) {
					match[3] = Sizzle(match[3], null, null, curLoop);
				} else {
					var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
					if ( !inplace ) {
						result.push.apply( result, ret );
					}
					return false;
				}
			} else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
				return true;
			}

			return match;
		},
		POS: function(match){
			match.unshift( true );
			return match;
		}
	},
	filters: {
		enabled: function(elem){
			return elem.disabled === false && elem.type !== "hidden";
		},
		disabled: function(elem){
			return elem.disabled === true;
		},
		checked: function(elem){
			return elem.checked === true;
		},
		selected: function(elem){
			// Accessing this property makes selected-by-default
			// options in Safari work properly
			elem.parentNode.selectedIndex;
			return elem.selected === true;
		},
		parent: function(elem){
			return !!elem.firstChild;
		},
		empty: function(elem){
			return !elem.firstChild;
		},
		has: function(elem, i, match){
			return !!Sizzle( match[3], elem ).length;
		},
		header: function(elem){
			return /h\d/i.test( elem.nodeName );
		},
		text: function(elem){
			return "text" === elem.type;
		},
		radio: function(elem){
			return "radio" === elem.type;
		},
		checkbox: function(elem){
			return "checkbox" === elem.type;
		},
		file: function(elem){
			return "file" === elem.type;
		},
		password: function(elem){
			return "password" === elem.type;
		},
		submit: function(elem){
			return "submit" === elem.type;
		},
		image: function(elem){
			return "image" === elem.type;
		},
		reset: function(elem){
			return "reset" === elem.type;
		},
		button: function(elem){
			return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON";
		},
		input: function(elem){
			return /input|select|textarea|button/i.test(elem.nodeName);
		}
	},
	setFilters: {
		first: function(elem, i){
			return i === 0;
		},
		last: function(elem, i, match, array){
			return i === array.length - 1;
		},
		even: function(elem, i){
			return i % 2 === 0;
		},
		odd: function(elem, i){
			return i % 2 === 1;
		},
		lt: function(elem, i, match){
			return i < match[3] - 0;
		},
		gt: function(elem, i, match){
			return i > match[3] - 0;
		},
		nth: function(elem, i, match){
			return match[3] - 0 == i;
		},
		eq: function(elem, i, match){
			return match[3] - 0 == i;
		}
	},
	filter: {
		PSEUDO: function(elem, match, i, array){
			var name = match[1], filter = Expr.filters[ name ];

			if ( filter ) {
				return filter( elem, i, match, array );
			} else if ( name === "contains" ) {
				return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0;
			} else if ( name === "not" ) {
				var not = match[3];

				for ( var i = 0, l = not.length; i < l; i++ ) {
					if ( not[i] === elem ) {
						return false;
					}
				}

				return true;
			}
		},
		CHILD: function(elem, match){
			var type = match[1], node = elem;
			switch (type) {
				case 'only':
				case 'first':
					while (node = node.previousSibling)  {
						if ( node.nodeType === 1 ) return false;
					}
					if ( type == 'first') return true;
					node = elem;
				case 'last':
					while (node = node.nextSibling)  {
						if ( node.nodeType === 1 ) return false;
					}
					return true;
				case 'nth':
					var first = match[2], last = match[3];

					if ( first == 1 && last == 0 ) {
						return true;
					}

					var doneName = match[0],
						parent = elem.parentNode;

					if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {
						var count = 0;
						for ( node = parent.firstChild; node; node = node.nextSibling ) {
							if ( node.nodeType === 1 ) {
								node.nodeIndex = ++count;
							}
						}
						parent.sizcache = doneName;
					}

					var diff = elem.nodeIndex - last;
					if ( first == 0 ) {
						return diff == 0;
					} else {
						return ( diff % first == 0 && diff / first >= 0 );
					}
			}
		},
		ID: function(elem, match){
			return elem.nodeType === 1 && elem.getAttribute("id") === match;
		},
		TAG: function(elem, match){
			return (match === "*" && elem.nodeType === 1) || elem.nodeName === match;
		},
		CLASS: function(elem, match){
			return (" " + (elem.className || elem.getAttribute("class")) + " ")
				.indexOf( match ) > -1;
		},
		ATTR: function(elem, match){
			var name = match[1],
				result = Expr.attrHandle[ name ] ?
					Expr.attrHandle[ name ]( elem ) :
					elem[ name ] != null ?
						elem[ name ] :
						elem.getAttribute( name ),
				value = result + "",
				type = match[2],
				check = match[4];

			return result == null ?
				type === "!=" :
				type === "=" ?
				value === check :
				type === "*=" ?
				value.indexOf(check) >= 0 :
				type === "~=" ?
				(" " + value + " ").indexOf(check) >= 0 :
				!check ?
				value && result !== false :
				type === "!=" ?
				value != check :
				type === "^=" ?
				value.indexOf(check) === 0 :
				type === "$=" ?
				value.substr(value.length - check.length) === check :
				type === "|=" ?
				value === check || value.substr(0, check.length + 1) === check + "-" :
				false;
		},
		POS: function(elem, match, i, array){
			var name = match[2], filter = Expr.setFilters[ name ];

			if ( filter ) {
				return filter( elem, i, match, array );
			}
		}
	}
};

var origPOS = Expr.match.POS;

for ( var type in Expr.match ) {
	Expr.match[ type ] = RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source );
}

var makeArray = function(array, results) {
	array = Array.prototype.slice.call( array );

	if ( results ) {
		results.push.apply( results, array );
		return results;
	}

	return array;
};

// Perform a simple check to determine if the browser is capable of
// converting a NodeList to an array using builtin methods.
try {
	Array.prototype.slice.call( document.documentElement.childNodes );

// Provide a fallback method if it does not work
} catch(e){
	makeArray = function(array, results) {
		var ret = results || [];

		if ( toString.call(array) === "[object Array]" ) {
			Array.prototype.push.apply( ret, array );
		} else {
			if ( typeof array.length === "number" ) {
				for ( var i = 0, l = array.length; i < l; i++ ) {
					ret.push( array[i] );
				}
			} else {
				for ( var i = 0; array[i]; i++ ) {
					ret.push( array[i] );
				}
			}
		}

		return ret;
	};
}

var sortOrder;

if ( document.documentElement.compareDocumentPosition ) {
	sortOrder = function( a, b ) {
		var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
		if ( ret === 0 ) {
			hasDuplicate = true;
		}
		return ret;
	};
} else if ( "sourceIndex" in document.documentElement ) {
	sortOrder = function( a, b ) {
		var ret = a.sourceIndex - b.sourceIndex;
		if ( ret === 0 ) {
			hasDuplicate = true;
		}
		return ret;
	};
} else if ( document.createRange ) {
	sortOrder = function( a, b ) {
		var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
		aRange.selectNode(a);
		aRange.collapse(true);
		bRange.selectNode(b);
		bRange.collapse(true);
		var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
		if ( ret === 0 ) {
			hasDuplicate = true;
		}
		return ret;
	};
}

// Check to see if the browser returns elements by name when
// querying by getElementById (and provide a workaround)
(function(){
	// We're going to inject a fake input element with a specified name
	var form = document.createElement("form"),
		id = "script" + (new Date).getTime();
	form.innerHTML = "<input name='" + id + "'/>";

	// Inject it into the root element, check its status, and remove it quickly
	var root = document.documentElement;
	root.insertBefore( form, root.firstChild );

	// The workaround has to do additional checks after a getElementById
	// Which slows things down for other browsers (hence the branching)
	if ( !!document.getElementById( id ) ) {
		Expr.find.ID = function(match, context, isXML){
			if ( typeof context.getElementById !== "undefined" && !isXML ) {
				var m = context.getElementById(match[1]);
				return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : [];
			}
		};

		Expr.filter.ID = function(elem, match){
			var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
			return elem.nodeType === 1 && node && node.nodeValue === match;
		};
	}

	root.removeChild( form );
})();

(function(){
	// Check to see if the browser returns only elements
	// when doing getElementsByTagName("*")

	// Create a fake element
	var div = document.createElement("div");
	div.appendChild( document.createComment("") );

	// Make sure no comments are found
	if ( div.getElementsByTagName("*").length > 0 ) {
		Expr.find.TAG = function(match, context){
			var results = context.getElementsByTagName(match[1]);

			// Filter out possible comments
			if ( match[1] === "*" ) {
				var tmp = [];

				for ( var i = 0; results[i]; i++ ) {
					if ( results[i].nodeType === 1 ) {
						tmp.push( results[i] );
					}
				}

				results = tmp;
			}

			return results;
		};
	}

	// Check to see if an attribute returns normalized href attributes
	div.innerHTML = "<a href='#'></a>";
	if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
			div.firstChild.getAttribute("href") !== "#" ) {
		Expr.attrHandle.href = function(elem){
			return elem.getAttribute("href", 2);
		};
	}
})();

if ( document.querySelectorAll ) (function(){
	var oldSizzle = Sizzle, div = document.createElement("div");
	div.innerHTML = "<p class='TEST'></p>";

	// Safari can't handle uppercase or unicode characters when
	// in quirks mode.
	if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
		return;
	}

	Sizzle = function(query, context, extra, seed){
		context = context || document;

		// Only use querySelectorAll on non-XML documents
		// (ID selectors don't work in non-HTML documents)
		if ( !seed && context.nodeType === 9 && !isXML(context) ) {
			try {
				return makeArray( context.querySelectorAll(query), extra );
			} catch(e){}
		}

		return oldSizzle(query, context, extra, seed);
	};

	Sizzle.find = oldSizzle.find;
	Sizzle.filter = oldSizzle.filter;
	Sizzle.selectors = oldSizzle.selectors;
	Sizzle.matches = oldSizzle.matches;
})();

if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){
	var div = document.createElement("div");
	div.innerHTML = "<div class='test e'></div><div class='test'></div>";

	// Opera can't find a second classname (in 9.6)
	if ( div.getElementsByClassName("e").length === 0 )
		return;

	// Safari caches class attributes, doesn't catch changes (in 3.2)
	div.lastChild.className = "e";

	if ( div.getElementsByClassName("e").length === 1 )
		return;

	Expr.order.splice(1, 0, "CLASS");
	Expr.find.CLASS = function(match, context, isXML) {
		if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
			return context.getElementsByClassName(match[1]);
		}
	};
})();

function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
	var sibDir = dir == "previousSibling" && !isXML;
	for ( var i = 0, l = checkSet.length; i < l; i++ ) {
		var elem = checkSet[i];
		if ( elem ) {
			if ( sibDir && elem.nodeType === 1 ){
				elem.sizcache = doneName;
				elem.sizset = i;
			}
			elem = elem[dir];
			var match = false;

			while ( elem ) {
				if ( elem.sizcache === doneName ) {
					match = checkSet[elem.sizset];
					break;
				}

				if ( elem.nodeType === 1 && !isXML ){
					elem.sizcache = doneName;
					elem.sizset = i;
				}

				if ( elem.nodeName === cur ) {
					match = elem;
					break;
				}

				elem = elem[dir];
			}

			checkSet[i] = match;
		}
	}
}

function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
	var sibDir = dir == "previousSibling" && !isXML;
	for ( var i = 0, l = checkSet.length; i < l; i++ ) {
		var elem = checkSet[i];
		if ( elem ) {
			if ( sibDir && elem.nodeType === 1 ) {
				elem.sizcache = doneName;
				elem.sizset = i;
			}
			elem = elem[dir];
			var match = false;

			while ( elem ) {
				if ( elem.sizcache === doneName ) {
					match = checkSet[elem.sizset];
					break;
				}

				if ( elem.nodeType === 1 ) {
					if ( !isXML ) {
						elem.sizcache = doneName;
						elem.sizset = i;
					}
					if ( typeof cur !== "string" ) {
						if ( elem === cur ) {
							match = true;
							break;
						}

					} else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
						match = elem;
						break;
					}
				}

				elem = elem[dir];
			}

			checkSet[i] = match;
		}
	}
}

var contains = document.compareDocumentPosition ?  function(a, b){
	return a.compareDocumentPosition(b) & 16;
} : function(a, b){
	return a !== b && (a.contains ? a.contains(b) : true);
};

var isXML = function(elem){
	return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" ||
		!!elem.ownerDocument && isXML( elem.ownerDocument );
};

var posProcess = function(selector, context){
	var tmpSet = [], later = "", match,
		root = context.nodeType ? [context] : context;

	// Position selectors must be done after the filter
	// And so must :not(positional) so we move all PSEUDOs to the end
	while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
		later += match[0];
		selector = selector.replace( Expr.match.PSEUDO, "" );
	}

	selector = Expr.relative[selector] ? selector + "*" : selector;

	for ( var i = 0, l = root.length; i < l; i++ ) {
		Sizzle( selector, root[i], tmpSet );
	}

	return Sizzle.filter( later, tmpSet );
};

// EXPOSE
jQuery.find = Sizzle;
jQuery.filter = Sizzle.filter;
jQuery.expr = Sizzle.selectors;
jQuery.expr[":"] = jQuery.expr.filters;

Sizzle.selectors.filters.hidden = function(elem){
	return elem.offsetWidth === 0 || elem.offsetHeight === 0;
};

Sizzle.selectors.filters.visible = function(elem){
	return elem.offsetWidth > 0 || elem.offsetHeight > 0;
};

Sizzle.selectors.filters.animated = function(elem){
	return jQuery.grep(jQuery.timers, function(fn){
		return elem === fn.elem;
	}).length;
};

jQuery.multiFilter = function( expr, elems, not ) {
	if ( not ) {
		expr = ":not(" + expr + ")";
	}

	return Sizzle.matches(expr, elems);
};

jQuery.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;
};

jQuery.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;
};

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

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

	return r;
};

return;

window.Sizzle = Sizzle;

})();
/*
 * A number of helper functions used for managing events.
 * Many of the ideas behind this code originated 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 ( elem.setInterval && elem != window )
			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 );

			// 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
				return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
					jQuery.event.handle.apply(arguments.callee.elem, arguments) :
					undefined;
			});
		// 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 namespaces = type.split(".");
			type = namespaces.shift();
			handler.type = namespaces.slice().sort().join(".");

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

			if ( jQuery.event.specialAll[type] )
				jQuery.event.specialAll[type].setup.call(elem, data, namespaces);

			// 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, data, namespaces) === 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 namespaces = type.split(".");
					type = namespaces.shift();
					var namespace = RegExp("(^|\\.)" + namespaces.slice().sort().join(".*\\.") + "(\\.|$)");

					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 ( var handle in events[type] )
								// Handle the removal of namespaced events
								if ( namespace.test(events[type][handle].type) )
									delete events[type][handle];

						if ( jQuery.event.specialAll[type] )
							jQuery.event.specialAll[type].teardown.call(elem, namespaces);

						// 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, namespaces) === 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" );
			}
		}
	},

	// bubbling is internal
	trigger: function( event, data, elem, bubbling ) {
		// Event object or event type
		var type = event.type || event;

		if( !bubbling ){
			event = typeof event === "object" ?
				// jQuery.Event object
				event[expando] ? event :
				// Object literal
				jQuery.extend( jQuery.Event(type), event ) :
				// Just the event type (string)
				jQuery.Event(type);

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

			// Handle a global trigger
			if ( !elem ) {
				// Don't bubble custom events when global (to avoid too much overhead)
				event.stopPropagation();
				// Only trigger if we've ever bound an event for it
				if ( this.global[type] )
					jQuery.each( jQuery.cache, function(){
						if ( this.events && this.events[type] )
							jQuery.event.trigger( event, data, this.handle.elem );
					});
			}

			// Handle triggering a single element

			// don't do events on text and comment nodes
			if ( !elem || elem.nodeType == 3 || elem.nodeType == 8 )
				return undefined;

			// Clean up in case it is reused
			event.result = undefined;
			event.target = elem;

			// Clone the incoming data, if any
			data = jQuery.makeArray(data);
			data.unshift( event );
		}

		event.currentTarget = elem;

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

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

		// Trigger the native events (except for clicks on links)
		if ( !bubbling && elem[type] && !event.isDefaultPrevented() && !(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;

		if ( !event.isPropagationStopped() ) {
			var parent = elem.parentNode || elem.ownerDocument;
			if ( parent )
				jQuery.event.trigger(event, data, parent, true);
		}
	},

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

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

		// Namespaced event handlers
		var namespaces = event.type.split(".");
		event.type = namespaces.shift();

		// Cache this now, all = true means, any handler
		all = !namespaces.length && !event.exclusive;

		var namespace = RegExp("(^|\\.)" + namespaces.slice().sort().join(".*\\.") + "(\\.|$)");

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

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

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

				var ret = handler.apply(this, arguments);

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

				if( event.isImmediatePropagationStopped() )
					break;

			}
		}
	},

	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 toElement view wheelDelta which".split(" "),

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

		// store a copy of the original event object
		// and "clone" to set read-only properties
		var originalEvent = event;
		event = jQuery.Event( originalEvent );

		for ( var i = this.props.length, prop; i; ){
			prop = this.props[ --i ];
			event[ prop ] = originalEvent[ prop ];
		}

		// 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 ){
		proxy = proxy || function(){ return fn.apply(this, arguments); };
		// 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: {
			// Make sure the ready event is setup
			setup: bindReady,
			teardown: function() {}
		}
	},

	specialAll: {
		live: {
			setup: function( selector, namespaces ){
				jQuery.event.add( this, namespaces[0], liveHandler );
			},
			teardown:  function( namespaces ){
				if ( namespaces.length ) {
					var remove = 0, name = RegExp("(^|\\.)" + namespaces[0] + "(\\.|$)");

					jQuery.each( (jQuery.data(this, "events").live || {}), function(){
						if ( name.test(this.type) )
							remove++;
					});

					if ( remove < 1 )
						jQuery.event.remove( this, namespaces[0], liveHandler );
				}
			}
		}
	}
};

jQuery.Event = function( src ){
	// Allow instantiation without the 'new' keyword
	if( !this.preventDefault )
		return new jQuery.Event(src);

	// Event object
	if( src && src.type ){
		this.originalEvent = src;
		this.type = src.type;
	// Event type
	}else
		this.type = src;

	// timeStamp is buggy for some events on Firefox(#3843)
	// So we won't rely on the native value
	this.timeStamp = now();

	// Mark it as fixed
	this[expando] = true;
};

function returnFalse(){
	return false;
}
function returnTrue(){
	return true;
}

// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
jQuery.Event.prototype = {
	preventDefault: function() {
		this.isDefaultPrevented = returnTrue;

		var e = this.originalEvent;
		if( !e )
			return;
		// if preventDefault exists run it on the original event
		if (e.preventDefault)
			e.preventDefault();
		// otherwise set the returnValue property of the original event to false (IE)
		e.returnValue = false;
	},
	stopPropagation: function() {
		this.isPropagationStopped = returnTrue;

		var e = this.originalEvent;
		if( !e )
			return;
		// if stopPropagation exists run it on the original event
		if (e.stopPropagation)
			e.stopPropagation();
		// otherwise set the cancelBubble property of the original event to true (IE)
		e.cancelBubble = true;
	},
	stopImmediatePropagation:function(){
		this.isImmediatePropagationStopped = returnTrue;
		this.stopPropagation();
	},
	isDefaultPrevented: returnFalse,
	isPropagationStopped: returnFalse,
	isImmediatePropagationStopped: returnFalse
};
// Checks if an event happened on an element within another element
// Used in jQuery.event.special.mouseenter and mouseleave handlers
var withinElement = function(event) {
	// Check if mouse(over|out) are still within the same parent element
	var parent = event.relatedTarget;
	// Traverse up the tree
	while ( parent && parent != this )
		try { parent = parent.parentNode; }
		catch(e) { parent = this; }

	if( parent != this ){
		// set the correct event type
		event.type = event.data;
		// handle event if we actually just moused on to a non sub-element
		jQuery.event.handle.apply( this, arguments );
	}
};

jQuery.each({
	mouseover: 'mouseenter',
	mouseout: 'mouseleave'
}, function( orig, fix ){
	jQuery.event.special[ fix ] = {
		setup: function(){
			jQuery.event.add( this, orig, withinElement, fix );
		},
		teardown: function(){
			jQuery.event.remove( this, orig, withinElement );
		}
	};
});

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 ) {
		return this.each(function(){
			jQuery.event.trigger( type, data, this );
		});
	},

	triggerHandler: function( type, data ) {
		if( this[0] ){
			var event = jQuery.Event(type);
			event.preventDefault();
			event.stopPropagation();
			jQuery.event.trigger( event, data, this[0] );
			return event.result;
		}
	},

	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.mouseenter(fnOver).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( fn );

		return this;
	},

	live: function( type, fn ){
		var proxy = jQuery.event.proxy( fn );
		proxy.guid += this.selector + type;

		jQuery(document).bind( liveConvert(type, this.selector), this.selector, proxy );

		return this;
	},

	die: function( type, fn ){
		jQuery(document).unbind( liveConvert(type, this.selector), fn ? { guid: fn.guid + this.selector + type } : null );
		return this;
	}
});

function liveHandler( event ){
	var check = RegExp("(^|\\.)" + event.type + "(\\.|$)"),
		stop = true,
		elems = [];

	jQuery.each(jQuery.data(this, "events").live || [], function(i, fn){
		if ( check.test(fn.type) ) {
			var elem = jQuery(event.target).closest(fn.data)[0];
			if ( elem )
				elems.push({ elem: elem, fn: fn });
		}
	});

	elems.sort(function(a,b) {
		return jQuery.data(a.elem, "closest") - jQuery.data(b.elem, "closest");
	});

	jQuery.each(elems, function(){
		if ( this.fn.call(this.elem, event, this.fn.data) === false )
			return (stop = false);
	});

	return stop;
}

function liveConvert(type, selector){
	return ["live", type, selector.replace(/\./g, "`").replace(/ /g, "|")].join(".");
}

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

				// 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 and webkit nightlies currently support this event
	if ( document.addEventListener ) {
		// Use the handy event callback
		document.addEventListener( "DOMContentLoaded", function(){
			document.removeEventListener( "DOMContentLoaded", arguments.callee, false );
			jQuery.ready();
		}, false );

	// If IE event model is used
	} else if ( document.attachEvent ) {
		// ensure firing before onload,
		// maybe late but safe also for iframes
		document.attachEvent("onreadystatechange", function(){
			if ( document.readyState === "complete" ) {
				document.detachEvent( "onreadystatechange", arguments.callee );
				jQuery.ready();
			}
		});

		// If IE and not an iframe
		// continually check to see if the document is ready
		if ( document.documentElement.doScroll && window == 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();
		})();
	}

	// 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,mouseenter,mouseleave," +
	"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);
	};
});

// 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(){
	for ( var id in jQuery.cache )
		// Skip the window
		if ( id != 1 && jQuery.cache[ id ].handle )
			jQuery.event.remove( jQuery.cache[ id ].handle.elem );
});
(function(){

	jQuery.support = {};

	var root = document.documentElement,
		script = document.createElement("script"),
		div = document.createElement("div"),
		id = "script" + (new Date).getTime();

	div.style.display = "none";
	div.innerHTML = '   <link/><table></table><a href="/a" style="color:red;float:left;opacity:.5;">a</a><select><option>text</option></select><object><param/></object>';

	var all = div.getElementsByTagName("*"),
		a = div.getElementsByTagName("a")[0];

	// Can't get basic test support
	if ( !all || !all.length || !a ) {
		return;
	}

	jQuery.support = {
		// IE strips leading whitespace when .innerHTML is used
		leadingWhitespace: div.firstChild.nodeType == 3,

		// Make sure that tbody elements aren't automatically inserted
		// IE will insert them into empty tables
		tbody: !div.getElementsByTagName("tbody").length,

		// Make sure that you can get all elements in an <object> element
		// IE 7 always returns no results
		objectAll: !!div.getElementsByTagName("object")[0]
			.getElementsByTagName("*").length,

		// Make sure that link elements get serialized correctly by innerHTML
		// This requires a wrapper element in IE
		htmlSerialize: !!div.getElementsByTagName("link").length,

		// Get the style information from getAttribute
		// (IE uses .cssText insted)
		style: /red/.test( a.getAttribute("style") ),

		// Make sure that URLs aren't manipulated
		// (IE normalizes it by default)
		hrefNormalized: a.getAttribute("href") === "/a",

		// Make sure that element opacity exists
		// (IE uses filter instead)
		opacity: a.style.opacity === "0.5",

		// Verify style float existence
		// (IE uses styleFloat instead of cssFloat)
		cssFloat: !!a.style.cssFloat,

		// Will be defined later
		scriptEval: false,
		noCloneEvent: true,
		boxModel: null
	};

	script.type = "text/javascript";
	try {
		script.appendChild( document.createTextNode( "window." + id + "=1;" ) );
	} catch(e){}

	root.insertBefore( script, root.firstChild );

	// Make sure that the execution of code works by injecting a script
	// tag with appendChild/createTextNode
	// (IE doesn't support this, fails, and uses .text instead)
	if ( window[ id ] ) {
		jQuery.support.scriptEval = true;
		delete window[ id ];
	}

	root.removeChild( script );

	if ( div.attachEvent && div.fireEvent ) {
		div.attachEvent("onclick", function(){
			// Cloning a node shouldn't copy over any
			// bound event handlers (IE does this)
			jQuery.support.noCloneEvent = false;
			div.detachEvent("onclick", arguments.callee);
		});
		div.cloneNode(true).fireEvent("onclick");
	}

	// Figure out if the W3C box model works as expected
	// document.body must exist before we can do this
	jQuery(function(){
		var div = document.createElement("div");
		div.style.width = div.style.paddingLeft = "1px";

		document.body.appendChild( div );
		jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2;
		document.body.removeChild( div ).style.display = 'none';
	});
})();

var styleFloat = jQuery.support.cssFloat ? "cssFloat" : "styleFloat";

jQuery.props = {
	"for": "htmlFor",
	"class": "className",
	"float": styleFloat,
	cssFloat: styleFloat,
	styleFloat: styleFloat,
	readonly: "readOnly",
	maxlength: "maxLength",
	cellspacing: "cellSpacing",
	rowspan: "rowSpan",
	tabindex: "tabIndex"
};
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);
		}

		// 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 if( typeof params === "object" ) {
				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 );

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

	serialize: function() {
		return jQuery.param(this.serializeArray());
	},
	serializeArray: function() {
		return this.map(function(){
			return this.elements ? jQuery.makeArray(this.elements) : this;
		})
		.filter(function(){
			return this.name && !this.disabled &&
				(this.checked || /select|textarea/i.test(this.nodeName) ||
					/text|hidden|password|search/i.test(this.type));
		})
		.map(function(i, elem){
			var val = jQuery(this).val();
			return val == null ? null :
				jQuery.isArray(val) ?
					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",
		contentType: "application/x-www-form-urlencoded",
		processData: true,
		async: true,
		/*
		timeout: 0,
		data: null,
		username: null,
		password: null,
		*/
		// Create the request object; Microsoft failed to properly
		// implement the XMLHttpRequest in IE7, so we use the ActiveXObject when it is available
		// This function can be overriden by calling jQuery.ajaxSetup
		xhr:function(){
			return window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();
		},
		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 parts = /^(\w+:)?\/\/([^\/?#]+)/.exec( s.url );

		// If we're requesting a remote document
		// and trying to load JSON or Script with a GET
		if ( s.dataType == "script" && type == "GET" && parts
			&& ( parts[1] && parts[1] != location.protocol || parts[2] != 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();

						// Handle memory leak in IE
						script.onload = script.onreadystatechange = null;
						head.removeChild( script );
					}
				};
			}

			head.appendChild(script);

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

		var requestDone = false;

		// Create the request object
		var xhr = s.xhr();

		// 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 and early abort
		if ( s.beforeSend && s.beforeSend(xhr, s) === false ) {
			// Handle the global AJAX counter
			if ( s.global && ! --jQuery.active )
				jQuery.event.trigger( "ajaxStop" );
			// 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 request was aborted, clear the interval and decrement jQuery.active
			if (xhr.readyState == 0) {
				if (ival) {
					// clear poll interval
					clearInterval(ival);
					ival = null;
					// Handle the global AJAX counter
					if ( s.global && ! --jQuery.active )
						jQuery.event.trigger( "ajaxStop" );
				}
			// The transfer is complete and the data is available, or the request timed out
			} else 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 );
					} 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();

				if ( isTimeout )
					xhr.abort();

				// 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 && !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;
		} 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];
		} catch(e){}
		return false;
	},

	httpData: function( xhr, type, s ) {
		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
		// s != null is checked to keep backwards compatibility
		if( s && s.dataFilter )
			data = s.dataFilter( data, type );

		// The filter can actually parse the response
		if( typeof data === "string" ){

			// 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 = window["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 = [ ];

		function add( key, value ){
			s[ s.length ] = encodeURIComponent(key) + '=' + encodeURIComponent(value);
		};

		// If an array was passed in, assume that it is an array
		// of form elements
		if ( jQuery.isArray(a) || a.jquery )
			// Serialize the form elements
			jQuery.each( a, function(){
				add( this.name, 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 ( jQuery.isArray(a[j]) )
					jQuery.each( a[j], function(){
						add( j, this );
					});
				else
					add( j, jQuery.isFunction(a[j]) ? a[j]() : a[j] );

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

});
var elemdisplay = {},
	timerId,
	fxAttrs = [
		// height animations
		[ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ],
		// width animations
		[ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ],
		// opacity animations
		[ "opacity" ]
	];

function genFx( type, num ){
	var obj = {};
	jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice(0,num)), function(){
		obj[ this ] = type;
	});
	return obj;
}

jQuery.fn.extend({
	show: function(speed,callback){
		if ( speed ) {
			return this.animate( genFx("show", 3), speed, callback);
		} else {
			for ( var i = 0, l = this.length; i < l; i++ ){
				var old = jQuery.data(this[i], "olddisplay");

				this[i].style.display = old || "";

				if ( jQuery.css(this[i], "display") === "none" ) {
					var tagName = this[i].tagName, display;

					if ( elemdisplay[ tagName ] ) {
						display = elemdisplay[ tagName ];
					} else {
						var elem = jQuery("<" + tagName + " />").appendTo("body");

						display = elem.css("display");
						if ( display === "none" )
							display = "block";

						elem.remove();

						elemdisplay[ tagName ] = display;
					}

					jQuery.data(this[i], "olddisplay", display);
				}
			}

			// Set the display of the elements in a second loop
			// to avoid the constant reflow
			for ( var i = 0, l = this.length; i < l; i++ ){
				this[i].style.display = jQuery.data(this[i], "olddisplay") || "";
			}

			return this;
		}
	},

	hide: function(speed,callback){
		if ( speed ) {
			return this.animate( genFx("hide", 3), speed, callback);
		} else {
			for ( var i = 0, l = this.length; i < l; i++ ){
				var old = jQuery.data(this[i], "olddisplay");
				if ( !old && old !== "none" )
					jQuery.data(this[i], "olddisplay", jQuery.css(this[i], "display"));
			}

			// Set the display of the elements in a second loop
			// to avoid the constant reflow
			for ( var i = 0, l = this.length; i < l; i++ ){
				this[i].style.display = "none";
			}

			return this;
		}
	},

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

	toggle: function( fn, fn2 ){
		var bool = typeof fn === "boolean";

		return jQuery.isFunction(fn) && jQuery.isFunction(fn2) ?
			this._toggle.apply( this, arguments ) :
			fn == null || bool ?
				this.each(function(){
					var state = bool ? fn : jQuery(this).is(":hidden");
					jQuery(this)[ state ? "show" : "hide" ]();
				}) :
				this.animate(genFx("toggle", 3), fn, fn2);
	},

	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(){

			var opt = jQuery.extend({}, optall), p,
				hidden = this.nodeType == 1 && 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" ) && this.style ) {
					// 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;
		});
	},

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

});

// Generate shortcuts for custom animations
jQuery.each({
	slideDown: genFx("show", 1),
	slideUp: genFx("hide", 1),
	slideToggle: genFx("toggle", 1),
	fadeIn: { opacity: "show" },
	fadeOut: { opacity: "hide" }
}, function( name, props ){
	jQuery.fn[ name ] = function( speed, callback ){
		return this.animate( props, speed, callback );
	};
});

jQuery.extend({

	speed: function(speed, easing, fn) {
		var opt = typeof speed === "object" ? speed : {
			complete: fn || !fn && easing ||
				jQuery.isFunction( speed ) && speed,
			duration: speed,
			easing: fn && easing || easing && !jQuery.isFunction(easing) && easing
		};

		opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
			jQuery.fx.speeds[opt.duration] || jQuery.fx.speeds._default;

		// 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: [],

	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 )
			this.elem.style.display = "block";
	},

	// Get the current size
	cur: function(force){
		if ( this.elem[this.prop] != null && (!this.elem.style || 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;

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

		t.elem = this.elem;

		if ( t() && jQuery.timers.push(t) && !timerId ) {
			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( timerId );
					timerId = undefined;
				}
			}, 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
		// Make sure that we start at a small width/height to avoid any
		// flash of content
		this.custom(this.prop == "width" || this.prop == "height" ? 1 : 0, this.cur());

		// 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 )
					jQuery(this.elem).hide();

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

				// 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
 		_default: 400
	},
	step: {

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

		_default: function(fx){
			if ( fx.elem.style && fx.elem.style[ fx.prop ] != null )
				fx.elem.style[ fx.prop ] = fx.now + fx.unit;
			else
				fx.elem[ fx.prop ] = fx.now;
		}
	}
});
if ( document.documentElement["getBoundingClientRect"] )
	jQuery.fn.offset = function() {
		if ( !this[0] ) return { top: 0, left: 0 };
		if ( this[0] === this[0].ownerDocument.body ) return jQuery.offset.bodyOffset( this[0] );
		var box  = this[0].getBoundingClientRect(), doc = this[0].ownerDocument, body = doc.body, docElem = doc.documentElement,
			clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0,
			top  = box.top  + (self.pageYOffset || jQuery.boxModel && docElem.scrollTop  || body.scrollTop ) - clientTop,
			left = box.left + (self.pageXOffset || jQuery.boxModel && docElem.scrollLeft || body.scrollLeft) - clientLeft;
		return { top: top, left: left };
	};
else
	jQuery.fn.offset = function() {
		if ( !this[0] ) return { top: 0, left: 0 };
		if ( this[0] === this[0].ownerDocument.body ) return jQuery.offset.bodyOffset( this[0] );
		jQuery.offset.initialized || jQuery.offset.initialize();

		var elem = this[0], offsetParent = elem.offsetParent, prevOffsetParent = elem,
			doc = elem.ownerDocument, computedStyle, docElem = doc.documentElement,
			body = doc.body, defaultView = doc.defaultView,
			prevComputedStyle = defaultView.getComputedStyle(elem, null),
			top = elem.offsetTop, left = elem.offsetLeft;

		while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {
			computedStyle = defaultView.getComputedStyle(elem, null);
			top -= elem.scrollTop, left -= elem.scrollLeft;
			if ( elem === offsetParent ) {
				top += elem.offsetTop, left += elem.offsetLeft;
				if ( jQuery.offset.doesNotAddBorder && !(jQuery.offset.doesAddBorderForTableAndCells && /^t(able|d|h)$/i.test(elem.tagName)) )
					top  += parseInt( computedStyle.borderTopWidth,  10) || 0,
					left += parseInt( computedStyle.borderLeftWidth, 10) || 0;
				prevOffsetParent = offsetParent, offsetParent = elem.offsetParent;
			}
			if ( jQuery.offset.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" )
				top  += parseInt( computedStyle.borderTopWidth,  10) || 0,
				left += parseInt( computedStyle.borderLeftWidth, 10) || 0;
			prevComputedStyle = computedStyle;
		}

		if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" )
			top  += body.offsetTop,
			left += body.offsetLeft;

		if ( prevComputedStyle.position === "fixed" )
			top  += Math.max(docElem.scrollTop, body.scrollTop),
			left += Math.max(docElem.scrollLeft, body.scrollLeft);

		return { top: top, left: left };
	};

jQuery.offset = {
	initialize: function() {
		if ( this.initialized ) return;
		var body = document.body, container = document.createElement('div'), innerDiv, checkDiv, table, td, rules, prop, bodyMarginTop = body.style.marginTop,
			html = '<div style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;"><div></div></div><table style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;" cellpadding="0" cellspacing="0"><tr><td></td></tr></table>';

		rules = { position: 'absolute', top: 0, left: 0, margin: 0, border: 0, width: '1px', height: '1px', visibility: 'hidden' };
		for ( prop in rules ) container.style[prop] = rules[prop];

		container.innerHTML = html;
		body.insertBefore(container, body.firstChild);
		innerDiv = container.firstChild, checkDiv = innerDiv.firstChild, td = innerDiv.nextSibling.firstChild.firstChild;

		this.doesNotAddBorder = (checkDiv.offsetTop !== 5);
		this.doesAddBorderForTableAndCells = (td.offsetTop === 5);

		innerDiv.style.overflow = 'hidden', innerDiv.style.position = 'relative';
		this.subtractsBorderForOverflowNotVisible = (checkDiv.offsetTop === -5);

		body.style.marginTop = '1px';
		this.doesNotIncludeMarginInBodyOffset = (body.offsetTop === 0);
		body.style.marginTop = bodyMarginTop;

		body.removeChild(container);
		this.initialized = true;
	},

	bodyOffset: function(body) {
		jQuery.offset.initialized || jQuery.offset.initialize();
		var top = body.offsetTop, left = body.offsetLeft;
		if ( jQuery.offset.doesNotIncludeMarginInBodyOffset )
			top  += parseInt( jQuery.curCSS(body, 'marginTop',  true), 10 ) || 0,
			left += parseInt( jQuery.curCSS(body, 'marginLeft', true), 10 ) || 0;
		return { top: top, left: left };
	}
};


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 || document.body;
		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 null;

		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
		lower = name.toLowerCase();

	// innerHeight and innerWidth
	jQuery.fn["inner" + name] = function(){
		return this[0] ?
			jQuery.css( this[0], lower, false, "padding" ) :
			null;
	};

	// outerHeight and outerWidth
	jQuery.fn["outer" + name] = function(margin) {
		return this[0] ?
			jQuery.css( this[0], lower, false, margin ? "margin" : "border" ) :
			null;
	};

	var type = name.toLowerCase();

	jQuery.fn[ type ] = function( size ) {
		// Get window width or height
		return this[0] == window ?
			// 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(
					document.documentElement["client" + name],
					document.body["scroll" + name], document.documentElement["scroll" + name],
					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, typeof size === "string" ? size : size + "px" );
	};

});
})();
/* jquery.tabs.js (142) */
/***
 * Tabs - jQuery plugin for accessible, unobtrusive tabs
 * @requires jQuery v1.1.1
 *
 * http://stilbuero.de/tabs/
 *
 * Copyright (c) 2006 Klaus Hartl (stilbuero.de)
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 *
 * Version: 2.7.4
 */

(function($) { // block scope

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

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

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

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

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

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

        // remember wrapper for later
        var container = this;

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

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

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

            });
        }

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

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

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

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

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

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

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

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

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

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

            var hash = this.hash;

            if ($.browser.msie) {

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

            } else if ($.browser.safari) {

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

            } else {

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

            }

        });

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

        });

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

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

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

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

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

            container['locked'] = true;

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

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

                var resetCSS = { display: '', overflow: '', height: '' };
                if (!$.browser.msie) { // not in IE to prevent ClearType font issue
                    resetCSS['opacity'] = '';
                }

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

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

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

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

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

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

        });

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

    });

};

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

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

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

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

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

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

})(jQuery);
/* jquery.tablesorter.js (138) */
/***
 *
 * TableSorter 2.0 - Client-side table sorting with ease!
 * Version 2.0.3
 * @requires jQuery v1.2.3
 *
 * Copyright (c) 2007 Christian Bach
 * Examples and docs at: http://tablesorter.com
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 *
 */
/**
 *
 * @description Create a sortable table with multi-column sorting capabilitys
 *
 * @example $('table').tablesorter();
 * @desc Create a simple tablesorter interface.
 *
 * @example $('table').tablesorter({ sortList:[[0,0],[1,0]] });
 * @desc Create a tablesorter interface and sort on the first and secound column in ascending order.
 *
 * @example $('table').tablesorter({ headers: { 0: { sorter: false}, 1: {sorter: false} } });
 * @desc Create a tablesorter interface and disableing the first and secound column headers.
 *
 * @example $('table').tablesorter({ 0: {sorter:"integer"}, 1: {sorter:"currency"} });
 * @desc Create a tablesorter interface and set a column parser for the first and secound column.
 *
 *
 * @param Object settings An object literal containing key/value pairs to provide optional settings.
 *
 * @option String cssHeader (optional) 			A string of the class name to be appended to sortable tr elements in the thead of the table.
 * 												Default value: "header"
 *
 * @option String cssAsc (optional) 			A string of the class name to be appended to sortable tr elements in the thead on a ascending sort.
 * 												Default value: "headerSortUp"
 *
 * @option String cssDesc (optional) 			A string of the class name to be appended to sortable tr elements in the thead on a descending sort.
 * 												Default value: "headerSortDown"
 *
 * @option String sortInitialOrder (optional) 	A string of the inital sorting order can be asc or desc.
 * 												Default value: "asc"
 *
 * @option String sortMultisortKey (optional) 	A string of the multi-column sort key.
 * 												Default value: "shiftKey"
 *
 * @option String textExtraction (optional) 	A string of the text-extraction method to use.
 * 												For complex html structures inside td cell set this option to "complex",
 * 												on large tables the complex option can be slow.
 * 												Default value: "simple"
 *
 * @option Object headers (optional) 			An array containing the forces sorting rules.
 * 												This option let's you specify a default sorting rule.
 * 												Default value: null
 *
 * @option Array sortList (optional) 			An array containing the forces sorting rules.
 * 												This option let's you specify a default sorting rule.
 * 												Default value: null
 *
 * @option Array sortForce (optional) 			An array containing forced sorting rules.
 * 												This option let's you specify a default sorting rule, which is prepended to user-selected rules.
 * 												Default value: null
 *
  * @option Array sortAppend (optional) 			An array containing forced sorting rules.
 * 												This option let's you specify a default sorting rule, which is appended to user-selected rules.
 * 												Default value: null
 *
 * @option Boolean widthFixed (optional) 		Boolean flag indicating if tablesorter should apply fixed widths to the table columns.
 * 												This is usefull when using the pager companion plugin.
 * 												This options requires the dimension jquery plugin.
 * 												Default value: false
 *
 * @option Boolean cancelSelection (optional) 	Boolean flag indicating if tablesorter should cancel selection of the table headers text.
 * 												Default value: true
 *
 * @option Boolean debug (optional) 			Boolean flag indicating if tablesorter should display debuging information usefull for development.
 *
 * @type jQuery
 *
 * @name tablesorter
 *
 * @cat Plugins/Tablesorter
 *
 * @author Christian Bach/christian.bach@polyester.se
 */

(function($) {
	$.extend({
		tablesorter: new function() {

			var parsers = [], widgets = [];

			this.defaults = {
				cssHeader: "header",
				cssAsc: "headerSortUp",
				cssDesc: "headerSortDown",
				sortInitialOrder: "asc",
				sortMultiSortKey: "shiftKey",
				sortForce: null,
				sortAppend: null,
				textExtraction: "simple",
				parsers: {},
				widgets: [],
				widgetZebra: {css: ["even","odd"]},
				headers: {},
				widthFixed: false,
				cancelSelection: true,
				sortList: [],
				headerList: [],
				dateFormat: "us",
				decimal: '.',
				debug: false
			};

			/* debuging utils */
			function benchmark(s,d) {
				log(s + "," + (new Date().getTime() - d.getTime()) + "ms");
			}

			this.benchmark = benchmark;

			function log(s) {
				if (typeof console != "undefined" && typeof console.debug != "undefined") {
					console.log(s);
				} else {
					alert(s);
				}
			}

			/* parsers utils */
			function buildParserCache(table,$headers) {

				if(table.config.debug) { var parsersDebug = ""; }

				var rows = table.tBodies[0].rows;

				if(table.tBodies[0].rows[0]) {

					var list = [], cells = rows[0].cells, l = cells.length;

					for (var i=0;i < l; i++) {
						var p = false;

						if($.metadata && ($($headers[i]).metadata() && $($headers[i]).metadata().sorter)  ) {

							p = getParserById($($headers[i]).metadata().sorter);

						} else if((table.config.headers[i] && table.config.headers[i].sorter)) {

							p = getParserById(table.config.headers[i].sorter);
						}
						if(!p) {
							p = detectParserForColumn(table,cells[i]);
						}

						if(table.config.debug) { parsersDebug += "column:" + i + " parser:" +p.id + "\n"; }

						list.push(p);
					}
				}

				if(table.config.debug) { log(parsersDebug); }

				return list;
			};

			function detectParserForColumn(table,node) {
				var l = parsers.length;
				for(var i=1; i < l; i++) {
					if(parsers[i].is($.trim(getElementText(table.config,node)),table,node)) {
						return parsers[i];
					}
				}
				// 0 is always the generic parser (text)
				return parsers[0];
			}

			function getParserById(name) {
				var l = parsers.length;
				for(var i=0; i < l; i++) {
					if(parsers[i].id.toLowerCase() == name.toLowerCase()) {
						return parsers[i];
					}
				}
				return false;
			}

			/* utils */
			function buildCache(table) {

				if(table.config.debug) { var cacheTime = new Date(); }


				var totalRows = (table.tBodies[0] && table.tBodies[0].rows.length) || 0,
					totalCells = (table.tBodies[0].rows[0] && table.tBodies[0].rows[0].cells.length) || 0,
					parsers = table.config.parsers,
					cache = {row: [], normalized: []};

					for (var i=0;i < totalRows; ++i) {

						/** Add the table data to main data array */
						var c = table.tBodies[0].rows[i], cols = [];

						cache.row.push($(c));

						for(var j=0; j < totalCells; ++j) {
							cols.push(parsers[j].format(getElementText(table.config,c.cells[j]),table,c.cells[j]));
						}

						cols.push(i); // add position for rowCache
						cache.normalized.push(cols);
						cols = null;
					};

				if(table.config.debug) { benchmark("Building cache for " + totalRows + " rows:", cacheTime); }

				return cache;
			};

			function getElementText(config,node) {

				if(!node) return "";

				var t = "";

				if(config.textExtraction == "simple") {
					if(node.childNodes[0] && node.childNodes[0].hasChildNodes()) {
						t = node.childNodes[0].innerHTML;
					} else {
						t = node.innerHTML;
					}
				} else {
					if(typeof(config.textExtraction) == "function") {
						t = config.textExtraction(node);
					} else {
						t = $(node).text();
					}
				}
				return t;
			}

			function appendToTable(table,cache) {

				if(table.config.debug) {var appendTime = new Date()}

				var c = cache,
					r = c.row,
					n= c.normalized,
					totalRows = n.length,
					checkCell = (n[0].length-1),
					tableBody = $(table.tBodies[0]),
					rows = [];

				for (var i=0;i < totalRows; i++) {
					rows.push(r[n[i][checkCell]]);
					if(!table.config.appender) {

						var o = r[n[i][checkCell]];
						var l = o.length;
						for(var j=0; j < l; j++) {

							tableBody[0].appendChild(o[j]);

						}

						//tableBody.append(r[n[i][checkCell]]);
					}
				}

				if(table.config.appender) {

					table.config.appender(table,rows);
				}

				rows = null;

				if(table.config.debug) { benchmark("Rebuilt table:", appendTime); }

				//apply table widgets
				applyWidget(table);

				// trigger sortend
				setTimeout(function() {
					$(table).trigger("sortEnd");
				},0);

			};

			function buildHeaders(table) {

				if(table.config.debug) { var time = new Date(); }

				var meta = ($.metadata) ? true : false, tableHeadersRows = [];

				for(var i = 0; i < table.tHead.rows.length; i++) { tableHeadersRows[i]=0; };

				$tableHeaders = $("thead th",table);

				$tableHeaders.each(function(index) {

					this.count = 0;
					this.column = index;
					this.order = formatSortingOrder(table.config.sortInitialOrder);

					if(checkHeaderMetadata(this) || checkHeaderOptions(table,index)) this.sortDisabled = true;

					if(!this.sortDisabled) {
						$(this).addClass(table.config.cssHeader);
					}

					// add cell to headerList
					table.config.headerList[index]= this;
				});

				if(table.config.debug) { benchmark("Built headers:", time); log($tableHeaders); }

				return $tableHeaders;

			};

		   	function checkCellColSpan(table, rows, row) {
                var arr = [], r = table.tHead.rows, c = r[row].cells;

				for(var i=0; i < c.length; i++) {
					var cell = c[i];

					if ( cell.colSpan > 1) {
						arr = arr.concat(checkCellColSpan(table, headerArr,row++));
					} else  {
						if(table.tHead.length == 1 || (cell.rowSpan > 1 || !r[row+1])) {
							arr.push(cell);
						}
						//headerArr[row] = (i+row);
					}
				}
				return arr;
			};

			function checkHeaderMetadata(cell) {
				if(($.metadata) && ($(cell).metadata().sorter === false)) { return true; };
				return false;
			}

			function checkHeaderOptions(table,i) {
				if((table.config.headers[i]) && (table.config.headers[i].sorter === false)) { return true; };
				return false;
			}

			function applyWidget(table) {
				var c = table.config.widgets;
				var l = c.length;
				for(var i=0; i < l; i++) {

					getWidgetById(c[i]).format(table);
				}

			}

			function getWidgetById(name) {
				var l = widgets.length;
				for(var i=0; i < l; i++) {
					if(widgets[i].id.toLowerCase() == name.toLowerCase() ) {
						return widgets[i];
					}
				}
			};

			function formatSortingOrder(v) {

				if(typeof(v) != "Number") {
					i = (v.toLowerCase() == "desc") ? 1 : 0;
				} else {
					i = (v == (0 || 1)) ? v : 0;
				}
				return i;
			}

			function isValueInArray(v, a) {
				var l = a.length;
				for(var i=0; i < l; i++) {
					if(a[i][0] == v) {
						return true;
					}
				}
				return false;
			}

			function setHeadersCss(table,$headers, list, css) {
				// remove all header information
				$headers.removeClass(css[0]).removeClass(css[1]);

				var h = [];
				$headers.each(function(offset) {
						if(!this.sortDisabled) {
							h[this.column] = $(this);
						}
				});

				var l = list.length;
				for(var i=0; i < l; i++) {
					h[list[i][0]].addClass(css[list[i][1]]);
				}
			}

			function fixColumnWidth(table,$headers) {
				var c = table.config;
				if(c.widthFixed) {
					var colgroup = $('<colgroup>');
					$("tr:first td",table.tBodies[0]).each(function() {
						colgroup.append($('<col>').css('width',$(this).width()));
					});
					$(table).prepend(colgroup);
				};
			}

			function updateHeaderSortCount(table,sortList) {
				var c = table.config, l = sortList.length;
				for(var i=0; i < l; i++) {
					var s = sortList[i], o = c.headerList[s[0]];
					o.count = s[1];
					o.count++;
				}
			}

			/* sorting methods */
			function multisort(table,sortList,cache) {

				if(table.config.debug) { var sortTime = new Date(); }

				var dynamicExp = "var sortWrapper = function(a,b) {", l = sortList.length;

				for(var i=0; i < l; i++) {

					var c = sortList[i][0];
					var order = sortList[i][1];
					var s = (getCachedSortType(table.config.parsers,c) == "text") ? ((order == 0) ? "sortText" : "sortTextDesc") : ((order == 0) ? "sortNumeric" : "sortNumericDesc");

					var e = "e" + i;

					dynamicExp += "var " + e + " = " + s + "(a[" + c + "],b[" + c + "]); ";
					dynamicExp += "if(" + e + ") { return " + e + "; } ";
					dynamicExp += "else { ";
				}

				// if value is the same keep orignal order
				var orgOrderCol = cache.normalized[0].length - 1;
				dynamicExp += "return a[" + orgOrderCol + "]-b[" + orgOrderCol + "];";

				for(var i=0; i < l; i++) {
					dynamicExp += "}; ";
				}

				dynamicExp += "return 0; ";
				dynamicExp += "}; ";

				eval(dynamicExp);

				cache.normalized.sort(sortWrapper);

				if(table.config.debug) { benchmark("Sorting on " + sortList.toString() + " and dir " + order+ " time:", sortTime); }

				return cache;
			};

			function sortText(a,b) {
				return ((a < b) ? -1 : ((a > b) ? 1 : 0));
			};

			function sortTextDesc(a,b) {
				return ((b < a) ? -1 : ((b > a) ? 1 : 0));
			};

	 		function sortNumeric(a,b) {
				return a-b;
			};

			function sortNumericDesc(a,b) {
				return b-a;
			};

			function getCachedSortType(parsers,i) {
				return parsers[i].type;
			};

			/* public methods */
			this.construct = function(settings) {

				return this.each(function() {

					if(!this.tHead || !this.tBodies) return;

					var $this, $document,$headers, cache, config, shiftDown = 0, sortOrder;

					this.config = {};

					config = $.extend(this.config, $.tablesorter.defaults, settings);

					// store common expression for speed
					$this = $(this);

					// build headers
					$headers = buildHeaders(this);

					// try to auto detect column type, and store in tables config
					this.config.parsers = buildParserCache(this,$headers);


					// build the cache for the tbody cells
					cache = buildCache(this);

					// get the css class names, could be done else where.
					var sortCSS = [config.cssDesc,config.cssAsc];

					// fixate columns if the users supplies the fixedWidth option
					fixColumnWidth(this);

					// apply event handling to headers
					// this is to big, perhaps break it out?
					$headers.click(function(e) {

						$this.trigger("sortStart");

						var totalRows = ($this[0].tBodies[0] && $this[0].tBodies[0].rows.length) || 0;

						if(!this.sortDisabled && totalRows > 0) {


							// store exp, for speed
							var $cell = $(this);

							// get current column index
							var i = this.column;

							// get current column sort order
							this.order = this.count++ % 2;

							// user only whants to sort on one column
							if(!e[config.sortMultiSortKey]) {

								// flush the sort list
								config.sortList = [];

								if(config.sortForce != null) {
									var a = config.sortForce;
									for(var j=0; j < a.length; j++) {
										if(a[j][0] != i) {
											config.sortList.push(a[j]);
										}
									}
								}

								// add column to sort list
								config.sortList.push([i,this.order]);

							// multi column sorting
							} else {
								// the user has clicked on an all ready sortet column.
								if(isValueInArray(i,config.sortList)) {

									// revers the sorting direction for all tables.
									for(var j=0; j < config.sortList.length; j++) {
										var s = config.sortList[j], o = config.headerList[s[0]];
										if(s[0] == i) {
											o.count = s[1];
											o.count++;
											s[1] = o.count % 2;
										}
									}
								} else {
									// add column to sort list array
									config.sortList.push([i,this.order]);
								}
							};
							setTimeout(function() {
								//set css for headers
								setHeadersCss($this[0],$headers,config.sortList,sortCSS);
								appendToTable($this[0],multisort($this[0],config.sortList,cache));
							},1);
							// stop normal event by returning false
							return false;
						}
					// cancel selection
					}).mousedown(function() {
						if(config.cancelSelection) {
							this.onselectstart = function() {return false};
							return false;
						}
					});

					// apply easy methods that trigger binded events
					$this.bind("update",function() {

						// rebuild parsers.
						this.config.parsers = buildParserCache(this,$headers);

						// rebuild the cache map
						cache = buildCache(this);

					}).bind("sorton",function(e,list) {

						$(this).trigger("sortStart");

						config.sortList = list;

						// update and store the sortlist
						var sortList = config.sortList;

						// update header count index
						updateHeaderSortCount(this,sortList);

						//set css for headers
						setHeadersCss(this,$headers,sortList,sortCSS);


						// sort the table and append it to the dom
						appendToTable(this,multisort(this,sortList,cache));

					}).bind("appendCache",function() {

						appendToTable(this,cache);

					}).bind("applyWidgetId",function(e,id) {

						getWidgetById(id).format(this);

					}).bind("applyWidgets",function() {
						// apply widgets
						applyWidget(this);
					});

					if($.metadata && ($(this).metadata() && $(this).metadata().sortlist)) {
						config.sortList = $(this).metadata().sortlist;
					}
					// if user has supplied a sort list to constructor.
					if(config.sortList.length > 0) {
						$this.trigger("sorton",[config.sortList]);
					}

					// apply widgets
					applyWidget(this);
				});
			};

			this.addParser = function(parser) {
				var l = parsers.length, a = true;
				for(var i=0; i < l; i++) {
					if(parsers[i].id.toLowerCase() == parser.id.toLowerCase()) {
						a = false;
					}
				}
				if(a) { parsers.push(parser); };
			};

			this.addWidget = function(widget) {
				widgets.push(widget);
			};

			this.formatFloat = function(s) {
				var i = parseFloat(s);
				return (isNaN(i)) ? 0 : i;
			};
			this.formatInt = function(s) {
				var i = parseInt(s);
				return (isNaN(i)) ? 0 : i;
			};

			this.isDigit = function(s,config) {
				var DECIMAL = '\\' + config.decimal;
				var exp = '/(^[+]?0(' + DECIMAL +'0+)?$)|(^([-+]?[1-9][0-9]*)$)|(^([-+]?((0?|[1-9][0-9]*)' + DECIMAL +'(0*[1-9][0-9]*)))$)|(^[-+]?[1-9]+[0-9]*' + DECIMAL +'0+$)/';
				return RegExp(exp).test($.trim(s));
			};

			this.clearTableBody = function(table) {
				if($.browser.msie) {
					function empty() {
						while ( this.firstChild ) this.removeChild( this.firstChild );
					}
					empty.apply(table.tBodies[0]);
				} else {
					table.tBodies[0].innerHTML = "";
				}
			};
		}
	});

	// extend plugin scope
	$.fn.extend({
        tablesorter: $.tablesorter.construct
	});

	var ts = $.tablesorter;

	// add default parsers
	ts.addParser({
		id: "text",
		is: function(s) {
			return true;
		},
		format: function(s) {
			return $.trim(s.toLowerCase());
		},
		type: "text"
	});

	ts.addParser({
		id: "digit",
		is: function(s,table) {
			var c = table.config;
			return $.tablesorter.isDigit(s,c);
		},
		format: function(s) {
			return $.tablesorter.formatFloat(s);
		},
		type: "numeric"
	});

	ts.addParser({
		id: "currency",
		is: function(s) {
			return /^[Ã‚Â£$Ã¢â€šÂ¬?.]/.test(s);
		},
		format: function(s) {
			return $.tablesorter.formatFloat(s.replace(new RegExp(/[^0-9.]/g),""));
		},
		type: "numeric"
	});

	ts.addParser({
		id: "ipAddress",
		is: function(s) {
			return /^\d{2,3}[\.]\d{2,3}[\.]\d{2,3}[\.]\d{2,3}$/.test(s);
		},
		format: function(s) {
			var a = s.split("."), r = "", l = a.length;
			for(var i = 0; i < l; i++) {
				var item = a[i];
			   	if(item.length == 2) {
					r += "0" + item;
			   	} else {
					r += item;
			   	}
			}
			return $.tablesorter.formatFloat(r);
		},
		type: "numeric"
	});

	ts.addParser({
		id: "url",
		is: function(s) {
			return /^(https?|ftp|file):\/\/$/.test(s);
		},
		format: function(s) {
			return jQuery.trim(s.replace(new RegExp(/(https?|ftp|file):\/\//),''));
		},
		type: "text"
	});

	ts.addParser({
		id: "isoDate",
		is: function(s) {
			return /^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(s);
		},
		format: function(s) {
			return $.tablesorter.formatFloat((s != "") ? new Date(s.replace(new RegExp(/-/g),"/")).getTime() : "0");
		},
		type: "numeric"
	});

	ts.addParser({
		id: "percent",
		is: function(s) {
			return /\%$/.test($.trim(s));
		},
		format: function(s) {
			return $.tablesorter.formatFloat(s.replace(new RegExp(/%/g),""));
		},
		type: "numeric"
	});

	ts.addParser({
		id: "usLongDate",
		is: function(s) {
			return s.match(new RegExp(/^[A-Za-z]{3,10}\.? [0-9]{1,2}, ([0-9]{4}|'?[0-9]{2}) (([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(AM|PM)))$/));
		},
		format: function(s) {
			return $.tablesorter.formatFloat(new Date(s).getTime());
		},
		type: "numeric"
	});

	ts.addParser({
		id: "shortDate",
		is: function(s) {
			return /\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}/.test(s);
		},
		format: function(s,table) {
			var c = table.config;
			s = s.replace(/\-/g,"/");
			if(c.dateFormat == "us") {
				// reformat the string in ISO format
				s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/, "$3/$1/$2");
			} else if(c.dateFormat == "uk") {
				//reformat the string in ISO format
				s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/, "$3/$2/$1");
			} else if(c.dateFormat == "dd/mm/yy" || c.dateFormat == "dd-mm-yy") {
				s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2})/, "$1/$2/$3");
			}
			return $.tablesorter.formatFloat(new Date(s).getTime());
		},
		type: "numeric"
	});

	ts.addParser({
	    id: "time",
	    is: function(s) {
	        return /^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(am|pm)))$/.test(s);
	    },
	    format: function(s) {
	        return $.tablesorter.formatFloat(new Date("2000/01/01 " + s).getTime());
	    },
	  type: "numeric"
	});


	ts.addParser({
	    id: "metadata",
	    is: function(s) {
	        return false;
	    },
	    format: function(s,table,cell) {
			var c = table.config, p = (!c.parserMetadataName) ? 'sortValue' : c.parserMetadataName;
	        return $(cell).metadata()[p];
	    },
	  type: "numeric"
	});

	// add default widgets
	ts.addWidget({
		id: "zebra",
		format: function(table) {
			if(table.config.debug) { var time = new Date(); }
			$("tr:visible",table.tBodies[0])
	        .filter(':even')
	        .removeClass(table.config.widgetZebra.css[1]).addClass(table.config.widgetZebra.css[0])
	        .end().filter(':odd')
	        .removeClass(table.config.widgetZebra.css[0]).addClass(table.config.widgetZebra.css[1]);
			if(table.config.debug) { $.tablesorter.benchmark("Applying Zebra widget", time); }
		}
	});
})(jQuery);
/* jquery.corner.js (154) */
/***
 * jQuery corner plugin: simple corner rounding
 * Examples and documentation at: http://jquery.malsup.com/corner/
 * version 2.03 (05-DEC-2009)
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 */

/**
 *  corner() takes a single string argument:  $('#myDiv').corner("effect corners width")
 *
 *  effect:  name of the effect to apply, such as round, bevel, notch, bite, etc (default is round).
 *  corners: one or more of: top, bottom, tr, tl, br, or bl.
 *           by default, all four corners are adorned.
 *  width:   width of the effect; in the case of rounded corners this is the radius.
 *           specify this value using the px suffix such as 10px (and yes, it must be pixels).
 *
 * @author Dave Methvin (http://methvin.com/jquery/jq-corner.html)
 * @author Mike Alsup   (http://jquery.malsup.com/corner/)
 */
;(function($) {

var ua = navigator.userAgent;
var moz = $.browser.mozilla && /gecko/i.test(ua);
var webkit = $.browser.safari && /Safari\/[5-9]/.test(ua);

var expr = $.browser.msie && (function() {
    var div = document.createElement('div');
    try { div.style.setExpression('width','0+0'); div.style.removeExpression('width'); }
    catch(e) { return false; }
    return true;
})();

function sz(el, p) {
    return parseInt($.css(el,p))||0;
};
function hex2(s) {
    var s = parseInt(s).toString(16);
    return ( s.length < 2 ) ? '0'+s : s;
};
function gpc(node) {
    for ( ; node && node.nodeName.toLowerCase() != 'html'; node = node.parentNode ) {
        var v = $.css(node,'backgroundColor');
        if (v == 'rgba(0, 0, 0, 0)')
            continue; // webkit
        if (v.indexOf('rgb') >= 0) {
            var rgb = v.match(/\d+/g);
            return '#'+ hex2(rgb[0]) + hex2(rgb[1]) + hex2(rgb[2]);
        }
        if ( v && v != 'transparent' )
            return v;
    }
    return '#ffffff';
};

function getWidth(fx, i, width) {
    switch(fx) {
    case 'round':  return Math.round(width*(1-Math.cos(Math.asin(i/width))));
    case 'cool':   return Math.round(width*(1+Math.cos(Math.asin(i/width))));
    case 'sharp':  return Math.round(width*(1-Math.cos(Math.acos(i/width))));
    case 'bite':   return Math.round(width*(Math.cos(Math.asin((width-i-1)/width))));
    case 'slide':  return Math.round(width*(Math.atan2(i,width/i)));
    case 'jut':    return Math.round(width*(Math.atan2(width,(width-i-1))));
    case 'curl':   return Math.round(width*(Math.atan(i)));
    case 'tear':   return Math.round(width*(Math.cos(i)));
    case 'wicked': return Math.round(width*(Math.tan(i)));
    case 'long':   return Math.round(width*(Math.sqrt(i)));
    case 'sculpt': return Math.round(width*(Math.log((width-i-1),width)));
    case 'dog':    return (i&1) ? (i+1) : width;
    case 'dog2':   return (i&2) ? (i+1) : width;
    case 'dog3':   return (i&3) ? (i+1) : width;
    case 'fray':   return (i%2)*width;
    case 'notch':  return width;
    case 'bevel':  return i+1;
    }
};

$.fn.corner = function(options) {
    // in 1.3+ we can fix mistakes with the ready state
	if (this.length == 0) {
        if (!$.isReady && this.selector) {
            var s = this.selector, c = this.context;
            $(function() {
                $(s,c).corner(options);
            });
        }
        return this;
	}

    return this.each(function(index){
		var $this = $(this);
		var o = [ options || '', $this.attr($.fn.corner.defaults.metaAttr) || ''].join(' ').toLowerCase();
		//var o = (options || $this.attr($.fn.corner.defaults.metaAttr) || '').toLowerCase();
		var keep = /keep/.test(o);                       // keep borders?
		var cc = ((o.match(/cc:(#[0-9a-f]+)/)||[])[1]);  // corner color
		var sc = ((o.match(/sc:(#[0-9a-f]+)/)||[])[1]);  // strip color
		var width = parseInt((o.match(/(\d+)px/)||[])[1]) || 10; // corner width
		var re = /round|bevel|notch|bite|cool|sharp|slide|jut|curl|tear|fray|wicked|sculpt|long|dog3|dog2|dog/;
		var fx = ((o.match(re)||['round'])[0]);
		var edges = { T:0, B:1 };
		var opts = {
			TL:  /top|tl|left/.test(o),       TR:  /top|tr|right/.test(o),
			BL:  /bottom|bl|left/.test(o),    BR:  /bottom|br|right/.test(o)
		};
		if ( !opts.TL && !opts.TR && !opts.BL && !opts.BR )
			opts = { TL:1, TR:1, BL:1, BR:1 };

		// support native rounding
		if ($.fn.corner.defaults.useNative && fx == 'round' && (moz || webkit) && !cc && !sc) {
			if (opts.TL)
				$this.css(moz ? '-moz-border-radius-topleft' : '-webkit-border-top-left-radius', width + 'px');
			if (opts.TR)
				$this.css(moz ? '-moz-border-radius-topright' : '-webkit-border-top-right-radius', width + 'px');
			if (opts.BL)
				$this.css(moz ? '-moz-border-radius-bottomleft' : '-webkit-border-bottom-left-radius', width + 'px');
			if (opts.BR)
				$this.css(moz ? '-moz-border-radius-bottomright' : '-webkit-border-bottom-right-radius', width + 'px');
			return;
		}

		var strip = document.createElement('div');
		strip.style.overflow = 'hidden';
		strip.style.height = '1px';
		strip.style.backgroundColor = sc || 'transparent';
		strip.style.borderStyle = 'solid';

        var pad = {
            T: parseInt($.css(this,'paddingTop'))||0,     R: parseInt($.css(this,'paddingRight'))||0,
            B: parseInt($.css(this,'paddingBottom'))||0,  L: parseInt($.css(this,'paddingLeft'))||0
        };

        if (typeof this.style.zoom != undefined) this.style.zoom = 1; // force 'hasLayout' in IE
        if (!keep) this.style.border = 'none';
        strip.style.borderColor = cc || gpc(this.parentNode);
        var cssHeight = $.curCSS(this, 'height');

        for (var j in edges) {
            var bot = edges[j];
            // only add stips if needed
            if ((bot && (opts.BL || opts.BR)) || (!bot && (opts.TL || opts.TR))) {
                strip.style.borderStyle = 'none '+(opts[j+'R']?'solid':'none')+' none '+(opts[j+'L']?'solid':'none');
                var d = document.createElement('div');
                $(d).addClass('jquery-corner');
                var ds = d.style;

                bot ? this.appendChild(d) : this.insertBefore(d, this.firstChild);

                if (bot && cssHeight != 'auto') {
                    if ($.css(this,'position') == 'static')
                        this.style.position = 'relative';
                    ds.position = 'absolute';
                    ds.bottom = ds.left = ds.padding = ds.margin = '0';
                    if (expr)
                        ds.setExpression('width', 'this.parentNode.offsetWidth');
                    else
                        ds.width = '100%';
                }
                else if (!bot && $.browser.msie) {
                    if ($.css(this,'position') == 'static')
                        this.style.position = 'relative';
                    ds.position = 'absolute';
                    ds.top = ds.left = ds.right = ds.padding = ds.margin = '0';

                    // fix ie6 problem when blocked element has a border width
                    if (expr) {
                        var bw = sz(this,'borderLeftWidth') + sz(this,'borderRightWidth');
                        ds.setExpression('width', 'this.parentNode.offsetWidth - '+bw+'+ "px"');
                    }
                    else
                        ds.width = '100%';
                }
                else {
                	ds.position = 'relative';
                    ds.margin = !bot ? '-'+pad.T+'px -'+pad.R+'px '+(pad.T-width)+'px -'+pad.L+'px' :
                                        (pad.B-width)+'px -'+pad.R+'px -'+pad.B+'px -'+pad.L+'px';
                }

                for (var i=0; i < width; i++) {
                    var w = Math.max(0,getWidth(fx,i, width));
                    var e = strip.cloneNode(false);
                    e.style.borderWidth = '0 '+(opts[j+'R']?w:0)+'px 0 '+(opts[j+'L']?w:0)+'px';
                    bot ? d.appendChild(e) : d.insertBefore(e, d.firstChild);
                }
            }
        }
    });
};

$.fn.uncorner = function() {
	if (moz || webkit)
		this.css(moz ? '-moz-border-radius' : '-webkit-border-radius', 0);
	$('div.jquery-corner', this).remove();
	return this;
};

// expose options
$.fn.corner.defaults = {
	useNative: true, // true if plugin should attempt to use native browser support for border radius rounding
	metaAttr:  'data-corner' // name of meta attribute to use for options
};

})(jQuery);
/* jquery.color.js (193) */
/*
 * jQuery Color Animations
 * Copyright 2007 John Resig
 * Released under the MIT and GPL licenses.
 */

(function(jQuery){

    // We override the animation for all of these color styles
    jQuery.each(['backgroundColor', 'borderBottomColor', 'borderLeftColor', 'borderRightColor', 'borderTopColor', 'color', 'outlineColor'], function(i,attr){
        jQuery.fx.step[attr] = function(fx){
            if ( fx.state == 0 ) {
                fx.start = getColor( fx.elem, attr );
                fx.end = getRGB( fx.end );
            }

            fx.elem.style[attr] = "rgb(" + [
                Math.max(Math.min( parseInt((fx.pos * (fx.end[0] - fx.start[0])) + fx.start[0]), 255), 0),
                Math.max(Math.min( parseInt((fx.pos * (fx.end[1] - fx.start[1])) + fx.start[1]), 255), 0),
                Math.max(Math.min( parseInt((fx.pos * (fx.end[2] - fx.start[2])) + fx.start[2]), 255), 0)
            ].join(",") + ")";
        }
    });

    // Color Conversion functions from highlightFade
    // By Blair Mitchelmore
    // http://jquery.offput.ca/highlightFade/

    // Parse strings looking for color tuples [255,255,255]
    function getRGB(color) {
        var result;

        // Check if we're already dealing with an array of colors
        if ( color && color.constructor == Array && color.length == 3 )
            return color;

        // Look for rgb(num,num,num)
        if (result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color))
            return [parseInt(result[1]), parseInt(result[2]), parseInt(result[3])];

        // Look for rgb(num%,num%,num%)
        if (result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(color))
            return [parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55];

        // Look for #a0b1c2
        if (result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color))
            return [parseInt(result[1],16), parseInt(result[2],16), parseInt(result[3],16)];

        // Look for #fff
        if (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color))
            return [parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16)];

        // Look for rgba(0, 0, 0, 0) == transparent in Safari 3
        if (result = /rgba\(0, 0, 0, 0\)/.exec(color))
            return colors['transparent'];

        // Otherwise, we're most likely dealing with a named color
        return colors[jQuery.trim(color).toLowerCase()];
    }

    function getColor(elem, attr) {
        var color;

        do {
            color = jQuery.curCSS(elem, attr);

            // Keep going until we find an element that has color, or we hit the body
            if ( color != '' && color != 'transparent' || jQuery.nodeName(elem, "body") )
                break;

            attr = "backgroundColor";
        } while ( elem = elem.parentNode );

        return getRGB(color);
    };

    // Some named colors to work with
    // From Interface by Stefan Petre
    // http://interface.eyecon.ro/

    var colors = {
        aqua:[0,255,255],
        azure:[240,255,255],
        beige:[245,245,220],
        black:[0,0,0],
        blue:[0,0,255],
        brown:[165,42,42],
        cyan:[0,255,255],
        darkblue:[0,0,139],
        darkcyan:[0,139,139],
        darkgrey:[169,169,169],
        darkgreen:[0,100,0],
        darkkhaki:[189,183,107],
        darkmagenta:[139,0,139],
        darkolivegreen:[85,107,47],
        darkorange:[255,140,0],
        darkorchid:[153,50,204],
        darkred:[139,0,0],
        darksalmon:[233,150,122],
        darkviolet:[148,0,211],
        fuchsia:[255,0,255],
        gold:[255,215,0],
        green:[0,128,0],
        indigo:[75,0,130],
        khaki:[240,230,140],
        lightblue:[173,216,230],
        lightcyan:[224,255,255],
        lightgreen:[144,238,144],
        lightgrey:[211,211,211],
        lightpink:[255,182,193],
        lightyellow:[255,255,224],
        lime:[0,255,0],
        magenta:[255,0,255],
        maroon:[128,0,0],
        navy:[0,0,128],
        olive:[128,128,0],
        orange:[255,165,0],
        pink:[255,192,203],
        purple:[128,0,128],
        violet:[128,0,128],
        red:[255,0,0],
        silver:[192,192,192],
        white:[255,255,255],
        yellow:[255,255,0],
        transparent: [255,255,255]
    };

})(jQuery);
/* jquery.ui.base.js (203) */
/***
 * jQuery UI 1.7.2
 *
 * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * http://docs.jquery.com/UI
 */
;jQuery.ui || (function($) {

var _remove = $.fn.remove,
	isFF2 = $.browser.mozilla && (parseFloat($.browser.version) < 1.9);

//Helper functions and ui object
$.ui = {
	version: "1.7.2",

	// $.ui.plugin is deprecated.  Use the proxy pattern instead.
	plugin: {
		add: function(module, option, set) {
			var proto = $.ui[module].prototype;
			for(var i in set) {
				proto.plugins[i] = proto.plugins[i] || [];
				proto.plugins[i].push([option, set[i]]);
			}
		},
		call: function(instance, name, args) {
			var set = instance.plugins[name];
			if(!set || !instance.element[0].parentNode) { return; }

			for (var i = 0; i < set.length; i++) {
				if (instance.options[set[i][0]]) {
					set[i][1].apply(instance.element, args);
				}
			}
		}
	},

	contains: function(a, b) {
		return document.compareDocumentPosition
			? a.compareDocumentPosition(b) & 16
			: a !== b && a.contains(b);
	},

	hasScroll: function(el, a) {

		//If overflow is hidden, the element might have extra content, but the user wants to hide it
		if ($(el).css('overflow') == 'hidden') { return false; }

		var scroll = (a && a == 'left') ? 'scrollLeft' : 'scrollTop',
			has = false;

		if (el[scroll] > 0) { return true; }

		// TODO: determine which cases actually cause this to happen
		// if the element doesn't have the scroll set, see if it's possible to
		// set the scroll
		el[scroll] = 1;
		has = (el[scroll] > 0);
		el[scroll] = 0;
		return has;
	},

	isOverAxis: function(x, reference, size) {
		//Determines when x coordinate is over "b" element axis
		return (x > reference) && (x < (reference + size));
	},

	isOver: function(y, x, top, left, height, width) {
		//Determines when x, y coordinates is over "b" element
		return $.ui.isOverAxis(y, top, height) && $.ui.isOverAxis(x, left, width);
	},

	keyCode: {
		BACKSPACE: 8,
		CAPS_LOCK: 20,
		COMMA: 188,
		CONTROL: 17,
		DELETE: 46,
		DOWN: 40,
		END: 35,
		ENTER: 13,
		ESCAPE: 27,
		HOME: 36,
		INSERT: 45,
		LEFT: 37,
		NUMPAD_ADD: 107,
		NUMPAD_DECIMAL: 110,
		NUMPAD_DIVIDE: 111,
		NUMPAD_ENTER: 108,
		NUMPAD_MULTIPLY: 106,
		NUMPAD_SUBTRACT: 109,
		PAGE_DOWN: 34,
		PAGE_UP: 33,
		PERIOD: 190,
		RIGHT: 39,
		SHIFT: 16,
		SPACE: 32,
		TAB: 9,
		UP: 38
	}
};

// WAI-ARIA normalization
if (isFF2) {
	var attr = $.attr,
		removeAttr = $.fn.removeAttr,
		ariaNS = "http://www.w3.org/2005/07/aaa",
		ariaState = /^aria-/,
		ariaRole = /^wairole:/;

	$.attr = function(elem, name, value) {
		var set = value !== undefined;

		return (name == 'role'
			? (set
				? attr.call(this, elem, name, "wairole:" + value)
				: (attr.apply(this, arguments) || "").replace(ariaRole, ""))
			: (ariaState.test(name)
				? (set
					? elem.setAttributeNS(ariaNS,
						name.replace(ariaState, "aaa:"), value)
					: attr.call(this, elem, name.replace(ariaState, "aaa:")))
				: attr.apply(this, arguments)));
	};

	$.fn.removeAttr = function(name) {
		return (ariaState.test(name)
			? this.each(function() {
				this.removeAttributeNS(ariaNS, name.replace(ariaState, ""));
			}) : removeAttr.call(this, name));
	};
}

//jQuery plugins
$.fn.extend({
	remove: function() {
		// Safari has a native remove event which actually removes DOM elements,
		// so we have to use triggerHandler instead of trigger (#3037).
		$("*", this).add(this).each(function() {
			$(this).triggerHandler("remove");
		});
		return _remove.apply(this, arguments );
	},

	enableSelection: function() {
		return this
			.attr('unselectable', 'off')
			.css('MozUserSelect', '')
			.unbind('selectstart.ui');
	},

	disableSelection: function() {
		return this
			.attr('unselectable', 'on')
			.css('MozUserSelect', 'none')
			.bind('selectstart.ui', function() { return false; });
	},

	scrollParent: function() {
		var scrollParent;
		if(($.browser.msie && (/(static|relative)/).test(this.css('position'))) || (/absolute/).test(this.css('position'))) {
			scrollParent = this.parents().filter(function() {
				return (/(relative|absolute|fixed)/).test($.curCSS(this,'position',1)) && (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1));
			}).eq(0);
		} else {
			scrollParent = this.parents().filter(function() {
				return (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1));
			}).eq(0);
		}

		return (/fixed/).test(this.css('position')) || !scrollParent.length ? $(document) : scrollParent;
	}
});


//Additional selectors
$.extend($.expr[':'], {
	data: function(elem, i, match) {
		return !!$.data(elem, match[3]);
	},

	focusable: function(element) {
		var nodeName = element.nodeName.toLowerCase(),
			tabIndex = $.attr(element, 'tabindex');
		return (/input|select|textarea|button|object/.test(nodeName)
			? !element.disabled
			: 'a' == nodeName || 'area' == nodeName
				? element.href || !isNaN(tabIndex)
				: !isNaN(tabIndex))
			// the element and all of its ancestors must be visible
			// the browser may report that the area is hidden
			&& !$(element)['area' == nodeName ? 'parents' : 'closest'](':hidden').length;
	},

	tabbable: function(element) {
		var tabIndex = $.attr(element, 'tabindex');
		return (isNaN(tabIndex) || tabIndex >= 0) && $(element).is(':focusable');
	}
});


// $.widget is a factory to create jQuery plugins
// taking some boilerplate code out of the plugin code
function getter(namespace, plugin, method, args) {
	function getMethods(type) {
		var methods = $[namespace][plugin][type] || [];
		return (typeof methods == 'string' ? methods.split(/,?\s+/) : methods);
	}

	var methods = getMethods('getter');
	if (args.length == 1 && typeof args[0] == 'string') {
		methods = methods.concat(getMethods('getterSetter'));
	}
	return ($.inArray(method, methods) != -1);
}

$.widget = function(name, prototype) {
	var namespace = name.split(".")[0];
	name = name.split(".")[1];

	// create plugin method
	$.fn[name] = function(options) {
		var isMethodCall = (typeof options == 'string'),
			args = Array.prototype.slice.call(arguments, 1);

		// prevent calls to internal methods
		if (isMethodCall && options.substring(0, 1) == '_') {
			return this;
		}

		// handle getter methods
		if (isMethodCall && getter(namespace, name, options, args)) {
			var instance = $.data(this[0], name);
			return (instance ? instance[options].apply(instance, args)
				: undefined);
		}

		// handle initialization and non-getter methods
		return this.each(function() {
			var instance = $.data(this, name);

			// constructor
			(!instance && !isMethodCall &&
				$.data(this, name, new $[namespace][name](this, options))._init());

			// method call
			(instance && isMethodCall && $.isFunction(instance[options]) &&
				instance[options].apply(instance, args));
		});
	};

	// create widget constructor
	$[namespace] = $[namespace] || {};
	$[namespace][name] = function(element, options) {
		var self = this;

		this.namespace = namespace;
		this.widgetName = name;
		this.widgetEventPrefix = $[namespace][name].eventPrefix || name;
		this.widgetBaseClass = namespace + '-' + name;

		this.options = $.extend({},
			$.widget.defaults,
			$[namespace][name].defaults,
			$.metadata && $.metadata.get(element)[name],
			options);

		this.element = $(element)
			.bind('setData.' + name, function(event, key, value) {
				if (event.target == element) {
					return self._setData(key, value);
				}
			})
			.bind('getData.' + name, function(event, key) {
				if (event.target == element) {
					return self._getData(key);
				}
			})
			.bind('remove', function() {
				return self.destroy();
			});
	};

	// add widget prototype
	$[namespace][name].prototype = $.extend({}, $.widget.prototype, prototype);

	// TODO: merge getter and getterSetter properties from widget prototype
	// and plugin prototype
	$[namespace][name].getterSetter = 'option';
};

$.widget.prototype = {
	_init: function() {},
	destroy: function() {
		this.element.removeData(this.widgetName)
			.removeClass(this.widgetBaseClass + '-disabled' + ' ' + this.namespace + '-state-disabled')
			.removeAttr('aria-disabled');
	},

	option: function(key, value) {
		var options = key,
			self = this;

		if (typeof key == "string") {
			if (value === undefined) {
				return this._getData(key);
			}
			options = {};
			options[key] = value;
		}

		$.each(options, function(key, value) {
			self._setData(key, value);
		});
	},
	_getData: function(key) {
		return this.options[key];
	},
	_setData: function(key, value) {
		this.options[key] = value;

		if (key == 'disabled') {
			this.element
				[value ? 'addClass' : 'removeClass'](
					this.widgetBaseClass + '-disabled' + ' ' +
					this.namespace + '-state-disabled')
				.attr("aria-disabled", value);
		}
	},

	enable: function() {
		this._setData('disabled', false);
	},
	disable: function() {
		this._setData('disabled', true);
	},

	_trigger: function(type, event, data) {
		var callback = this.options[type],
			eventName = (type == this.widgetEventPrefix
				? type : this.widgetEventPrefix + type);

		event = $.Event(event);
		event.type = eventName;

		// copy original event properties over to the new event
		// this would happen if we could call $.event.fix instead of $.Event
		// but we don't have a way to force an event to be fixed multiple times
		if (event.originalEvent) {
			for (var i = $.event.props.length, prop; i;) {
				prop = $.event.props[--i];
				event[prop] = event.originalEvent[prop];
			}
		}

		this.element.trigger(event, data);

		return !($.isFunction(callback) && callback.call(this.element[0], event, data) === false
			|| event.isDefaultPrevented());
	}
};

$.widget.defaults = {
	disabled: false
};


/** Mouse Interaction Plugin **/

$.ui.mouse = {
	_mouseInit: function() {
		var self = this;

		this.element
			.bind('mousedown.'+this.widgetName, function(event) {
				return self._mouseDown(event);
			})
			.bind('click.'+this.widgetName, function(event) {
				if(self._preventClickEvent) {
					self._preventClickEvent = false;
					event.stopImmediatePropagation();
					return false;
				}
			});

		// Prevent text selection in IE
		if ($.browser.msie) {
			this._mouseUnselectable = this.element.attr('unselectable');
			this.element.attr('unselectable', 'on');
		}

		this.started = false;
	},

	// TODO: make sure destroying one instance of mouse doesn't mess with
	// other instances of mouse
	_mouseDestroy: function() {
		this.element.unbind('.'+this.widgetName);

		// Restore text selection in IE
		($.browser.msie
			&& this.element.attr('unselectable', this._mouseUnselectable));
	},

	_mouseDown: function(event) {
		// don't let more than one widget handle mouseStart
		// TODO: figure out why we have to use originalEvent
		event.originalEvent = event.originalEvent || {};
		if (event.originalEvent.mouseHandled) { return; }

		// we may have missed mouseup (out of window)
		(this._mouseStarted && this._mouseUp(event));

		this._mouseDownEvent = event;

		var self = this,
			btnIsLeft = (event.which == 1),
			elIsCancel = (typeof this.options.cancel == "string" ? $(event.target).parents().add(event.target).filter(this.options.cancel).length : false);
		if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
			return true;
		}

		this.mouseDelayMet = !this.options.delay;
		if (!this.mouseDelayMet) {
			this._mouseDelayTimer = setTimeout(function() {
				self.mouseDelayMet = true;
			}, this.options.delay);
		}

		if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
			this._mouseStarted = (this._mouseStart(event) !== false);
			if (!this._mouseStarted) {
				event.preventDefault();
				return true;
			}
		}

		// these delegates are required to keep context
		this._mouseMoveDelegate = function(event) {
			return self._mouseMove(event);
		};
		this._mouseUpDelegate = function(event) {
			return self._mouseUp(event);
		};
		$(document)
			.bind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
			.bind('mouseup.'+this.widgetName, this._mouseUpDelegate);

		// preventDefault() is used to prevent the selection of text here -
		// however, in Safari, this causes select boxes not to be selectable
		// anymore, so this fix is needed
		($.browser.safari || event.preventDefault());

		event.originalEvent.mouseHandled = true;
		return true;
	},

	_mouseMove: function(event) {
		// IE mouseup check - mouseup happened when mouse was out of window
		if ($.browser.msie && !event.button) {
			return this._mouseUp(event);
		}

		if (this._mouseStarted) {
			this._mouseDrag(event);
			return event.preventDefault();
		}

		if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
			this._mouseStarted =
				(this._mouseStart(this._mouseDownEvent, event) !== false);
			(this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
		}

		return !this._mouseStarted;
	},

	_mouseUp: function(event) {
		$(document)
			.unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
			.unbind('mouseup.'+this.widgetName, this._mouseUpDelegate);

		if (this._mouseStarted) {
			this._mouseStarted = false;
			this._preventClickEvent = (event.target == this._mouseDownEvent.target);
			this._mouseStop(event);
		}

		return false;
	},

	_mouseDistanceMet: function(event) {
		return (Math.max(
				Math.abs(this._mouseDownEvent.pageX - event.pageX),
				Math.abs(this._mouseDownEvent.pageY - event.pageY)
			) >= this.options.distance
		);
	},

	_mouseDelayMet: function(event) {
		return this.mouseDelayMet;
	},

	// These are placeholder methods, to be overriden by extending plugin
	_mouseStart: function(event) {},
	_mouseDrag: function(event) {},
	_mouseStop: function(event) {},
	_mouseCapture: function(event) { return true; }
};

$.ui.mouse.defaults = {
	cancel: null,
	distance: 1,
	delay: 0
};

})(jQuery);
/* jquery.ui.sortable.js (204) */
/***
 * jQuery UI Sortable 1.7.2
 *
 * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * http://docs.jquery.com/UI/Sortables
 *
 * Depends:
 *	ui.core.js
 */
(function($) {

$.widget("ui.sortable", $.extend({}, $.ui.mouse, {
	_init: function() {

		var o = this.options;
		this.containerCache = {};
		this.element.addClass("ui-sortable");

		//Get the items
		this.refresh();

		//Let's determine if the items are floating
		this.floating = this.items.length ? (/left|right/).test(this.items[0].item.css('float')) : false;

		//Let's determine the parent's offset
		this.offset = this.element.offset();

		//Initialize mouse events for interaction
		this._mouseInit();

	},

	destroy: function() {
		this.element
			.removeClass("ui-sortable ui-sortable-disabled")
			.removeData("sortable")
			.unbind(".sortable");
		this._mouseDestroy();

		for ( var i = this.items.length - 1; i >= 0; i-- )
			this.items[i].item.removeData("sortable-item");
	},

	_mouseCapture: function(event, overrideHandle) {

		if (this.reverting) {
			return false;
		}

		if(this.options.disabled || this.options.type == 'static') return false;

		//We have to refresh the items data once first
		this._refreshItems(event);

		//Find out if the clicked node (or one of its parents) is a actual item in this.items
		var currentItem = null, self = this, nodes = $(event.target).parents().each(function() {
			if($.data(this, 'sortable-item') == self) {
				currentItem = $(this);
				return false;
			}
		});
		if($.data(event.target, 'sortable-item') == self) currentItem = $(event.target);

		if(!currentItem) return false;
		if(this.options.handle && !overrideHandle) {
			var validHandle = false;

			$(this.options.handle, currentItem).find("*").andSelf().each(function() { if(this == event.target) validHandle = true; });
			if(!validHandle) return false;
		}

		this.currentItem = currentItem;
		this._removeCurrentsFromItems();
		return true;

	},

	_mouseStart: function(event, overrideHandle, noActivation) {

		var o = this.options, self = this;
		this.currentContainer = this;

		//We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture
		this.refreshPositions();

		//Create and append the visible helper
		this.helper = this._createHelper(event);

		//Cache the helper size
		this._cacheHelperProportions();

		/*
		 * - Position generation -
		 * This block generates everything position related - it's the core of draggables.
		 */

		//Cache the margins of the original element
		this._cacheMargins();

		//Get the next scrolling parent
		this.scrollParent = this.helper.scrollParent();

		//The element's absolute position on the page minus margins
		this.offset = this.currentItem.offset();
		this.offset = {
			top: this.offset.top - this.margins.top,
			left: this.offset.left - this.margins.left
		};

		// Only after we got the offset, we can change the helper's position to absolute
		// TODO: Still need to figure out a way to make relative sorting possible
		this.helper.css("position", "absolute");
		this.cssPosition = this.helper.css("position");

		$.extend(this.offset, {
			click: { //Where the click happened, relative to the element
				left: event.pageX - this.offset.left,
				top: event.pageY - this.offset.top
			},
			parent: this._getParentOffset(),
			relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
		});

		//Generate the original position
		this.originalPosition = this._generatePosition(event);
		this.originalPageX = event.pageX;
		this.originalPageY = event.pageY;

		//Adjust the mouse offset relative to the helper if 'cursorAt' is supplied
		if(o.cursorAt)
			this._adjustOffsetFromHelper(o.cursorAt);

		//Cache the former DOM position
		this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };

		//If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way
		if(this.helper[0] != this.currentItem[0]) {
			this.currentItem.hide();
		}

		//Create the placeholder
		this._createPlaceholder();

		//Set a containment if given in the options
		if(o.containment)
			this._setContainment();

		if(o.cursor) { // cursor option
			if ($('body').css("cursor")) this._storedCursor = $('body').css("cursor");
			$('body').css("cursor", o.cursor);
		}

		if(o.opacity) { // opacity option
			if (this.helper.css("opacity")) this._storedOpacity = this.helper.css("opacity");
			this.helper.css("opacity", o.opacity);
		}

		if(o.zIndex) { // zIndex option
			if (this.helper.css("zIndex")) this._storedZIndex = this.helper.css("zIndex");
			this.helper.css("zIndex", o.zIndex);
		}

		//Prepare scrolling
		if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML')
			this.overflowOffset = this.scrollParent.offset();

		//Call callbacks
		this._trigger("start", event, this._uiHash());

		//Recache the helper size
		if(!this._preserveHelperProportions)
			this._cacheHelperProportions();


		//Post 'activate' events to possible containers
		if(!noActivation) {
			 for (var i = this.containers.length - 1; i >= 0; i--) { this.containers[i]._trigger("activate", event, self._uiHash(this)); }
		}

		//Prepare possible droppables
		if($.ui.ddmanager)
			$.ui.ddmanager.current = this;

		if ($.ui.ddmanager && !o.dropBehaviour)
			$.ui.ddmanager.prepareOffsets(this, event);

		this.dragging = true;

		this.helper.addClass("ui-sortable-helper");
		this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position
		return true;

	},

	_mouseDrag: function(event) {

		//Compute the helpers position
		this.position = this._generatePosition(event);
		this.positionAbs = this._convertPositionTo("absolute");

		if (!this.lastPositionAbs) {
			this.lastPositionAbs = this.positionAbs;
		}

		//Do scrolling
		if(this.options.scroll) {
			var o = this.options, scrolled = false;
			if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') {

				if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
					this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
				else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity)
					this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;

				if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
					this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
				else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity)
					this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;

			} else {

				if(event.pageY - $(document).scrollTop() < o.scrollSensitivity)
					scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
				else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
					scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);

				if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
					scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
				else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
					scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);

			}

			if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
				$.ui.ddmanager.prepareOffsets(this, event);
		}

		//Regenerate the absolute position used for position checks
		this.positionAbs = this._convertPositionTo("absolute");

		//Set the helper position
		if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
		if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px';

		//Rearrange
		for (var i = this.items.length - 1; i >= 0; i--) {

			//Cache variables and intersection, continue if no intersection
			var item = this.items[i], itemElement = item.item[0], intersection = this._intersectsWithPointer(item);
			if (!intersection) continue;

			if(itemElement != this.currentItem[0] //cannot intersect with itself
				&&	this.placeholder[intersection == 1 ? "next" : "prev"]()[0] != itemElement //no useless actions that have been done before
				&&	!$.ui.contains(this.placeholder[0], itemElement) //no action if the item moved is the parent of the item checked
				&& (this.options.type == 'semi-dynamic' ? !$.ui.contains(this.element[0], itemElement) : true)
			) {

				this.direction = intersection == 1 ? "down" : "up";

				if (this.options.tolerance == "pointer" || this._intersectsWithSides(item)) {
					this._rearrange(event, item);
				} else {
					break;
				}

				this._trigger("change", event, this._uiHash());
				break;
			}
		}

		//Post events to containers
		this._contactContainers(event);

		//Interconnect with droppables
		if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);

		//Call callbacks
		this._trigger('sort', event, this._uiHash());

		this.lastPositionAbs = this.positionAbs;
		return false;

	},

	_mouseStop: function(event, noPropagation) {

		if(!event) return;

		//If we are using droppables, inform the manager about the drop
		if ($.ui.ddmanager && !this.options.dropBehaviour)
			$.ui.ddmanager.drop(this, event);

		if(this.options.revert) {
			var self = this;
			var cur = self.placeholder.offset();

			self.reverting = true;

			$(this.helper).animate({
				left: cur.left - this.offset.parent.left - self.margins.left + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft),
				top: cur.top - this.offset.parent.top - self.margins.top + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop)
			}, parseInt(this.options.revert, 10) || 500, function() {
				self._clear(event);
			});
		} else {
			this._clear(event, noPropagation);
		}

		return false;

	},

	cancel: function() {

		var self = this;

		if(this.dragging) {

			this._mouseUp();

			if(this.options.helper == "original")
				this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
			else
				this.currentItem.show();

			//Post deactivating events to containers
			for (var i = this.containers.length - 1; i >= 0; i--){
				this.containers[i]._trigger("deactivate", null, self._uiHash(this));
				if(this.containers[i].containerCache.over) {
					this.containers[i]._trigger("out", null, self._uiHash(this));
					this.containers[i].containerCache.over = 0;
				}
			}

		}

		//$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
		if(this.placeholder[0].parentNode) this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
		if(this.options.helper != "original" && this.helper && this.helper[0].parentNode) this.helper.remove();

		$.extend(this, {
			helper: null,
			dragging: false,
			reverting: false,
			_noFinalSort: null
		});

		if(this.domPosition.prev) {
			$(this.domPosition.prev).after(this.currentItem);
		} else {
			$(this.domPosition.parent).prepend(this.currentItem);
		}

		return true;

	},

	serialize: function(o) {

		var items = this._getItemsAsjQuery(o && o.connected);
		var str = []; o = o || {};

		$(items).each(function() {
			var res = ($(o.item || this).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/));
			if(res) str.push((o.key || res[1]+'[]')+'='+(o.key && o.expression ? res[1] : res[2]));
		});

		return str.join('&');

	},

	toArray: function(o) {

		var items = this._getItemsAsjQuery(o && o.connected);
		var ret = []; o = o || {};

		items.each(function() { ret.push($(o.item || this).attr(o.attribute || 'id') || ''); });
		return ret;

	},

	/* Be careful with the following core functions */
	_intersectsWith: function(item) {

		var x1 = this.positionAbs.left,
			x2 = x1 + this.helperProportions.width,
			y1 = this.positionAbs.top,
			y2 = y1 + this.helperProportions.height;

		var l = item.left,
			r = l + item.width,
			t = item.top,
			b = t + item.height;

		var dyClick = this.offset.click.top,
			dxClick = this.offset.click.left;

		var isOverElement = (y1 + dyClick) > t && (y1 + dyClick) < b && (x1 + dxClick) > l && (x1 + dxClick) < r;

		if(	   this.options.tolerance == "pointer"
			|| this.options.forcePointerForContainers
			|| (this.options.tolerance != "pointer" && this.helperProportions[this.floating ? 'width' : 'height'] > item[this.floating ? 'width' : 'height'])
		) {
			return isOverElement;
		} else {

			return (l < x1 + (this.helperProportions.width / 2) // Right Half
				&& x2 - (this.helperProportions.width / 2) < r // Left Half
				&& t < y1 + (this.helperProportions.height / 2) // Bottom Half
				&& y2 - (this.helperProportions.height / 2) < b ); // Top Half

		}
	},

	_intersectsWithPointer: function(item) {

		var isOverElementHeight = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),
			isOverElementWidth = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),
			isOverElement = isOverElementHeight && isOverElementWidth,
			verticalDirection = this._getDragVerticalDirection(),
			horizontalDirection = this._getDragHorizontalDirection();

		if (!isOverElement)
			return false;

		return this.floating ?
			( ((horizontalDirection && horizontalDirection == "right") || verticalDirection == "down") ? 2 : 1 )
			: ( verticalDirection && (verticalDirection == "down" ? 2 : 1) );

	},

	_intersectsWithSides: function(item) {

		var isOverBottomHalf = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),
			isOverRightHalf = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
			verticalDirection = this._getDragVerticalDirection(),
			horizontalDirection = this._getDragHorizontalDirection();

		if (this.floating && horizontalDirection) {
			return ((horizontalDirection == "right" && isOverRightHalf) || (horizontalDirection == "left" && !isOverRightHalf));
		} else {
			return verticalDirection && ((verticalDirection == "down" && isOverBottomHalf) || (verticalDirection == "up" && !isOverBottomHalf));
		}

	},

	_getDragVerticalDirection: function() {
		var delta = this.positionAbs.top - this.lastPositionAbs.top;
		return delta != 0 && (delta > 0 ? "down" : "up");
	},

	_getDragHorizontalDirection: function() {
		var delta = this.positionAbs.left - this.lastPositionAbs.left;
		return delta != 0 && (delta > 0 ? "right" : "left");
	},

	refresh: function(event) {
		this._refreshItems(event);
		this.refreshPositions();
	},

	_connectWith: function() {
		var options = this.options;
		return options.connectWith.constructor == String
			? [options.connectWith]
			: options.connectWith;
	},

	_getItemsAsjQuery: function(connected) {

		var self = this;
		var items = [];
		var queries = [];
		var connectWith = this._connectWith();

		if(connectWith && connected) {
			for (var i = connectWith.length - 1; i >= 0; i--){
				var cur = $(connectWith[i]);
				for (var j = cur.length - 1; j >= 0; j--){
					var inst = $.data(cur[j], 'sortable');
					if(inst && inst != this && !inst.options.disabled) {
						queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper"), inst]);
					}
				};
			};
		}

		queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper"), this]);

		for (var i = queries.length - 1; i >= 0; i--){
			queries[i][0].each(function() {
				items.push(this);
			});
		};

		return $(items);

	},

	_removeCurrentsFromItems: function() {

		var list = this.currentItem.find(":data(sortable-item)");

		for (var i=0; i < this.items.length; i++) {

			for (var j=0; j < list.length; j++) {
				if(list[j] == this.items[i].item[0])
					this.items.splice(i,1);
			};

		};

	},

	_refreshItems: function(event) {

		this.items = [];
		this.containers = [this];
		var items = this.items;
		var self = this;
		var queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]];
		var connectWith = this._connectWith();

		if(connectWith) {
			for (var i = connectWith.length - 1; i >= 0; i--){
				var cur = $(connectWith[i]);
				for (var j = cur.length - 1; j >= 0; j--){
					var inst = $.data(cur[j], 'sortable');
					if(inst && inst != this && !inst.options.disabled) {
						queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
						this.containers.push(inst);
					}
				};
			};
		}

		for (var i = queries.length - 1; i >= 0; i--) {
			var targetData = queries[i][1];
			var _queries = queries[i][0];

			for (var j=0, queriesLength = _queries.length; j < queriesLength; j++) {
				var item = $(_queries[j]);

				item.data('sortable-item', targetData); // Data for target checking (mouse manager)

				items.push({
					item: item,
					instance: targetData,
					width: 0, height: 0,
					left: 0, top: 0
				});
			};
		};

	},

	refreshPositions: function(fast) {

		//This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change
		if(this.offsetParent && this.helper) {
			this.offset.parent = this._getParentOffset();
		}

		for (var i = this.items.length - 1; i >= 0; i--){
			var item = this.items[i];

			//We ignore calculating positions of all connected containers when we're not over them
			if(item.instance != this.currentContainer && this.currentContainer && item.item[0] != this.currentItem[0])
				continue;

			var t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;

			if (!fast) {
				item.width = t.outerWidth();
				item.height = t.outerHeight();
			}

			var p = t.offset();
			item.left = p.left;
			item.top = p.top;
		};

		if(this.options.custom && this.options.custom.refreshContainers) {
			this.options.custom.refreshContainers.call(this);
		} else {
			for (var i = this.containers.length - 1; i >= 0; i--){
				var p = this.containers[i].element.offset();
				this.containers[i].containerCache.left = p.left;
				this.containers[i].containerCache.top = p.top;
				this.containers[i].containerCache.width	= this.containers[i].element.outerWidth();
				this.containers[i].containerCache.height = this.containers[i].element.outerHeight();
			};
		}

	},

	_createPlaceholder: function(that) {

		var self = that || this, o = self.options;

		if(!o.placeholder || o.placeholder.constructor == String) {
			var className = o.placeholder;
			o.placeholder = {
				element: function() {

					var el = $(document.createElement(self.currentItem[0].nodeName))
						.addClass(className || self.currentItem[0].className+" ui-sortable-placeholder")
						.removeClass("ui-sortable-helper")[0];

					if(!className)
						el.style.visibility = "hidden";

					return el;
				},
				update: function(container, p) {

					// 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that
					// 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified
					if(className && !o.forcePlaceholderSize) return;

					//If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item
					if(!p.height()) { p.height(self.currentItem.innerHeight() - parseInt(self.currentItem.css('paddingTop')||0, 10) - parseInt(self.currentItem.css('paddingBottom')||0, 10)); };
					if(!p.width()) { p.width(self.currentItem.innerWidth() - parseInt(self.currentItem.css('paddingLeft')||0, 10) - parseInt(self.currentItem.css('paddingRight')||0, 10)); };
				}
			};
		}

		//Create the placeholder
		self.placeholder = $(o.placeholder.element.call(self.element, self.currentItem));

		//Append it after the actual current item
		self.currentItem.after(self.placeholder);

		//Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
		o.placeholder.update(self, self.placeholder);

	},

	_contactContainers: function(event) {
		for (var i = this.containers.length - 1; i >= 0; i--){

			if(this._intersectsWith(this.containers[i].containerCache)) {
				if(!this.containers[i].containerCache.over) {

					if(this.currentContainer != this.containers[i]) {

						//When entering a new container, we will find the item with the least distance and append our item near it
						var dist = 10000; var itemWithLeastDistance = null; var base = this.positionAbs[this.containers[i].floating ? 'left' : 'top'];
						for (var j = this.items.length - 1; j >= 0; j--) {
							if(!$.ui.contains(this.containers[i].element[0], this.items[j].item[0])) continue;
							var cur = this.items[j][this.containers[i].floating ? 'left' : 'top'];
							if(Math.abs(cur - base) < dist) {
								dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j];
							}
						}

						if(!itemWithLeastDistance && !this.options.dropOnEmpty) //Check if dropOnEmpty is enabled
							continue;

						this.currentContainer = this.containers[i];
						itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[i].element, true);
						this._trigger("change", event, this._uiHash());
						this.containers[i]._trigger("change", event, this._uiHash(this));

						//Update the placeholder
						this.options.placeholder.update(this.currentContainer, this.placeholder);

					}

					this.containers[i]._trigger("over", event, this._uiHash(this));
					this.containers[i].containerCache.over = 1;
				}
			} else {
				if(this.containers[i].containerCache.over) {
					this.containers[i]._trigger("out", event, this._uiHash(this));
					this.containers[i].containerCache.over = 0;
				}
			}

		};
	},

	_createHelper: function(event) {

		var o = this.options;
		var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper == 'clone' ? this.currentItem.clone() : this.currentItem);

		if(!helper.parents('body').length) //Add the helper to the DOM if that didn't happen already
			$(o.appendTo != 'parent' ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);

		if(helper[0] == this.currentItem[0])
			this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") };

		if(helper[0].style.width == '' || o.forceHelperSize) helper.width(this.currentItem.width());
		if(helper[0].style.height == '' || o.forceHelperSize) helper.height(this.currentItem.height());

		return helper;

	},

	_adjustOffsetFromHelper: function(obj) {
		if(obj.left != undefined) this.offset.click.left = obj.left + this.margins.left;
		if(obj.right != undefined) this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
		if(obj.top != undefined) this.offset.click.top = obj.top + this.margins.top;
		if(obj.bottom != undefined) this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
	},

	_getParentOffset: function() {


		//Get the offsetParent and cache its position
		this.offsetParent = this.helper.offsetParent();
		var po = this.offsetParent.offset();

		// This is a special case where we need to modify a offset calculated on start, since the following happened:
		// 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
		// 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
		//    the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
		if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) {
			po.left += this.scrollParent.scrollLeft();
			po.top += this.scrollParent.scrollTop();
		}

		if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information
		|| (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix
			po = { top: 0, left: 0 };

		return {
			top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
			left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
		};

	},

	_getRelativeOffset: function() {

		if(this.cssPosition == "relative") {
			var p = this.currentItem.position();
			return {
				top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
				left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
			};
		} else {
			return { top: 0, left: 0 };
		}

	},

	_cacheMargins: function() {
		this.margins = {
			left: (parseInt(this.currentItem.css("marginLeft"),10) || 0),
			top: (parseInt(this.currentItem.css("marginTop"),10) || 0)
		};
	},

	_cacheHelperProportions: function() {
		this.helperProportions = {
			width: this.helper.outerWidth(),
			height: this.helper.outerHeight()
		};
	},

	_setContainment: function() {

		var o = this.options;
		if(o.containment == 'parent') o.containment = this.helper[0].parentNode;
		if(o.containment == 'document' || o.containment == 'window') this.containment = [
			0 - this.offset.relative.left - this.offset.parent.left,
			0 - this.offset.relative.top - this.offset.parent.top,
			$(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left,
			($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
		];

		if(!(/^(document|window|parent)$/).test(o.containment)) {
			var ce = $(o.containment)[0];
			var co = $(o.containment).offset();
			var over = ($(ce).css("overflow") != 'hidden');

			this.containment = [
				co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left,
				co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top,
				co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left,
				co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top
			];
		}

	},

	_convertPositionTo: function(d, pos) {

		if(!pos) pos = this.position;
		var mod = d == "absolute" ? 1 : -1;
		var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);

		return {
			top: (
				pos.top																	// The absolute mouse position
				+ this.offset.relative.top * mod										// Only for relative positioned nodes: Relative offset from element to offset parent
				+ this.offset.parent.top * mod											// The offsetParent's offset without borders (offset + border)
				- ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
			),
			left: (
				pos.left																// The absolute mouse position
				+ this.offset.relative.left * mod										// Only for relative positioned nodes: Relative offset from element to offset parent
				+ this.offset.parent.left * mod											// The offsetParent's offset without borders (offset + border)
				- ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
			)
		};

	},

	_generatePosition: function(event) {

		var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);

		// This is another very weird special case that only happens for relative elements:
		// 1. If the css position is relative
		// 2. and the scroll parent is the document or similar to the offset parent
		// we have to refresh the relative offset during the scroll so there are no jumps
		if(this.cssPosition == 'relative' && !(this.scrollParent[0] != document && this.scrollParent[0] != this.offsetParent[0])) {
			this.offset.relative = this._getRelativeOffset();
		}

		var pageX = event.pageX;
		var pageY = event.pageY;

		/*
		 * - Position constraining -
		 * Constrain the position to a mix of grid, containment.
		 */

		if(this.originalPosition) { //If we are not dragging yet, we won't check for options

			if(this.containment) {
				if(event.pageX - this.offset.click.left < this.containment[0]) pageX = this.containment[0] + this.offset.click.left;
				if(event.pageY - this.offset.click.top < this.containment[1]) pageY = this.containment[1] + this.offset.click.top;
				if(event.pageX - this.offset.click.left > this.containment[2]) pageX = this.containment[2] + this.offset.click.left;
				if(event.pageY - this.offset.click.top > this.containment[3]) pageY = this.containment[3] + this.offset.click.top;
			}

			if(o.grid) {
				var top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
				pageY = this.containment ? (!(top - this.offset.click.top < this.containment[1] || top - this.offset.click.top > this.containment[3]) ? top : (!(top - this.offset.click.top < this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;

				var left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
				pageX = this.containment ? (!(left - this.offset.click.left < this.containment[0] || left - this.offset.click.left > this.containment[2]) ? left : (!(left - this.offset.click.left < this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
			}

		}

		return {
			top: (
				pageY																// The absolute mouse position
				- this.offset.click.top													// Click offset (relative to the element)
				- this.offset.relative.top												// Only for relative positioned nodes: Relative offset from element to offset parent
				- this.offset.parent.top												// The offsetParent's offset without borders (offset + border)
				+ ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
			),
			left: (
				pageX																// The absolute mouse position
				- this.offset.click.left												// Click offset (relative to the element)
				- this.offset.relative.left												// Only for relative positioned nodes: Relative offset from element to offset parent
				- this.offset.parent.left												// The offsetParent's offset without borders (offset + border)
				+ ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
			)
		};

	},

	_rearrange: function(event, i, a, hardRefresh) {

		a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction == 'down' ? i.item[0] : i.item[0].nextSibling));

		//Various things done here to improve the performance:
		// 1. we create a setTimeout, that calls refreshPositions
		// 2. on the instance, we have a counter variable, that get's higher after every append
		// 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
		// 4. this lets only the last addition to the timeout stack through
		this.counter = this.counter ? ++this.counter : 1;
		var self = this, counter = this.counter;

		window.setTimeout(function() {
			if(counter == self.counter) self.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
		},0);

	},

	_clear: function(event, noPropagation) {

		this.reverting = false;
		// We delay all events that have to be triggered to after the point where the placeholder has been removed and
		// everything else normalized again
		var delayedTriggers = [], self = this;

		// We first have to update the dom position of the actual currentItem
		// Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088)
		if(!this._noFinalSort && this.currentItem[0].parentNode) this.placeholder.before(this.currentItem);
		this._noFinalSort = null;

		if(this.helper[0] == this.currentItem[0]) {
			for(var i in this._storedCSS) {
				if(this._storedCSS[i] == 'auto' || this._storedCSS[i] == 'static') this._storedCSS[i] = '';
			}
			this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
		} else {
			this.currentItem.show();
		}

		if(this.fromOutside && !noPropagation) delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); });
		if((this.fromOutside || this.domPosition.prev != this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent != this.currentItem.parent()[0]) && !noPropagation) delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed
		if(!$.ui.contains(this.element[0], this.currentItem[0])) { //Node was moved out of the current element
			if(!noPropagation) delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); });
			for (var i = this.containers.length - 1; i >= 0; i--){
				if($.ui.contains(this.containers[i].element[0], this.currentItem[0]) && !noPropagation) {
					delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); };  }).call(this, this.containers[i]));
					delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this));  }; }).call(this, this.containers[i]));
				}
			};
		};

		//Post events to containers
		for (var i = this.containers.length - 1; i >= 0; i--){
			if(!noPropagation) delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); };  }).call(this, this.containers[i]));
			if(this.containers[i].containerCache.over) {
				delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); };  }).call(this, this.containers[i]));
				this.containers[i].containerCache.over = 0;
			}
		}

		//Do what was originally in plugins
		if(this._storedCursor) $('body').css("cursor", this._storedCursor); //Reset cursor
		if(this._storedOpacity) this.helper.css("opacity", this._storedOpacity); //Reset cursor
		if(this._storedZIndex) this.helper.css("zIndex", this._storedZIndex == 'auto' ? '' : this._storedZIndex); //Reset z-index

		this.dragging = false;
		if(this.cancelHelperRemoval) {
			if(!noPropagation) {
				this._trigger("beforeStop", event, this._uiHash());
				for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events
				this._trigger("stop", event, this._uiHash());
			}
			return false;
		}

		if(!noPropagation) this._trigger("beforeStop", event, this._uiHash());

		//$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
		this.placeholder[0].parentNode.removeChild(this.placeholder[0]);

		if(this.helper[0] != this.currentItem[0]) this.helper.remove(); this.helper = null;

		if(!noPropagation) {
			for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events
			this._trigger("stop", event, this._uiHash());
		}

		this.fromOutside = false;
		return true;

	},

	_trigger: function() {
		if ($.widget.prototype._trigger.apply(this, arguments) === false) {
			this.cancel();
		}
	},

	_uiHash: function(inst) {
		var self = inst || this;
		return {
			helper: self.helper,
			placeholder: self.placeholder || $([]),
			position: self.position,
			absolutePosition: self.positionAbs, //deprecated
			offset: self.positionAbs,
			item: self.currentItem,
			sender: inst ? inst.element : null
		};
	}

}));

$.extend($.ui.sortable, {
	getter: "serialize toArray",
	version: "1.7.2",
	eventPrefix: "sort",
	defaults: {
		appendTo: "parent",
		axis: false,
		cancel: ":input,option",
		connectWith: false,
		containment: false,
		cursor: 'auto',
		cursorAt: false,
		delay: 0,
		distance: 1,
		dropOnEmpty: true,
		forcePlaceholderSize: false,
		forceHelperSize: false,
		grid: false,
		handle: false,
		helper: "original",
		items: '> *',
		opacity: false,
		placeholder: false,
		revert: false,
		scroll: true,
		scrollSensitivity: 20,
		scrollSpeed: 20,
		scope: "default",
		tolerance: "intersect",
		zIndex: 1000
	}
});

})(jQuery);
/* jquery.simpleColor.js (212) */
/*
 * jQuery simpleColor plugin
 * @requires jQuery v1.1 or later
 *
 * Examples at: http://recurser.com/articles/2007/12/18/jquery-simplecolor-color-picker/
 * 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.0  Aug-03-2007
 */
 (function($) {
/**
 * simpleColor() provides a mechanism for displaying simple color-pickers.
 *
 * If an options Object is provided, the following attributes are supported:
 *
 *  defaultColor: Default (initially selected) color
 *                 default value: '#FFF'
 *
 *  border:       CSS border properties
 *                 default value: '1px solid #000'
 *
 *  cellWidth:    Width of each individual color cell
 *                 default value: 10
 *
 *  cellHeight:   Height of each individual color cell
 *                 default value: 10
 *
 *  cellMargin:   Margin of each individual color cell
 *                 default value: 1
 *
 *  boxWidth:     Width of the color display box
 *                 default value: 115px
 *
 *  boxHeight:    Height of the color display box
 *                 default value: 20px
 *
 *  columns:      Number of columns to display. Color order may look strange if this is altered
 *                 default value: 16
 *
 *  insert:       The position to insert the color picker. 'before' or 'after'
 *                 default value: 'after'
 */
$.fn.simpleColor = function(options) {
	
	var default_colors = 
		['990033','ff3366','cc0033','ff0033','ff9999','cc3366','ffccff','cc6699',
		'993366','660033','cc3399','ff99cc','ff66cc','ff99ff','ff6699','cc0066',
		'ff0066','ff3399','ff0099','ff33cc','ff00cc','ff66ff','ff33ff','ff00ff',
		'cc0099','990066','cc66cc','cc33cc','cc99ff','cc66ff','cc33ff','993399',
		'cc00cc','cc00ff','9900cc','990099','cc99cc','996699','663366','660099',
		'9933cc','660066','9900ff','9933ff','9966cc','330033','663399','6633cc',
		'6600cc','9966ff','330066','6600ff','6633ff','ccccff','9999ff','9999cc',
		'6666cc','6666ff','666699','333366','333399','330099','3300cc','3300ff',
		'3333ff','3333cc','0066ff','0033ff','3366ff','3366cc','000066','000033',
		'0000ff','000099','0033cc','0000cc','336699','0066cc','99ccff','6699ff',
		'003366','6699cc','006699','3399cc','0099cc','66ccff','3399ff','003399',
		'0099ff','33ccff','00ccff','99ffff','66ffff','33ffff','00ffff','00cccc',
		'009999','669999','99cccc','ccffff','33cccc','66cccc','339999','336666',
		'006666','003333','00ffcc','33ffcc','33cc99','00cc99','66ffcc','99ffcc',
		'00ff99','339966','006633','336633','669966','66cc66','99ff99','66ff66',
		'339933','99cc99','66ff99','33ff99','33cc66','00cc66','66cc99','009966',
		'009933','33ff66','00ff66','ccffcc','ccff99','99ff66','99ff33','00ff33',
		'33ff33','00cc33','33cc33','66ff33','00ff00','66cc33','006600','003300',
		'009900','33ff00','66ff00','99ff00','66cc00','00cc00','33cc00','339900',
		'99cc66','669933','99cc33','336600','669900','99cc00','ccff66','ccff33',
		'ccff00','999900','cccc00','cccc33','333300','666600','999933','cccc66',
		'666633','999966','cccc99','ffffcc','ffff99','ffff66','ffff33','ffff00',
		'ffcc00','ffcc66','ffcc33','cc9933','996600','cc9900','ff9900','cc6600',
		'993300','cc6633','663300','ff9966','ff6633','ff9933','ff6600','cc3300',
		'996633','330000','663333','996666','cc9999','993333','cc6666','ffcccc',
		'ff3333','cc3333','ff6666','660000','990000','cc0000','ff0000','ff3300',
		'cc9966','ffcc99','ffffff','cccccc','999999','666666','333333','000000',
		'000000','000000','000000','000000','000000','000000','000000','000000'];
		
	// Option defaults
    options = $.extend({
        defaultColor:  this.attr('defaultColor') || '#FFF',
        border:        this.attr('border') || '1px solid #000',
        cellWidth:     this.attr('cellWidth') || 10,
        cellHeight:    this.attr('cellHeight') || 10,
        cellMargin:    this.attr('cellMargin') || 1,
        boxWidth:      this.attr('boxWidth') || '115px',
        boxHeight:     this.attr('boxHeight') || '20px',
        columns:       this.attr('columns') || 16,
        insert:        this.attr('insert') || 'after',
        buttonClass:   this.attr('buttonClass') || '',
        colors:        this.attr('colors') || default_colors,
        indicator:     this.attr('indicator') || null
    }, options || {});
	
	// Hide the input
	this.hide();
	
	// Figure out the cell dimensions
	options.totalWidth = options.columns * (options.cellWidth + (2 * options.cellMargin));
	if ($.browser.msie) {
		options.totalWidth += 2;
	}
	
	options.totalHeight = Math.ceil(options.colors.length / options.columns) * (options.cellHeight + (2 * options.cellMargin));
	
	// Store these options so they'll be available to the other functions
	// TODO - must be a better way to do this, not sure what the 'official'
	// jQuery method is. Ideally i want to pass these as a parameter to the 
	// each() function but i'm not sure how
	$.simpleColorOptions = options;
	
	this.each(buildSelector);
	
	return this;
	
	
	
	function buildSelector(index) {
		
		var options = $.simpleColorOptions;
		
		// Create a container to hold everything
		var container = $("<div class='simpleColorContainer' />");
		
		// Create the color display box
		var default_color = (this.value && this.value != '') ? this.value : options.defaultColor;
		
		var display_box = $("<div class='simpleColorDisplay' />");
		display_box.css('backgroundColor', default_color);
		display_box.css('border',          options.border);
		display_box.css('width',           options.boxWidth);
		display_box.css('height',          options.boxHeight);
		container.append(display_box);
		
		// Create the select button 
		var select_button = $("<input type='button' value='Select'" + 
							  " class='simpleColorSelectButton "+options.buttonClass+"'>");
		container.append(select_button);
		
		// Create the cancel button
		var cancel_button = $("<input type='button' value='Cancel'" + 
							  " class='simpleColorCancelButton "+options.buttonClass+"'>");
		cancel_button.hide();
		container.append(cancel_button);
		
		// Bind the select button to display the chooser
		select_button.bind('click', {
				container: container, 
				input: this, 
				cancel_button: cancel_button, 
				display_box: display_box}, 
			function (event) {
				$(this).hide();
				event.data.cancel_button.show();
				
				// Use an existing chooser if there is one
				if (event.data.container.chooser) {
					event.data.container.chooser.show();
					
				// Build the chooser
				} else {
		
					// Make a chooser div to hold the cells
					var chooser = $("<div class='simpleColorChooser'/>");
					chooser.css('border',  options.border);
					chooser.css('margin',  '0px');
					chooser.css('margin-top',  '3px');
					chooser.css('width',   options.totalWidth + 'px');
					chooser.css('height',  options.totalHeight + 'px');
					
					event.data.container.chooser = chooser;
					event.data.container.append(chooser);
					
					// Create the cells
					for (var i=0; i<options.colors.length; i++) {
						var cell = $("<div class='simpleColorCell' id='" + options.colors[i] + "'/>");
						cell.css('width',           options.cellWidth + 'px');
						cell.css('height',          options.cellHeight + 'px');
						cell.css('margin',          options.cellMargin + 'px');
						cell.css('cursor',          'pointer');
						cell.css('lineHeight',      options.cellHeight + 'px');
						cell.css('fontSize',        '1px');
						cell.css('float',           'left');
						cell.css('backgroundColor', '#'+options.colors[i]);
						chooser.append(cell);
						
						cell.bind('click', {
								input: event.data.input, 
								chooser: chooser, 
								select_button: select_button, 
								cancel_button: cancel_button, 
								display_box: display_box}, 
							function(event) {
								event.data.input.value = '#' + this.id;
								event.data.display_box.css('backgroundColor', '#' + this.id);
								event.data.chooser.hide();
								event.data.cancel_button.hide();
								event.data.display_box.show();
								event.data.select_button.show();
							}
						);
					}
				}
			}
		);
		
		// Bind the cancel button to hide the chooser
		cancel_button.bind('click', {
				container: container, 
				select_button: select_button, 
				display_box: display_box}, 
			function (event) {
				$(this).hide();
				event.data.container.find('.simpleColorChooser').hide();
				event.data.display_box.show();
				event.data.select_button.show();
			}
		);
		
		$(this).after(container);
		
	};
};
	
/*
 * Close the given color selectors
 */
$.fn.closeSelector = function() {
	this.each( function(index) {
		var container = $(this).parent().find('div.simpleColorContainer');
		container.find('.simpleColorCancelButton').hide();
		container.find('.simpleColorChooser').hide();
		container.find('.simpleColorDisplay').show();
		container.find('.simpleColorSelectButton').show();
	});
	
	return this;
}
	
	
	


})(jQuery);
/* jquery.lightbox.js (225) */
/**
 * jQuery lightBox plugin
 * This jQuery plugin was inspired and based on Lightbox 2 by Lokesh Dhakar (http://www.huddletogether.com/projects/lightbox2/)
 * and adapted to me for use like a plugin from jQuery.
 * @name jquery-lightbox-0.5.js
 * @author Leandro Vieira Pinho - http://leandrovieira.com
 * @version 0.5
 * @date April 11, 2008
 * @category jQuery plugin
 * @copyright (c) 2008 Leandro Vieira Pinho (leandrovieira.com)
 * @license CC Attribution-No Derivative Works 2.5 Brazil - http://creativecommons.org/licenses/by-nd/2.5/br/deed.en_US
 * @example Visit http://leandrovieira.com/projects/jquery/lightbox/ for more informations about this jQuery plugin
 */
 /**
  * Modified to include additional settings which allows lightbox of flash with 
  *	swfObject
  *
  * Changes:
  *		To work with jQuery 1.2.1 originally required 1.2.3
  *	 	All IDs as jQuery selectors were not working,
  *		Broke down .css calls into individual lines as previous the css was not being updated	
  *	
  */
// Offering a Custom Alias suport - More info: http://docs.jquery.com/Plugins/Authoring#Custom_Alias
(function($) {
	/**
	 * $ is an alias to jQuery object
	 *
	 */
	$.fn.lightBox = function(settings) {
		// Settings to configure the jQuery lightBox plugin how you like
		settings = jQuery.extend({
			// Configuration related to overlay
			overlayBgColor: 		'#000',		// (string) Background color to overlay; inform a hexadecimal value like: #RRGGBB. Where RR, GG, and BB are the hexadecimal values for the red, green, and blue values of the color.
			overlayOpacity:			0.8,		// (integer) Opacity value to overlay; inform: 0.X. Where X are number from 0 to 9
			// Configuration related to navigation
			fixedNavigation:		false,		// (boolean) Boolean that informs if the navigation (next and prev button) will be fixed or not in the interface.
			// Configuration related to container image box
			containerBorderSize:	10,			// (integer) If you adjust the padding in the CSS for the container, #lightbox-container-image-box, you will need to update this value
			containerResizeSpeed:	400,		// (integer) Specify the resize duration of container image. These number are miliseconds. 400 is default.
			// Configuration related to images
			imageLoading:			'images/lightbox-ico-loading.gif',		// (string) Path and the name of the loading icon
			imageBtnPrev:			'images/lightbox-btn-prev.gif',			// (string) Path and the name of the prev button image
			imageBtnNext:			'images/lightbox-btn-next.gif',			// (string) Path and the name of the next button image
			imageBtnClose:			'images/lightbox-btn-close.gif',		// (string) Path and the name of the close btn
			imageBlank:				'images/lightbox-blank.gif',			// (string) Path and the name of a blank image (one pixel)
			// Configuration related to texts in caption. For example: Image 2 of 8. You can alter either "Image" and "of" texts.
			txtImage:				'Image',	// (string) Specify text "Image"
			txtOf:					'of',		// (string) Specify text "of"
			// Configuration related to keyboard navigation
			keyToClose:				'c',		// (string) (c = close) Letter to close the jQuery lightBox interface. Beyond this letter, the letter X and the SCAPE key is used to.
			keyToPrev:				'p',		// (string) (p = previous) Letter to show the previous image
			keyToNext:				'n',		// (string) (n = next) Letter to show the next image.
			// Don´t alter these variables in any way
			imageArray:				[],
			activeImage:			0,
			
			/****************************************************************************************/
			//Custom settings
			type:					'image',  	// to determine where we are loading flash or images.
			width:					200,		// used by ONLY flash
			height:					200,		// used by ONLY flash
			file:					'test.flv',	// Flash Video file
			flvPlayer:				'flash/videoplayer.swf'
			/****************************************************************************************/
		},settings);
		// Caching the jQuery object with all elements matched
		var jQueryMatchedObj = this; // This, in this context, refer to jQuery object
		/**
		 * Initializing the plugin calling the start function
		 *
		 * @return boolean false
		 */
		function _initialize() {
			_start(this,jQueryMatchedObj); // This, in this context, refer to object (link) which the user have clicked
			return false; // Avoid the browser following the link
		}
		/**
		 * Start the jQuery lightBox plugin
		 *
		 * @param object objClicked The object (link) whick the user have clicked
		 * @param object jQueryMatchedObj The jQuery object with all elements matched
		 */
		function _start(objClicked,jQueryMatchedObj) {
			// Hime some elements to avoid conflict with overlay in IE. These elements appear above the overlay.
			$('embed, object, select').css({ 'visibility' : 'hidden' });
			// Call the function to create the markup structure; style some elements; assign events in some elements.
			_set_interface();
			
			// Unset total images in imageArray
			settings.imageArray.length = 0;
			// Unset image active information
			settings.activeImage = 0;
			// We have an image set? Or just an image? Let´s see it.
			if ( jQueryMatchedObj.length == 1 ) {
				settings.imageArray.push(new Array(objClicked.getAttribute('href'),objClicked.getAttribute('title')));
			} else {
				// Add an Array (as many as we have), with href and title atributes, inside the Array that storage the images references		
				for ( var i = 0; i < jQueryMatchedObj.length; i++ ) {
					settings.imageArray.push(new Array(jQueryMatchedObj[i].getAttribute('href'),jQueryMatchedObj[i].getAttribute('title')));
				}
			}
			while ( settings.imageArray[settings.activeImage][0] != objClicked.getAttribute('href') ) {
				settings.activeImage++;
			}
			// Call the function that prepares image exibition
			_set_image_to_view();
		}
		/**
		 * Create the jQuery lightBox plugin interface
		 *
		 * The HTML markup will be like that:
			<div id="jqueryOverlay"></div>
			<div id="jqueryLightbox">
				<div id="lightboxContainerImageBox">
					<div id="lightboxContainerImage">
						<img src="../fotos/XX.jpg" id="lightboxImage">
						<div id="lightboxNav">
							<a href="#" id="lightboxNavBtnPrev"></a>
							<a href="#" id="lightboxNavBtnNext"></a>
						</div>
						<div id="lightboxLoading">
							<a href="#" id="lightboxLoadingLink">
								<img src="../images/lightbox-ico-loading.gif">
							</a>
						</div>
					</div>
				</div>
				<div id="lightboxContainerImageDataBox">
					<div id="lightboxContainerImageData">
						<div id="lightboxImageDetails">
							<span id="lightboxImageDetailsCaption"></span>
							<span id="lightboxImageDetailsCurrentNumber"></span>
						</div>
						<div id="lightboxSecNav">
							<a href="#" id="lightboxSecNavBtnClose">
								<img src="../images/lightbox-btn-close.gif">
							</a>
						</div>
					</div>
				</div>
			</div>
		 *
		 */
		function _set_interface() {
			// Apply the HTML markup into body tag
			$('body').append('<div id="jqueryOverlay"></div><div id="jqueryLightbox"><div id="lightboxContainerImageBox"><div id="lightboxContainerImage"><img id="lightboxImage"><div style="" id="lightboxNav"><a href="#" id="lightboxNavBtnPrev"></a><a href="#" id="lightboxNavBtnNext"></a></div><div id="lightboxLoading"><a href="#" id="lightboxLoadingLink"><img src="' + settings.imageLoading + '"></a></div></div></div><div id="lightboxContainerImageDataBox"><div id="lightboxContainerImageData"><div id="lightboxImageDetails"><span id="lightboxImageDetailsCaption"></span><span id="lightboxImageDetailsCurrentNumber"></span></div><div id="lightboxSecNav"><a href="#" id="lightboxSecNavBtnClose"><img src="' + settings.imageBtnClose + '"></a></div></div></div></div>');	
			// Get page sizes
			var arrPageSizes = ___getPageSize();
			
			// Style overlay and show it
			$('#jqueryOverlay').css({
				backgroundColor:	settings.overlayBgColor,
				opacity:			settings.overlayOpacity,
				width:				arrPageSizes[0],
				height:				arrPageSizes[1]
			}).fadeIn();
			
			// Get page scroll
			var arrPageScroll = ___getPageScroll();
			// Calculate top and left offset for the jquery-lightbox div object and show it
			$('#jqueryLightbox').css({
				top:	arrPageScroll[1] + (arrPageSizes[3] / 10),
				left:	arrPageScroll[0]
			}).show();
			// Assigning click events in elements to close overlay
			$('#lightboxContainerImageDataBox').click(function() {
				return false;
			});
			$('#jqueryOverlay').click(function() {
				_finish();									
			});
			$('#jqueryLightbox').click(function() {
				_finish();									
			});
			// Assign the _finish function to lightbox-loading-link and lightbox-secNav-btnClose objects
			$('#lightboxLoadingLink').click(function() {
				_finish();
				return false;
			});
			$('#lightboxSecNavBtnClose').click(function() {
				_finish();
				return false;
			});
			// If window was resized, calculate the new overlay dimensions
			$(window).resize(function() {
				// Get page sizes
				var arrPageSizes = ___getPageSize();
				// Style overlay and show it
				$('#jqueryOverlay').css({
					width:		arrPageSizes[0],
					height:		arrPageSizes[1]
				});
				// Get page scroll
				var arrPageScroll = ___getPageScroll();
				// Calculate top and left offset for the jquery-lightbox div object and show it
				$('#jqueryLightbox').css({
					top:	arrPageScroll[1] + (arrPageSizes[3] / 10),
					left:	arrPageScroll[0]
				});
			});
		}
		/**
		 * Prepares image exibition; doing a image´s preloader to calculate it´s size
		 *
		 */
		function _set_image_to_view() { // show the loading
			// Show the loading
			$('#lightboxLoading').show();
			if ( settings.fixedNavigation ) {
				$('#lightboxImage').hide();
				$('#lightboxContainerImageDataBox').hide();
				$('#lightboxImageDetailsCurrentNumber').hide();
			} else {
				// Hide some elements
				$('#lightboxImage').hide();
				$('#lightboxNav').hide();
				$('#lightboxNavBtnPrev').hide();
				$('#lightboxNavBtnNext').hide();
				$('#lightboxContainerImageDataBox').hide();
				$('#lightboxImageDetailsCurrentNumber').hide();
			}
			switch (settings.type) {
				case 'image':
					// Image preload process
					var objImagePreloader = new Image();
					objImagePreloader.onload = function() {
						$('#lightboxImage').attr('src',settings.imageArray[settings.activeImage][0]);
						// Perfomance an effect in the image container resizing it
						_resize_container_image_box(objImagePreloader.width,objImagePreloader.height);
						//	clear onLoad, IE behaves irratically with animated gifs otherwise
						objImagePreloader.onload=function(){};
					};
					objImagePreloader.src = settings.imageArray[settings.activeImage][0];
					break;
				case 'flashVideo':
					// We are handing flash, therefore use the width and height from the conMediaFile
					_resize_container_image_box(settings.width, settings.height);
					// swfobject used insert video player, called in _show_image() (see line 283)
					break;
				case 'flash':
				default:
			}
		};
		/**
		 * Perfomance an effect in the image container resizing it
		 *
		 * @param integer intImageWidth The image´s width that will be showed
		 * @param integer intImageHeight The image´s height that will be showed
		 */
		function _resize_container_image_box(intImageWidth,intImageHeight) {
			// Get current width and height
			var intCurrentWidth = $('#lightboxContainerImageBox').width();
			var intCurrentHeight = $('#lightboxContainerImageBox').height();
			// Get the width and height of the selected image plus the padding
			var intWidth = (intImageWidth + (settings.containerBorderSize * 2)); // Plus the image´s width and the left and right padding value
			var intHeight = (intImageHeight + (settings.containerBorderSize * 2)); // Plus the image´s height and the left and right padding value
			// Diferences
			var intDiffW = intCurrentWidth - intWidth;
			var intDiffH = intCurrentHeight - intHeight;
			// Perfomance the effect
			$('#lightboxContainerImageBox').animate({ width: intWidth, height: intHeight },settings.containerResizeSpeed,function() { _show_image(); });
			if ( ( intDiffW == 0 ) && ( intDiffH == 0 ) ) {
				if ( $.browser.msie ) {
					___pause(250);
				} else {
					___pause(100);	
				}
			}
			$('#lightboxContainerImageDataBox').css({ width: intImageWidth });
			$('#lightboxNavBtnNext').css({ height: intImageHeight + (settings.containerBorderSize * 2) });
			$('#lightboxNavBtnPrev').css({ height: intImageHeight + (settings.containerBorderSize * 2) });
		};
		/**
		 * Show the prepared image
		 *
		 */
		function _show_image() {
			
			/*  Wait until the animation has completed before loading flash video.
				If we do not wait, the flash content overlap the edge of the lightbox */		
			if( settings.type == 'flashVideo' ) {
				swfobject.embedSWF(settings.flvPlayer, 
									'lightboxImage', 
									settings.width, 
									settings.height, 
									"9.0.0",'', 
									{gXMLFilename:settings.file, file:settings.file},{},{});
			}
			
			$('#lightboxLoading').hide();
			$('#lightboxImage').fadeIn(function() {
				_show_image_data();
				_set_navigation();
			});
			_preload_neighbor_images();
		};
		/**
		 * Show the image information
		 *
		 */
		function _show_image_data() {
			$('#lightboxContainerImageDataBox').slideDown('fast');
			$('#lightboxImageDetailsCaption').hide();
			if ( settings.imageArray[settings.activeImage][1] ) {
				$('#lightboxImageDetailsCaption').html(settings.imageArray[settings.activeImage][1]).show();
			}
			// If we have a image set, display 'Image X of X'
			if ( settings.imageArray.length > 1 ) {
				$('#lightboxImageDetailsCurrentNumber').html(settings.txtImage + ' ' + ( settings.activeImage + 1 ) + ' ' + settings.txtOf + ' ' + settings.imageArray.length).show();
			}		
		}
		/**
		 * Display the button navigations
		 *
		 */
		function _set_navigation() {
			$('#lightboxNav').show();
			// Instead to define this configuration in CSS file, we define here. And it´s need to IE. Just.
			$('#lightboxNavBtnPrev').css({ 'background' : 'transparent url(' + settings.imageBlank + ') no-repeat' });
			$('#lightboxNavBtnNext').css({ 'background' : 'transparent url(' + settings.imageBlank + ') no-repeat' });
			
			// Show the prev button, if not the first image in set
			if ( settings.activeImage != 0 ) {
				if ( settings.fixedNavigation ) {
					$('#lightboxNavBtnPrev').css({ 'background' : 'url(' + settings.imageBtnPrev + ') left 15% no-repeat' })
						.unbind()
						.bind('click',function() {
							settings.activeImage = settings.activeImage - 1;
							_set_image_to_view();
							return false;
						});
				} else {
					// Show the images button for Next buttons
					$('#lightboxNavBtnPrev').unbind().hover(function() {
						$(this).css({ 'background' : 'url(' + settings.imageBtnPrev + ') left 15% no-repeat' });
					},function() {
						$(this).css({ 'background' : 'transparent url(' + settings.imageBlank + ') no-repeat' });
					}).show().bind('click',function() {
						settings.activeImage = settings.activeImage - 1;
						_set_image_to_view();
						return false;
					});
				}
			}
			
			// Show the next button, if not the last image in set
			if ( settings.activeImage != ( settings.imageArray.length -1 ) ) {
				if ( settings.fixedNavigation ) {
					$('#lightboxNavBtnNext').css({ 'background' : 'url(' + settings.imageBtnNext + ') right 15% no-repeat' })
						.unbind()
						.bind('click',function() {
							settings.activeImage = settings.activeImage + 1;
							_set_image_to_view();
							return false;
						});
				} else {
					// Show the images button for Next buttons
					$('#lightboxNavBtnNext').unbind().hover(function() {
						$(this).css({ 'background' : 'url(' + settings.imageBtnNext + ') right 15% no-repeat' });
					},function() {
						$(this).css({ 'background' : 'transparent url(' + settings.imageBlank + ') no-repeat' });
					}).show().bind('click',function() {
						settings.activeImage = settings.activeImage + 1;
						_set_image_to_view();
						return false;
					});
				}
			}
			// Enable keyboard navigation
			_enable_keyboard_navigation();
		}
		/**
		 * Enable a support to keyboard navigation
		 *
		 */
		function _enable_keyboard_navigation() {
			$(document).keydown(function(objEvent) {
				_keyboard_action(objEvent);
			});
		}
		/**
		 * Disable the support to keyboard navigation
		 *
		 */
		function _disable_keyboard_navigation() {
			$(document).unbind();
		}
		/**
		 * Perform the keyboard actions
		 *
		 */
		function _keyboard_action(objEvent) {
			// To ie
			if ( objEvent == null ) {
				keycode = event.keyCode;
				escapeKey = 27;
			// To Mozilla
			} else {
				keycode = objEvent.keyCode;
				escapeKey = objEvent.DOM_VK_ESCAPE;
			}
			// Get the key in lower case form
			key = String.fromCharCode(keycode).toLowerCase();
			// Verify the keys to close the ligthBox
			if ( ( key == settings.keyToClose ) || ( key == 'x' ) || ( keycode == escapeKey ) ) {
				_finish();
			}
			// Verify the key to show the previous image
			if ( ( key == settings.keyToPrev ) || ( keycode == 37 ) ) {
				// If we´re not showing the first image, call the previous
				if ( settings.activeImage != 0 ) {
					settings.activeImage = settings.activeImage - 1;
					_set_image_to_view();
					_disable_keyboard_navigation();
				}
			}
			// Verify the key to show the next image
			if ( ( key == settings.keyToNext ) || ( keycode == 39 ) ) {
				// If we´re not showing the last image, call the next
				if ( settings.activeImage != ( settings.imageArray.length - 1 ) ) {
					settings.activeImage = settings.activeImage + 1;
					_set_image_to_view();
					_disable_keyboard_navigation();
				}
			}
		}
		/**
		 * Preload prev and next images being showed
		 *
		 */
		function _preload_neighbor_images() {
			if ( (settings.imageArray.length -1) > settings.activeImage ) {
				objNext = new Image();
				objNext.src = settings.imageArray[settings.activeImage + 1][0];
			}
			if ( settings.activeImage > 0 ) {
				objPrev = new Image();
				objPrev.src = settings.imageArray[settings.activeImage -1][0];
			}
		}
		/**
		 * Remove jQuery lightBox plugin HTML markup
		 *
		 */
		function _finish() {
			$('#jqueryLightbox').remove();
			$('#jqueryOverlay').fadeOut(function() { $('#jqueryOverlay').remove(); });
			// Show some elements to avoid conflict with overlay in IE. These elements appear above the overlay.
			$('embed, object, select').css({ 'visibility' : 'visible' });
		}
		/**
		 / THIRD FUNCTION
		 * getPageSize() by quirksmode.com
		 *
		 * @return Array Return an array with page width, height and window width, height
		 */
		function ___getPageSize() {
			var xScroll, yScroll;
			if (window.innerHeight && window.scrollMaxY) {	
				xScroll = window.innerWidth + window.scrollMaxX;
				yScroll = window.innerHeight + window.scrollMaxY;
			} else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
				xScroll = document.body.scrollWidth;
				yScroll = document.body.scrollHeight;
			} else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
				xScroll = document.body.offsetWidth;
				yScroll = document.body.offsetHeight;
			}
			var windowWidth, windowHeight;
			if (self.innerHeight) {	// all except Explorer
				if(document.documentElement.clientWidth){
					windowWidth = document.documentElement.clientWidth; 
				} else {
					windowWidth = self.innerWidth;
				}
				windowHeight = self.innerHeight;
			} else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
				windowWidth = document.documentElement.clientWidth;
				windowHeight = document.documentElement.clientHeight;
			} else if (document.body) { // other Explorers
				windowWidth = document.body.clientWidth;
				windowHeight = document.body.clientHeight;
			}	
			// for small pages with total height less then height of the viewport
			if(yScroll < windowHeight){
				pageHeight = windowHeight;
			} else { 
				pageHeight = yScroll;
			}
			// for small pages with total width less then width of the viewport
			if(xScroll < windowWidth){	
				pageWidth = xScroll;		
			} else {
				pageWidth = windowWidth;
			}
			arrayPageSize = new Array(pageWidth,pageHeight,windowWidth,windowHeight);
			return arrayPageSize;
		}
		/**
		 / THIRD FUNCTION
		 * getPageScroll() by quirksmode.com
		 *
		 * @return Array Return an array with x,y page scroll values.
		 */
		function ___getPageScroll() {
			var xScroll, yScroll;
			if (self.pageYOffset) {
				yScroll = self.pageYOffset;
				xScroll = self.pageXOffset;
			} else if (document.documentElement && document.documentElement.scrollTop) {	 // Explorer 6 Strict
				yScroll = document.documentElement.scrollTop;
				xScroll = document.documentElement.scrollLeft;
			} else if (document.body) {// all other Explorers
				yScroll = document.body.scrollTop;
				xScroll = document.body.scrollLeft;	
			}
			arrayPageScroll = new Array(xScroll,yScroll);
			return arrayPageScroll;
		}
		 /**
		  * Stop the code execution from a escified time in milisecond
		  *
		  */
		 function ___pause(ms) {
			var date = new Date(); 
			curDate = null;
			do { var curDate = new Date(); }
			while ( curDate - date < ms);
		 }
		// Return the jQuery object for chaining. The unbind method is used to avoid click conflict when the plugin is called more than once
		return this.unbind('click').click(_initialize);
	};
})(jQuery); // Call and execute the function immediately passing the jQuery object
/* jquery.simplemodal.js (243) */
/***
 * SimpleModal 1.3.3 - jQuery Plugin
 * http://www.ericmmartin.com/projects/simplemodal/
 * Copyright (c) 2009 Eric Martin (http://twitter.com/EricMMartin)
 * Dual licensed under the MIT and GPL licenses
 * Revision: $Id: jquery.simplemodal.js 228 2009-10-30 13:34:27Z emartin24 $
 */

/**
 * Box UK modifications:
 * - changed wrapper class names from 'simplemodal-xxx/' to 'modalXxx' for backwards compatibility with 1.1.1
 * - options.autoPosition: can now take object specifying horizontal and vertical positioning independently
 * - options.minHeight: set to false to let lightbox be whatever height it wants
 */

/**
 * SimpleModal is a lightweight jQuery plugin that provides a simple
 * interface to create a modal dialog.
 *
 * The goal of SimpleModal is to provide developers with a cross-browser
 * overlay and container that will be populated with data provided to
 * SimpleModal.
 *
 * There are two ways to call SimpleModal:
 * 1) As a chained function on a jQuery object, like $('#myDiv').modal();.
 * This call would place the DOM object, #myDiv, inside a modal dialog.
 * Chaining requires a jQuery object. An optional options object can be
 * passed as a parameter.
 *
 * @example $('<div>my data</div>').modal({options});
 * @example $('#myDiv').modal({options});
 * @example jQueryObject.modal({options});
 *
 * 2) As a stand-alone function, like $.modal(data). The data parameter
 * is required and an optional options object can be passed as a second
 * parameter. This method provides more flexibility in the types of data
 * that are allowed. The data could be a DOM object, a jQuery object, HTML
 * or a string.
 *
 * @example $.modal('<div>my data</div>', {options});
 * @example $.modal('my data', {options});
 * @example $.modal($('#myDiv'), {options});
 * @example $.modal(jQueryObject, {options});
 * @example $.modal(document.getElementById('myDiv'), {options});
 *
 * A SimpleModal call can contain multiple elements, but only one modal
 * dialog can be created at a time. Which means that all of the matched
 * elements will be displayed within the modal container.
 *
 * SimpleModal internally sets the CSS needed to display the modal dialog
 * properly in all browsers, yet provides the developer with the flexibility
 * to easily control the look and feel. The styling for SimpleModal can be
 * done through external stylesheets, or through SimpleModal, using the
 * overlayCss and/or containerCss options.
 *
 * SimpleModal has been tested in the following browsers:
 * - IE 6, 7, 8
 * - Firefox 2, 3
 * - Opera 9, 10
 * - Safari 3, 4
 * - Chrome 1, 2
 *
 * @name SimpleModal
 * @type jQuery
 * @requires jQuery v1.2.2
 * @cat Plugins/Windows and Overlays
 * @author Eric Martin (http://ericmmartin.com)
 * @version 1.3.3
 */
;(function ($) {
	var ie6 = $.browser.msie && parseInt($.browser.version) == 6 && typeof window['XMLHttpRequest'] != "object",
		ieQuirks = null,
		w = [];

	/*
	 * Stand-alone function to create a modal dialog.
	 *
	 * @param {string, object} data A string, jQuery object or DOM object
	 * @param {object} [options] An optional object containing options overrides
	 */
	$.modal = function (data, options) {
		return $.modal.impl.init(data, options);
	};

	/*
	 * Stand-alone close function to close the modal dialog
	 */
	$.modal.close = function () {
		$.modal.impl.close();
	};

	/*
	 * Chained function to create a modal dialog.
	 *
	 * @param {object} [options] An optional object containing options overrides
	 */
	$.fn.modal = function (options) {
		return $.modal.impl.init(this, options);
	};

	/*
	 * SimpleModal default options
	 *
	 * appendTo:		(String:'body') The jQuery selector to append the elements to. For ASP.NET, use 'form'.
	 * focus:			(Boolean:true) Forces focus to remain on the modal dialog
	 * opacity:			(Number:50) The opacity value for the overlay div, from 0 - 100
	 * overlayId:		(String:'simplemodal-overlay') The DOM element id for the overlay div
	 * overlayCss:		(Object:{}) The CSS styling for the overlay div
	 * containerId:		(String:'simplemodal-container') The DOM element id for the container div
	 * containerCss:	(Object:{}) The CSS styling for the container div
	 * dataId:			(String:'simplemodal-data') The DOM element id for the data div
	 * dataCss:			(Object:{}) The CSS styling for the data div
	 * minHeight:		(Number:200) The minimum height for the container
	 * minWidth:		(Number:200) The minimum width for the container
	 * maxHeight:		(Number:null) The maximum height for the container. If not specified, the window height is used.
	 * maxWidth:		(Number:null) The maximum width for the container. If not specified, the window width is used.
	 * autoResize:		(Boolean:false) Resize container on window resize? Use with caution - this may have undesirable side-effects.
	 * autoPosition:	(Boolean:true) Reposition container on window resize?
	 * zIndex:			(Number: 1000) Starting z-index value
	 * close:			(Boolean:true) If true, closeHTML, escClose and overClose will be used if set.
	 							If false, none of them will be used.
	 * closeHTML:		(String:'<a class="modalCloseImg" title="Close"></a>') The HTML for the
							default close link. SimpleModal will automatically add the closeClass to this element.
	 * closeClass:		(String:'simplemodal-close') The CSS class used to bind to the close event
	 * escClose:		(Boolean:true) Allow Esc keypress to close the dialog?
	 * overlayClose:	(Boolean:false) Allow click on overlay to close the dialog?
	 * position:		(Array:null) Position of container [top, left]. Can be number of pixels or percentage
	 * persist:			(Boolean:false) Persist the data across modal calls? Only used for existing
								DOM elements. If true, the data will be maintained across modal calls, if false,
								the data will be reverted to its original state.
	 * onOpen:			(Function:null) The callback function used in place of SimpleModal's open
	 * onShow:			(Function:null) The callback function used after the modal dialog has opened
	 * onClose:			(Function:null) The callback function used in place of SimpleModal's close
	 */
	$.modal.defaults = {
		appendTo: 'body',
		focus: true,
		opacity: 50,
		overlayId: 'simplemodal-overlay',
		overlayCss: {},
		containerId: 'simplemodal-container',
		containerCss: {},
		dataId: 'simplemodal-data',
		dataCss: {},
		minHeight: 200,
		minWidth: 300,
		maxHeight: null,
		maxWidth: null,
		autoResize: false,
		autoPosition: {
                    horizontal:true,
                    vertical:false
                },
		zIndex: 1000,
		close: true,
		closeHTML: '<a class="modalCloseImg" title="Close"></a>',
		closeClass: 'simplemodal-close',
		escClose: true,
		overlayClose: false,
		position: null,
		persist: false,
		onOpen: null,
		onShow: null,
		onClose: null
	};

	/*
	 * Main modal object
	 */
	$.modal.impl = {
		/*
		 * Modal dialog options
		 */
		o: null,
		/*
		 * Contains the modal dialog elements and is the object passed
		 * back to the callback (onOpen, onShow, onClose) functions
		 */
		d: {},
		/*
		 * Initialize the modal dialog
		 */
		init: function (data, options) {
			var s = this;

			// don't allow multiple calls
			if (s.d.data) {
				return false;
			}

			// $.boxModel is undefined if checked earlier
			ieQuirks = $.browser.msie && !$.boxModel;

			// merge defaults and user options
			s.o = $.extend({}, $.modal.defaults, options);

			// keep track of z-index
			s.zIndex = s.o.zIndex;

			// set the onClose callback flag
			s.occb = false;

			// determine how to handle the data based on its type
			if (typeof data == 'object') {
				// convert DOM object to a jQuery object
				data = data instanceof jQuery ? data : $(data);

				// if the object came from the DOM, keep track of its parent
				if (data.parent().parent().size() > 0) {
					s.d.parentNode = data.parent();

					// persist changes? if not, make a clone of the element
					if (!s.o.persist) {
						s.d.orig = data.clone(true);
					}
				}
			}
			else if (typeof data == 'string' || typeof data == 'number') {
				// just insert the data as innerHTML
				data = $('<div></div>').html(data);
			}
			else {
				// unsupported data type!
				alert('SimpleModal Error: Unsupported data type: ' + typeof data);
				return s;
			}

			// create the modal overlay, container and, if necessary, iframe
			s.create(data);
			data = null;

			// display the modal dialog
			s.open();

			// useful for adding events/manipulating data in the modal dialog
			if ($.isFunction(s.o.onShow)) {
				s.o.onShow.apply(s, [s.d]);
			}

			// don't break the chain =)
			return s;
		},
		/*
		 * Create and add the modal overlay and container to the page
		 */
		create: function (data) {
			var s = this;

			// get the window properties
			w = s.getDimensions();

			// add an iframe to prevent select options from bleeding through
			if (ie6) {
				s.d.iframe = $('<iframe src="javascript:false;"></iframe>')
					.css($.extend(s.o.iframeCss, {
						display: 'none',
						opacity: 0,
						position: 'fixed',
						height: w[0],
						width: w[1],
						zIndex: s.o.zIndex,
						top: 0,
						left: 0
					}))
					.appendTo(s.o.appendTo);
			}

			// create the overlay
			s.d.overlay = $('<div></div>')
				.attr('id', s.o.overlayId)
				.addClass('simplemodal-overlay')
                                .addClass('modalOverlay')
				.css($.extend(s.o.overlayCss, {
					display: 'none',
					opacity: s.o.opacity / 100,
					height: w[0],
					width: w[1],
					position: 'fixed',
					left: 0,
					top: 0,
					zIndex: s.o.zIndex + 1
				}))
				.appendTo(s.o.appendTo);

			// create the container
			s.d.container = $('<div></div>')
				.attr('id', s.o.containerId)
				.addClass('simplemodal-container')
                                .addClass('modalContainer')   /* For backwards compatibility with 1.1.1 */
				.css($.extend(s.o.containerCss, {
					display: 'none',
					position: 'fixed',
					zIndex: s.o.zIndex + 2
				}))
				.append(s.o.close && s.o.closeHTML
					? $(s.o.closeHTML).addClass(s.o.closeClass)
					: '')
				.appendTo(s.o.appendTo);

			s.d.wrap = $('<div></div>')
				.attr('tabIndex', -1)
				.addClass('simplemodal-wrap')
				.css({height: '100%', outline: 0, width: '100%'})
				.appendTo(s.d.container);

			// add styling and attributes to the data
			// append to body to get correct dimensions, then move to wrap
			s.d.data = data
				.attr('id', data.attr('id') || s.o.dataId)
				.addClass('simplemodal-data')
                                .addClass('modalData') /* For compatibility with version 1.1.1 */
				.css($.extend(s.o.dataCss, {
						display: 'none'
				}))
				.appendTo('body');
			data = null;

			s.setContainerDimensions();
			s.d.data.appendTo(s.d.wrap);

			// fix issues with IE
			if (ie6 || ieQuirks) {
				s.fixIE();
			}
		},
		/*
		 * Bind events
		 */
		bindEvents: function () {
			var s = this;

			// bind the close event to any element with the closeClass class
			$('.' + s.o.closeClass).bind('click.simplemodal', function (e) {
				e.preventDefault();
				s.close();
			});

			// bind the overlay click to the close function, if enabled
			if (s.o.close && s.o.overlayClose) {
				s.d.overlay.bind('click.simplemodal', function (e) {
					e.preventDefault();
					s.close();
				});
			}

			// bind keydown events
			$(document).bind('keydown.simplemodal', function (e) {
				if (s.o.focus && e.keyCode == 9) { // TAB
					s.watchTab(e);
				}
				else if ((s.o.close && s.o.escClose) && e.keyCode == 27) { // ESC
					e.preventDefault();
					s.close();
				}
			});

			// update window size
			$(window).bind('resize.simplemodal', function () {
				// redetermine the window width/height
				w = s.getDimensions();

				// reposition the dialog
				s.setContainerDimensions(true);

				if (ie6 || ieQuirks) {
					s.fixIE();
				}
				else {
					// update the iframe & overlay
					s.d.iframe && s.d.iframe.css({height: w[0], width: w[1]});
					s.d.overlay.css({height: w[0], width: w[1]});
				}
			});
		},
		/*
		 * Unbind events
		 */
		unbindEvents: function () {
			$('.' + this.o.closeClass).unbind('click.simplemodal');
			$(document).unbind('keydown.simplemodal');
			$(window).unbind('resize.simplemodal');
			this.d.overlay.unbind('click.simplemodal');
		},
		/*
		 * Fix issues in IE6 and IE7 in quirks mode
		 */
		fixIE: function () {
			var s=this, p = s.o.position;

			// simulate fixed position - adapted from BlockUI
			$.each([s.d.iframe || null, s.d.overlay, s.d.container], function (i, el) {
				if (el) {
					var bch = 'document.body.clientHeight', bcw = 'document.body.clientWidth',
						bsh = 'document.body.scrollHeight', bsl = 'document.body.scrollLeft',
						bst = 'document.body.scrollTop', bsw = 'document.body.scrollWidth',
						ch = 'document.documentElement.clientHeight', cw = 'document.documentElement.clientWidth',
						sl = 'document.documentElement.scrollLeft', st = 'document.documentElement.scrollTop',
						s = el[0].style;

					s.position = 'absolute';
					if (i < 2) {
						s.removeExpression('height');
						s.removeExpression('width');
						s.setExpression('height','' + bsh + ' > ' + bch + ' ? ' + bsh + ' : ' + bch + ' + "px"');
						s.setExpression('width','' + bsw + ' > ' + bcw + ' ? ' + bsw + ' : ' + bcw + ' + "px"');
					}
					else {
						var te, le;
						if (p && p.constructor == Array) {
							var top = p[0]
								? typeof p[0] == 'number' ? p[0].toString() : p[0].replace(/px/, '')
								: el.css('top').replace(/px/, '');
							te = top.indexOf('%') == -1
								? top + ' + (t = ' + st + ' ? ' + st + ' : ' + bst + ') + "px"'
								: parseInt(top.replace(/%/, '')) + ' * ((' + ch + ' || ' + bch + ') / 100) + (t = ' + st + ' ? ' + st + ' : ' + bst + ') + "px"';

							if (p[1]) {
								var left = typeof p[1] == 'number' ? p[1].toString() : p[1].replace(/px/, '');
								le = left.indexOf('%') == -1
									? left + ' + (t = ' + sl + ' ? ' + sl + ' : ' + bsl + ') + "px"'
									: parseInt(left.replace(/%/, '')) + ' * ((' + cw + ' || ' + bcw + ') / 100) + (t = ' + sl + ' ? ' + sl + ' : ' + bsl + ') + "px"';
							}
						}
						else {
							te = '(' + ch + ' || ' + bch + ') / 2 - (this.offsetHeight / 2) + (t = ' + st + ' ? ' + st + ' : ' + bst + ') + "px"';
							le = '(' + cw + ' || ' + bcw + ') / 2 - (this.offsetWidth / 2) + (t = ' + sl + ' ? ' + sl + ' : ' + bsl + ') + "px"';
						}
						s.removeExpression('top');
						s.removeExpression('left');
						s.setExpression('top', te);
						s.setExpression('left', le);
					}
				}
			});
		},
		focus: function (pos) {
			var s = this, p = pos || 'first';

			// focus on dialog or the first visible/enabled input element
			var input = $(':input:enabled:visible:' + p, s.d.wrap);
			input.length > 0 ? input.focus() : s.d.wrap.focus();
		},
		getDimensions: function () {
			var el = $(window);

			// fix a jQuery/Opera bug with determining the window height
			var h = $.browser.opera && $.browser.version > '9.5' && $.fn.jquery <= '1.2.6' ? document.documentElement['clientHeight'] :
				$.browser.opera && $.browser.version < '9.5' && $.fn.jquery > '1.2.6' ? window.innerHeight :
				el.height();

			return [h, el.width()];
		},
		getVal: function (v) {
			return v == 'auto' ? 0
				: v.indexOf('%') > 0 ? v
					: parseInt(v.replace(/px/, ''));
		},
		setContainerDimensions: function (resize) {
			var s = this;

			if (!resize || (resize && s.o.autoResize)) {
				// get the dimensions for the container and data
				var ch = s.getVal(s.d.container.css('height')), cw = s.getVal(s.d.container.css('width')),
					dh = s.d.data.outerHeight(true), dw = s.d.data.outerWidth(true);

				var mh = s.o.maxHeight && s.o.maxHeight < w[0] ? s.o.maxHeight : w[0],
					mw = s.o.maxWidth && s.o.maxWidth < w[1] ? s.o.maxWidth : w[1];

				// height
				if (!ch) {
                                        if (s.o.minHeight === false) {
                                            ch = 'auto';
                                        } else {
                                            if (!dh) {
                                                ch = s.o.minHeight;
                                            } else {
                                                if (dh > mh) {
                                                    ch = mh;
                                                } else if (dh < s.o.minHeight) {
                                                    ch = s.o.minHeight;
                                                } else {
                                                    ch = dh;
                                                }
                                            }
                                        }
                                        

				}
				else {
                                        ch = ch > mh ? mh : ch;
				}

				// width
				if (!cw) {
					if (!dw) {cw = s.o.minWidth;}
					else {
						if (dw > mw) {cw = mw;}
						else if (dw < s.o.minWidth) {cw = s.o.minWidth;}
						else {cw = dw;}
					}
				}
				else {
					cw = cw > mw ? mw : cw;
				}

				s.d.container.css({height: ch, width: cw});
				if (dh > ch || dw > cw) {
					//s.d.wrap.css({overflow:'auto'});
				}
			}

			if (s.o.autoPosition) {
				s.setPosition();
			}
		},
		setPosition: function () {
			var s = this, top, left,
				hc = (w[0]/2) - (s.d.container.outerHeight(true)/2),
				vc = (w[1]/2) - (s.d.container.outerWidth(true)/2);

			if (s.o.position && Object.prototype.toString.call(s.o.position) === "[object Array]") {
				top = s.o.position[0] || hc;
				left = s.o.position[1] || vc;
			} else {
				top = hc;
				left = vc;
			}
                        
                        if (typeof s.o.autoPosition == 'object') {
                            switch (s.o.autoPosition.horizontal.toString()+':'+s.o.autoPosition.vertical.toString()) {                                   
                                case 'false:true':
                                    s.d.container.css({top: top});
                                    break;
                                    
                                case 'true:false':
                                    s.d.container.css({left: left});
                                    break;
                                    
                                case 'true:true':
                                    s.d.container.css({left: left, top: top}); 
                                    break;                                    
                                    
                                 default:                                     
                                     break;
                            }                            
                        } else {
                            s.d.container.css({left: left, top: top});                            
                        }
                        
                            
		},
		watchTab: function (e) {
			var s = this;

			if ($(e.target).parents('.simplemodal-container').length > 0) {
				// save the list of inputs
				s.inputs = $(':input:enabled:visible:first, :input:enabled:visible:last', s.d.data[0]);

				// if it's the first or last tabbable element, refocus
				if ((!e.shiftKey && e.target == s.inputs[s.inputs.length -1]) ||
						(e.shiftKey && e.target == s.inputs[0]) ||
						s.inputs.length == 0) {
					e.preventDefault();
					var pos = e.shiftKey ? 'last' : 'first';
					setTimeout(function () {s.focus(pos);}, 10);
				}
			}
			else {
				// might be necessary when custom onShow callback is used
				e.preventDefault();
				setTimeout(function () {s.focus();}, 10);
			}
		},
		/*
		 * Open the modal dialog elements
		 * - Note: If you use the onOpen callback, you must "show" the
		 *	        overlay and container elements manually
		 *         (the iframe will be handled by SimpleModal)
		 */
		open: function () {
			var s = this;
			// display the iframe
			s.d.iframe && s.d.iframe.show();

			if ($.isFunction(s.o.onOpen)) {
				// execute the onOpen callback
				s.o.onOpen.apply(s, [s.d]);
			}
			else {
				// display the remaining elements
				s.d.overlay.show();
				s.d.container.show();
				s.d.data.show();
			}

			s.focus();

			// bind default events
			s.bindEvents();
		},
		/*
		 * Close the modal dialog
		 * - Note: If you use an onClose callback, you must remove the
		 *         overlay, container and iframe elements manually
		 *
		 * @param {boolean} external Indicates whether the call to this
		 *     function was internal or external. If it was external, the
		 *     onClose callback will be ignored
		 */
		close: function () {
			var s = this;

			// prevent close when dialog does not exist
			if (!s.d.data) {
				return false;
			}

			// remove the default events
			s.unbindEvents();

			if ($.isFunction(s.o.onClose) && !s.occb) {
				// set the onClose callback flag
				s.occb = true;

				// execute the onClose callback
				s.o.onClose.apply(s, [s.d]);
			}
			else {
				// if the data came from the DOM, put it back
				if (s.d.parentNode) {
					// save changes to the data?
					if (s.o.persist) {
						// insert the (possibly) modified data back into the DOM
						s.d.data.hide().appendTo(s.d.parentNode);
					}
					else {
						// remove the current and insert the original,
						// unmodified data back into the DOM
						s.d.data.hide().remove();
						s.d.orig.appendTo(s.d.parentNode);
					}
				}
				else {
					// otherwise, remove it
					s.d.data.hide().remove();
				}

				// remove the remaining elements
				s.d.container.hide().remove();
				s.d.overlay.hide().remove();
				s.d.iframe && s.d.iframe.hide().remove();

				// reset the dialog object
				s.d = {};
			}
		}
	};
})(jQuery);
/* jquery.tooltip.js (339) */
/**
 * @package private_output_careers_wales_learningpathways
 * @version $Id: jquery.tooltip.js 8432 2008-05-23 14:09:25Z jamesrc $
 * @copyright Copyright (c) 2008 Box UK Ltd. All rights reserved.
 *
 * Simple plugin to add tool tips to a page.
 *
 * @audit
 * - 2009-08-11  JRC  Created file.
 */
(function($) {

    /**
     *
     *
     *
     */
    $.fn.qToolTip = function (options) {
        var defaults = {
            'selectors': {
                'content': '.content',
                'icon'   : 'img'
            }
        };

        var settings = $.extend({}, defaults, options);

        return this.each(function () {
            $.fn.qToolTip.initialiseElement($(this), settings);
        });
    };


    /**
     *
     * @param element jQuery
     * @param {} settings
     */
    $.fn.qToolTip.initialiseElement = function (tip, settings) {
        // Examine element and determine most ideal help icon placement
        // -> input, select, radio, checkbox: to the right of the field
        // -> textarea: after the label preceding the field

        var content = $(settings.selectors.content, tip);
        var icon = $(settings.selectors.icon, tip);

        // Apply qtip plugin with behaviours to match original tooltip style and behaviour
        var qtipOptions = {
           content: content,
           show: 'mouseover',
           hide: 'mouseout',
           position: {
               adjust: {
                   screen: true
               }
           },
           style: {
              background:'transparent',
//              width: 270,
              padding: 0,
              border: {
                 width: 0,
                 radius: 0,
                 color: 'transparent'
              }
           }
        };
        
        if (settings.style) {
            if (settings.style.classes) {
                qtipOptions.style.classes = settings.style.classes;
            }
        } 

        icon.qtip(qtipOptions);
    };

    /**
     * Clone an existing tooltip by specifying a selector for the element to which the to-be-cloned
     * tooltip is associated
     * -> this simply finds the next tooltip following the specified element
     *
     * @param selector string a jQuery selector for the element preceiding the required tooltip
     * @return jQuery a jQuery object containing a copy of the toolip
     *
     */

    $.fn.qToolTip.clone = function (selector) {
        var targetElement = $(selector);
        var targetElementParent = targetElement.parent();
        var tooltips = $('.toolTip', targetElementParent).clone();

        return tooltips[0];
    };

})(jQuery);
/* jquery.tooglePathways.js (340) */
/**
 * @package private_output_careers_wales_learningpathways
 * @version $Id: jquery.tooglePathways.js 8432 2008-05-23 14:09:25Z jamesrc $
 * @copyright Copyright (c) 2008 Box UK Ltd. All rights reserved.
 *
 * Simple plugin to add tool tips to a page.
 *
 * @audit
 * - 2009-08-11  JRC  Created file.
 */
(function($) {

    /**
     * Main access to method, allows the user to override the defualts
     * options set by the plugin.
     *
     * @param Object options
     */
    $.fn.tooglePathways = function(options) {

        var defaults = {
            'form': 'form.new',
            'introduction': '.introduction:first',
            'content': '.content',
            'module' : 'CertificateAndCourses'
        };
        var settings = $.extend(defaults, options);
        
        return this.each(function() {
            $.fn.tooglePathways.init( this, settings );
        });
    };

    /**
     * Sets up hover state a tool tip.
     *
     * @param HTMLElement element
     * @param Object options
     */
    $.fn.tooglePathways.init = function( element, options ) {

        var block   = $(element);
        var heading = $(options.introduction, block);
        var content = $(options.content, block);
        var form    = $(options.form, block);
        var errMsg  = $('.errorMessage', form);
        var cancel  = getCancelContent();

        if (content.size() && errMsg.size()) {
            form.show();
        } else {
            form.hide();
        }

        content.size() && !errMsg.size() ? form.hide() : form.show();
        heading.css({'cursor' : 'pointer'});
        cancel.appendTo(form);

        form.css('float', 'right');
        
        heading.toggle(
            function() {
                form.css('display') == 'none' ? form.slideDown() && $('.toolTip', form).show() : $('.toolTip', form).hide() && form.slideUp();
            },
            function() {
                form.css('display') == 'none' ? form.slideDown() && $('.toolTip', form).show() : $('.toolTip', form).hide() && form.slideUp();
            }
        );

        function getCancelContent() {
            var cancelAnchor = $('<a href="#" />')
                .append(oLocale.getTranslation(options.module, 'labelCancel'))
                .click(function(){
                    form.slideUp();
                    return false;
                });
            var cancelText = $('<p />')
                .addClass('cancel')
                .append(oLocale.getTranslation(options.module, 'labelOr')+' ')
                .append(cancelAnchor)
                .append(' '+oLocale.getTranslation(options.module, 'labelToClose'));
            return cancelText;
        };
    };
})(jQuery);
/* jquery.lightBoxDelete.js (341) */
/**
 * @package private_output_careers_wales_learningpathways
 * @version $Id: jquery.tooltip.js 8432 2008-05-23 14:09:25Z jamesrc $
 * @copyright Copyright (c) 2008 Box UK Ltd. All rights reserved.
 *
 * Simple plugin to add tool tips to a page.
 *
 * @request js.modal
 * @audit
 * - 2009-08-11  JRC  Created file.
 */

(function($) {

    /**
     * Main access to method, allows the user to override the defualts
     * options set by the plugin.
     *
     * @param Object options
     */
    $.fn.lightBoxDelete = function(options) {

        var defaults = {
            'module'        : 'CertificatesAndCourses',
            'overlayId'     : 'removalOverlay',
            'containerId'   : 'removalContainer',
            'contentClass'  : 'removeContent',
            'removeButton'  : SITE_WEB_ROOT+ 'custom/careers_wales/img/learningPathways/buttons/button_remove_'+oLocale.getFieldValue('id')+'.png',
            'preloadAction' : function(oParameter) { return oParameter.callback(oParameter.form); },
            'onConfirm'     : function() { return false; },
            'getThumbnail'  : function() { return false; },
            showPreLoadIndicator: false
        };
        var settings = $.extend(defaults, options);

        return this.each(function() {
            $.fn.lightBoxDelete.init( this, settings );
        });
    };

    /**
     * Sets up hover state a tool tip.
     *
     * @param HTMLElement element
     * @param Object options
     */
    $.fn.lightBoxDelete.init = function( element, options ) {

        var handleFormConfirmation = function (element, options) {
            var form    = $(element);
            var id      = $('input[name*="contentId"]', form).attr('value');

            form.submit( function () {
                var lightboxForm = getLightboxForm(form);

                if (options.showPreLoadIndicator==true){
                    var loadMask = $('<div class="loadMask"><img src="custom/careers_wales/img/ajax/spinner.gif" /></div>');
                    lightboxForm.append(loadMask);
                    lightboxForm.cwmodal({
                        overlayId: options.overlayId,
                        containerId: options.containerId,
                        persists: true
                    });
                    loadMask.css({
                        position: 'absolute',
                        top: '45px',
                        left: '12px',
                        width: '535px',
                        'background-color': '#fff',
                        'text-align': 'center',
                        'padding-top': ($(lightboxForm).height()/2)-30
                    });
                    loadMask.height(($(lightboxForm).height()/2)-10);
                }

                return options.preloadAction({
                    'id'       : id,
                    'form'     : lightboxForm,
                    'callback' : onSubmit
                });
            });
        };

        /**
         * Handles a "generic" confirmation, not really sure what this is...
         * Assume that it just allows the user to follow the link in the
         * lightbox?
         */
        var handleGenericConfirmation = function (element, options) {
            getLightBoxContent().cwmodal({
                overlayId  : options.overlayId,
                containerId: options.containerId
            });
        };

        /**
         * Handles displaying of the lightbox and submission of form
         *
         * @return false
         */
        var onSubmit = function(form) {
            if (options.showPreLoadIndicator==false){
                form.cwmodal({
                    overlayId   : options.overlayId,
                    containerId : options.containerId,
                    persist     : true
                });
            } else {
                $('.loadMask', $('div.simplemodal-container')).remove();
            }
            return false;
        };

        /**
         * Handles the setting up of the form for displaying in the lightbox
         *
         * @return jQuery
         */
        var getLightboxForm = function(form) {
            var lightboxForm = form.clone();
            lightboxForm.find('input[type="image"]').attr('src', options.removeButton);
            
            return lightboxForm.addClass(options.contentClass)
                .prepend(getTitle())
                .append(getCancelText())
                .hide();
        };

        /**
         * Returns content to be displayed in the lightbox
         *
         * @return jQuery
         */
        var getLightBoxContent = function () {

            return $('<div />').addClass(options.contentClass)
                .append(getThumbnail())
                .append(getTitle())
                .append(getRemoveButton().click(function() {
                    handleGenericSubmission();
                }))
                .append(getCancelText())
                .hide();
        };

        /**
         * Return the cancel content
         *
         * @return jQuery
         */
        var getCancelText = function () {
            var cancelAnchor  = $('<a href="#" />').append(oLocale.getTranslation(options.module, 'labelCancel'))
                .click(function() {
                    $.cwmodal.close();
                    return false;
            });

            return $('<p />')
                .append(oLocale.getTranslation(options.module, 'labelOr')+' ') .append(cancelAnchor)
                .append(' '+oLocale.getTranslation(options.module, 'labelToClose')
            );
        };

        /**
         * Returns the lightbox title
         *
         * @return jQuery
         */
        var getTitle = function() {
            return $('<h3 />').html(oLocale.getTranslation(options.module, 'labelRemoveItem'));
        };

        /**
         * Returns the thumbnail for the lightbox
         *
         * @return mixed
         */
        var getThumbnail = function() {
            return options.getThumbnail();
        };

        /**
         * Returns the remove button
         *
         * @return jQuery
         */
        var getRemoveButton = function() {
            return $('<img />').attr({
                'src': options.removeButton,
                'alt': oLocale.getTranslation(options.module, 'removeButtonAltText')
            }).css({'cursor':'pointer'});
        };

        /**
         * Handles the clicking of the submission button
         */
        var handleGenericSubmission = function() {
           options.onConfirm();

           if (typeof options.closeModal != 'boolean' || options.closeModal !== false) {
               $.cwmodal.close();
           }
        };
        
        if(element.nodeName.toLowerCase() == 'form' ) {
            handleFormConfirmation(element, options);
            return;
        }
        handleGenericConfirmation(element, options);
    };
})(jQuery);
/* jquery.lightBoxEdit.js (342) */
/**
 * @package private_output_careers_wales_learningpathways
 * @version $Id: jquery.tooltip.js 8432 2008-05-23 14:09:25Z jamesrc $
 * @copyright Copyright (c) 2008 Box UK Ltd. All rights reserved.
 *
 * Simple plugin to add tool tips to a page.
 *
 * @request js.modal
 * @audit
 * - 2009-08-11  JRC  Created file.
 */
(function($) {

    /**
     * Main access to method, allows the user to override the defualts
     * options set by the plugin.
     *
     * @param Object options
     */
    $.fn.lightBoxEdit = function(options) {

        var defaults = {
            'selectors': {
                'form' : '.edit form',
                'editForm' : 'form.new',
                'editField' : 'edit'
            },
            'module': 'SupportTeam',
            'overlayId': 'removalOverlay',
            'containerId' : 'editContainer',
            'action': 'editMember',
            'name' : 'member',
            'formClass': 'supportTeam',
            'aFields': '',
            'instanceId' : null,
            showPreLoadIndicator: false,
            'preLoadAction' : function( parameters ) {
                parameters.callBack();
            }
        };
        var settings = $.extend(defaults, options);
        
        return this.each(function() {
            $.fn.lightBoxEdit.init( this, settings );
        });
    };

    /**
     * Sets up hover state a tool tip.
     *
     * @param HTMLElement element
     * @param Object options
     */
    $.fn.lightBoxEdit.init = function( element, options ) {
        
        var content         = $(element);
        var currentBlock    = $(element).parents('.block:last');
        var cancelContent   = getCancelContent();
        var form            = $(options.selectors.form, content);
        var editForm        = $(options.selectors.editForm, currentBlock).clone().removeClass('new').addClass('edit').addClass(options.formClass);
        var editId          = $('input[name="'+ getFieldFormName(options.selectors.editField)+'"]', form).attr('value');

        // If we cannot load the form or the edit form then return
        if( !(form.length && editForm.length) ) {
            return false;
        }

        updateFormValues();
        updateFormHelper();

        //Remove class 'defaultGreyText' from all textarea elements
        $('textarea', $(editForm)).removeClass('defaultGreyText');
        
        form.submit( function () {
            if (options.showPreLoadIndicator==true){
                //Add an overlay onto the lightbox so that
                //the user can't do anything while it is loading
                var loadMask = $('<div class="loadMask"><img src="custom/careers_wales/img/ajax/spinner.gif" /></div>');

                $(editForm).append(loadMask);
                $(editForm).modal({
                    overlayId: options.overlayId,
                    containerId: options.containerId,
                    persist: true,
                    minHeight: false,
                    onEsc:function(){
                        return true;
                    }
                });
                loadMask.css({
                    position: 'absolute',
                    top: '45px',
                    left: '12px',
                    width: '535px',
                    'background-color': '#fff',
                    'text-align': 'center',
                    'padding-top': ($(editForm).height()/2)-30
                });
                loadMask.height(($(editForm).height()/2)-10);
            }
            options.preLoadAction({
                'id': editId,
                'form' : editForm,
                'callBack' : function() {
                    if (options.showPreLoadIndicator==false){
                        $(editForm).modal( {
                           overlayId: options.overlayId,
                           containerId: options.containerId,
                           persist: true,
                           minHeight:false,
                           onEsc:function(){
                                return true;
                           }
                        });
                    } else {
                        $('.loadMask',$(editForm)).remove();
                    }
                    
                    //add the cancel event handler here
                    $('a.cancelButton',$(editForm)).bind('click', function(){
                        $.modal.close();
                        return false;
                    });
                }
            });
            return false;
        });

        /**
         * Returns an Amaxus friendly form name
         */
        function getFieldFormName( key ) {
            return 'Module['+options.instanceId+']['+key+']';
        };

        /**
         * Returns a cancel text for reverting the edit form back to the
         * way it was.
         */
        function getCancelContent() {
            var cancelAnchor = $('<a class="cancelButton" href="#" />')
                .append(oLocale.getTranslation(options.module, 'labelCancel'));
            var cancelText = $('<p />')
                .addClass('cancel')
                .append(oLocale.getTranslation(options.module, 'labelOr')+' ')
                .append(cancelAnchor)
                .append(' '+oLocale.getTranslation(options.module, 'labelToClose'));
            return cancelText;
        };

        function updateFormHelper() {

            // Add the cancel button
            $('a', editForm).remove();
            $('p.cancel', editForm).remove();
            $('.actionDispatcherMessages', editForm).remove();
            editForm.append(cancelContent);

            $('input, textarea, select', editForm).each(function() {
                var id = $(this).attr('id');

                if( id != undefined ) {
                    var newId    = id+editId;
                    $(this).attr('id', newId);
                }
            });
            
            $('label', editForm).each(function() {
                var forValue = $(this).attr('for');
                var newId    = forValue+editId;
                $(this).attr('for', newId);
            });

            $('<h3 />')
                .text(oLocale.getTranslation(options.module, 'titleEditMember'))
                .prependTo(editForm);

        };

        function updateFormValues() {       

            $('input[name="'+getFieldFormName('action')+'"]', editForm).attr('value', options.action);
            $('input[name="'+getFieldFormName('action')+'"]', editForm)
                .clone()
                .attr('value', editId)
                .attr('name', getFieldFormName(options.name))
                .insertAfter($('input[name="'+getFieldFormName('action')+'"]', editForm));

            for( var name in options.aField ) {
                var fieldName = options.aField[name];
                var fieldValue = $('.'+fieldName, content).text();

                $('input[name="'+getFieldFormName(fieldName)+'"]', editForm).attr('value', fieldValue);
                $('textarea[name="'+getFieldFormName(fieldName)+'"]', editForm).attr('value', fieldValue);

                $('select[name="'+getFieldFormName(fieldName)+'"]', editForm).each(function() {
                    $('option[value="'+fieldValue+'"]', $(this)).attr('selected', 'selected');
                });
            }
        };
    };
})(jQuery);
/* jquery.editInPlace.js (343) */
/**
 * @package private_output_careers_wales_learningpathways
 * @version $Id: jquery.tooltip.js 8432 2008-05-23 14:09:25Z jamesrc $
 * @copyright Copyright (c) 2008 Box UK Ltd. All rights reserved.
 *
 * Simple plugin to allow edit in place
 *
 * @request js.modal
 * @audit
 * - 2009-08-11  JRC  Created file.
 */
(function($) {

    /**
     * Main access to method, allows the user to override the defualts
     * options set by the plugin.
     *
     * @param Object options
     */
    $.fn.editInPlace = function(options) {
        var defaults = {
            'selectors': {
                'form' : '.edit form',    // The form on which submission should cause the edit-in-place to be triggered
                'editForm' : 'form.new'   // The form for adding a new item, which is then copied for editing an existing item
            },
            'instanceId' : null,
            'module': 'CertificatesAndCourses',
            'action': 'editCertificate',
            'name'  : 'certificate',
            'aField' : '',
            'preLoadAction': function( parameters ) {
                parameters.callBack();
            },
            'postLoadAction' : function() {}
        };
        var settings = $.extend(defaults, options);

        return this.each(function() {
            $.fn.editInPlace.init( this, settings );
        });
    };

    /**
     * Takes the content of each element and allows you to edit the
     * content in place
     *
     * @param HTMLElement element
     * @param Object options
     */
    $.fn.editInPlace.init = function( element, options ) {
        
        var oldContent      = $(element).wrap($('<div />').addClass($(element).attr('class')))
                                .css('border-bottom', 'none 0px')
                                .addClass('content');

        var content         = $(element).parent();
        var currentBlock    = $(element).parents('.block:last');
        
        if(currentBlock.size() == 0) {
            currentBlock    = $(element).parents('.amax-block:last');
        }
        
        if( $('form.edit', content).size() > 0 ) {
            return false;
        }
        
        var form            = $(options.selectors.form, content);
        var cancelContent   = getCancelContent();
        var editForm        =  $(options.selectors.editForm, currentBlock).clone(0).removeClass('new').addClass('edit');
        var editId          = $('input[name="'+ getFieldFormName('edit')+'"]', form).attr('value');

        editForm.css('float', 'right');
        
        $('textarea', editForm).removeClass('defaultGreyText');

        updateFormValues();
        updateFormHelper();
        
        form.submit( function() {            
            options.preLoadAction({
                'id': editId,
                'form' : editForm,
                'callBack' : function() {
                    oldContent.slideUp(function() {
                        content.append(editForm);
                        options.postLoadAction({
                            'id': editId,
                            'form' : editForm
                        });
                        editForm.slideDown();
                    });
                }
            });
            return false;
        });

        /**
         * Returns an Amaxus friendly form name
         */
        function getFieldFormName( key ) {
            return 'Module['+options.instanceId+']['+key+']';
        }

        /**
         * Returns a cancel text for reverting the edit form back to the
         * way it was.
         */
        function getCancelContent() {
            var cancelAnchor = $('<a href="#" />')
                .append(oLocale.getTranslation(options.module, 'labelCancel'))
                .click(function(){
                    editForm.slideUp(function() {
                        oldContent.slideDown();
                    });
                    return false;
                });
            var cancelText = $('<p />')
                .addClass('cancel')
                .append(oLocale.getTranslation(options.module, 'labelOr')+' ')
                .append(cancelAnchor)
                .append(' '+oLocale.getTranslation(options.module, 'labelToClose'));

            return cancelText;
        }

        function updateFormValues() {

            $('input[type="hidden"]', editForm).attr('value', options.action);
            $('input[type="hidden"]', editForm).clone()
                .attr('value', editId)
                .attr('name', getFieldFormName(options.name))
                .insertAfter($('input[type="hidden"]', editForm));
                
            for( var name in options.aField ) {
                if (options.aField.hasOwnProperty(name)) {
                    var fieldName = options.aField[name];
                    var fieldValue = $('.'+fieldName, content).text();

                    $('input[name="'+getFieldFormName(fieldName)+'"]', editForm).val(fieldValue);
                    $('textarea[name="'+getFieldFormName(fieldName)+'"]', editForm).val(fieldValue);
                }
            }
        }

        function updateFormHelper() {
            // Remove the calendar and add a new one
            $('.calendar', editForm).addClass('editCalendar').removeClass('calendar');
            
            // Add the cancel button
            $('a', editForm).remove();
            $('p.cancel', editForm).remove();
            $('.actionDispatcherMessages', editForm).remove();
            editForm.append(cancelContent);

            $('input, textarea, select', editForm).each( function() {
                var id = $(this).attr('id');

                if( id !==  undefined ) {
                    var newId = id+editId;
                    $(this).attr('id', newId);
                }
            });
            
            $('label', editForm).each(function() {
                var forValue = $(this).attr('for');
                var newId    = forValue+editId;    
                $(this).attr('for', newId);
            });
            

            // Remove tooltips.
            $('.toolTip', editForm).remove();
            Common_addCalendarControls( 'editCalendar', 'editCalendar', editForm );
        }

    };
})(jQuery);
/* jquery.lightBoxDownload.js (345) */
/**
 * @package private_output_careers_wales_learningpathways
 * @version $Id: jquery.tooltip.js 8432 2008-05-23 14:09:25Z jamesrc $
 * @copyright Copyright (c) 2008 Box UK Ltd. All rights reserved.
 *
 * Simple plugin to add tool tips to a page.
 *
 * @request js.modal
 * @audit
 * - 2009-08-11  JRC  Created file.
 */
(function($) {

    /**
     * Main access to method, allows the user to override the defualts
     * options set by the plugin.
     *
     * @param Object options
     */
    $.fn.lightBoxDownload = function(options) {

        var defaults = {
            'module': 'LearningPathways',
            'overlayId': 'downloadOverlay',
            'containerId' : 'downloadContainer',
            'openClass'   : 'open',
            'saveClass'   : 'save',
            'languageCode' : oLocale.getFieldValue('id'),
            'filename'    : 'LearningPathwaysDocument.pdf'
        };
        var settings = $.extend(defaults, options);
        
        return this.each(function() {
            $.fn.lightBoxDownload.init( this, settings );
        });
    };

    /**
     * Sets up hover state a tool tip.
     *
     * @param HTMLElement element
     * @param Object options
     */
    $.fn.lightBoxDownload.init = function( element, options ) {
        var downloadLink = $(element);
        var title   = $('<h3 />').html(oLocale.getTranslation(options.module, 'titleDownload'));
        var introText = $('<p />').html(oLocale.getTranslation(options.module, 'downloadIntro'));
        var cancelAnchor = $('<a href="#" class="cancel" />').append(oLocale.getTranslation(options.module, 'labelCancel'));
        var cancelText = $('<p />')
                            .append(oLocale.getTranslation(options.module, 'labelOr')+' ')
                            .append(cancelAnchor)
                            .append(' '+oLocale.getTranslation(options.module, 'labelToClose'))
                            .addClass('cancel')
                            .addClass('center');
                            
        var openClass  = options.languageCode > 0 ? options.openClass+'_1' : options.openClass;
        var openButton = $('<a />')
                            .attr('href', downloadLink.attr('href'))
                            .attr('target', '_blank')
                            .html(oLocale.getTranslation(options.module, 'labelOpen'))
                            .addClass(openClass)
                            .click(function(){
                                $.cwmodal.close();
                            });
                            
        var saveClass  = options.languageCode > 0 ? options.saveClass+'_1' : options.saveClass;
        var downloadButton = $('<a />')
                            .attr('href', downloadLink.attr('href')+'&forceDownload=true&filename='+options.filename)
                            .html(oLocale.getTranslation(options.module, 'labelSaveToComputer'))
                            .addClass(saveClass)
                            .click(function(){
                                window.setTimeout(function(){
                                    $.cwmodal.close();
                                }, 3000);
                            });
        
        var content = $('<div />')
                            .addClass('downloadContent')
                            .append(title)
                            .append(introText)
                            .append(
                                $('<p />').append(downloadButton).append(openButton).addClass('center')
                            )
                            .append(cancelText)
                            .hide();

        downloadLink.click( function(){
            $(content).cwmodal({
                overlayId: options.overlayId,
                containerId: options.containerId,
                persist: false
            });

            $('a.cancel', content).click(function(){
                $.cwmodal.close();
                return false;
            });

            return false;
        });
    };
})(jQuery);
/* jquery.associateQualifications.js (349) */
(function($) {

    /**
     * Main method for plugin
     *
     * @param {Object} inOptions
     */
    $.fn.associateQualification = function(inOptions) {

        var options = $.extend({}, $.fn.associateQualification.defaults, inOptions);

        return this.each(function() {
            $.fn.associateQualification.associate( this, options );
        });
    };

    /**
     * Public plugin function
     *
     * @return string
     */
    $.fn.associateQualification.associate = function( element, options ) {

        var button = $(element);
        var table  = $(options.selector.table);
        var form   = $(options.selector.form);
        var searchButton = $(options.selector.button);

        var requestXHR = null;

        var initQualificationSearch = function () {
            initQualificationTable();
            initLaunchButton();
            initSearchButton();
        };

        initQualificationSearch();

        /**
         * Show the qualification table if we have qualifications. Initialise
         * delete links so that qualifications can be removed.
         *
         */
        function initQualificationTable() {

            showQualficationTable();
            $('a.actionDelete', table ).click(function() {
                removeQualification( this );
            });
        }

        /**
         * Launches the lightbox search when the button is clicked
         *
         */
        function initLaunchButton() {
            $(button).click(function() {
                $( form ).cwmodal( {
                    overlayId: options.overlayId,
                    containerId: options.containerId,
                    persist: true,
                    onOpen: function (dialog) {
                        dialog.overlay.fadeIn('fast', function () {
                            dialog.container.slideDown('normal', function () {
                                dialog.data.fadeIn('fast');
                            });
                        });
                    },
                    onClose: function (dialog) {
                        dialog.data.fadeOut('fast', function () {
                            dialog.container.slideUp('normal', function () {
                                dialog.overlay.fadeOut('fast', function () {
                                    $('.modalClose').hide();
                                    $.modal.close();
                                });
                            });
                        });
                    }
                });
            });
        }

        function initSearchButton() {
            $( searchButton ).click( function(event) {
                $( options.selector.feedback ).html('');
                sendRequest();
            });
        }

        /**
         * Main function that send request for getting qualifications
         * Also sets up second request for all the information for a
         * qualification after it has been selected
         *
         * @param HTMLInputElement selector
         * @param HTMLDivElement block
         */
        function sendRequest () {

            // Clear existing request, if present
            if (requestXHR !== null) {
                if (typeof requestXHR.abort == 'function') {
                    requestXHR.abort();
                }
            }

            // Set up feedback and message areas
            var feedback  = $('#qualFeedback');
            var currValue = $( options.selector.field ).val();
            var search      = $('<div />').attr('id', 'searching').prependTo(feedback);
            var loading      = $('<div />').attr('id', 'loading').hide().prependTo(feedback);
            var helpText  = $('<div />').attr('id', 'helpText').hide().prependTo(feedback);

            search.append('<img src="'+ SITE_WEB_ROOT + 'custom/careers_wales/img/ajax/largeSpinner.gif" />')
            .append(oLocale.getTranslation(options.module,'lblSearching'));
            helpText.append(oLocale.getTranslation(options.module,'lblSearchQualifications'));
            loading.append('<img src="'+ SITE_WEB_ROOT + 'custom/careers_wales/img/ajax/largeSpinner.gif" />')
            .append(oLocale.getTranslation(options.module,'lblLoading'));

            // send request for qualifications
            var submitUrl   = SITE_WEB_ROOT + 'server.php?change='+ options.template + getQualificationsRequest();

            requestXHR = $.getJSON(submitUrl, function(json) {

                var module = json.Module;
                search.fadeOut ( 'slow', function() {

                    if (!(module.aQualifications)) {
                        Common_makeMessage( 'error', oLocale.getTranslation(options.module,'msgNoQualifications') )
                        .appendTo( feedback );
                        return;
                    }

                    if (module.aQualifications.length === 0) {
                        Common_makeMessage( 'error', oLocale.getTranslation(options.module,'msgNoQualifications') )
                        .appendTo( feedback );
                        return;
                    }

                    if ( module.aQualifications.length > 150 ) {
                        Common_makeMessage( 'error', oLocale.getTranslation(options.module,'msgTooManyQualifications') )
                        .appendTo( feedback );
                        return;
                    }

                    // Create a list to attach qualifications and provide helper text for user
                    helpText.fadeIn('fast');
                    var wrapper = $('<div />').addClass('qualificationWrapper').appendTo( feedback );
                    var results = $('<table />').append(
                        $('<thead />').append(
                            $('<tr />').append(
                                $('<th />').html(oLocale.getTranslation(options.module,'lblReference'))
                                )
                            .append(
                                $('<th />').html(oLocale.getTranslation(options.module,'lblQualfication'))
                                )
                            )
                        )
                    .append($('<tbody />'))
                    .addClass('qualifications').appendTo(wrapper);

                    // Loop over qualifications, adding them to the list
                    for( var i = 0; i < module.aQualifications.length; i++ ) {
                        var aQual       = module.aQualifications[i];
                        var contentId   = aQual.contentId;
                        var title       = aQual.title;
                        var ndaqRef     = aQual.refNumber;
                        var isArchived  = aQual.isArchived;
                        var cellClass   = i % 2 === 0 ? 'even' : 'odd' ;
                        var item        = $('<tr></tr>').addClass(cellClass).appendTo($('tbody', results)).attr('name', contentId);

                        $('<a />').appendTo($('<td />').appendTo(item))
                        .html(ndaqRef)
                        .attr('href', getNDAQUrl(ndaqRef))
                        .attr('target', '_blank');

                        $('<a />').appendTo($('<td />').appendTo(item))
                        .addClass(isArchived ? 'archived' : '')
                        .attr('href', '#'+contentId)
                        .attr('id', contentId)
                        .html(title)
                        .click( function() {
                            helpText.fadeOut('fast', function() {
                                loading.fadeIn('fast');
                            });
                            loading.append(' '+ $(this).html());
                            $(this).parent().parent().find('.over').removeClass('over');
                            $(this).addClass('over');

                            contentId = $(this).attr('id');
                            var submitUrl = SITE_WEB_ROOT + 'server.php?change='+options.template+getQualificationRequest(contentId);

                            $.getJSON(submitUrl, function(json) {
                                updateForm(json);
                                helpText.remove();
                                loading.remove();
                                search.remove();
                                wrapper.remove();
                                $('#qualificationsTable').show();
                                closeDialog();
                            });
                            return false;
                        });
                    }
                });
            });
        }

        /**
         *  Build the request for extracting all qualifications,
         *  Request involves awarding body, level and free text
         *
         *    @param HTMLDivElement block
         */
        function getQualificationsRequest() {
            var prefix  = '&Module['+options.instanceId+']';
            var request = '';

            form.each(function(){
                // Which levels are we selecting?
                $('input[type=checkbox].level:checked', $(this)).each(function() {
                    request += prefix+'[fld_level][]=' + $(this).val();
                });

                // Which awarding body is selected? If any
                $('select option:selected', $(this)).each(function() {
                    if( $(this).val() > 0 && $(this).val() !== null) {
                        request += prefix+'[fld_awardingBody]='+ $(this).val();
                    }
                });

                // Get the search string
                $('input[type=text]', $(this)).each(function() {
                    if( $(this).val().length > 0 ) {
                        request += prefix + '[' + $(this).attr('id') + ']=' + $(this).val();
                    }
                });

                // Is it vocational?
                $('input[type=checkbox]:checked', $(this)).each(function() {
                    request += prefix+'['+$(this).attr('id')+']=' + $(this).val();
                });
            });

            request += prefix + '[action]=getQualifications&jsonOutput='+options.instanceId;
            return request;
        }

        function getAdditionalLimits() {
            var prefix  = '&Module['+options.instanceId+']';

            var domainQualTypeLimiter = '';
            var qualificationId = $('input[name="Module['+options.instanceId+'][fld_qualifications][]"]:first').attr('value');
            if( qualificationId ) {
                domainQualTypeLimiter = prefix+'[domainQualTypeLimiter]='+qualificationId;
            }

            var removeQualifcations = '';
            $('input[name="Module['+options.instanceId+'][fld_qualifications][]"]').each(function() {
                removeQualifcations += prefix+'[exclude][]='+$(this).attr('value');
            });

            return removeQualifcations + domainQualTypeLimiter;
        }

        /**
         * update the form after a user has selected a qualification
         *
         * @param Json data
         */
        function updateForm ( data ) {
            var statusMap = {
                1: 'archived',
                2: 'comingSoon',
                4: 'approved',
                8: 'archived'
            };

            var module     = data.Module;
            var content    = module.oQualification.oContent;
            var metadata   = module.oQualification.oMetadataManager.oMetadata;
            var categories = module.oQualification.oMetadataManager.aoCategory;

            $('.qualifications').show();
            // Create a new table row every time the user has selected a qualification
            $('tbody', table).append($('<tr />'));

            $('<input type="hidden" />')
            .attr('name', 'Module['+options.instanceId+'][fld_qualifications][]')
            .attr('value', content.aField.contentId)
            .insertAfter( table );

            // Qualification title
            var qualTitle = metadata.aField.title;
            $('tr:last', table).append ($('<td>'+qualTitle+'</td>'));

            // Qualification title
            var qualRef = content.aField.refNumber;
            $('tr:last', table).append ($('<td><a target="_blank" href="'+getNDAQUrl(qualRef)+'">'+qualRef+'</a></td>'));

            // Get all meta roots needed to determine which category is which
            var qualificationRoot = module.qualificationRoot;
            var awardingBody      = module.awardingBodyRoot;
            var qualificationCat  = null;
            var awardingBodyCat   = null;

            // Loop through all of the qualifications categories
            for(var i = 0; i < categories.length; i++ ) {
                var currCatId = categories[i].aField.categoryId;

                // Select the awarding body
                if ( currCatId.match(awardingBody)) {
                    awardingBodyCat = categories[i].aField.name;
                }

                // Select the qualification title
                if ( currCatId.match(qualificationRoot)) {
                    qualificationCat = categories[i].aField.name;

                }
            }
            $('tr:last', table).append ($('<td>'+qualificationCat+'</td>'));
            $('tr:last', table).append ($('<td>'+awardingBodyCat+'</td>'));

            // Vocational
            var isVocational = '';
            switch (content.aField.isVocational) {
                case 'V':
                    isVocational = oLocale.getTranslation(options.module, 'vocationalLabel');
                    break;
                case 'G':
                    isVocational = oLocale.getTranslation(options.module, 'generalLabel');
                    break;
                default:
                    isVocational = 'U'; //see SID:18103
            }
            $('tr:last',table).append ($('<td>'+isVocational+'</td>'));

            // Base Score
            var currentUrl = window.location.search;
            var baseScore = 0;
            if( currentUrl.indexOf('ProviderCourseAdminDisplayPost16') >= 0 ) {
                baseScore = content.aField.scorePost16 > 0 ? content.aField.scorePost16 : '0';
            } else {
                baseScore = content.aField.scorePre16 > 0 ? content.aField.scorePre16 : '0';
            }
            $('tr:last', table).append ($('<td>'+baseScore+'</td>'));

            var status = '';

            if (module.aXslText["status_"+statusMap[content.aField.status]]) {
                status = module.aXslText["status_"+statusMap[content.aField.status]];
            } else if (module.aXslText["'status_"+statusMap[content.aField.status]+"'"]) {
                status = module.aXslText["'status_"+statusMap[content.aField.status]+"'"];
            }

            $('tr:last', table).append ($('<td>'+status+'</td>'));


            $('tr:last', table).append ($('<td>'+content.formattedApprovalEndDate+'</td>'));
            
            var course      = $('input[name$="[getCourse]"]').val();
            var fundGranted = 'tab-'+course+'-'+content.aField.contentId;
            $('tr:last', table).append ($('<td />').append(
                $('<input />').attr({
                    'type' : 'checkbox',
                    'name' : 'Module['+options.instanceId+'][isGrantFunded]['+fundGranted+'] />' 
                })
            ));

            $('tr:last', table).append (
                $('<td />').append(
                    $('<a />')
                    .attr('href', '#')
                    .attr('id', content.aField.contentId)
                    .addClass('actionDelete')
                    .html( oLocale.getTranslation(options.module, 'field_remove'))
                    .click( function() {
                        removeQualification( this );
                    })
                    )
                );
        }

        /**
         * Returns the request URL for extracting a conQualification in json format
         * @param int qualContentID
         * @param HTMLDivElement block
         */
        function getQualificationRequest( qualContentId ) {
            var prefix  = '&Module['+options.instanceId+']';
            return prefix + '[action]=getQualification'+prefix+'[qualId]='+qualContentId+'&jsonOutput='+options.instanceId;
        }

        /**
         * Removes qualification from the table and the form.
         */
        function removeQualification ( element ) {
            var id  = $(element).attr('id');
            var row = $(element).parent().parent();

            getFormField('fld_qualifications').each(function() {
                if( $(this).attr('value').match( id ) ) {
                    $(this).remove();
                }
            });
            row.remove();

            hideQualificationTable();
            return false;
        }

        function showQualficationTable() {
            if( $('tbody tr td', table).size() > 0 ) {
                table.show();
            }
        }

        function hideQualificationTable() {
            if( $('tbody tr td', table).size() === 0 ) {
                $(table).hide();
            }
        }

        function getFormField( fieldName ) {
            return $('input[name="Module['+options.instanceId+']['+fieldName+'][]"]');
        }

        function getNDAQUrl( referenceId ) {
            referenceId = referenceId.substr(0,3) + '_' + referenceId.substr(3,4) + '_' + referenceId.substr(7,1);
            return options.ndaqUrl.replace('%id%', referenceId);
        }

        function closeDialog() {
            $(".modalData").fadeOut('fast', function () {
                $(".modalContainer").slideUp('fast', function () {
                    $(".modalOverlay").fadeOut('fast', function () {
                        $('.modalClose').hide();
                        $.modal.close();
                    });
                });
            });
        }
    };

    /**
     * Default settings
     */
    $.fn.associateQualification.defaults = {
        'overlayId' : 'qualificationOverlay',
        'containerId' : 'qualificationContainer'
    };

})(jQuery);
/* jquery.dimensions.js (390) */
///* Copyright (c) 2007 Paul Bakaus (paul.bakaus@googlemail.com) and Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net)
// * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
// * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
// *
// * $LastChangedDate: 2007-12-20 08:46:55 -0600 (Thu, 20 Dec 2007) $
// * $Rev: 4259 $
// *
// * Version: 1.2
// *
// * Requires: jQuery 1.2+
// */
//
//(function($){
//
//$.dimensions = {
//	version: '1.2'
//};
//
//// Create innerHeight, innerWidth, outerHeight and outerWidth methods
//$.each( [ 'Height', 'Width' ], function(i, name){
//
//	// innerHeight and innerWidth
//	$.fn[ 'inner' + name ] = function() {
//		if (!this[0]) return;
//
//		var torl = name == 'Height' ? 'Top'    : 'Left',  // top or left
//		    borr = name == 'Height' ? 'Bottom' : 'Right'; // bottom or right
//
//		return this.is(':visible') ? this[0]['client' + name] : num( this, name.toLowerCase() ) + num(this, 'padding' + torl) + num(this, 'padding' + borr);
//	};
//
//	// outerHeight and outerWidth
//	$.fn[ 'outer' + name ] = function(options) {
//		if (!this[0]) return;
//
//		var torl = name == 'Height' ? 'Top'    : 'Left',  // top or left
//		    borr = name == 'Height' ? 'Bottom' : 'Right'; // bottom or right
//
//		options = $.extend({ margin: false }, options || {});
//
//		var val = this.is(':visible') ?
//				this[0]['offset' + name] :
//				num( this, name.toLowerCase() )
//					+ num(this, 'border' + torl + 'Width') + num(this, 'border' + borr + 'Width')
//					+ num(this, 'padding' + torl) + num(this, 'padding' + borr);
//
//		return val + (options.margin ? (num(this, 'margin' + torl) + num(this, 'margin' + borr)) : 0);
//	};
//});
//
//// Create scrollLeft and scrollTop methods
//$.each( ['Left', 'Top'], function(i, name) {
//	$.fn[ 'scroll' + name ] = function(val) {
//		if (!this[0]) return;
//
//		return val != undefined ?
//
//			// Set the scroll offset
//			this.each(function() {
//				this == window || this == document ?
//					window.scrollTo(
//						name == 'Left' ? val : $(window)[ 'scrollLeft' ](),
//						name == 'Top'  ? val : $(window)[ 'scrollTop'  ]()
//					) :
//					this[ 'scroll' + name ] = val;
//			}) :
//
//			// Return the scroll offset
//			this[0] == window || this[0] == document ?
//				self[ (name == 'Left' ? 'pageXOffset' : 'pageYOffset') ] ||
//					$.boxModel && document.documentElement[ 'scroll' + name ] ||
//					document.body[ 'scroll' + name ] :
//				this[0][ 'scroll' + name ];
//	};
//});
//
//$.fn.extend({
//	position: function() {
//		var left = 0, top = 0, elem = this[0], offset, parentOffset, offsetParent, results;
//
//		if (elem) {
//			// Get *real* offsetParent
//			offsetParent = this.offsetParent();
//
//			// Get correct offsets
//			offset       = this.offset();
//			parentOffset = offsetParent.offset();
//
//			// Subtract element margins
//			offset.top  -= num(elem, 'marginTop');
//			offset.left -= num(elem, '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) && $.css(offsetParent, 'position') == 'static') )
//			offsetParent = offsetParent.offsetParent;
//		return $(offsetParent);
//	}
//});
//
//function num(el, prop) {
//	return parseInt($.curCSS(el.jquery?el[0]:el,prop,true))||0;
//};
//
//})(jQuery);
/* jquery.cwmodal.js (392) */
/***
 *
 * jQuery modal dialog for Careers Wales
 * - adds:
 *   * auto-height adjustment (still in development, 99% working 99% of the time)
 *   * auto-content scrolling (still in development)
 *   * auto-pagination (still in development)
 *
 * Build as a wrapper around simplemodal
 *
 * Revision: $Id: jquery.cwmodal.js 93 2008-01-15 16:14:20Z emartin24 $
 *
 */

/*
 * Custom event handler
 * Triggers when the content of an element changes
 * -> need to put custom event handlers into a separate JS file ...
 */
(function(){

    var interval;

    jQuery.event.special.contentchange = {
        setup: function(){
            var self = this,
            $this = $(this),
            $originalContent = $this.text();
            interval = setInterval(function(){
                if($originalContent != $this.text()) {
                        $originalContent = $this.text();
                    jQuery.event.handle.call(self, {type:'contentchange'});
                }
            },500);
        },
        teardown: function(){
            clearInterval(interval);
        }
    };

})(jQuery);


(function($) {
    /*
     * Stand-alone function to create a modal dialog.
     *
     * @param {string, object} data A string, jQuery object or DOM object
     * @param {object} [options] An optional object containing options overrides
     */
    $.cwmodal = function (data, options) {
        return $.cwmodal.impl.init(data, options);
    };

    /*
     * Stand-alone close function to close the modal dialog
     */
    $.cwmodal.close = function () {
        $.cwmodal.impl.close();
    };

    /*
     * Chained function to create a modal dialog.
     *
     * @param {object} [options] An optional object containing options overrides
     */
    $.fn.cwmodal = function (options) {
        $.cwmodal.impl.init(this, options);
    };

    $.cwmodal.triggerContentChange = function () {
        var handleKeepAboveTheFold = function () {
            if ($.cwmodal.impl.willKeepAboveTheFold('contentchange')) {
                $.cwmodal.impl.keepAboveTheFold.apply('contentchange');
            }
        };
        
        // Keep above the fold?
        handleKeepAboveTheFold();

        // Re-apply content change event to handle on-open resizing
        // -> otherwise the /second/ time a dialog is opened in a viewport too small to handle it, it won't resize itself
        var dialog = $('#'+$.cwmodal.impl.settings.containerId);
        if (typeof dialog.data('events') == 'undefined') {
            $.cwmodal.impl.resize.init();

            for (var area in $.cwmodal.impl.allowedAreas) {
                if ($.cwmodal.impl.allowedAreas.hasOwnProperty(area)) {
                    $.cwmodal.impl.resize.apply('contentchange', 'belowTheFold');
                }
            }
        }
    };

    /*
     * Main implementation
     */
    $.cwmodal.impl = {
        defaults:{
            minHeight: false,               // Overrides simplemodal default of 200px
            escClose: true,
            onEsc:false,                    // Callback to run on pressing Esc
            resize:false,
            keepAboveTheFold:false
        },
        settings:{},
        dialog:false,
        
        allowedAreas:{
            belowTheFold:false,
            aboveTheTop:false,
            leftOfScreen:false,
            rightOfScreen:false
        },

        isAllowedEvent:function(eventName) {
             var allowedEventName = {
                open:true,
                resize:true,
                contentchange:true
            };

            return allowedEventName.hasOwnProperty(eventName);
        },

        isAllowedArea:function(area) {
            return $.cwmodal.impl.allowedAreas.hasOwnProperty(area);
        },

        init: function (data, options) {
            var sanitizeOptions = function(options) {
                if (typeof options != 'object') {
                    options = {};
                }

                if (typeof options.keepAboveTheFold == 'boolean' && options.keepAboveTheFold === true) {
                    options.keepAboveTheFold = {
                        events:['open', 'resize', 'contentchange'],
                        params:{min:0}
                    };
                }

                return options;
            };

            options = sanitizeOptions(options);
            this.settings = $.extend({}, this.defaults, options);

            this.dialog = $('#'+this.settings.containerId);

            // Run callback on pressing Esc?
            // -> can set onClose callback, but doing so disables Esc to close on simplemodal
            if (typeof this.settings.onEsc == 'function') {
                $().keydown(function(event){
                    if (event.keyCode == 27)  { // Esc key, I tell you
                        $.cwmodal.impl.settings.onEsc();
                    }
                });
            }

            // Keep dialog above the fold?
            $.cwmodal.impl.keepAboveTheFold.init();

            // Resize dialog when things get too tight?
            $.cwmodal.impl.resize.init();

            var modal = $.modal(data, this.settings);

            return modal;
        },

        close: function () {
            // Unbind resize and content change events
            //$.cwmodal.impl.dialog.unbind('contentchange');
            $(window).unbind('resize.cwmodal'); // Will eventually need to narrow this down

            // Call simplemodal close
            $.modal.close();
        },

        dialogIsBelowTheFold:function(offset) {
            var options = {
                selector:'#'+$.cwmodal.impl.settings.containerId,
                bottomEdge:true
            };

            if (typeof offset == 'number') {
                options.offset = offset;
            }

            return AMAXUS.dimensions.element.isBelowTheFold(options);
        },

        willKeepAboveTheFold:function (eventName) {
            if (typeof $.cwmodal.impl.settings.keepAboveTheFold.events != 'object') {
                return false;
            }

            if (eventName.indexOf('.') > -1) {
                eventName = eventName.substring(0, eventName.indexOf('.'));
            }

             for (var currentEventKey in $.cwmodal.impl.settings.keepAboveTheFold.events) {
                 if ($.cwmodal.impl.settings.keepAboveTheFold.events.hasOwnProperty(currentEventKey)) {
                     var currentEventName = $.cwmodal.impl.settings.keepAboveTheFold.events[currentEventKey];
                     if (currentEventName == eventName) {
                         return true;
                     }
                 }
             }

             return false;
        },

        willResizeFor: function(area, eventName) {
            if (!$.cwmodal.impl.isAllowedArea(area)) {
                return false;
            }
            
            if (!$.cwmodal.impl.isAllowedEvent(eventName)) {
                return false;
            }

            var resizeOptions = $.cwmodal.impl.settings.resize;

            if (typeof resizeOptions[area] != 'object') {
                return false;
            }

            if (typeof resizeOptions[area].events != 'object') {
                return false;
            }

            return resizeOptions[area].events[eventName] === true;
        },

        isDialogOpen: function () {
            return $('#'+$.cwmodal.impl.settings.containerId).length > 0;
        },

        /*
         * Handle making dialog scared of the bottom edge of the browser
         */
        keepAboveTheFold:{
            isBusy:false,

            init:function () {
                if (typeof $.cwmodal.impl.settings.keepAboveTheFold.events != 'object') {
                    return true;
                }

                for (var eventName in $.cwmodal.impl.settings.keepAboveTheFold.events) {
                    if ($.cwmodal.impl.settings.keepAboveTheFold.events.hasOwnProperty(eventName)) {
                        switch ($.cwmodal.impl.settings.keepAboveTheFold.events[eventName]) {
                        case 'open':
                            $.cwmodal.impl.keepAboveTheFold.apply('open');
                            break;

                        case 'resize':
                            $(window).bind('resize.cwmodal', function(){
                                $.cwmodal.impl.keepAboveTheFold.apply('resize');
                            });
                            break;

                        default:
                            $.cwmodal.impl.dialog.bind($.cwmodal.impl.settings.keepAboveTheFold.events[eventName], function(){
                                $.cwmodal.impl.keepAboveTheFold.apply($.cwmodal.impl.settings.keepAboveTheFold.events[eventName]);
                            });
                        }
                    }
                }

                return true;                
            },

            apply:function(eventName) {
                // We have to re-grab the dialog each time
                // -> otherwise we end up with an offset() of {top:0,left:0}
                $.cwmodal.impl.dialog = $('#'+$.cwmodal.impl.settings.containerId);

                // Check if we're not too early
                // -> until the dialog is recognised by the DOM it won't have any offset position
                var dialog = $.cwmodal.impl.dialog;
                var distanceFromTop = dialog.offset().top;
                var distanceFromBottom = Math.ceil($(window).height() - AMAXUS.dimensions.element.edges(dialog).bottom);

                if ($.cwmodal.impl.dialogIsBelowTheFold()) {
                    if (distanceFromTop > 0) {
                        var distanceBelowTheFold = -1 * distanceFromBottom;
                        var distanceToShift = (distanceFromTop < distanceBelowTheFold) ? distanceFromTop : distanceBelowTheFold;

                        var newTopPosition = Math.floor(distanceFromTop - distanceToShift);
                        dialog.css('top', newTopPosition);                      
                    }

                } else {
                    if ($.cwmodal.impl.settings.keepAboveTheFold.params) {
                        if ($.cwmodal.impl.settings.keepAboveTheFold.params.restoreTopPosition) {
                            var restorePosition = $.cwmodal.impl.settings.keepAboveTheFold.params.restoreTopPosition;
                            if (typeof restorePosition != 'number') {
                                if (restorePosition.charAt(restorePosition.length-1) == '%') {
                                    var restorePercentage = parseInt(restorePosition, 10);
                                    restorePosition = ($(window).height() / 100) * restorePercentage;
                                }

                                if (distanceFromTop < restorePosition) {
                                    if (distanceFromBottom < restorePosition) {
                                        restorePosition = distanceFromBottom;
                                    }
                                }
                            }
//
                            dialog.css('top', restorePosition);
                        }
                    }
                }
            }
        },

        /*
         * Handle auto-resizing (setting up event handlers and performing resizing when events happen)
         */
        resize:{
            applyOnOpen:{
                belowTheFold:false,
                aboveTheTop:false,
                leftOfScreen:false,
                rightOfScreen:false
            },

            init: function () {
                var resizeOptions = $.cwmodal.impl.settings.resize;

                for (var area in resizeOptions) {
                    if ($.cwmodal.impl.isAllowedArea(area)) {
                        for (var currentEventName in resizeOptions[area].events) {
                            if (resizeOptions[area].events.hasOwnProperty(currentEventName)) {
                                if ($.cwmodal.impl.isAllowedEvent(currentEventName)) {

                                    if (resizeOptions[area].events[currentEventName]) {
                                        switch (currentEventName) {
                                        case 'open':
                                            //$.cwmodal.impl.resize.applyOnOpen[area] = resizeOptions[area].events;
                                            break;

                                        case 'resize':
                                            $(window).bind('resize', function(){
                                                //$.cwmodal.impl.resize.hasCalledPostResizeCallback = false;
                                                $.cwmodal.impl.resize.apply('resize.cwmodal', area);
                                            });
                                            break;

                                        default:
                                            $.cwmodal.impl.dialog.bind(currentEventName, function(){
                                                $.cwmodal.impl.resize.apply(currentEventName, area);
                                            });
                                        }
                                    }

                                }
                            }
                        }
                    }
                }
            },

            apply: function (eventName, area) {
                // We have to re-grab the dialog each time
                // -> otherwise we end up with an offset() of {top:0,left:0}
                $.cwmodal.impl.dialog = $('#'+$.cwmodal.impl.settings.containerId);
                var dialog = $.cwmodal.impl.dialog;
                var params = $.cwmodal.impl.settings.resize[area].params;

                var setScrollableAreaHeight = function() {
                    var scrollableArea = $('.cwScrollable', dialog);

                    var beforeScrollableAreaHeight = 0;
                     scrollableArea.prevAll().each(function(){
                        beforeScrollableAreaHeight += $(this).height();
                    });

                    var afterScrollableAreaHeight = 0;
                    scrollableArea.nextAll().each(function(){
                        afterScrollableAreaHeight += $(this).height();
                    });

                    var scrollableAreaHeight = dialog.height() - beforeScrollableAreaHeight - afterScrollableAreaHeight - 100;
                    scrollableArea.height(scrollableAreaHeight+'px');
                };

                var getScrollableAreaHeight = function() {
                    var scrollableArea = $('.cwScrollable', dialog);
                    return scrollableArea.height();
                };

                var getScrollableContent = function () {
                    return $(params.scrollableContent.selector, dialog);
                };

                var getScrollableContentHeight = function() {
                    return getScrollableContent().height();
                };
                
                var hasScrollingEnabled = function() {
                    return $('.cwScrollable', dialog).length > 0;
                };

                var setDialogHeight = function (height) {
                    dialog.height(height);
                    if (jQuery.browser.msie) {
                        dialog.css({bottom:0});  // Doesn't seem to want to work in IE6,7 without, otherwise has no effect whatsoever
                    }
                };

                var resizeWhenBelowTheFold = function() {
                    // Determine required lightbox height
                    // -> as much as the window will allow
                    var newHeight = $(window).height();
                    setDialogHeight(newHeight);

                    // Scroll around scrollable content                
                    var scrollableContent = $(params.scrollableContent.selector, dialog);
                    if (!scrollableContent.length) {
                        return true;
                    }
                    
                    // Add scrollable container around items to be scrolled
                    // -> if not already present
                    if (!hasScrollingEnabled()) {
                        var nextElement = $(scrollableContent.get(scrollableContent.length-1)).next();
                        var newScrollableContent = scrollableContent.clone();
                        scrollableContent.remove();

                        nextElement.before(
                            $('<div />')
                            .addClass('cwScrollable')
                            .css('overflow', 'auto')
                            .append(newScrollableContent)
                        );

                        dialog.width(dialog.width() + 30);
                    }
                    
                    // Set height of scrollable area
                    // -> wrt what is before and after so as to get the right overall height
                    setScrollableAreaHeight();
                    return true;
                    
                };

                var cancelNotInView = function() {
                    var dialogEdges = AMAXUS.dimensions.element.edges(dialog);
                    var dialogCancel = $('p.cancel', dialog);

                    var cancelEdges = AMAXUS.dimensions.element.edges(dialogCancel);
                    return (cancelEdges.bottom  + dialogCancel.height() + 30) > dialogEdges.bottom;
                };

                var resizeWhenAboveTheFold = function () {
                    if (!$.cwmodal.impl.isDialogOpen()) {
                        return true;
                    }

                    if (!hasScrollingEnabled() && !cancelNotInView()) {
                        return true;
                    }

                    if ($.cwmodal.impl.dialogIsBelowTheFold()) {
                        return true;
                    }

                    var newHeight = dialog.height() + 1;
                    setDialogHeight(newHeight);
                    setScrollableAreaHeight();

                    // Remove scrolling?
                    if (getScrollableAreaHeight() > getScrollableContentHeight()) {
                        var scrollableContent = $('.cwScrollable').children().clone();
                        var nextElement = $('.cwScrollable', dialog).next();

                        $('.cwScrollable').remove();
                        nextElement.before(scrollableContent);
                        dialog.width(dialog.width() - 30);
                    }

                    resizeWhenAboveTheFold();

                };

                switch (area) {
                    case 'belowTheFold':                        

                        if ($.cwmodal.impl.dialogIsBelowTheFold()) {
                            var distanceFromBottom = Math.ceil($(window).height() - AMAXUS.dimensions.element.edges(dialog).bottom);
                            if (distanceFromBottom >= 0) {
                                return true;
                            }                            
                            
                            // If we are below the fold, at least wait a little to have the dialog
                            // shunted up a bit
                            if ($.cwmodal.impl.willKeepAboveTheFold(eventName)) {
                                if (dialog.offset().top > 0) {
                                    setTimeout(function(){
                                        $.cwmodal.impl.resize.apply(eventName, area);
                                    }, 100);

                                    return true;
                                }
                            }

                            // Do the actual resizing
                            resizeWhenBelowTheFold();
                            return true;
                        }

                        // Do the actual resizing
                        resizeWhenAboveTheFold();
                        return true;

                    case 'aboveTheTop':
                        break;

                    case 'leftOfScreen':
                        break;

                    case 'rightOfScreen':
                        break;
                }
            }
        }
    };

})(jQuery);
/* jquery.qtip.js (421) */
/***
 * jquery.qtip. The jQuery tooltip plugin
 *
 * Copyright (c) 2009 Craig Thompson
 * http://craigsworks.com
 *
 * Licensed under MIT
 * http://www.opensource.org/licenses/mit-license.php
 *
 * Launch  : February 2009
 * Version : 1.0.0-rc3
 * Released: Tuesday 12th May, 2009 - 00:00
 * Debug: jquery.qtip.debug.js
 */
(function($)
{
   // Implementation
   $.fn.qtip = function(options, blanket)
   {
      var i, id, interfaces, opts, obj, command, config, api;

      // Return API / Interfaces if requested
      if(typeof options == 'string')
      {
         // Make sure API data exists if requested
         if(typeof $(this).data('qtip') !== 'object')
            $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.NO_TOOLTIP_PRESENT, false);

         // Return requested object
         if(options == 'api')
            return $(this).data('qtip').interfaces[ $(this).data('qtip').current ];
         else if(options == 'interfaces')
            return $(this).data('qtip').interfaces;
      }

      // Validate provided options
      else
      {
         // Set null options object if no options are provided
         if(!options) options = {};

         // Sanitize option data
         if(typeof options.content !== 'object' || (options.content.jquery && options.content.length > 0)) options.content = { text: options.content };
         if(typeof options.content.title !== 'object') options.content.title = { text: options.content.title };
         if(typeof options.position !== 'object') options.position = { corner: options.position };
         if(typeof options.position.corner !== 'object') options.position.corner = { target: options.position.corner, tooltip: options.position.corner };
         if(typeof options.show !== 'object') options.show = { when: options.show };
         if(typeof options.show.when !== 'object') options.show.when = { event: options.show.when };
         if(typeof options.show.effect !== 'object') options.show.effect = { type: options.show.effect };
         if(typeof options.hide !== 'object') options.hide = { when: options.hide };
         if(typeof options.hide.when !== 'object') options.hide.when = { event: options.hide.when };
         if(typeof options.hide.effect !== 'object') options.hide.effect = { type: options.hide.effect };
         if(typeof options.style !== 'object') options.style = { name: options.style };
         options.style = sanitizeStyle(options.style);

         // Build main options object
         opts = $.extend(true, {}, $.fn.qtip.defaults, options);

         // Inherit all style properties into one syle object and include original options
         opts.style = buildStyle.call({ options: opts }, opts.style);
         opts.user = $.extend(true, {}, options);
      };

      // Iterate each matched element
      return $(this).each(function() // Return original elements as per jQuery guidelines
      {
         // Check for API commands
         if(typeof options == 'string')
         {
            command = options.toLowerCase();
            interfaces = $(this).qtip('interfaces');

            // Make sure API data exists$('.qtip').qtip('destroy')
            if(typeof interfaces == 'object')
            {
               // Check if API call is a BLANKET DESTROY command
               if(blanket === true && command == 'destroy')
                  while(interfaces.length > 0) interfaces[interfaces.length-1].destroy();

               // API call is not a BLANKET DESTROY command
               else
               {
                  // Check if supplied command effects this tooltip only (NOT BLANKET)
                  if(blanket !== true) interfaces = [ $(this).qtip('api') ];

                  // Execute command on chosen qTips
                  for(i = 0; i < interfaces.length; i++)
                  {
                     // Destroy command doesn't require tooltip to be rendered
                     if(command == 'destroy') interfaces[i].destroy();

                     // Only call API if tooltip is rendered and it wasn't a destroy call
                     else if(interfaces[i].status.rendered === true)
                     {
                        if(command == 'show') interfaces[i].show();
                        else if(command == 'hide') interfaces[i].hide();
                        else if(command == 'focus') interfaces[i].focus();
                        else if(command == 'disable') interfaces[i].disable(true);
                        else if(command == 'enable') interfaces[i].disable(false);
                     };
                  };
               };
            };
         }

         // No API commands, continue with qTip creation
         else
         {
            // Create unique configuration object
            config = $.extend(true, {}, opts);
            config.hide.effect.length = opts.hide.effect.length;
            config.show.effect.length = opts.show.effect.length;

            // Sanitize target options
            if(config.position.container === false) config.position.container = $(document.body);
            if(config.position.target === false) config.position.target = $(this);
            if(config.show.when.target === false) config.show.when.target = $(this);
            if(config.hide.when.target === false) config.hide.when.target = $(this);

            // Determine tooltip ID (Reuse array slots if possible)
            id = $.fn.qtip.interfaces.length;
            for(i = 0; i < id; i++)
            {
               if(typeof $.fn.qtip.interfaces[i] == 'undefined'){ id = i; break; };
            };

            // Instantiate the tooltip
            obj = new qTip($(this), config, id);

            // Add API references
            $.fn.qtip.interfaces[id] = obj;

            // Check if element already has qTip data assigned
            if(typeof $(this).data('qtip') == 'object')
            {
               // Set new current interface id
               if(typeof $(this).attr('qtip') === 'undefined')
                  $(this).data('qtip').current = $(this).data('qtip').interfaces.length;

               // Push new API interface onto interfaces array
               $(this).data('qtip').interfaces.push(obj);
            }

            // No qTip data is present, create now
            else $(this).data('qtip', { current: 0, interfaces: [obj] });

            // If prerendering is disabled, create tooltip on showEvent
            if(config.content.prerender === false && config.show.when.event !== false && config.show.ready !== true)
            {
               config.show.when.target.bind(config.show.when.event+'.qtip-'+id+'-create', { qtip: id }, function(event)
               {
                  // Retrieve API interface via passed qTip Id
                  api = $.fn.qtip.interfaces[ event.data.qtip ];

                  // Unbind show event and cache mouse coords
                  api.options.show.when.target.unbind(api.options.show.when.event+'.qtip-'+event.data.qtip+'-create');
                  api.cache.mouse = { x: event.pageX, y: event.pageY };

                  // Render tooltip and start the event sequence
                  construct.call( api );
                  api.options.show.when.target.trigger(api.options.show.when.event);
               });
            }

            // Prerendering is enabled, create tooltip now
            else
            {
               // Set mouse position cache to top left of the element
               obj.cache.mouse = {
                  x: config.show.when.target.offset().left,
                  y: config.show.when.target.offset().top
               };

               // Construct the tooltip
               construct.call(obj);
            }
         };
      });
   };

   // Instantiator
   function qTip(target, options, id)
   {
      // Declare this reference
      var self = this;

      // Setup class attributes
      self.id = id;
      self.options = options;
      self.status = {
         animated: false,
         rendered: false,
         disabled: false,
         focused: false
      };
      self.elements = {
         target: target.addClass(self.options.style.classes.target),
         tooltip: null,
         wrapper: null,
         content: null,
         contentWrapper: null,
         title: null,
         button: null,
         tip: null,
         bgiframe: null
      };
      self.cache = {
         mouse: {},
         position: {},
         toggle: 0
      };
      self.timers = {};

      // Define exposed API methods
      $.extend(self, self.options.api,
      {
         show: function(event)
         {
            var returned, solo;

            // Make sure tooltip is rendered and if not, return
            if(!self.status.rendered)
               return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'show');

            // Only continue if element is visible
            if(self.elements.tooltip.css('display') !== 'none') return self;

            // Clear animation queue
            self.elements.tooltip.stop(true, false);

            // Call API method and if return value is false, halt
            returned = self.beforeShow.call(self, event);
            if(returned === false) return self;

            // Define afterShow callback method
            function afterShow()
            {
               // Call API method and focus if it isn't static
               if(self.options.position.type !== 'static') self.focus();
               self.onShow.call(self, event);

               // Prevent antialias from disappearing in IE7 by removing filter attribute
               if($.browser.msie) self.elements.tooltip.get(0).style.removeAttribute('filter');
            };

            // Maintain toggle functionality if enabled
            self.cache.toggle = 1;

            // Update tooltip position if it isn't static
            if(self.options.position.type !== 'static')
               self.updatePosition(event, (self.options.show.effect.length > 0));

            // Hide other tooltips if tooltip is solo
            if(typeof self.options.show.solo == 'object') solo = $(self.options.show.solo);
            else if(self.options.show.solo === true) solo = $('div.qtip').not(self.elements.tooltip);
            if(solo) solo.each(function(){ if($(this).qtip('api').status.rendered === true) $(this).qtip('api').hide(); });

            // Show tooltip
            if(typeof self.options.show.effect.type == 'function')
            {
               self.options.show.effect.type.call(self.elements.tooltip, self.options.show.effect.length);
               self.elements.tooltip.queue(function(){ afterShow(); $(this).dequeue(); });
            }
            else
            {
               switch(self.options.show.effect.type.toLowerCase())
               {
                  case 'fade':
                     self.elements.tooltip.fadeIn(self.options.show.effect.length, afterShow);
                     break;
                  case 'slide':
                     self.elements.tooltip.slideDown(self.options.show.effect.length, function()
                     {
                        afterShow();
                        if(self.options.position.type !== 'static') self.updatePosition(event, true);
                     });
                     break;
                  case 'grow':
                     self.elements.tooltip.show(self.options.show.effect.length, afterShow);
                     break;
                  default:
                     self.elements.tooltip.show(null, afterShow);
                     break;
               };

               // Add active class to tooltip
               self.elements.tooltip.addClass(self.options.style.classes.active);
            };

            // Log event and return
            return $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_SHOWN, 'show');
         },

         hide: function(event)
         {
            var returned;

            // Make sure tooltip is rendered and if not, return
            if(!self.status.rendered)
               return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'hide');

            // Only continue if element is visible
            else if(self.elements.tooltip.css('display') === 'none') return self;

            // Stop show timer and animation queue
            clearTimeout(self.timers.show);
            self.elements.tooltip.stop(true, false);

            // Call API method and if return value is false, halt
            returned = self.beforeHide.call(self, event);
            if(returned === false) return self;

            // Define afterHide callback method
            function afterHide(){ self.onHide.call(self, event); };

            // Maintain toggle functionality if enabled
            self.cache.toggle = 0;

            // Hide tooltip
            if(typeof self.options.hide.effect.type == 'function')
            {
               self.options.hide.effect.type.call(self.elements.tooltip, self.options.hide.effect.length);
               self.elements.tooltip.queue(function(){ afterHide(); $(this).dequeue(); });
            }
            else
            {
               switch(self.options.hide.effect.type.toLowerCase())
               {
                  case 'fade':
                     self.elements.tooltip.fadeOut(self.options.hide.effect.length, afterHide);
                     break;
                  case 'slide':
                     self.elements.tooltip.slideUp(self.options.hide.effect.length, afterHide);
                     break;
                  case 'grow':
                     self.elements.tooltip.hide(self.options.hide.effect.length, afterHide);
                     break;
                  default:
                     self.elements.tooltip.hide(null, afterHide);
                     break;
               };

               // Remove active class to tooltip
               self.elements.tooltip.removeClass(self.options.style.classes.active);
            };

            // Log event and return
            return $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_HIDDEN, 'hide');
         },

         updatePosition: function(event, animate)
         {
            var i, target, tooltip, coords, mapName, imagePos, newPosition, ieAdjust, ie6Adjust, borderAdjust, mouseAdjust, offset, curPosition, returned;

            // Make sure tooltip is rendered and if not, return
            if(!self.status.rendered)
               return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'updatePosition');

            // If tooltip is static, return
            else if(self.options.position.type == 'static')
               return $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.CANNOT_POSITION_STATIC, 'updatePosition');

            // Define property objects
            target = {
               position: { left: 0, top: 0 },
               dimensions: { height: 0, width: 0 },
               corner: self.options.position.corner.target
            };
            tooltip = {
               position: self.getPosition(),
               dimensions: self.getDimensions(),
               corner: self.options.position.corner.tooltip
            };

            // Target is an HTML element
            if(self.options.position.target !== 'mouse')
            {
               // If the HTML element is AREA, calculate position manually
               if(self.options.position.target.get(0).nodeName.toLowerCase() == 'area')
               {
                  // Retrieve coordinates from coords attribute and parse into integers
                  coords = self.options.position.target.attr('coords').split(',');
                  for(i = 0; i < coords.length; i++) coords[i] = parseInt(coords[i], 10);

                  // Setup target position object
                  mapName = self.options.position.target.parent('map').attr('name');
                  imagePos = $('img[usemap="#'+mapName+'"]:first').offset();
                  target.position = {
                     left: Math.floor(imagePos.left + coords[0]),
                     top: Math.floor(imagePos.top + coords[1])
                  };

                  // Determine width and height of the area
                  switch(self.options.position.target.attr('shape').toLowerCase())
                  {
                     case 'rect':
                        target.dimensions = {
                           width: Math.ceil(Math.abs(coords[2] - coords[0])),
                           height: Math.ceil(Math.abs(coords[3] - coords[1]))
                        };
                        break;

                     case 'circle':
                        target.dimensions = {
                           width: coords[2] + 1,
                           height: coords[2] + 1
                        };
                        break;

                     case 'poly':
                        target.dimensions = {
                           width: coords[0],
                           height: coords[1]
                        };

                        for(i = 0; i < coords.length; i++)
                        {
                           if(i % 2 == 0)
                           {
                              if(coords[i] > target.dimensions.width)
                                 target.dimensions.width = coords[i];
                              if(coords[i] < coords[0])
                                 target.position.left = Math.floor(imagePos.left + coords[i]);
                           }
                           else
                           {
                              if(coords[i] > target.dimensions.height)
                                 target.dimensions.height = coords[i];
                              if(coords[i] < coords[1])
                                 target.position.top = Math.floor(imagePos.top + coords[i]);
                           };
                        };

                        target.dimensions.width = target.dimensions.width - (target.position.left - imagePos.left);
                        target.dimensions.height = target.dimensions.height - (target.position.top - imagePos.top);
                        break;

                     default:
                        return $.fn.qtip.log.error.call(self, 4, $.fn.qtip.constants.INVALID_AREA_SHAPE, 'updatePosition');
                        break;
                  };

                  // Adjust position by 2 pixels (Positioning bug?)
                  target.dimensions.width -= 2; target.dimensions.height -= 2;
               }

               // Target is the document
               else if(self.options.position.target.add(document.body).length === 1)
               {
                  target.position = { left: $(document).scrollLeft(), top: $(document).scrollTop() };
                  target.dimensions = { height: $(window).height(), width: $(window).width() };
               }

               // Target is a regular HTML element, find position normally
               else
               {
                  // Check if the target is another tooltip. If its animated, retrieve position from newPosition data
                  if(typeof self.options.position.target.attr('qtip') !== 'undefined')
                     target.position = self.options.position.target.qtip('api').cache.position;
                  else
                     target.position = self.options.position.target.offset();

                  // Setup dimensions objects
                  target.dimensions = {
                     height: self.options.position.target.outerHeight(),
                     width: self.options.position.target.outerWidth()
                  };
               };

               // Calculate correct target corner position
               newPosition = $.extend({}, target.position);
               if(target.corner.search(/right/i) !== -1)
                  newPosition.left += target.dimensions.width;

               if(target.corner.search(/bottom/i) !== -1)
                  newPosition.top += target.dimensions.height;

               if(target.corner.search(/((top|bottom)Middle)|center/) !== -1)
                  newPosition.left += (target.dimensions.width / 2);

               if(target.corner.search(/((left|right)Middle)|center/) !== -1)
                  newPosition.top += (target.dimensions.height / 2);
            }

            // Mouse is the target, set position to current mouse coordinates
            else
            {
               // Setup target position and dimensions objects
               target.position = newPosition = { left: self.cache.mouse.x, top: self.cache.mouse.y };
               target.dimensions = { height: 1, width: 1 };
            };

            // Calculate correct target corner position
            if(tooltip.corner.search(/right/i) !== -1)
               newPosition.left -= tooltip.dimensions.width;

            if(tooltip.corner.search(/bottom/i) !== -1)
               newPosition.top -= tooltip.dimensions.height;

            if(tooltip.corner.search(/((top|bottom)Middle)|center/) !== -1)
               newPosition.left -= (tooltip.dimensions.width / 2);

            if(tooltip.corner.search(/((left|right)Middle)|center/) !== -1)
               newPosition.top -= (tooltip.dimensions.height / 2);

            // Setup IE adjustment variables (Pixel gap bugs)
            ieAdjust = ($.browser.msie) ? 1 : 0; // And this is why I hate IE...
            ie6Adjust = ($.browser.msie && parseInt($.browser.version.charAt(0), 10) === 6) ? 1 : 0; // ...and even more so IE6!

            // Adjust for border radius
            if(self.options.style.border.radius > 0)
            {
               if(tooltip.corner.search(/Left/) !== -1)
                  newPosition.left -= self.options.style.border.radius;
               else if(tooltip.corner.search(/Right/) !== -1)
                  newPosition.left += self.options.style.border.radius;

               if(tooltip.corner.search(/Top/) !== -1)
                  newPosition.top -= self.options.style.border.radius;
               else if(tooltip.corner.search(/Bottom/) !== -1)
                  newPosition.top += self.options.style.border.radius;
            };

            // IE only adjustments (Pixel perfect!)
            if(ieAdjust)
            {
               if(tooltip.corner.search(/top/) !== -1)
                  newPosition.top -= ieAdjust;
               else if(tooltip.corner.search(/bottom/) !== -1)
                  newPosition.top += ieAdjust;

               if(tooltip.corner.search(/left/) !== -1)
                  newPosition.left -= ieAdjust;
               else if(tooltip.corner.search(/right/) !== -1)
                  newPosition.left += ieAdjust;

               if(tooltip.corner.search(/leftMiddle|rightMiddle/) !== -1)
                  newPosition.top -= 1;
            };

            // If screen adjustment is enabled, apply adjustments
            if(self.options.position.adjust.screen === true)
               newPosition = screenAdjust.call(self, newPosition, target, tooltip);

            // If mouse is the target, prevent tooltip appearing directly under the mouse
            if(self.options.position.target === 'mouse' && self.options.position.adjust.mouse === true)
            {
               if(self.options.position.adjust.screen === true && self.elements.tip)
                  mouseAdjust = self.elements.tip.attr('rel');
               else
                  mouseAdjust = self.options.position.corner.tooltip;

               newPosition.left += (mouseAdjust.search(/right/i) !== -1) ? -6 : 6;
               newPosition.top += (mouseAdjust.search(/bottom/i) !== -1) ? -6 : 6;
            }

            // Initiate bgiframe plugin in IE6 if tooltip overlaps a select box or object element
            if(!self.elements.bgiframe && $.browser.msie && parseInt($.browser.version.charAt(0), 10) == 6)
            {
               $('select, object').each(function()
               {
                  offset = $(this).offset();
                  offset.bottom = offset.top + $(this).height();
                  offset.right = offset.left + $(this).width();

                  if(newPosition.top + tooltip.dimensions.height >= offset.top
                  && newPosition.left + tooltip.dimensions.width >= offset.left)
                     bgiframe.call(self);
               });
            };

            // Add user xy adjustments
            newPosition.left += self.options.position.adjust.x;
            newPosition.top += self.options.position.adjust.y;

            // Set new tooltip position if its moved, animate if enabled
            curPosition = self.getPosition();
            if(newPosition.left != curPosition.left || newPosition.top != curPosition.top)
            {
               // Call API method and if return value is false, halt
               returned = self.beforePositionUpdate.call(self, event);
               if(returned === false) return self;

               // Cache new position
               self.cache.position = newPosition;

               // Check if animation is enabled
               if(animate === true)
               {
                  // Set animated status
                  self.status.animated = true;

                  // Animate and reset animated status on animation end
                  self.elements.tooltip.animate(newPosition, 200, 'swing', function(){ self.status.animated = false; });
               }

               // Set new position via CSS
               else self.elements.tooltip.css(newPosition);

               // Call API method and log event if its not a mouse move
               self.onPositionUpdate.call(self, event);
               if(typeof event !== 'undefined' && event.type && event.type !== 'mousemove')
                  $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_POSITION_UPDATED, 'updatePosition');
            };

            return self;
         },

         updateWidth: function(newWidth)
         {
            var hidden;

            // Make sure tooltip is rendered and if not, return
            if(!self.status.rendered)
               return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'updateWidth');

            // Make sure supplied width is a number and if not, return
            else if(newWidth && typeof newWidth !== 'number')
               return $.fn.qtip.log.error.call(self, 2, 'newWidth must be of type number', 'updateWidth');

            // Setup elements which must be hidden during width update
            hidden = self.elements.contentWrapper.siblings().add(self.elements.tip).add(self.elements.button);

            // Calculate the new width if one is not supplied
            if(!newWidth)
            {
               // Explicit width is set
               if(typeof self.options.style.width.value == 'number')
                  newWidth = self.options.style.width.value;

               // No width is set, proceed with auto detection
               else
               {
                  // Set width to auto initally to determine new width and hide other elements
                  self.elements.tooltip.css({ width: 'auto' });
                  hidden.hide();

                  // Set position and zoom to defaults to prevent IE hasLayout bug
                  if($.browser.msie)
                     self.elements.wrapper.add(self.elements.contentWrapper.children()).css({ zoom: 'normal' });

                  // Set the new width
                  newWidth = self.getDimensions().width + 1;

                  // Make sure its within the maximum and minimum width boundries
                  if(!self.options.style.width.value)
                  {
                     if(newWidth > self.options.style.width.max) newWidth = self.options.style.width.max;
                     if(newWidth < self.options.style.width.min) newWidth = self.options.style.width.min;
                  };
               };
            };

            // Adjust newWidth by 1px if width is odd (IE6 rounding bug fix)
            if(newWidth % 2 !== 0) newWidth -= 1;

            // Set the new calculated width and unhide other elements
            self.elements.tooltip.width(newWidth);
            hidden.show();

            // Set the border width, if enabled
            if(self.options.style.border.radius)
            {
               self.elements.tooltip.find('.qtip-betweenCorners').each(function(i)
               {
                  $(this).width(newWidth - (self.options.style.border.radius * 2));
               });
            }

            // IE only adjustments
            if($.browser.msie)
            {
               // Reset position and zoom to give the wrapper layout (IE hasLayout bug)
               self.elements.wrapper.add(self.elements.contentWrapper.children()).css({ zoom: '1' });

               // Set the new width
               self.elements.wrapper.width(newWidth);

               // Adjust BGIframe height and width if enabled
               if(self.elements.bgiframe) self.elements.bgiframe.width(newWidth).height(self.getDimensions.height);
            };

            // Log event and return
            return $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_WIDTH_UPDATED, 'updateWidth');
         },

         updateStyle: function(name)
         {
            var tip, borders, context, corner, coordinates;

            // Make sure tooltip is rendered and if not, return
            if(!self.status.rendered)
               return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'updateStyle');

            // Return if style is not defined or name is not a string
            else if(typeof name !== 'string' || !$.fn.qtip.styles[name])
               return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.STYLE_NOT_DEFINED, 'updateStyle');

            // Set the new style object
            self.options.style = buildStyle.call(self, $.fn.qtip.styles[name], self.options.user.style);

            // Update initial styles of content and title elements
            self.elements.content.css( jQueryStyle(self.options.style) );
            if(self.options.content.title.text !== false)
               self.elements.title.css( jQueryStyle(self.options.style.title, true) );

            // Update CSS border colour
            self.elements.contentWrapper.css({ borderColor: self.options.style.border.color });

            // Update tip color if enabled
            if(self.options.style.tip.corner !== false)
            {
               if($('<canvas>').get(0).getContext)
               {
                  // Retrieve canvas context and clear
                  tip = self.elements.tooltip.find('.qtip-tip canvas:first');
                  context = tip.get(0).getContext('2d');
                  context.clearRect(0,0,300,300);

                  // Draw new tip
                  corner = tip.parent('div[rel]:first').attr('rel');
                  coordinates = calculateTip(corner, self.options.style.tip.size.width, self.options.style.tip.size.height);
                  drawTip.call(self, tip, coordinates, self.options.style.tip.color || self.options.style.border.color);
               }
               else if($.browser.msie)
               {
                  // Set new fillcolor attribute
                  tip = self.elements.tooltip.find('.qtip-tip [nodeName="shape"]');
                  tip.attr('fillcolor', self.options.style.tip.color || self.options.style.border.color);
               };
            };

            // Update border colors if enabled
            if(self.options.style.border.radius > 0)
            {
               self.elements.tooltip.find('.qtip-betweenCorners').css({ backgroundColor: self.options.style.border.color });

               if($('<canvas>').get(0).getContext)
               {
                  borders = calculateBorders(self.options.style.border.radius);
                  self.elements.tooltip.find('.qtip-wrapper canvas').each(function()
                  {
                     // Retrieve canvas context and clear
                     context = $(this).get(0).getContext('2d');
                     context.clearRect(0,0,300,300);

                     // Draw new border
                     corner = $(this).parent('div[rel]:first').attr('rel');
                     drawBorder.call(self, $(this), borders[corner],
                        self.options.style.border.radius, self.options.style.border.color);
                  });
               }
               else if($.browser.msie)
               {
                  // Set new fillcolor attribute on each border corner
                  self.elements.tooltip.find('.qtip-wrapper [nodeName="arc"]').each(function()
                  {
                     $(this).attr('fillcolor', self.options.style.border.color);
                  });
               };
            };

            // Log event and return
            return $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_STYLE_UPDATED, 'updateStyle');
         },

         updateContent: function(content, reposition)
         {
            var parsedContent, images, loadedImages;

            // Make sure tooltip is rendered and if not, return
            if(!self.status.rendered)
               return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'updateContent');

            // Make sure content is defined before update
            else if(!content)
               return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.NO_CONTENT_PROVIDED, 'updateContent');

            // Call API method and set new content if a string is returned
            parsedContent = self.beforeContentUpdate.call(self, content);
            if(typeof parsedContent == 'string') content = parsedContent;
            else if(parsedContent === false) return;

            // Set position and zoom to defaults to prevent IE hasLayout bug
            if($.browser.msie) self.elements.contentWrapper.children().css({ zoom: 'normal' });

            // Append new content if its a DOM array and show it if hidden
            if(content.jquery && content.length > 0)
               content.clone(true).appendTo(self.elements.content).show();

            // Content is a regular string, insert the new content
            else self.elements.content.html(content);

            // Check if images need to be loaded before position is updated to prevent mis-positioning
            images = self.elements.content.find('img[complete=false]');
            if(images.length > 0)
            {
               loadedImages = 0;
               images.each(function(i)
               {
                  $('<img src="'+ $(this).attr('src') +'" />')
                     .load(function(){ if(++loadedImages == images.length) afterLoad(); });
               });
            }
            else afterLoad();

            function afterLoad()
            {
               // Update the tooltip width
               self.updateWidth();

               // If repositioning is enabled, update positions
               if(reposition !== false)
               {
                  // Update position if tooltip isn't static
                  if(self.options.position.type !== 'static')
                     self.updatePosition(self.elements.tooltip.is(':visible'), true);

                  // Reposition the tip if enabled
                  if(self.options.style.tip.corner !== false)
                     positionTip.call(self);
               };
            };

            // Call API method and log event
            self.onContentUpdate.call(self);
            return $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_CONTENT_UPDATED, 'loadContent');
         },

         loadContent: function(url, data, method)
         {
            var returned;

            // Make sure tooltip is rendered and if not, return
            if(!self.status.rendered)
               return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'loadContent');

            // Call API method and if return value is false, halt
            returned = self.beforeContentLoad.call(self);
            if(returned === false) return self;

            // Load content using specified request type
            if(method == 'post')
               $.post(url, data, setupContent);
            else
               $.get(url, data, setupContent);

            function setupContent(content)
            {
               // Call API method and log event
               self.onContentLoad.call(self);
               $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_CONTENT_LOADED, 'loadContent');

               // Update the content
               self.updateContent(content);
            };

            return self;
         },

         updateTitle: function(content)
         {
            // Make sure tooltip is rendered and if not, return
            if(!self.status.rendered)
               return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'updateTitle');

            // Make sure content is defined before update
            else if(!content)
               return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.NO_CONTENT_PROVIDED, 'updateTitle');

            // Call API method and if return value is false, halt
            returned = self.beforeTitleUpdate.call(self);
            if(returned === false) return self;

            // Set the new content and reappend the button if enabled
            if(self.elements.button) self.elements.button = self.elements.button.clone(true);
            self.elements.title.html(content);
            if(self.elements.button) self.elements.title.prepend(self.elements.button);

            // Call API method and log event
            self.onTitleUpdate.call(self);
            return $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_TITLE_UPDATED, 'updateTitle');
         },

         focus: function(event)
         {
            var curIndex, newIndex, elemIndex, returned;

            // Make sure tooltip is rendered and if not, return
            if(!self.status.rendered)
               return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'focus');

            else if(self.options.position.type == 'static')
               return $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.CANNOT_FOCUS_STATIC, 'focus');

            // Set z-index variables
            curIndex = parseInt( self.elements.tooltip.css('z-index'), 10 );
            newIndex = 6000 + $('div.qtip[qtip]').length - 1;

            // Only update the z-index if it has changed and tooltip is not already focused
            if(!self.status.focused && curIndex !== newIndex)
            {
               // Call API method and if return value is false, halt
               returned = self.beforeFocus.call(self, event);
               if(returned === false) return self;

               // Loop through all other tooltips
               $('div.qtip[qtip]').not(self.elements.tooltip).each(function()
               {
                  if($(this).qtip('api').status.rendered === true)
                  {
                     elemIndex = parseInt($(this).css('z-index'), 10);

                     // Reduce all other tooltip z-index by 1
                     if(typeof elemIndex == 'number' && elemIndex > -1)
                        $(this).css({ zIndex: parseInt( $(this).css('z-index'), 10 ) - 1 });

                     // Set focused status to false
                     $(this).qtip('api').status.focused = false;
                  }
               });

               // Set the new z-index and set focus status to true
               self.elements.tooltip.css({ zIndex: newIndex });
               self.status.focused = true;

               // Call API method and log event
               self.onFocus.call(self, event);
               $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_FOCUSED, 'focus');
            };

            return self;
         },

         disable: function(state)
         {
            // Make sure tooltip is rendered and if not, return
            if(!self.status.rendered)
               return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'disable');

            if(state)
            {
               // Tooltip is not already disabled, proceed
               if(!self.status.disabled)
               {
                  // Set the disabled flag and log event
                  self.status.disabled = true;
                  $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_DISABLED, 'disable');
               }

               // Tooltip is already disabled, inform user via log
               else  $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.TOOLTIP_ALREADY_DISABLED, 'disable');
            }
            else
            {
               // Tooltip is not already enabled, proceed
               if(self.status.disabled)
               {
                  // Reassign events, set disable status and log
                  self.status.disabled = false;
                  $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_ENABLED, 'disable');
               }

               // Tooltip is already enabled, inform the user via log
               else $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.TOOLTIP_ALREADY_ENABLED, 'disable');
            };

            return self;
         },

         destroy: function()
         {
            var i, returned, interfaces;

            // Call API method and if return value is false, halt
            returned = self.beforeDestroy.call(self);
            if(returned === false) return self;

            // Check if tooltip is rendered
            if(self.status.rendered)
            {
               // Remove event handlers and remove element
               self.options.show.when.target.unbind('mousemove.qtip', self.updatePosition);
               self.options.show.when.target.unbind('mouseout.qtip', self.hide);
               self.options.show.when.target.unbind(self.options.show.when.event + '.qtip');
               self.options.hide.when.target.unbind(self.options.hide.when.event + '.qtip');
               self.elements.tooltip.unbind(self.options.hide.when.event + '.qtip');
               self.elements.tooltip.unbind('mouseover.qtip', self.focus);
               self.elements.tooltip.remove();
            }

            // Tooltip isn't yet rendered, remove render event
            else self.options.show.when.target.unbind(self.options.show.when.event+'.qtip-create');

            // Check to make sure qTip data is present on target element
            if(typeof self.elements.target.data('qtip') == 'object')
            {
               // Remove API references from interfaces object
               interfaces = self.elements.target.data('qtip').interfaces;
               if(typeof interfaces == 'object' && interfaces.length > 0)
               {
                  // Remove API from interfaces array
                  for(i = 0; i < interfaces.length - 1; i++)
                     if(interfaces[i].id == self.id) interfaces.splice(i, 1);
               }
            }
            delete $.fn.qtip.interfaces[self.id];

            // Set qTip current id to previous tooltips API if available
            if(typeof interfaces == 'object' && interfaces.length > 0)
               self.elements.target.data('qtip').current = interfaces.length -1;
            else
               self.elements.target.removeData('qtip');

            // Call API method and log destroy
            self.onDestroy.call(self);
            $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_DESTROYED, 'destroy');

            return self.elements.target;
         },

         getPosition: function()
         {
            var show, offset;

            // Make sure tooltip is rendered and if not, return
            if(!self.status.rendered)
               return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'getPosition');

            show = (self.elements.tooltip.css('display') !== 'none') ? false : true;

            // Show and hide tooltip to make sure coordinates are returned
            if(show) self.elements.tooltip.css({ visiblity: 'hidden' }).show();
            offset = self.elements.tooltip.offset();
            if(show) self.elements.tooltip.css({ visiblity: 'visible' }).hide();

            return offset;
         },

         getDimensions: function()
         {
            var show, dimensions;

            // Make sure tooltip is rendered and if not, return
            if(!self.status.rendered)
               return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'getDimensions');

            show = (!self.elements.tooltip.is(':visible')) ? true : false;

            // Show and hide tooltip to make sure dimensions are returned
            if(show) self.elements.tooltip.css({ visiblity: 'hidden' }).show();
            dimensions = {
               height: self.elements.tooltip.outerHeight(),
               width: self.elements.tooltip.outerWidth()
            };
            if(show) self.elements.tooltip.css({ visiblity: 'visible' }).hide();

            return dimensions;
         }
      });
   };

   // Define priamry construct function
   function construct()
   {
      var self, adjust, content, url, data, method, tempLength;
      self = this;

      // Call API method
      self.beforeRender.call(self);

      // Set rendered status to true
      self.status.rendered = true;

      // Create initial tooltip elements
      self.elements.tooltip =  '<div qtip="'+self.id+'" ' +
         'class="qtip '+(self.options.style.classes.tooltip || self.options.style)+'"' +
         'style="display:none; -moz-border-radius:0; -webkit-border-radius:0; border-radius:0;' +
         'position:'+self.options.position.type+';">' +
         '  <div class="qtip-wrapper" style="position:relative; overflow:hidden; text-align:left;">' +
         '    <div class="qtip-contentWrapper" style="overflow:hidden;">' +
         '       <div class="qtip-content '+self.options.style.classes.content+'"></div>' +
         '</div></div></div>';

      // Append to container element
      self.elements.tooltip = $(self.elements.tooltip);
      self.elements.tooltip.appendTo(self.options.position.container);

      // Setup tooltip qTip data
      self.elements.tooltip.data('qtip', { current: 0, interfaces: [self] });

      // Setup element references
      self.elements.wrapper = self.elements.tooltip.children('div:first');
      self.elements.contentWrapper = self.elements.wrapper.children('div:first').css({ background: self.options.style.background });
      self.elements.content = self.elements.contentWrapper.children('div:first').css( jQueryStyle(self.options.style) );

      // Apply IE hasLayout fix to wrapper and content elements
      if($.browser.msie) self.elements.wrapper.add(self.elements.content).css({ zoom: 1 });

      // Setup tooltip attributes
      if(self.options.hide.when.event == 'unfocus') self.elements.tooltip.attr('unfocus', true);

      // If an explicit width is set, updateWidth prior to setting content to prevent dirty rendering
      if(typeof self.options.style.width.value == 'number') self.updateWidth();

      // Create borders and tips if supported by the browser
      if($('<canvas>').get(0).getContext || $.browser.msie)
      {
         // Create border
         if(self.options.style.border.radius > 0)
            createBorder.call(self);
         else
            self.elements.contentWrapper.css({ border: self.options.style.border.width+'px solid '+self.options.style.border.color  });

         // Create tip if enabled
         if(self.options.style.tip.corner !== false)
            createTip.call(self);
      }

      // Neither canvas or VML is supported, tips and borders cannot be drawn!
      else
      {
         // Set defined border width
         self.elements.contentWrapper.css({ border: self.options.style.border.width+'px solid '+self.options.style.border.color  });

         // Reset border radius and tip
         self.options.style.border.radius = 0;
         self.options.style.tip.corner = false;

         // Inform via log
         $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.CANVAS_VML_NOT_SUPPORTED, 'render');
      };

      // Use the provided content string or DOM array
      if((typeof self.options.content.text == 'string' && self.options.content.text.length > 0)
      || (self.options.content.text.jquery && self.options.content.text.length > 0))
         content = self.options.content.text;

      // Use title string for content if present
      else if(typeof self.elements.target.attr('title') == 'string' && self.elements.target.attr('title').length > 0)
      {
         content = self.elements.target.attr('title').replace("\\n", '<br />');
         self.elements.target.attr('title', ''); // Remove title attribute to prevent default tooltip showing
      }

      // No title is present, use alt attribute instead
      else if(typeof self.elements.target.attr('alt') == 'string' && self.elements.target.attr('alt').length > 0)
      {
         content = self.elements.target.attr('alt').replace("\\n", '<br />');
         self.elements.target.attr('alt', ''); // Remove alt attribute to prevent default tooltip showing
      }

      // No valid content was provided, inform via log
      else
      {
         content = ' ';
         $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.NO_VALID_CONTENT, 'render');
      };

      // Set the tooltips content and create title if enabled
      if(self.options.content.title.text !== false) createTitle.call(self);
      self.updateContent(content);

      // Assign events and toggle tooltip with focus
      assignEvents.call(self);
      if(self.options.show.ready === true) self.show();

      // Retrieve ajax content if provided
      if(self.options.content.url !== false)
      {
         url = self.options.content.url;
         data = self.options.content.data;
         method = self.options.content.method || 'get';
         self.loadContent(url, data, method);
      };

      // Call API method and log event
      self.onRender.call(self);
      $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_RENDERED, 'render');
   };

   // Create borders using canvas and VML
   function createBorder()
   {
      var self, i, width, radius, color, coordinates, containers, size, betweenWidth, betweenCorners, borderTop, borderBottom, borderCoord, sideWidth, vertWidth;
      self = this;

      // Destroy previous border elements, if present
      self.elements.wrapper.find('.qtip-borderBottom, .qtip-borderTop').remove();

      // Setup local variables
      width = self.options.style.border.width;
      radius = self.options.style.border.radius;
      color = self.options.style.border.color || self.options.style.tip.color;

      // Calculate border coordinates
      coordinates = calculateBorders(radius);

      // Create containers for the border shapes
      containers = {};
      for(i in coordinates)
      {
         // Create shape container
         containers[i] = '<div rel="'+i+'" style="'+((i.search(/Left/) !== -1) ? 'left' : 'right') + ':0; ' +
            'position:absolute; height:'+radius+'px; width:'+radius+'px; overflow:hidden; line-height:0.1px; font-size:1px">';

         // Canvas is supported
         if($('<canvas>').get(0).getContext)
            containers[i] += '<canvas height="'+radius+'" width="'+radius+'" style="vertical-align: top"></canvas>';

         // No canvas, but if it's IE use VML
         else if($.browser.msie)
         {
            size = radius * 2 + 3;
            containers[i] += '<v:arc stroked="false" fillcolor="'+color+'" startangle="'+coordinates[i][0]+'" endangle="'+coordinates[i][1]+'" ' +
               'style="width:'+size+'px; height:'+size+'px; margin-top:'+((i.search(/bottom/) !== -1) ? -2 : -1)+'px; ' +
               'margin-left:'+((i.search(/Right/) !== -1) ? coordinates[i][2] - 3.5 : -1)+'px; ' +
               'vertical-align:top; display:inline-block; behavior:url(#default#VML)"></v:arc>';

         };

         containers[i] += '</div>';
      };

      // Create between corners elements
      betweenWidth = self.getDimensions().width - (Math.max(width, radius) * 2);
      betweenCorners = '<div class="qtip-betweenCorners" style="height:'+radius+'px; width:'+betweenWidth+'px; ' +
         'overflow:hidden; background-color:'+color+'; line-height:0.1px; font-size:1px;">';

      // Create top border container
      borderTop = '<div class="qtip-borderTop" dir="ltr" style="height:'+radius+'px; ' +
         'margin-left:'+radius+'px; line-height:0.1px; font-size:1px; padding:0;">' +
         containers['topLeft'] + containers['topRight'] + betweenCorners;
      self.elements.wrapper.prepend(borderTop);

      // Create bottom border container
      borderBottom = '<div class="qtip-borderBottom" dir="ltr" style="height:'+radius+'px; ' +
         'margin-left:'+radius+'px; line-height:0.1px; font-size:1px; padding:0;">' +
         containers['bottomLeft'] + containers['bottomRight'] + betweenCorners;
      self.elements.wrapper.append(borderBottom);

      // Draw the borders if canvas were used (Delayed til after DOM creation)
      if($('<canvas>').get(0).getContext)
      {
         self.elements.wrapper.find('canvas').each(function()
         {
            borderCoord = coordinates[ $(this).parent('[rel]:first').attr('rel') ];
            drawBorder.call(self, $(this), borderCoord, radius, color);
         });
      }

      // Create a phantom VML element (IE won't show the last created VML element otherwise)
      else if($.browser.msie) self.elements.tooltip.append('<v:image style="behavior:url(#default#VML);"></v:image>');

      // Setup contentWrapper border
      sideWidth = Math.max(radius, (radius + (width - radius)) );
      vertWidth = Math.max(width - radius, 0);
      self.elements.contentWrapper.css({
         border: '0px solid ' + color,
         borderWidth: vertWidth + 'px ' + sideWidth + 'px'
      });
   }

   // Border canvas draw method
   function drawBorder(canvas, coordinates, radius, color)
   {
      // Create corner
      var context = canvas.get(0).getContext('2d');
      context.fillStyle = color;
      context.beginPath();
      context.arc(coordinates[0], coordinates[1], radius, 0, Math.PI * 2, false);
      context.fill();
   };

   // Create tip using canvas and VML
   function createTip(corner)
   {
      var self, color, coordinates, coordsize, path;
      self = this;

      // Destroy previous tip, if there is one
      if(self.elements.tip !== null) self.elements.tip.remove();

      // Setup color and corner values
      color = self.options.style.tip.color || self.options.style.border.color;
      if(self.options.style.tip.corner === false) return;
      else if(!corner) corner = self.options.style.tip.corner;

      // Calculate tip coordinates
      coordinates = calculateTip(corner, self.options.style.tip.size.width, self.options.style.tip.size.height);

      // Create tip element
      self.elements.tip =  '<div class="'+self.options.style.classes.tip+'" dir="ltr" rel="'+corner+'" style="position:absolute; ' +
         'height:'+self.options.style.tip.size.height+'px; width:'+self.options.style.tip.size.width+'px; ' +
         'margin:0 auto; line-height:0.1px; font-size:1px;">';

      // Use canvas element if supported
      if($('<canvas>').get(0).getContext)
          self.elements.tip += '<canvas height="'+self.options.style.tip.size.height+'" width="'+self.options.style.tip.size.width+'"></canvas>';

      // Canvas not supported - Use VML (IE)
      else if($.browser.msie)
      {
         // Create coordize and tip path using tip coordinates
         coordsize = self.options.style.tip.size.width + ',' + self.options.style.tip.size.height;
         path = 'm' + coordinates[0][0] + ',' + coordinates[0][1];
         path += ' l' + coordinates[1][0] + ',' + coordinates[1][1];
         path += ' ' + coordinates[2][0] + ',' + coordinates[2][1];
         path += ' xe';

         // Create VML element
         self.elements.tip += '<v:shape fillcolor="'+color+'" stroked="false" filled="true" path="'+path+'" coordsize="'+coordsize+'" ' +
            'style="width:'+self.options.style.tip.size.width+'px; height:'+self.options.style.tip.size.height+'px; ' +
            'line-height:0.1px; display:inline-block; behavior:url(#default#VML); ' +
            'vertical-align:'+((corner.search(/top/) !== -1) ? 'bottom' : 'top')+'"></v:shape>';

         // Create a phantom VML element (IE won't show the last created VML element otherwise)
         self.elements.tip += '<v:image style="behavior:url(#default#VML);"></v:image>';

         // Prevent tooltip appearing above the content (IE z-index bug)
         self.elements.contentWrapper.css('position', 'relative');
      };

      // Attach new tip to tooltip element
      self.elements.tooltip.prepend(self.elements.tip + '</div>');

      // Create element reference and draw the canvas tip (Delayed til after DOM creation)
      self.elements.tip = self.elements.tooltip.find('.'+self.options.style.classes.tip).eq(0);
      if($('<canvas>').get(0).getContext)
         drawTip.call(self, self.elements.tip.find('canvas:first'), coordinates, color);

      // Fix IE small tip bug
      if(corner.search(/top/) !== -1 && $.browser.msie && parseInt($.browser.version.charAt(0), 10) === 6)
         self.elements.tip.css({ marginTop: -4 });

      // Set the tip position
      positionTip.call(self, corner);
   };

   // Canvas tip drawing method
   function drawTip(canvas, coordinates, color)
   {
      // Setup properties
      var context = canvas.get(0).getContext('2d');
      context.fillStyle = color;

      // Create tip
      context.beginPath();
      context.moveTo(coordinates[0][0], coordinates[0][1]);
      context.lineTo(coordinates[1][0], coordinates[1][1]);
      context.lineTo(coordinates[2][0], coordinates[2][1]);
      context.fill();
   };

   function positionTip(corner)
   {
      var self, ieAdjust, paddingCorner, paddingSize, newMargin;
      self = this;

      // Return if tips are disabled or tip is not yet rendered
      if(self.options.style.tip.corner === false || !self.elements.tip) return;
      if(!corner) corner = self.elements.tip.attr('rel');

      // Setup adjustment variables
      ieAdjust = positionAdjust = ($.browser.msie) ? 1 : 0;

      // Set initial position
      self.elements.tip.css(corner.match(/left|right|top|bottom/)[0], 0);

      // Set position of tip to correct side
      if(corner.search(/top|bottom/) !== -1)
      {
         // Adjustments for IE6 - 0.5px border gap bug
         if($.browser.msie)
         {
            if(parseInt($.browser.version.charAt(0), 10) === 6)
               positionAdjust = (corner.search(/top/) !== -1) ? -3 : 1;
            else
               positionAdjust = (corner.search(/top/) !== -1) ? 1 : 2;
         };

         if(corner.search(/Middle/) !== -1)
            self.elements.tip.css({ left: '50%', marginLeft: -(self.options.style.tip.size.width / 2) });

         else if(corner.search(/Left/) !== -1)
            self.elements.tip.css({ left: self.options.style.border.radius - ieAdjust });

         else if(corner.search(/Right/) !== -1)
            self.elements.tip.css({ right: self.options.style.border.radius + ieAdjust });

         if(corner.search(/top/) !== -1)
            self.elements.tip.css({ top: -positionAdjust });
         else
            self.elements.tip.css({ bottom: positionAdjust });

      }
      else if(corner.search(/left|right/) !== -1)
      {
         // Adjustments for IE6 - 0.5px border gap bug
         if($.browser.msie)
            positionAdjust = (parseInt($.browser.version.charAt(0), 10) === 6) ? 1 : ((corner.search(/left/) !== -1) ? 1 : 2);

         if(corner.search(/Middle/) !== -1)
            self.elements.tip.css({ top: '50%', marginTop: -(self.options.style.tip.size.height / 2) });

         else if(corner.search(/Top/) !== -1)
            self.elements.tip.css({ top: self.options.style.border.radius - ieAdjust });

         else if(corner.search(/Bottom/) !== -1)
            self.elements.tip.css({ bottom: self.options.style.border.radius + ieAdjust });

         if(corner.search(/left/) !== -1)
            self.elements.tip.css({ left: -positionAdjust });
         else
            self.elements.tip.css({ right: positionAdjust });
      };

      // Adjust tooltip padding to compensate for tip
      paddingCorner = 'padding-' + corner.match(/left|right|top|bottom/)[0];
      paddingSize = self.options.style.tip.size[ (paddingCorner.search(/left|right/) !== -1) ? 'width' : 'height' ];
      self.elements.tooltip.css('padding', 0);
      self.elements.tooltip.css(paddingCorner, paddingSize);

      // Match content margin to prevent gap bug in IE6 ONLY
      if($.browser.msie && parseInt($.browser.version.charAt(0), 10) == 6)
      {
         newMargin = parseInt(self.elements.tip.css('margin-top'), 10) || 0;
         newMargin += parseInt(self.elements.content.css('margin-top'), 10) || 0;

         self.elements.tip.css({ marginTop: newMargin });
      };
   };

   // Create title bar for content
   function createTitle()
   {
      var self = this;

      // Destroy previous title element, if present
      if(self.elements.title !== null) self.elements.title.remove();

      // Create title element
      self.elements.title = $('<div class="'+self.options.style.classes.title+'">')
         .css( jQueryStyle(self.options.style.title, true) )
         .css({ zoom: ($.browser.msie) ? 1 : 0 })
         .prependTo(self.elements.contentWrapper);

      // Update title with contents if enabled
      if(self.options.content.title.text) self.updateTitle.call(self, self.options.content.title.text);

      // Create title close buttons if enabled
      if(self.options.content.title.button !== false
      && typeof self.options.content.title.button == 'string')
      {
         self.elements.button = $('<a class="'+self.options.style.classes.button+'" style="float:right; position: relative"></a>')
            .css( jQueryStyle(self.options.style.button, true) )
            .html(self.options.content.title.button)
            .prependTo(self.elements.title)
            .click(function(event){ if(!self.status.disabled) self.hide(event); });
      }
   }

   // Assign hide and show events
   function assignEvents()
   {
      var self, showTarget, hideTarget, inactiveEvents;
      self = this;

      // Setup event target variables
      showTarget = self.options.show.when.target;
      hideTarget = self.options.hide.when.target;

      // Add tooltip as a hideTarget is its fixed
      if(self.options.hide.fixed) hideTarget = hideTarget.add(self.elements.tooltip);

      // Check if the hide event is special 'inactive' type
      if(self.options.hide.when.event == 'inactive')
      {
         // Define events which reset the 'inactive' event handler
         inactiveEvents = ['click', 'dblclick', 'mousedown', 'mouseup', 'mousemove',
         'mouseout', 'mouseenter', 'mouseleave', 'mouseover' ];

         // Define 'inactive' event timer method
         function inactiveMethod(event)
         {
            if(self.status.disabled === true) return;

            //Clear and reset the timer
            clearTimeout(self.timers.inactive);
            self.timers.inactive = setTimeout(function()
            {
               // Unassign 'inactive' events
               $(inactiveEvents).each(function()
               {
                  hideTarget.unbind(this+'.qtip-inactive');
                  self.elements.content.unbind(this+'.qtip-inactive');
               });

               // Hide the tooltip
               self.hide(event);
            }
            , self.options.hide.delay);
         };
      }

      // Check if the tooltip is 'fixed'
      else if(self.options.hide.fixed === true)
      {
         self.elements.tooltip.bind('mouseover.qtip', function()
         {
            if(self.status.disabled === true) return;

            // Reset the hide timer
            clearTimeout(self.timers.hide);
         });
      };

      // Define show event method
      function showMethod(event)
      {
         if(self.status.disabled === true) return;

         // If set, hide tooltip when inactive for delay period
         if(self.options.hide.when.event == 'inactive')
         {
            // Assign each reset event
            $(inactiveEvents).each(function()
            {
               hideTarget.bind(this+'.qtip-inactive', inactiveMethod);
               self.elements.content.bind(this+'.qtip-inactive', inactiveMethod);
            });

            // Start the inactive timer
            inactiveMethod();
         };

         // Clear hide timers
         clearTimeout(self.timers.show);
         clearTimeout(self.timers.hide);

         // Start show timer
         self.timers.show = setTimeout(function(){ self.show(event); }, self.options.show.delay);
      };

      // Define hide event method
      function hideMethod(event)
      {
         if(self.status.disabled === true) return;

         // Prevent hiding if tooltip is fixed and event target is the tooltip
         if(self.options.hide.fixed === true
         && self.options.hide.when.event.search(/mouse(out|leave)/i) !== -1
         && $(event.relatedTarget).parents('div.qtip[qtip]').length > 0)
         {
            // Prevent default and popagation
            event.stopPropagation();
            event.preventDefault();

            // Reset the hide timer
            clearTimeout(self.timers.hide);
            return false;
         };

         // Clear timers and stop animation queue
         clearTimeout(self.timers.show);
         clearTimeout(self.timers.hide);
         self.elements.tooltip.stop(true, true);

         // If tooltip has displayed, start hide timer
         self.timers.hide = setTimeout(function(){ self.hide(event); }, self.options.hide.delay);
      };

      // Both events and targets are identical, apply events using a toggle
      if((self.options.show.when.target.add(self.options.hide.when.target).length === 1
      && self.options.show.when.event == self.options.hide.when.event
      && self.options.hide.when.event !== 'inactive')
      || self.options.hide.when.event == 'unfocus')
      {
         self.cache.toggle = 0;
         // Use a toggle to prevent hide/show conflicts
         showTarget.bind(self.options.show.when.event + '.qtip', function(event)
         {
            if(self.cache.toggle == 0) showMethod(event);
            else hideMethod(event);
         });
      }

      // Events are not identical, bind normally
      else
      {
         showTarget.bind(self.options.show.when.event + '.qtip', showMethod);

         // If the hide event is not 'inactive', bind the hide method
         if(self.options.hide.when.event !== 'inactive')
            hideTarget.bind(self.options.hide.when.event + '.qtip', hideMethod);
      };

      // Focus the tooltip on mouseover
      if(self.options.position.type.search(/(fixed|absolute)/) !== -1)
         self.elements.tooltip.bind('mouseover.qtip', self.focus);

      // If mouse is the target, update tooltip position on mousemove
      if(self.options.position.target === 'mouse' && self.options.position.type !== 'static')
      {
         showTarget.bind('mousemove.qtip', function(event)
         {
            // Set the new mouse positions if adjustment is enabled
            self.cache.mouse = { x: event.pageX, y: event.pageY };

            // Update the tooltip position only if the tooltip is visible and adjustment is enabled
            if(self.status.disabled === false
            && self.options.position.adjust.mouse === true
            && self.options.position.type !== 'static'
            && self.elements.tooltip.css('display') !== 'none')
               self.updatePosition(event);
         });
      };
   };

   // Screen position adjustment
   function screenAdjust(position, target, tooltip)
   {
      var self, adjustedPosition, adjust, newCorner, overflow, corner;
      self = this;

      // Setup corner and adjustment variable
      if(tooltip.corner == 'center') return target.position; // TODO: 'center' corner adjustment
      adjustedPosition = $.extend({}, position);
      newCorner = { x: false, y: false };

      // Define overflow properties
      overflow = {
         left: (adjustedPosition.left < $.fn.qtip.cache.screen.scroll.left),
         right: (adjustedPosition.left + tooltip.dimensions.width + 2 >= $.fn.qtip.cache.screen.width + $.fn.qtip.cache.screen.scroll.left),
         top: (adjustedPosition.top < $.fn.qtip.cache.screen.scroll.top),
         bottom: (adjustedPosition.top + tooltip.dimensions.height + 2 >= $.fn.qtip.cache.screen.height + $.fn.qtip.cache.screen.scroll.top)
      };

      // Determine new positioning properties
      adjust = {
         left: (overflow.left && (tooltip.corner.search(/right/i) != -1 || (tooltip.corner.search(/right/i) == -1 && !overflow.right))),
         right: (overflow.right && (tooltip.corner.search(/left/i) != -1 || (tooltip.corner.search(/left/i) == -1 && !overflow.left))),
         top: (overflow.top && tooltip.corner.search(/top/i) == -1),
         bottom: (overflow.bottom && tooltip.corner.search(/bottom/i) == -1)
      };

      // Tooltip overflows off the left side of the screen
      if(adjust.left)
      {
         if(self.options.position.target !== 'mouse')
            adjustedPosition.left = target.position.left + target.dimensions.width;
         else
            adjustedPosition.left = self.cache.mouse.x;

         newCorner.x = 'Left';
      }

      // Tooltip overflows off the right side of the screen
      else if(adjust.right)
      {
         if(self.options.position.target !== 'mouse')
            adjustedPosition.left = target.position.left - tooltip.dimensions.width;
         else
            adjustedPosition.left = self.cache.mouse.x - tooltip.dimensions.width;

         newCorner.x = 'Right';
      };

      // Tooltip overflows off the top of the screen
      if(adjust.top)
      {
         if(self.options.position.target !== 'mouse')
            adjustedPosition.top = target.position.top + target.dimensions.height;
         else
            adjustedPosition.top = self.cache.mouse.y;

         newCorner.y = 'top';
      }

      // Tooltip overflows off the bottom of the screen
      else if(adjust.bottom)
      {
         if(self.options.position.target !== 'mouse')
            adjustedPosition.top = target.position.top - tooltip.dimensions.height;
         else
            adjustedPosition.top = self.cache.mouse.y - tooltip.dimensions.height;

         newCorner.y = 'bottom';
      };

      // Don't adjust if resulting position is negative
      if(adjustedPosition.left < 0)
      {
         adjustedPosition.left = position.left;
         newCorner.x = false;
      };
      if(adjustedPosition.top < 0)
      {
         adjustedPosition.top = position.top;
         newCorner.y = false;
      };

      // Change tip corner if positioning has changed and tips are enabled
      if(self.options.style.tip.corner !== false)
      {
         // Determine new corner properties
         adjustedPosition.corner = new String(tooltip.corner);
         if(newCorner.x !== false) adjustedPosition.corner = adjustedPosition.corner.replace(/Left|Right|Middle/, newCorner.x);
         if(newCorner.y !== false) adjustedPosition.corner = adjustedPosition.corner.replace(/top|bottom/, newCorner.y);

         // Adjust tip if position has changed and tips are enabled
         if(adjustedPosition.corner !== self.elements.tip.attr('rel'))
            createTip.call(self, adjustedPosition.corner);
      };

      return adjustedPosition;
   };

   // Build a jQuery style object from supplied style object
   function jQueryStyle(style, sub)
   {
      var styleObj, i;

      styleObj = $.extend(true, {}, style);
      for(i in styleObj)
      {
         if(sub === true && i.search(/(tip|classes)/i) !== -1)
            delete styleObj[i];
         else if(!sub && i.search(/(width|border|tip|title|classes|user)/i) !== -1)
            delete styleObj[i];
      };

      return styleObj;
   };

   // Sanitize styles
   function sanitizeStyle(style)
   {
      if(typeof style.tip !== 'object') style.tip = { corner: style.tip };
      if(typeof style.tip.size !== 'object') style.tip.size = { width: style.tip.size, height: style.tip.size };
      if(typeof style.border !== 'object') style.border = { width: style.border };
      if(typeof style.width !== 'object') style.width = { value: style.width };
      if(typeof style.width.max == 'string') style.width.max = parseInt(style.width.max.replace(/([0-9]+)/i, "$1"), 10);
      if(typeof style.width.min == 'string') style.width.min = parseInt(style.width.min.replace(/([0-9]+)/i, "$1"), 10);

      // Convert deprecated x and y tip values to width/height
      if(typeof style.tip.size.x == 'number')
      {
         style.tip.size.width = style.tip.size.x;
         delete style.tip.size.x;
      };
      if(typeof style.tip.size.y == 'number')
      {
         style.tip.size.height = style.tip.size.y;
         delete style.tip.size.y;
      };

      return style;
   };

   // Build styles recursively with inheritance
   function buildStyle()
   {
      var self, i, styleArray, styleExtend, finalStyle, ieAdjust;
      self = this;

      // Build style options from supplied arguments
      styleArray = [true, {}];
      for(i = 0; i < arguments.length; i++)
         styleArray.push(arguments[i]);
      styleExtend = [ $.extend.apply($, styleArray) ];

      // Loop through each named style inheritance
      while(typeof styleExtend[0].name == 'string')
      {
         // Sanitize style data and append to extend array
         styleExtend.unshift( sanitizeStyle($.fn.qtip.styles[ styleExtend[0].name ]) );
      };

      // Make sure resulting tooltip className represents final style
      styleExtend.unshift(true, {classes:{ tooltip: 'qtip-' + (arguments[0].name || 'defaults') }}, $.fn.qtip.styles.defaults);

      // Extend into a single style object
      finalStyle = $.extend.apply($, styleExtend);

      // Adjust tip size if needed (IE 1px adjustment bug fix)
      ieAdjust = ($.browser.msie) ? 1 : 0;
      finalStyle.tip.size.width += ieAdjust;
      finalStyle.tip.size.height += ieAdjust;

      // Force even numbers for pixel precision
      if(finalStyle.tip.size.width % 2 > 0) finalStyle.tip.size.width += 1;
      if(finalStyle.tip.size.height % 2 > 0) finalStyle.tip.size.height += 1;

      // Sanitize final styles tip corner value
      if(finalStyle.tip.corner === true)
         finalStyle.tip.corner = (self.options.position.corner.tooltip === 'center') ? false : self.options.position.corner.tooltip;

      return finalStyle;
   };

   // Tip coordinates calculator
   function calculateTip(corner, width, height)
   {
      // Define tip coordinates in terms of height and width values
      var tips = {
         bottomRight:   [[0,0],              [width,height],      [width,0]],
         bottomLeft:    [[0,0],              [width,0],           [0,height]],
         topRight:      [[0,height],         [width,0],           [width,height]],
         topLeft:       [[0,0],              [0,height],          [width,height]],
         topMiddle:     [[0,height],         [width / 2,0],       [width,height]],
         bottomMiddle:  [[0,0],              [width,0],           [width / 2,height]],
         rightMiddle:   [[0,0],              [width,height / 2],  [0,height]],
         leftMiddle:    [[width,0],          [width,height],      [0,height / 2]]
      };
      tips.leftTop = tips.bottomRight;
      tips.rightTop = tips.bottomLeft;
      tips.leftBottom = tips.topRight;
      tips.rightBottom = tips.topLeft;

      return tips[corner];
   };

   // Border coordinates calculator
   function calculateBorders(radius)
   {
      var borders;

      // Use canvas element if supported
      if($('<canvas>').get(0).getContext)
      {
         borders = {
            topLeft: [radius,radius], topRight: [0,radius],
            bottomLeft: [radius,0], bottomRight: [0,0]
         };
      }

      // Canvas not supported - Use VML (IE)
      else if($.browser.msie)
      {
         borders = {
            topLeft: [-90,90,0], topRight: [-90,90,-radius],
            bottomLeft: [90,270,0], bottomRight: [90, 270,-radius]
         };
      };

      return borders;
   };

   // BGIFRAME JQUERY PLUGIN ADAPTION
   //   Special thanks to Brandon Aaron for this plugin
   //   http://plugins.jquery.com/project/bgiframe
   function bgiframe()
   {
      var self, html, dimensions;
      self = this;
      dimensions = self.getDimensions();

      // Setup iframe HTML string
      html = '<iframe class="qtip-bgiframe" frameborder="0" tabindex="-1" src="javascript:false" '+
         'style="display:block; position:absolute; z-index:-1; filter:alpha(opacity=\'0\'); border: 1px solid red; ' +
         'height:'+dimensions.height+'px; width:'+dimensions.width+'px" />';

      // Append the new HTML and setup element reference
      self.elements.bgiframe = self.elements.wrapper.prepend(html).children('.qtip-bgiframe:first');
   };

   // Assign cache and event initialisation on document load
   $(document).ready(function()
   {
      // Setup library cache with window scroll and dimensions of document
      $.fn.qtip.cache = {
         screen: {
            scroll: { left: $(window).scrollLeft(), top: $(window).scrollTop() },
            width: $(window).width(),
            height: $(window).height()
         }
      };

      // Adjust positions of the tooltips on window resize or scroll if enabled
      var adjustTimer;
      $(window).bind('resize scroll', function(event)
      {
         clearTimeout(adjustTimer);
         adjustTimer = setTimeout(function()
         {
            // Readjust cached screen values
            if(event.type === 'scroll')
               $.fn.qtip.cache.screen.scroll = { left: $(window).scrollLeft(), top: $(window).scrollTop() };
            else
            {
               $.fn.qtip.cache.screen.width = $(window).width();
               $.fn.qtip.cache.screen.height = $(window).height();
            };

            for(i = 0; i < $.fn.qtip.interfaces.length; i++)
            {
               // Access current elements API
               var api = $.fn.qtip.interfaces[i];

               // Update position if resize or scroll adjustments are enabled
               if(api.status.rendered === true
               && (api.options.position.type !== 'static'
               || api.options.position.adjust.scroll && event.type === 'scroll'
               || api.options.position.adjust.resize && event.type === 'resize'))
               {
                  // Queue the animation so positions are updated correctly
                  api.updatePosition(event, true);
               }
            };
         }
         , 100);
      });

      // Hide unfocus toolipts on document mousedown
      $(document).bind('mousedown.qtip', function(event)
      {
         if($(event.target).parents('div.qtip').length === 0)
         {
            $('.qtip[unfocus]').each(function()
            {
               var api = $(this).qtip("api");

               // Only hide if its visible and not the tooltips target
               if($(this).is(':visible') && !api.status.disabled
               && $(event.target).add(api.elements.target).length > 1)
                  api.hide(event);
            });
         };
      });
   });

   // Define qTip API interfaces array
   $.fn.qtip.interfaces = [];

   // Define log and constant place holders
   $.fn.qtip.log = { error: function(){ return this; } };
   $.fn.qtip.constants = {};

   // Define configuration defaults
   $.fn.qtip.defaults = {
      // Content
      content: {
         prerender: false,
         text: false,
         url: false,
         data: null,
         title: {
            text: false,
            button: false
         }
      },
      // Position
      position: {
         target: false,
         corner: {
            target: 'bottomRight',
            tooltip: 'topLeft'
         },
         adjust: {
            x: 0, y: 0,
            mouse: true,
            screen: false,
            scroll: true,
            resize: true
         },
         type: 'absolute',
         container: false
      },
      // Effects
      show: {
         when: {
            target: false,
            event: 'mouseover'
         },
         effect: {
            type: 'fade',
            length: 100
         },
         delay: 140,
         solo: false,
         ready: false
      },
      hide: {
         when: {
            target: false,
            event: 'mouseout'
         },
         effect: {
            type: 'fade',
            length: 100
         },
         delay: 0,
         fixed: false
      },
      // Callbacks
      api: {
         beforeRender: function(){},
         onRender: function(){},
         beforePositionUpdate: function(){},
         onPositionUpdate: function(){},
         beforeShow: function(){},
         onShow: function(){},
         beforeHide: function(){},
         onHide: function(){},
         beforeContentUpdate: function(){},
         onContentUpdate: function(){},
         beforeContentLoad: function(){},
         onContentLoad: function(){},
         beforeTitleUpdate: function(){},
         onTitleUpdate: function(){},
         beforeDestroy: function(){},
         onDestroy: function(){},
         beforeFocus: function(){},
         onFocus: function(){}
      }
   };

   $.fn.qtip.styles = {
      defaults: {
         background: 'white',
         color: '#111',
         overflow: 'hidden',
         textAlign: 'left',
         width: {
            min: 0,
            max: 250
         },
         padding: '5px 9px',
         border: {
            width: 1,
            radius: 0,
            color: '#d3d3d3'
         },
         tip: {
            corner: false,
            color: false,
            size: { width: 13, height: 13 },
            opacity: 1
         },
         title: {
            background: '#e1e1e1',
            fontWeight: 'bold',
            padding: '7px 12px'
         },
         button: {
            cursor: 'pointer'
         },
         classes: {
            target: '',
            tip: 'qtip-tip',
            title: 'qtip-title',
            button: 'qtip-button',
            content: 'qtip-content',
            active: 'qtip-active'
         }
      },
      cream: {
         border: {
            width: 3,
            radius: 0,
            color: '#F9E98E'
         },
         title: {
            background: '#F0DE7D',
            color: '#A27D35'
         },
         background: '#FBF7AA',
         color: '#A27D35',

         classes: { tooltip: 'qtip-cream' }
      },
      light: {
         border: {
            width: 3,
            radius: 0,
            color: '#E2E2E2'
         },
         title: {
            background: '#f1f1f1',
            color: '#454545'
         },
         background: 'white',
         color: '#454545',

         classes: { tooltip: 'qtip-light' }
      },
      dark: {
         border: {
            width: 3,
            radius: 0,
            color: '#303030'
         },
         title: {
            background: '#404040',
            color: '#f3f3f3'
         },
         background: '#505050',
         color: '#f3f3f3',

         classes: { tooltip: 'qtip-dark' }
      },
      red: {
         border: {
            width: 3,
            radius: 0,
            color: '#CE6F6F'
         },
         title: {
            background: '#f28279',
            color: '#9C2F2F'
         },
         background: '#F79992',
         color: '#9C2F2F',

         classes: { tooltip: 'qtip-red' }
      },
      green: {
         border: {
            width: 3,
            radius: 0,
            color: '#A9DB66'
         },
         title: {
            background: '#b9db8c',
            color: '#58792E'
         },
         background: '#CDE6AC',
         color: '#58792E',

         classes: { tooltip: 'qtip-green' }
      },
      blue: {
         border: {
            width: 3,
            radius: 0,
            color: '#ADD9ED'
         },
         title: {
            background: '#D0E9F5',
            color: '#5E99BD'
         },
         background: '#E5F6FE',
         color: '#4D9FBF',

         classes: { tooltip: 'qtip-blue' }
      }
   };
})(jQuery);
/* jquery.associateProvider.js (471) */
(function($) {

    /**
     * Main method for plugin
     *
     * @param {Object} inOptions
     */
    $.fn.associateProvider = function(inOptions) {

        var options = $.extend({}, $.fn.associateProvider.defaults, inOptions);

        return this.each(function() {
            $.fn.associateProvider.associate( this, options );
        });
    };

    /**
     * Public plugin function
     *
     * @return string
     */
    $.fn.associateProvider.associate = function( element, options ) {

        var button = $(element);
        var form   = $(options.selector.form);
        var searchButton = $(options.selector.searchButton);
        var deliveredByMyProviderButton = $(options.selector.deliveredByMyProviderButton);
        var addButton = $(options.selector.addButton);
        var letters = $(options.selector.letters);
        
        var letter = null;

        var requestXHR = null;

        var initProviderSearch = function () {            
            initLaunchButton();
            initSearchButton();
            initLetterButton();
            initDeliveredByMyProviderButton();
            initAddButton();
        };
        
        initProviderSearch();


        /**
         * Launches the lightbox search when the button is clicked
         * 
         */
        function initLaunchButton() {
            $(button).click(function() {
                $( form ).modal( {
                    overlayId: options.overlayId,
                    containerId: options.containerId,
                    containerCss: {'width':'490px'},
                    persist: true,
                    onOpen: function (dialog) {
                        dialog.overlay.fadeIn('fast', function () {
                            dialog.container.slideDown('normal', function () {
                                dialog.data.fadeIn('fast');
                            });
                        });
                    },
                    onClose: function (dialog) {
                        dialog.data.fadeOut('fast', function () {
                            dialog.container.slideUp('normal', function () {
                                dialog.overlay.fadeOut('fast', function () {
                                    $('.modalClose').hide();
                                    $.modal.close();
                                });
                            });
                        });
                    }
                });
            });            
        }

        function initSearchButton() {
            $( searchButton ).click( function(event) {
                $( options.selector.feedback ).html('');
                // Remove any currently selected letters
                $('.current', letters).removeClass('current');
                sendRequest();
            });
        }
        
        function initLetterButton() {
            
            $.each($('li a', letters), function(key,val) {
                $( this ).click( function(event) {
                    $( options.selector.feedback ).html('');
                    // Remove any search terms
                    $('#providerQuery', form).val('');
                    $(this).parent().parent().find('.current').removeClass('current');
                    $(this).parent().addClass('current');
                    letter = $(this).attr('rel');                    
                    sendRequest();          
                    event.preventDefault();
                });                
            });
            
        }
        
        function initDeliveredByMyProviderButton() {
            $( deliveredByMyProviderButton).click( function(event) {                   
                var providerId    = getProviderId();
                var providerTitle = getProviderTitle();
                
                $('#fld_deliveredByProviderId').val(providerId);
                $('#fld_deliveredByProviderName').val(providerTitle);
                closeDialog();
               
                return false;
            });
            
        }
        
        function initAddButton() { 
            $( addButton).click( function(event) {
                var feedback  = $('#providerFeedback');

                var providerId    = $('.providers .over').attr('id');
                var providerTitle = $('.providers .over').html();

                $('.actionDispatcherMessages', feedback).remove();

                if (!providerId){
                    Common_makeMessage( 'error', oLocale.getTranslation(options.module,'msgNoProviderSelected') )
                        .appendTo( feedback );
                    return;
                }
                options.addProviderToUI(providerId, providerTitle);
                closeDialog();
                return false;
            });        
        }

        function getProviderId() {                                    
            return $('#providerId').val();            
        }

        function getProviderTitle(){
            return $('#providerTitle').val();
        }
        

        /**
         * Main function that send request for getting providerss
         * Also sets up second request for all the information for a
         * provider after it has been selected
         *
         * @param HTMLInputElement selector
         * @param HTMLDivElement block
         */
        function sendRequest () {

            // Clear existing request, if present
            if (requestXHR !== null) {
                if (typeof requestXHR.abort == 'function') {
                    requestXHR.abort();
                }
            }                        
                        
            // Set up feedback and message areas
            var feedback  = $('#providerFeedback');
            var currValue = $( options.selector.field ).val();
            var search      = $('<div />').attr('id', 'searching').prependTo(feedback);
            var loading      = $('<div />').attr('id', 'loading').hide().prependTo(feedback);
            var helpText  = $('<div />').attr('id', 'helpText').hide().prependTo(feedback);

            search.append('<img src="'+ SITE_WEB_ROOT + 'custom/careers_wales/img/ajax/largeSpinner.gif" />')
            .append(oLocale.getTranslation(options.module,'lblSearchingProvider'));
            helpText.append(oLocale.getTranslation(options.module,'lblSearchProviders'));
            loading.append('<img src="'+ SITE_WEB_ROOT + 'custom/careers_wales/img/ajax/largeSpinner.gif" />')
            .append(oLocale.getTranslation(options.module,'lblLoadingProvider'));

            // send request for providers
            var submitUrl   = SITE_WEB_ROOT + 'server.php?change='+ options.template + getProvidersRequest();
            
            requestXHR = $.getJSON(submitUrl, function(json) {
                
                var module = json.Module;
                search.fadeOut ( 'slow', function() {
                    
                    if (!(module.aProviders)) {
                        Common_makeMessage( 'error', oLocale.getTranslation(options.module,'msgNoProviders') )
                        .appendTo( feedback );
                        return;
                    }
                    
                    if (module.aProviders.length === 0) {
                        Common_makeMessage( 'error', oLocale.getTranslation(options.module,'msgNoProviders') )
                        .appendTo( feedback );
                        return;
                    }

                    if ( module.aProviders.length > 150 ) {
                        Common_makeMessage( 'error', oLocale.getTranslation(options.module,'msgTooManyProviders') )
                        .appendTo( feedback );
                        return;
                    }

                    // Create a list to attach providers and provide helper text for user
                    helpText.fadeIn('fast');
                    var wrapper = $('<div />').addClass('providerWrapper').appendTo( feedback );
                    var results = $('<table />')
                    .append($('<tbody />'))
                    .addClass('providers').appendTo(wrapper);


                    // IE doesn't seem to set this correctly when done in the CSS
                    // so doing it here instead
                    if (/msie|MSIE/.test(navigator.userAgent)){
                        wrapper.css({
                            'height':'200px',
                            'overflow':'auto'
                        });
                        results.css({
                            width: '100%'
                        });
                    }


                    // Loop over providers, adding them to the list
                    for( var i = 0; i < module.aProviders.length; i++ ) {
                        var aProv       = module.aProviders[i];
                        var contentId     = aProv.oContent.aField.contentId;
                        var title     = aProv.oMetadataManager.oMetadata.aField.title;
                        var cellClass    = i % 2 === 0 ? 'even' : 'odd' ;
                        var item        = $('<tr></tr>').addClass(cellClass).appendTo($('tbody', results)).attr('name', contentId);

                        $('<a />').appendTo($('<td />').appendTo(item))
                        .attr('href', '#'+contentId)
                        .attr('id', contentId)
                        .html(title)
                        .click( function() {
                            helpText.fadeOut('fast');
                            $(this).parent().parent().parent().find('.over').removeClass('over');
                            $(this).addClass('over');

                            return false;
                        });
                    }
                });
            });
        }

        /**
         *  Build the request for extracting providers
         *  
         *  @param isLetterSearch Is user filtering by letter?
         */
        function getProvidersRequest() {
            var prefix  = '&Module['+options.instanceId+']';
            var request = '';

            form.each(function(){

                // Get the search string
                $('input[type=text]', $(this)).each(function() {
                    if( $(this).val().length > 0 ) {
                        request += prefix+'[providerQuery]='+ $(this).val();
                    } else if (letter) {
                        request += prefix + '[letter]=' + letter;
                    }
                });                

            });
            
            request += prefix + '[action]=getProviders&jsonOutput='+options.instanceId;
            return request;
        }

        /**
         * update the form after a user has selected a provider
         *
         * @param Json data
         */
        function updateForm ( data ) {
            var module     = data.Module;
            
            var content    = module.oProvider.oContent;
            var metadata   = module.oProvider.oMetadataManager.oMetadata;
            var categories = module.oProvider.oMetadataManager.aoCategory;                        
            
            if (content.aField.contentId) {
                $('#fld_deliveredByProviderId').val(content.aField.contentId);
            }
            if (metadata.aField.title) {
                $('#fld_deliveredByProviderName').val(metadata.aField.title);
            }
        }

        /**
         * Returns the request URL for extracting a conProvider in json format
         * @param int qualContentID
         * @param HTMLDivElement block
         */
        function getProviderRequest( providerContentId ) {
            var prefix  = '&Module['+options.instanceId+']';
            return prefix + '[action]=getProvider'+prefix+'[providerId]='+providerContentId+'&jsonOutput='+options.instanceId;
        }

        function getFormField( fieldName ) {
            return $('input[name="Module['+options.instanceId+']['+fieldName+'][]"]');
        }

        function closeDialog() {
            $(".modalData").fadeOut('fast', function () {
                $(".modalContainer").slideUp('fast', function () {
                    $(".modalOverlay").fadeOut('fast', function () {
                        $('.modalClose').hide();
                        $.modal.close();
                    });
                });
            });
        }
    };

    /**
     * Default settings
     */
    $.fn.associateProvider.defaults = {
        'overlayId' : 'providerOverlay',
        'containerId' : 'providerContainer',
        'addProviderToUI' : function(contentId, title) {
            $('#fld_deliveredByProviderId').val(contentId);
            $('#fld_deliveredByProviderName').val(title);
        }
    };

})(jQuery);
/* jquery.fixedheadertable.js (502) */
/*!
* jquery.fixedHeaderTable. The jQuery fixedHeaderTable plugin
*
* Copyright (c) 2011 Mark Malek
* http://fixedheadertable.com
*
* Licensed under MIT
* http://www.opensource.org/licenses/mit-license.php
*
* http://docs.jquery.com/Plugins/Authoring
* jQuery authoring guidelines
*
* Launch  : October 2009
* Version : 1.3
* Released: May 9th, 2011
*
*
* all CSS sizing (width,height) is done in pixels (px)
*/

(function($) {

    $.fn.fixedHeaderTable = function( method ) {

        // plugin's default options
        var defaults = {

            width: '100%',
            height: '100%',
            themeClass: 'fht-default',

            borderCollapse: true,
            fixedColumn: false, // fixed first column
            sortable: false,
            autoShow: true, // hide table after its created
            footer: false, // show footer
            cloneHeadToFoot: false, // clone head and use as footer
            autoResize: false, // resize table if its parent wrapper changes size

            create: null // callback after plugin completes

        };

        var settings = {};

        // public methods
        var methods = {

            init : function(options) {

                settings = $.extend({}, defaults, options);

                // iterate through all the DOM elements we are attaching the plugin to
                return this.each(function() {

                    var $self = $(this), // reference the jQuery version of the current DOM element
                    self = this; // reference to the actual DOM element

                    if ( helpers._isTable($self) ) {
                        methods.setup.apply(this, Array.prototype.slice.call(arguments, 1));

                        $.isFunction(settings.create) && settings.create.call(this);
                    } else {
                        $.error('Invalid table mark-up');
                    }

                });

            },

            /*
			 * Setup table structure for fixed headers and optional footer
			 */
            setup: function( options ) {
                var $self  = $(this),
                self   = this,
                $thead = $self.find('thead'),
                $tfoot = $self.find('tfoot'),
                $tbody = $self.find('tbody'),
                $wrapper,
                $divHead,
                $divFoot,
                $divBody,
                $fixedHeadRow,
                $temp,
                tfootHeight = 0;

                settings.includePadding = helpers._isPaddingIncludedWithWidth();
                settings.scrollbarOffset = helpers._getScrollbarWidth();
                settings.themeClassName = settings.themeClass;

                if ( settings.width.search('%') > -1 ) {
                    var widthMinusScrollbar = $self.parent().width() - settings.scrollbarOffset;
                } else {
                    var widthMinusScrollbar = settings.width - settings.scrollbarOffset;
                }

                $self.css({
                    width: widthMinusScrollbar
                });


                if ( !$self.closest('.fht-table-wrapper').length ) {
                    $self.addClass('fht-table');
                    $self.wrap('<div class="fht-table-wrapper"></div>');
                }

                $wrapper = $self.closest('.fht-table-wrapper');

                if ( settings.fixedColumn == true && $wrapper.find('.fht-fixed-column').length == 0 ) {
                    $self.wrap('<div class="fht-fixed-body"></div>');

                    var $fixedColumn = $('<div class="fht-fixed-column"></div>').prependTo($wrapper),
                    $fixedBody	 = $wrapper.find('.fht-fixed-body');
                }

                $wrapper.css({
                    width: settings.width,
                    height: settings.height
                })
                .addClass(settings.themeClassName);

                if ( !$self.hasClass('fht-table-init') ) {

                    $self.wrap('<div class="fht-tbody"></div>');

                }
                $divBody = $self.closest('.fht-tbody');

                var tableProps = helpers._getTableProps($self);

                helpers._setupClone( $divBody, tableProps.tbody );

                if ( !$self.hasClass('fht-table-init') ) {
                    if ( settings.fixedColumn == true ) {
                        $divHead = $('<div class="fht-thead"><table class="fht-table"></table></div>').prependTo($fixedBody);
                    } else {
                        $divHead = $('<div class="fht-thead"><table class="fht-table"></table></div>').prependTo($wrapper);
                    }

                    $thead.clone().appendTo($divHead.find('table'));
                } else {
                    $divHead = $wrapper.find('div.fht-thead');
                }

                helpers._setupClone( $divHead, tableProps.thead );

                $self.css({
                    'margin-top': -$divHead.outerHeight(true)
                });

                /*
                 * Check for footer
                 * Setup footer if present
                 */
                if ( settings.footer == true ) {

                    helpers._setupTableFooter( $self, self, tableProps );

                    if ( !$tfoot.length ) {
                        $tfoot = $wrapper.find('div.fht-tfoot table');
                    }

                    tfootHeight = $tfoot.outerHeight(true);
                }

                var tbodyHeight = $wrapper.height() - $thead.outerHeight(true) - tfootHeight - tableProps.border;

                $divBody.css({
                    'height': tbodyHeight
                });

                $self.addClass('fht-table-init');

                if ( typeof(settings.altClass) !== 'undefined' ) {
                    methods.altRows.apply( self );
                }

                if ( settings.fixedColumn == true ) {
                    helpers._setupFixedColumn( $self, self, tableProps );
                }

                if ( !settings.autoShow ) {
                    $wrapper.hide();
                }

                helpers._bindScroll( $divBody, tableProps );

                return self;
            },

            /*
             * Resize the table
             * Incomplete - not implemented yet
             */
            resize: function( options ) {
                var $self = $(this),
                self  = this;

                return self;
            },

            /*
             * Add CSS class to alternating rows
             */
            altRows: function( arg1 ) {
                var $self		= $(this),
                self		= this,
                altClass	= ( typeof(arg1) !== 'undefined' ) ? arg1 : settings.altClass;

                $self.closest('.fht-table-wrapper')
                .find('tbody tr:odd:not(:hidden)')
                .addClass(altClass);
            },

            /*
             * Show a hidden fixedHeaderTable table
             */
            show: function( arg1, arg2, arg3 ) {
                var $self		= $(this),
                self  		= this,
                $wrapper 	= $self.closest('.fht-table-wrapper');

                // User provided show duration without a specific effect
                if ( typeof(arg1) !== 'undefined' && typeof(arg1) === 'number' ) {

                    $wrapper.show(arg1, function() {
                        $.isFunction(arg2) && arg2.call(this);
                    });

                    return self;

                } else if ( typeof(arg1) !== 'undefined' && typeof(arg1) === 'string'
                    && typeof(arg2) !== 'undefined' && typeof(arg2) === 'number' ) {
                    // User provided show duration with an effect

                    $wrapper.show(arg1, arg2, function() {
                        $.isFunction(arg3) && arg3.call(this);
                    });

                    return self;

                }

                $self.closest('.fht-table-wrapper')
                .show();
                $.isFunction(arg1) && arg1.call(this);

                return self;
            },

            /*
             * Hide a fixedHeaderTable table
             */
            hide: function( arg1, arg2, arg3 ) {
                var $self 		= $(this),
                self		= this,
                $wrapper 	= $self.closest('.fht-table-wrapper');

                // User provided show duration without a specific effect
                if ( typeof(arg1) !== 'undefined' && typeof(arg1) === 'number' ) {
                    $wrapper.hide(arg1, function() {
                        $.isFunction(arg3) && arg3.call(this);
                    });

                    return self;
                } else if ( typeof(arg1) !== 'undefined' && typeof(arg1) === 'string'
                    && typeof(arg2) !== 'undefined' && typeof(arg2) === 'number' ) {

                    $wrapper.hide(arg1, arg2, function() {
                        $.isFunction(arg3) && arg3.call(this);
                    });

                    return self;
                }

                $self.closest('.fht-table-wrapper')
                .hide();

                $.isFunction(arg3) && arg3.call(this);



                return self;
            },

            /*
             * Destory fixedHeaderTable and return table to original state
             */
            destroy: function() {
                var $self    = $(this),
                self     = this,
                $wrapper = $self.closest('.fht-table-wrapper');

                $self.insertBefore($wrapper)
                .removeAttr('style')
                .append($wrapper.find('tfoot'))
                .removeClass('fht-table fht-table-init')
                .find('.fht-cell')
                .remove();

                $wrapper.remove();

                return self;
            }

        };

        // private methods
        var helpers = {

            /*
			 * return boolean
			 * True if a thead and tbody exist.
			 */
            _isTable: function( $obj ) {
                var $self = $obj,
                hasTable = $self.is('table'),
                hasThead = $self.find('thead').length > 0,
                hasTbody = $self.find('tbody').length > 0;

                if ( hasTable && hasThead && hasTbody ) {
                    return true;
                }

                return false;

            },

            /*
             * return void
             * bind scroll event
             */
            _bindScroll: function( $obj, tableProps ) {
                var $self = $obj,
                $wrapper = $self.closest('.fht-table-wrapper'),
                $thead = $self.siblings('.fht-thead'),
                $tfoot = $self.siblings('.fht-tfoot');

                $self.bind('scroll', function() {
                    if ( settings.fixedColumn == true ) {
                        var $fixedColumn = $wrapper.find('.fht-fixed-column');

                        $fixedColumn.find('.fht-tbody table')
                        .css({
                            'margin-top': -$self.scrollTop()
                        });
                    }

                    $thead.find('table')
                    .css({
                        'margin-left': -this.scrollLeft
                    });

                    if ( settings.cloneHeadToFoot ) {
                        $tfoot.find('table')
                        .css({
                            'margin-left': -this.scrollLeft
                        });
                    }
                });
            },

            /*
             * return void
             */
            _fixHeightWithCss: function ( $obj, tableProps ) {
                if ( settings.includePadding ) {
                    $obj.css({
                        'height': $obj.height() + tableProps.border
                    });
                } else {
                    $obj.css({
                        'height': $obj.parent().height() + tableProps.border
                    });
                }
            },

            /*
             * return void
             */
            _fixWidthWithCss: function( $obj, tableProps ) {
                if ( settings.includePadding ) {
                    $obj.css({
                        'width': $obj.width() + tableProps.border
                    });
                } else {
                    $obj.css({
                        'width': $obj.parent().width() + tableProps.border
                    });
                }
            },

            /*
             * return void
             */
            _setupFixedColumn: function ( $obj, obj, tableProps ) {
                var $self			= $obj,
                self			= obj,
                $wrapper		= $self.closest('.fht-table-wrapper'),
                $fixedBody		= $wrapper.find('.fht-fixed-body'),
                $fixedColumn	= $wrapper.find('.fht-fixed-column'),
                $thead			= $('<div class="fht-thead"><table class="fht-table"><thead><tr></tr></thead></table></div>'),
                $tbody			= $('<div class="fht-tbody"><table class="fht-table"><tbody></tbody></table></div>'),
                $tfoot			= $('<div class="fht-tfoot"><table class="fht-table"><thead><tr></tr></thead></table></div>'),
                $firstThChild   = $fixedBody.find('.fht-thead thead tr th:first-child'),
                $firstTdChildren,
                fixedColumnWidth = $firstThChild.outerWidth(true) + tableProps.border,
                fixedBodyWidth  = $wrapper.width(),
                fixedBodyHeight = $fixedBody.find('.fht-tbody').height() - settings.scrollbarOffset,
                $newRow;

                // Fix cell heights
                helpers._fixHeightWithCss( $firstThChild, tableProps );
                helpers._fixWidthWithCss( $firstThChild, tableProps );
                $firstTdChildren = $fixedBody.find('tbody tr td:first-child')
                .each( function(index) {
                    helpers._fixHeightWithCss( $(this), tableProps );
                    helpers._fixWidthWithCss( $(this), tableProps );
                });

                // clone header
                $thead.appendTo($fixedColumn)
                .find('tr')
                .append($firstThChild.clone());

                $tbody.appendTo($fixedColumn)
                .css({
                    'margin-top': -1,
                    'height': fixedBodyHeight + tableProps.border
                });
                $firstTdChildren.each(function(index) {
                    $newRow = $('<tr></tr>').appendTo($tbody.find('tbody'));

                    if ( settings.altClass && $(this).parent().hasClass(settings.altClass) ) {
                        $newRow.addClass(settings.altClass);
                    }

                    $(this).clone()
                    .appendTo($newRow);
                });

                // set width of fixed column wrapper
                $fixedColumn.css({
                    'width': fixedColumnWidth
                });

                // set width of body table wrapper
                $fixedBody.css({
                    'width': fixedBodyWidth
                });

                // setup clone footer with fixed column
                if ( settings.footer == true || settings.cloneHeadToFoot == true ) {
                    var $firstTdFootChild = $fixedBody.find('.fht-tfoot thead tr th:first-child');

                    helpers._fixHeightWithCss( $firstTdFootChild, tableProps );
                    $tfoot.appendTo($fixedColumn)
                    .find('tr')
                    .append($firstTdFootChild.clone());
                    $tfoot.css({
                        'top': settings.scrollbarOffset
                    });
                }
            },

            /*
             * return void
             */
            _setupTableFooter: function ( $obj, obj, tableProps ) {

                var $self 		= $obj,
                self  		= obj,
                $wrapper 	= $self.closest('.fht-table-wrapper'),
                $tfoot		= $self.find('tfoot'),
                $divFoot	= $wrapper.find('div.fht-tfoot');

                if ( !$divFoot.length ) {
                    if ( settings.fixedColumn == true ) {
                        $divFoot = $('<div class="fht-tfoot"><table class="fht-table"></table></div>').appendTo($wrapper.find('.fht-fixed-body'));
                    } else {
                        $divFoot = $('<div class="fht-tfoot"><table class="fht-table"></table></div>').appendTo($wrapper);
                    }
                }

                switch (true) {
                    case !$tfoot.length && settings.cloneHeadToFoot == true && settings.footer == true:

                        var $divHead = $wrapper.find('div.fht-thead');

                        $divFoot.empty();
                        $divHead.find('table')
                        .clone()
                        .appendTo($divFoot);

                        break;
                    case $tfoot.length && settings.cloneHeadToFoot == false && settings.footer == true:

                        $divFoot.find('table')
                        .append($tfoot)
                        .css({
                            'margin-top': -tableProps.border
                        });

                        helpers._setupClone( $divFoot, tableProps.tfoot );

                        break;
                }

            },

            /*
             * return object
             * Widths of each thead cell and tbody cell for the first rows.
             * Used in fixing widths for the fixed header and optional footer.
             */
            _getTableProps: function( $obj ) {
                var tableProp = {
                    thead: {},
                    tbody: {},
                    tfoot: {},
                    border: 0
                },
                borderCollapse = 1;

                if ( settings.borderCollapse == true ) {
                    borderCollapse = 2;
                }

                tableProp.border = ( $obj.find('th:first-child').outerWidth() - $obj.find('th:first-child').innerWidth() ) / borderCollapse;

                $obj.find('thead tr:first-child th').each(function(index) {
                    tableProp.thead[index] = $(this).width() + tableProp.border;
                });

                $obj.find('tfoot tr:first-child td').each(function(index) {
                    tableProp.tfoot[index] = $(this).width() + tableProp.border;
                });

                $obj.find('tbody tr:first-child td').each(function(index) {
                    tableProp.tbody[index] = $(this).width() + tableProp.border;
                });

                return tableProp;
            },

            /*
             * return void
             * Fix widths of each cell in the first row of obj.
             */
            _setupClone: function( $obj, cellArray ) {
                var $self    = $obj,
                selector = ( $self.find('thead').length ) ?
                'thead th' :
                ( $self.find('tfoot').length ) ?
                'tfoot td' :
                'tbody td',
                $cell;

                $self.find(selector).each(function(index) {
                    $cell = ( $(this).find('div.fht-cell').length ) ? $(this).find('div.fht-cell') : $('<div class="fht-cell"></div>').appendTo($(this));

                    $cell.css({
                        'width': parseInt(cellArray[index])
                    });

                    /*
                     * Fixed Header and Footer should extend the full width
                     * to align with the scrollbar of the body
                     */
                    if ( !$(this).closest('.fht-tbody').length && $(this).is(':last-child') && !$(this).closest('.fht-fixed-column').length ) {
                        var padding = ( ( $(this).innerWidth() - $(this).width() ) / 2 ) + settings.scrollbarOffset;
                        $(this).css({
                            'padding-right': padding + 'px'
                        });
                    }
                });
            },

            /*
             * return boolean
             * Determine how the browser calculates fixed widths with padding for tables
             * true if width = padding + width
             * false if width = width
             */
            _isPaddingIncludedWithWidth: function() {
                var $obj 			= $('<table class="fht-table"><tr><td style="padding: 10px; font-size: 10px;">test</td></tr></table>'),
                defaultHeight,
                newHeight;

                $obj.appendTo('body');

                defaultHeight = $obj.find('td').height();

                $obj.find('td')
                .css('height', $obj.find('tr').height());

                newHeight = $obj.find('td').height();
                $obj.remove();

                if ( defaultHeight != newHeight ) {
                    return true;
                } else {
                    return false;
                }

            },

            /*
             * return int
             * get the width of the browsers scroll bar
             */
            _getScrollbarWidth: function() {
                var scrollbarWidth = 0;

                if ( !scrollbarWidth ) {
                    if ( $.browser.msie ) {
                        var $textarea1 = $('<textarea cols="10" rows="2"></textarea>')
                        .css({
                            position: 'absolute',
                            top: -1000,
                            left: -1000
                        }).appendTo('body'),
                        $textarea2 = $('<textarea cols="10" rows="2" style="overflow: hidden;"></textarea>')
                        .css({
                            position: 'absolute',
                            top: -1000,
                            left: -1000
                        }).appendTo('body');
                        scrollbarWidth = $textarea1.width() - $textarea2.width() + 2; // + 2 for border offset
                        $textarea1.add($textarea2).remove();
                    } else {
                        var $div = $('<div />')
                        .css({
                            width: 100,
                            height: 100,
                            overflow: 'auto',
                            position: 'absolute',
                            top: -1000,
                            left: -1000
                        })
                        .prependTo('body').append('<div />').find('div')
                        .css({
                            width: '100%',
                            height: 200
                        });
                        scrollbarWidth = 100 - $div.width();
                        $div.parent().remove();
                    }
                }

                return scrollbarWidth;
            }

        };


        // if a method as the given argument exists
        if ( methods[method] ) {

            // call the respective method
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));

        // if an object is given as method OR nothing is given as argument
        } else if ( typeof method === 'object' || !method ) {

            // call the initialization method
            return methods.init.apply(this, arguments);

        // otherwise
        } else {

            // trigger an error
            $.error( 'Method "' +  method + '" does not exist in fixedHeaderTable plugin!');

        }

    }

})(jQuery);
/* ConfirmationOfOffer.js (522) */
/**
 *
 * @package private_output_careers_wales_professionals
 * @version $Id: ConfirmationOfOffer.js.522.allsites.js 36430 2010-11-08 16:01:59Z james $
 * @copyright Copyright (c) 2008 Box UK Ltd. All rights reserved.
 */

var confirmationOfOffer = function() {
     
     var self = this;
     
     /**
      * Listen to events on show/hide click and toggle
      * display of courses
      * 
      */
     function attachShowHideListener(block) {
         $('.expandView a', block).click(function(e) {
             
             var link      = $(this);
             var table     = link.parent().parent().parent();
             var dataRow   = link.parent().parent();
             var id        = dataRow.attr('id').split('-')[1];
             var courseRow = $('#courses-' + id + ' td', block);
             
             if(courseRow.css('display') == 'none') {
                 link.text(self.getTranslation('hideCourses'));
                 courseRow.fadeIn();
             }
             else {
                 link.text(self.getTranslation('viewCourses'));
                 courseRow.fadeOut();
             }
             e.preventDefault();
         });
     };
     
     /**
      * Confirm dialog
      */
     function getConfirmDeleteDialog() {
         return $('<div />').append(
            $('<div class="outter" />').append(
                $('<div class="inner" />').append(
                    $('<h2 />').text(self.getTranslation('headerDeleteConfirmation'))
                ).append(
                    $('<p />').text(self.getTranslation('labelDeleteConfirmation'))
                ).append(
                    $('<a />').addClass('confirm').text(self.getTranslation('labelYes'))
                ).append(
                    $('<a />').click(function(e) {
                        $.cwmodal.close();
                        e.preventDefault();
                    }).addClass('decline').attr('href', '#').text(self.getTranslation('labelDecline'))
                )
            )
        );
     };
     
     /**
      * Attach click handler to delete links in confirmation of offer
      */
     function attachDeleteHandler(block) {
         $('.delete a', block).click(function(e) {
            e.preventDefault();
            var overlay = getConfirmDeleteDialog();
            overlay.find('.confirm').attr('href', $(this).attr('href'));
            
            overlay.cwmodal({
                persist: false,
                containerId: 'confirmationOfOffer',
                autoPosition: {
                    horizontal:false,
                    vertical:false
                }
            });
         });
     };
    
     self.initialise = function(block) {
        attachShowHideListener(block);
        attachDeleteHandler(block);
     };
};
/* LearningPathwaysCourses.js (525) */
/**
 * @package CareersWales\Professionals
 */
var learningPathwaysCourses = function() {

    var self = this;
    
    /**
     *
     */
    self.addDynamicSearch = function(block) {
        var table = $('table tbody', block);

        $('.search input', block).keyup(function() {
            var searchPhrase = $(this).val().toLowerCase();
            var hasSearchPhrase = searchPhrase.length > 0;

            $('tr td:nth-child(2)', table).each(function(index) {
                var anchor = $(this);
                var tr = anchor.parent();
                
                !hasSearchPhrase || anchor.text().toLowerCase().indexOf(searchPhrase) >= 0
                    ? tr.show()
                    : tr.hide();
            });
        });
    };
    
    /**
     * Initialise the module
     */
    self.initialise = function( block ) {    
        self.addDynamicSearch(block);
        $( '.learningPathwaysCourses table', block).tablesorter({
            headers: {
                5: {sorter: false},
                6: {sorter: false}
            },
            cssAsc: 'sortableHeaderSortUp',
            cssDesc: 'sortableHeaderSortDown',
            cssHeader: 'sortableHeader'
        });
        Common_initTableZebraStripe(block);
    };
    
};
/* ProviderPartnershipCourses.js (469) */
// KS4
var providerPartnershipCourses = function(){
    var self = this;

    self.block = null;

    self.initialise = function(block){
        self.block = block;

        self.initHideShowCourses();
        self.hideAllCourses();
        
        self.initPost16();
    };

    self.initHideShowCourses = function(){
        $('td.courses a.showCourses').click(function(){                        
            if ($(this).parent().parent().attr('class') == 'coursesShown'){
                //hide the courses
                $(this).parent().parent().attr('class', 'coursesHidden');

                var trEl = $(this).parent().parent().next('tr');
                $(trEl).removeClass('rowOpen');
                $(trEl).addClass('rowClosed');
                $('.innerContent',trEl).slideUp(400, function(){
                    $('td', $(trEl)).css({padding:'0'});
                });

                $(this).html(oLocale.getTranslation('ProviderPartnershipCourses', 'viewCourses'));
            } else {
                //show the courses
                $(this).parent().parent().attr('class', 'coursesShown');
                
                var trEl = $(this).parent().parent().next('tr');
                $(trEl).addClass('rowOpen');
                $(trEl).removeClass('rowClosed');
                $('td', $(trEl)).css({padding:'5px'});
                $('.innerContent',trEl).slideDown();

                $(this).html(oLocale.getTranslation('ProviderPartnershipCourses', 'hideCourses'));
            }
            
            return false;
        });
    };

    self.hideAllCourses = function(){
        $('tr.open').each(function(){
            $(this).removeClass('open');
            $(this).addClass('rowClosed');
            $('td', $(this)).css({padding:'0'});
            $('div.innerContent', $(this)).hide();
            $('a.showCourses', this).html(oLocale.getTranslation('ProviderPartnershipCourses', 'viewCourses'));
        });
        $('tr.coursesShown').each(function(){
            $(this).attr('class', 'coursesHidden');
            $('a.showCourses', this).html(oLocale.getTranslation('ProviderPartnershipCourses', 'viewCourses'));
        });
    };
    
    /**
     * Add show/hide functionality to each parternship for Post 16
     */
    self.initPost16 = function(block) {
        $('.post16Courses .item').each(function() {
            var section = $('.section', $(this));
            $('<a />').text(oLocale.getTranslation('ProviderPartnershipCourses', 'viewCourses')).click(function() {
                
                if(section.is(':hidden')) {
                    section.slideDown();
                    $(this).text(oLocale.getTranslation('ProviderPartnershipCourses', 'hideCourses'));
                }
                else {
                    section.slideUp();
                    $(this).text(oLocale.getTranslation('ProviderPartnershipCourses', 'viewCourses'));
                }
                return false;
            }).attr('href', '#').addClass('actionView').insertBefore(section);
            section.slideUp(); 
        });
    };
};
/* MessagingAdmin.js (252) */
var messagingAdmin = function(){

	var self = this;
	
	self.initialise = function(block){
		self.initSelectAllOptions();
	};
	
	self.initSelectAllOptions = function(){
		
		$('#selectAllRead').click(function(){
			$("input[value='1']").attr("checked", "checked");
		});
		
		$('#selectAllreadWrite').click(function(){
			$("input[value='4']").attr("checked", "checked");
		});
		
		$('#selectAllHide').click(function(){
			$("input[value='0']").attr("checked", "checked");
		});
		
	};
	
};
/* OptionBlockFitzalan.js (175) */
function OptionBlockFitzalan_CourseRule( from, to, type ) {
    this.from = from;
    this.to = to;
    this.type = type;
}

function OptionBlockFitzalan_Block( id, numberOfChoices, hasDoubleAward ) {
    this.id = id;
    this.numberOfChoices = numberOfChoices;
    this.hasDoubleAward = ( hasDoubleAward == '1' ) ? true : false;
}

function OptionBlockFitzalan_Domain( id, name, numberOfOptions ) {
    this.id = id;
    this.name = name;
    this.numberOfOptions = numberOfOptions;
    this.cats = new Array();
}

function OptionBlockFitzalan_BlockCourse( id, name, weighting, blockId, courseId, isCompulsory ) {
    this.id = id;
    this.name = name;
    this.isDoubleAward = ( weighting == '2' ) ? true : false;
    this.blockId = blockId;
    this.courseId = courseId;
    this.isCompulsory = ( isCompulsory == '1' ) ? true : false;
    this.domains = new Array();
}

function OptionBlockFitzalan_Course( id, name, isCompulsory, isDoubleAward, blockCourseId ) {
    this.id = id;
    this.name = name;
    this.isCompulsory = isCompulsory;
    this.isDoubleAward = isDoubleAward;
    this.blockCourseId = blockCourseId;
}

function OptionBlockFitzalan_CourseInfo( id, text ) {
    this.id = id;
    this.text = text;
    this.cats = new Array();
}

var OptionBlockFitzalan = {

    // course rule types
    CANT_SELECT: '1',
    MUST_SELECT: '2',
    ONLY_SELECT_IF: '3',

    COURSE_SELECTION_COUNT: 4,

    // info stores
    rules: new Array(),
    blocks: new Array(),
    domains: new Array(),
    blockCourses: new Array(),
    courseInfo: new Array(),

    // properties
    locale: 'OptionBlockFitzalan',

    // elements
    tooltip: null,
    feedback: null,

    /**
     *  inits the form to be controlled for validation
     *
     */

    init: function() {

        var self = this;

        self.tooltip = $( '<div></div>' )
            .css({ position: 'absolute' })
            .addClass( 'optTooltip' )
            .prependTo( '#OBForm' )
            .hide();
        self.feedback = $( '<ul></ul>' )
            .addClass( 'feedbackInfo' )
            .appendTo( '#OBForm' );

        // add click handlers to the option checkboxes
        $( ".optinput[type='checkbox']" )
            .click( OptionBlockFitzalan.optionClicked );

        Common_replaceFormButtons( 'OptionBlockFitzalan', 'buttons', self.resetClicked, self.submitClicked );

        // add hover handlers to course labels for tooltip
        $( "td.oblabel" )
            .hover( OptionBlockFitzalan.courseHoverOver, OptionBlockFitzalan.courseHoverOut );

        this.applyRules();
        this.updateFeedback();

    },
    
    /**
     *  shows the course tooltip displaying the course description
     *
     */
    
    courseHoverOver: function( evt ) {

        var self = OptionBlockFitzalan;
        var info = $(this).attr( 'id' ).match( /^oblabel-(\d+)$/ );
        var blockCourseId = info[ 1 ];
        var blockCourse = self.getBlockCourse( blockCourseId );
        var courseInfo = self.getCourseInfo( blockCourse.courseId );

        // make sure popup doesn't go off the bottom of the screen
        var top = evt.pageY + 5;
        var popHeight = self.tooltip.height();
        var winHeight = $( window ).height();

        if ( top + popHeight + 20 > winHeight )
            top -= ((top + popHeight) - winHeight) + 30;

        //if the popup doesn't contain any text, don't show it
        if ( courseInfo.text != '' ) {
            self.tooltip
                .html( self.decodeXmlEntities(courseInfo.text) )
                .css({
                    top: top,
                    left: evt.pageX + 10,
                    zIndex: '100'
                })
                .fadeIn( 'fast' );
        }

    },

    /**
     *  decodes some xml entities and replaces with with their
     *  normal characters
     *
     *  @param str the string to do replacements in
     *  @return decoded string
     *
     */

    decodeXmlEntities: function( str ) {

        var entities = new Array(
            '&lt;', '<',
            '&gt;', '>',
            '&amp;', '&',
            '&quot;', '"'
        );

        for ( var i=0; i<entities.length; i+=2 )
            str = str.replace( new RegExp(entities[i],'g'), entities[i+1] );

        return str;

    },

    /**
     *  hides the course information tooltip
     *
     */
    
    courseHoverOut: function() {

        var self = OptionBlockFitzalan;

        self.tooltip.fadeOut( 'fast' );

    },

    /**
     *  returns the course info object for a course id
     *
     *  @param courseId {integer} i of course to fetch
     *  @return OptionBlockFitzalan_CourseInfo
     *
     */
    
    getCourseInfo: function( courseId ) {

        for ( var i=0; i<this.courseInfo.length; i++ )
            if ( this.courseInfo[i].id == courseId )
                return this.courseInfo[i];

        return null;

    },
    
    /**
     *  submit button has been clicked, need to hceck everything is
     *  ok before we actually submit the data
     *
     */

    submitClicked: function() {

        var isValid = OptionBlockFitzalan.validateOptions();

        // if all is ok and we're going to go ahead and submit the form then
        // we need to enable the selected options incase they're disabled
        // (if they're disabled then they won't be submitted in the request)
        if ( isValid )
            $( ".optinput[checked]" )
                .attr({ disabled: false });

        return isValid;

    },

    /**
     *  the reset button on the form has been pressed
     *
     */

    resetClicked: function() {

        var self = OptionBlockFitzalan;

        document.getElementById( 'OBForm' ).reset();

        self.applyRules();
        self.updateFeedback();

        // stop form resetting itself
        return false;

    },
    
    /**
     *  returns a block course for a specific ID
     *
     *  @param blockCourseId {integer} id of course to fetch
     *  @returns OptionBlockFitzalan_Course (null if not found)
     *
     */
    
    getBlockCourse: function( blockCourseId ) {

        for ( var i=0; i<this.blockCourses.length; i++ )
            if ( this.blockCourses[i].id == blockCourseId )
                return this.blockCourses[i];

        return null;

    },
    
    /**
     *  returns an array of unique courses that this set of options uses.  a
     *  course may be on two different blocks so we have the BlockCourse object
     *  which represents this.  this function extracts unique courses from these
     *
     *  @returns {Array} array of Course objects
     *
     */
    
    getCourses: function() {

        var courses = new Array();
        var added = new Array();

        $.each( this.blockCourses, function(i,blockCourse) {
            if ( !added[blockCourse.courseId] ) {
                courses.push( new OptionBlockFitzalan_Course(
                    blockCourse.courseId, blockCourse.name,
                    blockCourse.isCompulsory, blockCourse.isDoubleAward,
                    blockCourse.blockCourseId
                ));
                added[ blockCourse.courseId ] = true;
            }
        });

        return courses;

    },
    
    /**
     *  applies any rules we have about courses to the forms current selection
     *
     */
    
    applyRules: function() {

        var self = this;

        // enable everything first
        $( ".optinput[type='checkbox']" )
            .attr( 'disabled', '' );

        $.each( self.rules, function(i,rule) {

            var fromChoice = self.isChecked( rule.from );

            switch ( rule.type ) {

                case OptionBlockFitzalan.MUST_SELECT:
                    if ( fromChoice ) {

                        var fromBlockCourse = self.getBlockCourse( rule.from );
                        var toBlockCourse = self.getBlockCourse( rule.to );
                        var toChoice = fromChoice;
                        var toDisable = $( ".optinput[name^=ob-" +rule.to+ "-]" );

                        // if courses are in the same block, need to select a different choice
                        // to the current one (cause eg. you can't have 2 first choices)
                        if ( fromBlockCourse.blockId == toBlockCourse.blockId ) {
                            toChoice = toChoice < self.getBlock(toBlockCourse.blockId).numberOfChoices
                                ? toChoice + 1 : toChoice - 1;
                        }
                        // if rule is across blocks, constrain vertically aswell
                        else toDisable = toDisable.add( ".optinput[name$=-" +toChoice+ "-" +toBlockCourse.blockId+ "]" );

                        // disable restricted options
                        toDisable.attr({ disabled: true });

                        // need to look for associated double award courses
                        var blocks = self.getAssociatedBlocks( toBlockCourse.blockId );
                        $.each( blocks, function(i,block) {
                            $.each( self.blockCourses, function(j,blockCourse) {
                                if ( blockCourse.blockId == block.id && blockCourse.isDoubleAward )
                                    $( ".optinput[name^=ob-" +blockCourse.id+ "-" +toChoice+ "-]" )
                                        .attr({ disabled: true });
                            });
                        });

                        self.selectOption( toBlockCourse.id, toChoice, toBlockCourse.blockId, true, true );

                    }
                    break;

                case OptionBlockFitzalan.CANT_SELECT:
                    if ( fromChoice )
                        $( ".optinput[name^=ob-" +rule.to+ "-" +fromChoice+ "-]" )
                            .attr({ disabled: true })
                            .attr({ checked: false });
                    break;

                case OptionBlockFitzalan.ONLY_SELECT_IF:

                    var toChoice = self.isChecked( rule.to );
                    var fromBlockCourse = self.getBlockCourse( rule.from );
                    var toBlockCourse = self.getBlockCourse( rule.to );
                    var toSelect = ".optinput[name^=ob-" +rule.from+ "-" +toChoice+ "]";
                    var isFromChecked = $( toSelect ).attr( 'checked' );
                    var isToChecked = $( ".optinput[name^=ob-" +rule.to+ "-" +toChoice+ "]" ).attr( 'checked' );

                    $( ".optinput[name^=ob-" +rule.from+ "]" )
                        .attr({ disabled: true });

                    // behaviour depends on whether or not courses are in the same block.
                    if ( isToChecked && (fromBlockCourse.blockId == toBlockCourse.blockId) ) {
                        // *should* be able to do in 1 jquery this with a .not()...
                        $( ".optinput[name^=ob-" +rule.from+ "]" )
                            .attr({ disabled: false });
                        $( ".optinput[name^=ob-" +rule.from+ "-" +toChoice+ "-]" )
                            .attr({ disabled: true });
                    }
                    else $( toSelect )
                        .attr({ disabled: false })
                        .attr({ checked: isFromChecked });
                    break;

            }

        });

        // now the rules have been applied, if the user has reached their
        // maximum selection count, disable anything not selected
        if ( self.getSelectedCourseCount() == self.COURSE_SELECTION_COUNT )
            $( ".optinput[name^=ob-]" )
                .filter( function(){return !this.checked} )
                .attr({ disabled: true });

    },

    /**
     *  if a checkbox for a course is selected, returns the choice
     *  which is checked.  if none then returns false
     *
     *  @param blockCourseId {integer} course id to check
     *  @returns {mixed} integer of choice if selected, false otherwise
     *
     */

    isChecked: function( blockCourseId ) {

        var boxes = $( ".optinput[name^=ob-" + blockCourseId + "]" );

        for ( var i=0; i<boxes.length; i++ )
            if ( boxes[i].checked )
                return i + 1;

        return null;

    },

    /**
     *  this function finds out if a COURSE is checked.  remember a course is
     *  not the same as a "block course".
     *
     *  @param courseId {integer} course id to check
     *  @returns {boolean} true if it is, false otherwise
     *
     */

    isCourseChecked: function( courseId ) {

        var isChecked = false;
        var self = this;

        $.each( this.blockCourses, function(i,blockCourse) {
            if ( blockCourse.courseId == courseId && self.isChecked(blockCourse.id) )
                isChecked = true;
        });

        return isChecked;

    },

    /**
     *  returns any blocks that are associated with the specified block by
     *  double award courses.
     *
     *  @param blockId {integer} block id of current block
     *  @returns {array} associated blocks
     *
     */

    getAssociatedBlocks: function( blockId ) {

        var self = this;
        var associatedBlocks = new Array();

        // include this block
        $.each( self.blocks, function(i,block) {
            if ( block.id == blockId ) {
                associatedBlocks.push( block );
                //  if this block is double include next block
                if ( block.hasDoubleAward && i<self.blocks.length )
                    associatedBlocks.push( self.blocks[i+1] );
                // if prev block has double award include that
                if ( i>0 && self.blocks[i-1].hasDoubleAward )
                    associatedBlocks.push( self.blocks[i-1] );
            }
        });

        return associatedBlocks;

    },

    /**
     *  enforms radio group style functionality horizontally
     *
     *  @param blockCourseId {integer} course to constrain
     *  @param ignoreMustSelect (see selectOption)
     *
     */

    constrainHorizontally: function( blockCourseId, ignoreMustSelect ) {

        var self = OptionBlock;

        $( ".optinput[name^=ob-" +blockCourseId+ "]" ).each(function(i,checkbox) {
            self.selectCheckbox( checkbox, false, ignoreMustSelect );
        });

    },
    
    /**
     *  enforms radio group style functionality vertically
     *
     *  @param choice {integer} the column
     *  @param blockId {integer} the block id
     *  @param ignoreMustSelect (see selectOption)
     *
     */
    
    constrainVertically: function( choice, blockId, ignoreMustSelect ) {

        var self = OptionBlock;

        $( ".optinput[name$=-" +choice+ "-" +blockId+ "]" ).each(function(i,checkbox) {
            self.selectCheckbox( checkbox, false, ignoreMustSelect );
        });

    },

    /**
     *  this is a wrapper around selectOption(), so you can just pass it
     *  a checkbox and it'll extract the information from it's .name and
     *  then call selectOption().
     *
     *  @param checkbox option checkbox
     *  @param isChecked boolean indicating if you want the checkbox checked or not
     *  @param ignoreMustSelect (see selectOption)
     *
     */

    selectCheckbox: function( checkbox, isChecked, ignoreMustSelect ) {

        var self = OptionBlock;
        var info = checkbox.name.match( /^ob-(\d+)-(\d+)-(\d+)$/ );
        var blockCourseId = info[ 1 ];
        var choice = info[ 2 ];
        var blockId = info[ 3 ];

        self.selectOption( blockCourseId, choice, blockId, isChecked, ignoreMustSelect );

    },

    /**
     *  selects an option for a course, enforcing radio style functionality
     *  both horizontally (for the course) and possibly vertically.  also checks
     *  for dependent must have constraints (unless ignoreMustSelect is set to true)
     *  and takes into account double award courses in adjacent blocks that may
     *  be affected (phew!)
     *
     *  @param blockCourseId
     *  @param choice
     *  @param blockId
     *  @param isChecked
     *  @param ignoreMustSelect
     *
     */

    selectOption: function( blockCourseId, choice, blockId, isChecked, ignoreMustSelect ) {

        var self = OptionBlock;
        var course = self.getBlockCourse( blockCourseId );

        // we only need to wother about enforcing selection constraints
        // if this option is actually going to be checked.
        if ( isChecked ) {

            // find this block...
            $.each( self.blocks, function(blockIndex,block) {
                if ( block.id == blockId ) {

                    // check double award subjects from previous block
                    if ( blockIndex > 0 ) {
                        var prevBlock = self.blocks[ blockIndex - 1 ];
                        $.each( self.blockCourses, function(i,blockCourse) {
                            if ( blockCourse.blockId == prevBlock.id && blockCourse.isDoubleAward ) {
                                self.selectOption( blockCourse.id, choice, prevBlock.id, false, ignoreMustSelect );
                            }
                        });
                    }

                    // check this block
                    self.constrainHorizontally( blockCourseId, ignoreMustSelect );
                    self.constrainVertically( choice, blockId, ignoreMustSelect );

                    // if it's a double award then check the next block
                    if ( course.isDoubleAward ) {
                        var nextBlock = self.blocks[ blockIndex + 1 ];
                        $( ".optinput[name$=-" +choice+ "-" +nextBlock.id+ "]" ).each(function(i,checkbox){
                            self.selectCheckbox( checkbox, false, ignoreMustSelect );
                        });
                    }

               }
            });

        }

        else if ( !ignoreMustSelect ) self.checkDependentMustChooseRule( blockCourseId );

        $( ".optinput[name^=ob-" +blockCourseId+ "-" +choice+ "-]" )
            .attr({ checked: isChecked });

    },

    /**
     *  if there is a two-way "must-have" relation between two courses
     *  then if this course is part of the relation and unchecked we
     *  need to deselect the other part of the relation, otherwise
     *  there'll be a locked dependency betweent them
     *
     *  @param blockCourseId
     *
     */

    checkDependentMustChooseRule: function( blockCourseId ) {

        var self = OptionBlock;

        $.each( self.rules, function(i,rule) {
            if ( rule.from == blockCourseId && rule.type == OptionBlock.MUST_SELECT ) {
                $( ".optinput[name^=ob-" +rule.to+ "-]" )
                    .attr({ checked: false });
            }
        });

    },

    /**
     *  an option checkbox has been clicked
     *
     */

    optionClicked: function( evt ) {

        var self = OptionBlockFitzalan;
        var source = evt.target;
        var info = source.name.match( /^ob-(\d+)-(\d+)-(\d+)$/ );
        var isChecked = source.checked;
        var blockCourseId = info[ 1 ];
        var choice = info[ 2 ];
        var blockId = info[ 3 ];
        var blockCourse = self.getBlockCourse( blockCourseId );

        // if we're selecting a course, apply the restriction that
        // any other matching courses IN THE SAME OPTIONS COLUMN
        // can't be selected.
        if ( isChecked )
            $.each( self.blockCourses, function(i,otherBlockCourse) {
                 if ( blockCourse.courseId == otherBlockCourse.courseId ) {
                    $( "input[name^=ob-" +otherBlockCourse.id+ "-" +choice+ "-]" )
                        .attr({ checked: false });
                 }
            });

        self.selectOption( blockCourseId, choice, blockId, isChecked );
        self.applyRules();
        self.updateFeedback();

    },
    
    /**
     *  this function updates the "feedback" element below the option blocks
     *  to inform the user with text what their current option selections are
     *
     */
    
    updateFeedback: function() {

        var self = this;
        var checkedOptions = self.getCheckedOptions();

        // clear old text
        self.feedback.empty();

        $.each( checkedOptions, function(i,option) {

            var info = option.name.match( /ob-(\d+)-\d+-(\d+)/ );
            var blockCourseId = info[ 1 ];
            var blockId = info[ 2 ];
            var blockCourse = self.getBlockCourse( blockCourseId );

            // find the block this course is for (we need it's index in
            // the blocks array to say 'Option Block 1', etc...
            $.each( self.blocks, function(j,block) {
                if ( block.id == blockId )
                    $( '<li></li>' )
                        .html( self.getTranslation('youSelectedCourse',new Array(blockCourse.name,j+1)) )
                        .appendTo( self.feedback );
            });

        });

    },
    
    /**
     *  returns all the currently checked option checkbox elements
     *
     *  @return {array} selected checkboxes
     *
     */
    
    getCheckedOptions: function() {

        return $( ".optinput[name^=ob-]" )
            .filter(function(){ return this.checked; });

    },

    /**
     *  returns the number of courses that have been selected
     *
     *  @return int
     *
     */

    getSelectedCourseCount: function() {
        return $( ".optinput[name^=ob-]" )
                .filter( function(){return this.checked} )
                .length;
    },

    /**
     *  checks the selected options to make sure they conform to all the
     *  rules before submission.  if everything is ok then this will
     *  return true, otherwise error messages will be displayed and
     *  false is returned.
     *
     *  @return {boolean} true if all ok, false otherwise
     *  
     */
    
    validateOptions: function() {

        var errors = new Array();
        var self = this;

        // check selection count is ok
        var selectedCount = self.getSelectedCourseCount();
        if ( selectedCount != self.COURSE_SELECTION_COUNT )
            errors.push( 'You need to select 4 options'  );

        // check compulsory subjects
        $.each( self.getCourses(), function(i,course) {
            if ( course.isCompulsory && !self.isCourseChecked(course.id) )
                errors.push( self.getTranslation('errCompulsoryCourse',new Array(course.name)) );
        });

        // check domains are represented
        var checkedOptions = self.getCheckedOptions();
        $.each( self.domains, function(i,domain) {
            var counted = new Array();
            var optionCount = 0;
            // go through the checked options, and work out what domain it is
            // in, only count it if we haven't counted that COURSE before.
            $.each( checkedOptions, function(i,option) {
                var info = option.name.match( /ob-(\d+)-.*/ );
                var blockCourse = self.getBlockCourse( info[1] );
                var courseInfo = self.getCourseInfo( blockCourse.courseId );
                $.each( domain.cats, function(i,domainCat) {
                    $.each( courseInfo.cats, function(i,courseCat) {
                        if ( courseCat == domainCat && !counted[blockCourse.courseId] ) {
                            counted[ blockCourse.courseId ] = true;
                            optionCount++;
                        }
                    });
                });
            });
            if ( optionCount != domain.numberOfOptions )
                errors.push( self.getTranslation('errDomainChoices',new Array(domain.numberOfOptions,domain.name)) );
        });

        // display errors
        var errDiv = $( "#OBFormErrors" ).empty();
        for ( var i=0; i<errors.length; i++ )
            errDiv.append( '<li>' +errors[i]+ '</li>' );

        return ( errors.length == 0 );

    },
    
    /**
     *  a thin wrapper to the locale objects getTranslation method
     *
     *  @param message {string} the message to format
     *  @param options {array} array of replacements
     *  @returns {string} the formatted message
     *
     */

    getTranslation: function( message, options ) {

        var self = this;

        return oLocale.getTranslation( self.locale, message, options );

    },

    /**
     *  returns a block for specified id, if it's not found you'll get false
     *
     *  @param blockId block id to fetch
     *
     */

    getBlock: function( blockId ) {

        var self = this;

        for ( var i=0; i<self.blocks.length; i++ )
            if ( self.blocks[i].id == blockId )
                return self.blocks[i];

        return false;

    }

};
/* ProfLearningPathwayPlan.js (419) */
/**
 * @package private_output_careers_wales_learningpathways
 * @version $Id: AchievementsAndExperience.js 8432 2008-05-23 14:09:25Z jamesrc $
 * @copyright Copyright (c) 2008 Box UK Ltd. All rights reserved.
 *
 * Adds tool tips and lightbox functionality to block.
 *
 * @audit
 * - 2009-08-11  JRC  Created file.
 */
var profLearningPathwayPlan = function() {

    var self = this;
    

    self.initialise = function( block ) {
        self.initDeleteHandler(block);
        
        self.initLearningPathwaySectionHandler(block);
        self.hideLearningPathwaySections(block);
        
        self.initCommentHandler(block);
        self.hideComments(block);
    };
    
    self.initDeleteHandler = function(block){
        $('ul.action li.deleteComment a', $(block)).bind('click', function(){
            var deleteUrl = $(this).attr('href');
            var oLightbox = new profLearningPathwayPlan_deleteLightbox(block, deleteUrl);
            oLightbox.init();
            return false;
        });
    };
    
    self.initLearningPathwaySectionHandler = function(block){
        $('.lppSection h3', $(block)).bind('click', function(){
            var lppSectionContentContainer = $('.lppSectionContentContainer', $(this).parent());
            
            if ($(lppSectionContentContainer).attr('class')=='lppSectionContentContainer'){
                $(lppSectionContentContainer).attr('class', 'lppSectionContentContainer hidden');
                $(this).attr('class','arrowUp');
            } else {
                $(lppSectionContentContainer).attr('class', 'lppSectionContentContainer');
                $(this).attr('class', 'arrowDown');
            }
        });
    };
    
    self.hideLearningPathwaySections = function(block){
        var aLearningPathwaySection = $('.lppSection', $(block));
        
        if (aLearningPathwaySection.length > 1){
            //hidden sections
            var aHiddenSections = $('.lppSection .hidden', $(block));
            aHiddenSections.each(function(){
                $('h3', $(this).parent()).attr('class', 'arrowUp');
            });

            //open sections
            var aOpenSections = $('.lppSection .open', $(block));
            aOpenSections.each(function(){
                $('h3', $(this).parent()).attr('class', 'arrowDown');
                $(this).attr('class', 'lppSectionContentContainer')
            });
            
            //ensure that the make comment form is still shown
            var commentForm = $('.lppSection .comments .commentForm h3', $(block)).attr('class', '');
        } else {
            $('.lppSection h3', $(block)).attr('class', 'arrowDown');
            $('.lppSection .lppSectionContentContainer').attr('class', 'lppSectionContentContainer');
        }
        
        //If there is a comment that needs to be shown, ensure that the
        //lpp section is shown as well
        var commentShow = $('.lppSection .comments .commentsContainer .comment-show', $(block));
        
        if (commentShow.length == 1){
            commentShow.parent().parent().parent().parent().attr('class', 'lppSectionContentContainer');
        }
    };
    
    self.initCommentHandler = function(block){
        $('.lppSection .comments h4', $(block)).bind('click', function(){
            var commentsContainer = $('.commentsContainer', $(this).parent());
            
            if ($(commentsContainer).attr('class')=='commentsContainer'){
                $(commentsContainer).attr('class', 'commentsContainer hidden');
                $(this).attr('class', 'arrowUp');
            } else {
                $(commentsContainer).attr('class', 'commentsContainer');
                $(this).attr('class', 'arrowDown');
            }
        });
    };
    
    self.hideComments = function(block){
        $('.lppSection .comments h4', $(block)).attr('class', 'arrowUp');
        $('.lppSection .comments .commentsContainer', $(block)).attr('class', 'commentsContainer hidden');
        
        //If a comment is to be shown then we need to make sure we haven't hidden it
        var commentShow = $('.lppSection .comments .commentsContainer .comment-show', $(block));
        
        if (commentShow.length == 1) {
            $('h4', commentShow.parent().parent()).attr('class', 'arrowDown');
            commentShow.parent().attr('class', 'commentsContainer');
        }
    };
};



var profLearningPathwayPlan_deleteLightbox = function(block, deleteUrl){
    var self = this;
    self.deleteUrl = null;
    self.block = block;
    self.deleteUrl = deleteUrl;
    
    self.init = function(){
        var lightboxContainer = $('<div class=/>');
        var outerElement = $('<div />');
        var midElement = $('<div />').attr('class', 'mid');
        var innerElement = $('<div />').attr('class', 'inner');
        
        midElement.append(innerElement);
        outerElement.append(midElement);
        lightboxContainer.append(outerElement);
        
        innerElement.append('<h3>' + oLocale.getTranslation('ProfLearningPathwayPlan', 'confirm-title') + '</h3>');
        
        innerElement.append('<div class="message">' + oLocale.getTranslation('ProfLearningPathwayPlan', 'confirm-deleteMessage') + '</div>');
        
        var answerList = $('<ul />');
        answerList.append($('<li><div>' + oLocale.getTranslation('ProfLearningPathwayPlan', 'confirm-yes') + '</div></li>').bind('click', self.confirmDeleteNavigation));
        answerList.append($('<li><div>' + oLocale.getTranslation('ProfLearningPathwayPlan', 'confirm-no') + '</div></li>').bind('click', self.cancelDeleteNavigation));
        
        innerElement.append(answerList);
        
        innerElement.append($('<img class="close" alt="' + oLocale.getTranslation('ProfLearningPathwayPlan', 'confirm-cancel') + '" src="custom/careers_wales/img/buttons/button_cancel_' + oLocale.getFieldValue('id') + '.gif" />').bind('click', this.cancelDeleteNavigation));
        
        $.modal(lightboxContainer, {
            overlayId: 'qualificationOverlay',
            containerId: 'commentContainer',
            persist: true,
            onOpen: function (dialog) {
                dialog.overlay.fadeIn('fast', function () {
                    dialog.container.slideDown('normal', function () {
                            dialog.data.fadeIn('fast');
                    });
                });
            },
            onClose: function (dialog) {
                dialog.data.fadeOut('fast', function () {
                    dialog.container.slideUp('normal', function () {
                            dialog.overlay.fadeOut('fast', function () {
                                $('.modalClose').hide();
                            $.modal.close();
                        });
                    });
                });
            }
        });
    };
    
    self.confirmDeleteNavigation = function(){
        if (self.deleteUrl){
            document.location = self.deleteUrl;
        }
    };
    
    self.cancelDeleteNavigation = function(){
        $.modal.close();
        self.deleteUrl = null;
    };
};
/* jquery.associateCourses.js (347) */
/**
 * Associate Courses jQuery plugin - Luke Quinnell, Box UK 2009
 *
 */
(function($) {

    /**
     * Main method for plugin
     *
     * @param Object options
     */
    $.fn.associateCourses = function(settings) {
        settings = $.extend({}, $.fn.associateCourses.defaults, settings);
        
        return this.each(function() {
            //debug(this);
            $.fn.associateCourses.associateCourse( this, settings );
        });
    };

    /**
     * Debug output to console
     *
     * @param HTMLNode obj
     */
    function debug( obj ) {
        if (window.console && window.console.log) {
            window.console.log(obj.nodeName);
        }
    };

    /**
     * Public plugin function
     *
     * @return string
     */
    $.fn.associateCourses.associateCourse = function( element, settings ) {
        var form = $(element);
            
		_start();
        
        function _start() {
            //Set up lightbox effect
            form.modal( {
                overlayId: 'associateCoursesOverlay',
                containerId: 'associateCoursesContainer',
                persist: true,
                onOpen: function (dialog) {
                                dialog.overlay.fadeIn('fast', function () {
                                dialog.container.slideDown('normal', function () {
                                        dialog.data.fadeIn('fast');
                                        });
                                });
                        },
                        onClose: function (dialog) {
                                dialog.data.fadeOut('fast', function () {
                                dialog.container.slideUp('normal', function () {
                                        dialog.overlay.fadeOut('fast', function () {
                                                $('.modalClose').hide();
												$('.coursesWrapper').remove();
                                                $.modal.close();
                                        });
                                });
                        });
                }
            });
            _sendRequest( settings.instanceId );
        }
        
        /**
         *  Build the request for extracting all potential courses to associate,
         *
         *	@param HTMLDivElement block
         */
        function _getAssociateRequest( block ) {
            var prefix  = '&Module['+block+']';
            var request = '';
            var courseId = $('.associateCourseRow').attr('id');
            return request += prefix + '[action]=getPotentialCoursesToAssociate&courseId='+courseId+'&jsonOutput='+block;
        };
        
        function _sendRequest( block ) {
            // Set up feedback area
            var feedback = $('#courseFeedback');
            
            // send request for potential courses to associate
            var submitUrl = SITE_WEB_ROOT + 'server.php?change=ProviderCourseAdminDisplay' + _getAssociateRequest( block );
			var prefix = 'Module['+block+']';
            
            $.getJSON(submitUrl, function(json) {
                var module = json.Module;
                
                if( module.aoCourses ) {
                    // Check whether any courses were found
			    	if ( module.aoCourses.length > 0 ) {
						// Create a list to attach courses
                        var wrapper = $('<div />').addClass('coursesWrapper').appendTo( feedback );
                        var results = $('<table />')
                                   .append($('<tbody />'))
                                   .addClass('courses').appendTo(wrapper);
                        
			    		// Loop over courses
				    	for( var i = 0; i < module.aoCourses.length; i++ ) {
				    		var aCourse     = module.aoCourses[i];
				    		var contentId 	= aCourse.contentId;
							var courseName  = aCourse.title;
				    		var listClass	= i % 2 == 0 ? 'even' : 'odd' ;
                            var cellClass	= i % 2 == 0 ? 'even' : 'odd' ;
                            var item        = $('<tr></tr>').addClass(cellClass).appendTo($('tbody', results)).attr('name', contentId);
                            
				    		$('<span />').appendTo($('<td />').appendTo(item))
								.html(courseName);
								
							$('<input type="checkbox"></input>' ).appendTo($('<td />').appendTo(item))
								.attr('name', prefix+'[associateCourseId][]')
								.attr('value', contentId);
                        }
					}else{
						// There are no courses to associate, let them know
						Common_makeMessage( 'error', oLocale.getTranslation('ProviderCourseAdmin','msgNoCourses') )
							.appendTo( feedback );
					}
				}else{
					// There are no courses to associate, let them know
					Common_makeMessage( 'error', oLocale.getTranslation('ProviderCourseAdmin','msgNoCourses') )
						.appendTo( feedback );
				}
            });
		}
    };

    /**
     * Default settings
     */
    $.fn.associateCourses.defaults = {
        'overlayId' : 'associateCoursesOverlay',
        'containerId' : 'associateCoursesContainer'
    }
    
})(jQuery);
/* FaqAdmin.js (248) */
var faqAdmin = function() {

    var self = this;

    self.initialise = function( block ) {
    	Common_initTableZebraStripe(block);
        self.addConfirmDelete();
        self.addHover();
    };
    
    self.addConfirmDelete = function() {
    	$('.actionDelete').click(function() {
    		var answer = confirm(oLocale.getTranslation('FaqAdmin','msgDeleteConfirm'));
    		return answer;
    	});
    };
    
    self.addHover = function() {
		$('.sortableHeader').hover(
			function() {
				$(this).addClass('sortHover');
			},
			function() {
				$(this).removeClass('sortHover');
			}
		);
	};
};
/* RelatedMedia.js (219) */
/**
 * Default Javascript file for RelatedMedia.js
 *
 * @author James Cryer
 * 
 */
 var relatedMedia = function() {
	
	var self = this;
	
	self.initialise = function( block ) {
	
		self.locale = 'RelatedMedia';
		
	 	// loop over all Related Media Blocks that are displaying summary
		$("ul", block).each(function(i){
		    $numChildren = $(this).children().length-1;
		    $limit = ($(this).prev().text()-1) > 0? $(this).prev().text()-1 : null;
		
		    // Only edit list if more than specified related items are extracted
			if($numChildren > $limit && $limit !== null) {
		    	$(this).find("li:gt("+$limit+")").hide();
				$(this).parent().append('<a href=\"\" class="viewMore show">'+oLocale.getTranslation( self.locale, 'viewMore')+'</a>');
	
			   	$(this).parent().find(".viewMore").toggle(
				   	function() {
				   		//show more related content
				   		$limit = $(this).prev().prev().text()-1;
				   		$(this).addClass("hide")
				   			   .removeClass("show")
				   			   .text(oLocale.getTranslation( self.locale, 'hideMore'))
				   			   .prev()
				   			   .find("li:gt("+$limit+")")
				   			   .attr("style", "display:list-item")
				   			   .slideDown("slow");
				   	},
				   	function () {
				   		//hide more related content
				   		$limit = $(this).prev().prev().text()-1;
				   		$(this).addClass("show")
				   		       .removeClass("hide")
				   		       .text(oLocale.getTranslation( self.locale, 'viewMore'))
				   		       .prev()
				   		       .find("li:gt("+$limit+")")
				   		       .slideUp("slow");
				   	}
				);
			}
		});
 	};
 };
/* MyLearners.js (307) */

/* ProviderAdmin.js (143) */

/* CourseBrowser.js (145) */
/**
 * Handle changes to the number of learners field
 *
 */
var LearnerTakeUp = function(block, delegate) {

    var dialogOverlay   = 'qualificationLoader';
    var dialogContainer = 'qualificationLoaderContainer';

    /**
     * @var int
     */
    var pollIntervals   = 5000;

    var UI = {
        error : function() {
            $('<div />').append(
                $('<div />').addClass('outter').append(
                    $('<div />').addClass('inner').append(
                        $('<h2 />').text(delegate.getTranslation('headerLearnerData'))
                    ).append(
                        $('<p />').text(delegate.getTranslation('labelLearnerData'))
                    ).append(
                        $('<p />').css({'text-align': 'center', 'font-weight' : 'bold'}).append(
                            $('<a />').click(function(e) {
                                UI.close();
                                e.preventDefault();
                            }).text(delegate.getTranslation('labelClose'))
                        )
                    )
                )
            ).cwmodal({
                overlayId: dialogOverlay,
                containerId: dialogContainer,
                persist: false
            });
        },
        save : function() {
            $('<div />').append(
                $('<div />').addClass('outter').append(
                    $('<div />').addClass('inner').append(
                        $('<h2 />').text(delegate.getTranslation('headerLearnerDataSaving'))
                    ).append(
                        $('<p />').text(delegate.getTranslation('labelLearnerDataPleaseWait'))
                    )
                )
            ).cwmodal({
                overlayId: dialogOverlay,
                containerId: dialogContainer,
                persist: false
            });
        },
        close: function() {
            $.cwmodal.close();
        }
    };

    /**
     * Mark a input field as changed, if the saved option is not
     * available
     */
    function markChange(element) {
        element.addClass('changed');
        commitBtn.show();
    }

    /**
     * Return all changed coursess
     *
     * @return jQuery
     */
    function getChangedCourses() {
        return $('td input.changed', block);
    }

    /**
     * Return request to update pupil data
     *
     * @return string
     */
    function getUrl(courses) {
        return delegate.baseUrl + '&func=SavePupilChanges&'+courses;
    }

    /**
     * Sends ajax request
     *
     */
    function sendRequest(requestAsync) {
        var courses = getChangedCourses();
        $.ajax({
            url: getUrl(courses.serialize()),
            async: requestAsync,
            success: function(text) {
                courses.removeClass('changed');
                UI.close();
            }
        });
    }

    /**
     * Updates UI and sends request
     */
    function updateLearnerTakeUp() {
        UI.save();
        sendRequest(true);
    }


    /**
     * Determine whether we have changed form
     *
     * @return bool
     */
    function hasChangedElements() {
        return getChangedCourses().length > 0;
    }

    /**
     * Poll page for changes
     */
    function pollChanges() {
        setTimeout(function() {
           if(hasChangedElements()) {
               sendRequest(true);
           }
           pollChanges();
        }, pollIntervals);
    }

    (function() {

        $('td input.num-of-learners', block).change(function() {
            if($(this).val() == '') {
                $(this).attr('value', 0);
            }
            markChange($(this));
        });

        $(window).bind('unload', function() {
           if(hasChangedElements()) {
               sendRequest(false);
           }
           return true;
        });
        pollChanges();
    })();
};

/**
 * Loads qualification data for all courses on the screen
 * This reduces page load time and takes a fraction of the time because
 * we load all data at once.
 *
 * @TODO remove the need for this by refactoring CourseBrowser module
 */
var QualifcationLoader = function(block, settings, callback) {

    var self             = this;
    var archivedStatus   = 8;
    
    var vocationalLabel  = settings.getTranslation('labelVocational');
    var generalLabel     = settings.getTranslation('labelGeneral');
    var table            = $('table tbody', block);


    /**
     * Returns all course ids from course browser
     *
     * @return array
     */
    function getCourses() {
        var courses = [];
        $('table tr.course', block).each(function() {
            courses.push($(this).attr('id'));
        });
        return courses;
    }
    
    /**
     * Return request for the qualification for the information
     */
    function getRequest() {
        return settings.baseUrl + '&func=GetQualifications';
    }

    /**
     * Display qualification for the given courses
     *
     * @param courses array
     */
    function displayQualifications(courses) {
        if(courses.length === 0) {
            return;
        }        
        $.ajax({
            url: getRequest(),
            data: {"courses": courses.join(',')},
            type: 'POST',
            dataType: 'json',
            success: function(qualifications) {
                if($.browser.msie && $.browser.version < 9) { 
                    pollRefresh(qualifications);
                    return true;
                }
                refreshAll(qualifications);
                return true;
            }
        });
    }
    
    /**
     * Batch update courses
     * 
     * @param Array qualifications
     */ 
    function pollRefresh(qualifications) {
        setTimeout(function() {
            qualifications.length == 0 ? 
                onComplete() :
                updateCourse(qualifications);
        }, 1);        
    }
    
    /**
     * Update a qualification
     * 
     * @param Array qualifications
     */
    function updateCourse(qualifications) {
        refreshCourseContent(qualifications.pop(), table);
        pollRefresh(qualifications);
    }
         
    /**
     * Update all records
     * 
     * @param Array qualifications
     */
    function refreshAll(qualifications) {
        var originalTable      = $('table tbody', block);
        var table              = originalTable.clone();

        $(qualifications).each(function(i, qualification) {
            refreshCourseContent(qualification, table);
        });
        originalTable.remove();
        table.insertAfter($('table thead', block));
        onComplete();
    }
    
    /**
     * Finish processing
     */
    function onComplete() {
        callback(block);
    }
    
    /**
     * Returns locale string for table view
     * 
     * @param string vocational
     * @return string
     */
    function getVocationalLabel( vocational ) {
        if(vocational == 'V') {
            return vocationalLabel;
        }else if(vocational == 'G') {
            return generalLabel;
        }
        return '';
    }
    
    /**
     * Update an individual course within a given table
     * 
     * @param object
     * @param jQuery
     */
    function refreshCourseContent(qualification, table) {
        var course       = $('#'+ qualification.course, table);
        var cssClass     = qualification.status == archivedStatus ? 'archived-qualification' : '';
        
        $('td img', course).remove();
        $('.courseTitle', course).addClass(qualification.status == archivedStatus ? 'course-archived-qualification' : '');
        $('td:nth-child(4)', course).append(
            $('<div />').addClass(cssClass).text(qualification.qualType)
        ).removeClass('loading');
        $('td:nth-child(5)', course).append(
            $('<div />').addClass(cssClass).text(qualification.awardingBody)
        ).removeClass('loading');
        $('td:nth-child(6)', course).append(
            $('<div />').addClass(cssClass).text(getVocationalLabel( qualification.vocational ))
        ).removeClass('loading');
    }

    (function() {
        var courses = getCourses();
        displayQualifications(courses);
    })();
};

if ( !window.cw ) {
    cw = {};
}

cw.CopyToLppLightbox = function( options ) {

    $.extend( this, options );

};

cw.CopyToLppLightbox.prototype = {

    init: function() {

        this.container = $( '<div class="outter"></div>' );
        this.academicYears = $( '#course-browser-academic-years' );
        this.button
            .click( this.bind('onOpenClicked') );

    },

    /**
     * Bind a named handler to this object and return it
     *
     */
    bind: function( handler ) {

        var self = this;

        return function() {
            return self[ handler ]
                .apply( self, arguments );
        };

    },

    /**
     * Handler for when open button clicked
     *
     */
    onOpenClicked: function() {

        var courseIds = this.getCourseIds();

        if ( courseIds.length > 0 ) {
            this.initCopyControls();
            this.openLightbox();
        }

        else {
            alert( this.getText('lbNoCourses') );
        }

        return false;

    },

    /**
     * Returns locale value for specfied key
     *
     */
    getText: function( localeKey ) {

        return oLocale.getTranslation(
            'LearningPathwaysCourses',
            localeKey
        );

    },

    /**
     * Opens the ligtybox display
     *
     */
    openLightbox: function() {

        $.modal( this.container, {
            containerId: 'copyToLppContainer',
            autoPosition: {
                horizontal:true,
                vertical:true
            },
            containerCss: {
                width: '404px',
                height: '130px'
            }
        });

    },

    /**
     * Handler for when copy button clicked
     *
     */
    onCopyClicked: function() {

        var academicYear = this.academicYears.val();

        if ( academicYear ) {
            this.showCopying();
            $.ajax({
                url: SITE_WEB_ROOT + 'api.php',
                method: 'GET',
                data: {
                    'do': 'block.' +this.getBlockId(),
                    'func': 'CopyCourses',
                    'academicYear': academicYear,
                    'courses[]': this.getCourseIds()
                },
                success: this.bind( 'onCoursesCopied' ),
                failure: this.bind( 'onCopyFailed' )
            });
        }

    },

    /**
     * Handler for when courses have finished copying
     *
     */
    onCoursesCopied: function( responseText ) {

        if ( responseText == '1' ) {
            this.showSuccess( 'lbCoursesCopied' );
            setTimeout(function() {
                $.modal.close();
            }, 3000 );
        }

        else {
            this.showError();
        }

    },

    /**
     * Handler for when copying fails
     *
     */
    onCopyFailed: function() {

        this.showError();

    },

    /**
     * Shows a text message to the user
     *
     */
    showText: function( localeKey ) {

        var title = $( '<h3></h3>' )
            .html( this.getText('lbTitle') );

        var message = $( '<p></p>' )
            .html( this.getText(localeKey) );

        this.container
            .empty()
            .append(
                $('<div class="mid" />').append(
                    $('<div class="inner" />')
                        .append( title )
                        .append(message)
                )
        );
    },

    showSuccess: function(localeKey) {
        var title = $( '<h3></h3>' )
            .html( this.getText('lbTitle') );

        var message = Common_makeMessage('information', this.getText(localeKey));

        this.container
            .empty()
            .append(
                $('<div class="mid" />').append(
                    $('<div class="inner" />')
                        .append( title )
                        .append(message)
                )
        );
    },

    /**
     * Informs user copying is in progress
     *
     */
    showCopying: function() {

        this.showText( 'lbCopyingCourses' );

    },

    /**
     * Informs the user copying is complete
     *
     */
    showCopyComplete: function() {

        this.showText( 'lbCoursesCopied' );

    },

    /**
     * Indicates an error occurred
     *
     */
    showError: function() {

        this.showText( 'lbError' );

    },

    /**
     * Returns the lightbox container with all elements inside it
     *
     */
    initCopyControls: function() {

        var academicYears = this.academicYears.css({'display' : 'inline'});

        var title = $( '<h3></h3>' )
            .html( this.getText('lbTitle') );

        var label = $( '<label></label>' )
            .html( this.getText('lbAcademicYear') );

        var copyLink = $( '<a></a>' )
            .addClass( 'copy copy0' )
            .html( 'Copy' )
            .click( this.bind('onCopyClicked')) ;

        this.container
            .empty()
            .append(
                $('<div class="mid" />').append(
                    $('<div class="inner" />')
                        .append(title)
                        .append( label )
                        .append( academicYears )
                        .append( copyLink )
                )
            );
    },

    /**
     * Returns an array of the academic years to display
     *
     */
    getAcademicYears: function() {

        var years = [];
        var startYear = new Date().getFullYear() - 2;
        var endYear = startYear + 5;

        while ( startYear < endYear ) {
            years.push( startYear++ );
        }

        return years;

    },

    /**
     * Returns the block id of the LPP courses block
     *
     */
    getBlockId: function() {

        return this.button
                   .attr( 'data-blockid' );

    },

    /**
     * Returns the selected course ids
     *
     */
    getCourseIds: function() {

        var courseIds = [];

        $( 'input:checked[name*=courses]' ).each(function() {
            courseIds.push( $(this).val() );
        });

        return courseIds;

    }

};

/**
 * Handles saving of confirmations
 *
 */
var ConfirmationSaver = function(block, translator) {

    /**
     * UI Dialogs
     */
    var dialogs = {
        getConfirmation : function() {
            return $('<div />').append(
                $('<div class="outter" />').append(
                    $('<div class="inner" />').append(
                        $('<h2 />').text(translator.getTranslation('headerConfirmOffer'))
                    ).append(
                        $('<p />').text(
                            translator.getTranslation('labelConfirmationConfirm').replace('#confirmation-title#', $('#confirmation-title').text())
                        )
                    ).append(
                        $('<a />').addClass('confirm').text(translator.getTranslation('labelYes'))
                    ).append(
                        $('<a />').click(function(e) {
                            $.cwmodal.close();
                            e.preventDefault();
                        }).addClass('decline').attr('href', '#').text(translator.getTranslation('labelDecline'))
                    )
                )
            );
        },
        getFailed: function() {
            return $('<div />').append(
                $('<div class="outter" />').append(
                    $('<div class="inner" />').append(
                        $('<h2 />').text(translator.getTranslation('headerFailedConfirmation'))
                    ).append(
                        $('<p />').text(translator.getTranslation('labelPleaseSelectCourses'))
                    ).append(
                        $('<a />').click(function(e) {
                            $.cwmodal.close();
                            e.preventDefault();
                        }).addClass('decline').attr('href', '#').text(translator.getTranslation('labelClose'))
                    )

                )
            );
        }
    };

    /**
     * Remove all previous courses from form
     *
     * @param form jQuery
     */
    function removeAllCourses(form) {
        $('input[type=hidden][name*=courses]', form).remove();
    }
    /**
     * Returns selected courses
     *
     * @return array
     */
    function getSelectedCourses() {
        return $('table input[type=checkbox][name*=courses]:checked', block);
    }

    /**
     * Appends courses to form
     */
    function appendCourses(courses, form) {
        var lastElement = $('input:hidden:last', form);
        var name        = lastElement.attr('name').replace(']', '').split('[')[1];
        var inputName   = 'Module['+name+'][courses][]';

        $(courses).each(function(i, course) {
            $('<input />').attr({
                'type' : 'hidden',
                'name' : inputName,
                'value': $(course).val()
            }).insertAfter(lastElement);
        });
    }

    /**
     * Handle submission of confirmation for given courses
     *
     * @param form jQuery
     * @param courses array
     */
    function handleConfirmationSubmission(form, courses) {

        $('#confirmationOfOffer').animate({height: '70px'});
        var overlay = $('#confirmationOfOffer .inner');
        overlay.html('');
        overlay.append($('<h2 />').text(translator.getTranslation('headerSavingConfirm')))
            .append($('<p style="text-align: center" />').text(translator.getTranslation('labelSavingConfirm'))
        );
        form.unbind('submit').trigger('submit');
    }

    /**
     * Handles empty course selection
     *
     */
    function handleEmptyCourseSelection() {
        dialogs.getFailed().cwmodal({
            persist: false,
            containerId: 'confirmationOfOffer',
            autoPosition: {
                horizontal:false,
                vertical:false
            }
        });
    }

    /**
     * Handles showing confirmation when form is submitted
     */
    function showConfirmationDialog() {
        var form    = $(this);
        removeAllCourses(form);

        var courses = getSelectedCourses(block);

        if(courses.length == 0) {
            handleEmptyCourseSelection();
            return false;
        }
        appendCourses(courses, form);
        var overlay = dialogs.getConfirmation();
        overlay.find('.confirm').bind('click', function(e) {
            handleConfirmationSubmission(form, courses);
            e.preventDefault();
        });

        overlay.cwmodal({
            persist: false,
            containerId: 'confirmationOfOffer',
            autoPosition: {
                horizontal:false,
                vertical:false
            }
        });
        return false;
    }

    (function() {
        $('#confirmation-submit').bind('submit', showConfirmationDialog);
    })();
};

var courseBrowser = function() {

    var self = this;

    function afterQualificationLoad(block) {
        self.addEditConfirmationForPost16();
        self.addNetworkApprovalLightbox();
        self.addDynamicSearch(block);
        new LearnerTakeUp(block, {
            baseUrl: self.getApiUrl(),
            getTranslation: function(key) {
                return self.getTranslation(key);
            }
        });
    };
    self.initialise = function( block ) {
        if($('table', block).length == 0) {
            return;
        }
        new QualifcationLoader(block, {
           baseUrl: self.getApiUrl(),
           getTranslation: function(key) {
               return self.getTranslation(key);
           }
        }, afterQualificationLoad);
        Common_initTableZebraStripe(block);
        self.addConfirmDelete();
        self.addSelectAllLink();
        self.addHover();
        self.initCopyToLppButton();

        new ConfirmationSaver(block, {
            getTranslation : function(key) {
                return self.getTranslation(key);
            }
        });
    };



    self.initCopyToLppButton = function() {

        $( '#copyCourseToLearningPathways' ).each(function() {
            var copyToLpp = new cw.CopyToLppLightbox({
                button: $( this )
            });
            copyToLpp.init();
        });
    };



    self.addConfirmDelete = function() {
        $('.actionDelete').live('click', function() {

            var url     = $(this).attr('href');
            var confirm = $('<div />')
            .append($('<div />').addClass('outter')
                .append($('<div />').addClass('mid')
                    .append($('<div />').addClass('inner')
                        .append($('<h3 />').html(oLocale.getTranslation('CourseBrowser','msgDeleteCourse')))
                        .append($('<p />')
                            .append($('<h4 />').html(oLocale.getTranslation('CourseBrowser','msgDeleteConfirm')))
                            .append($('<a />')
                                .attr('href', url)
                                .html(oLocale.getTranslation('CourseBrowser','labelYes'))
                                )
                            .append($('<a href="#" />')
                                .html(oLocale.getTranslation('CourseBrowser','labelNo'))
                                .click(function() {
                                    $.modal.close();
                                    return false;
                                })
                                )
                            )
                        )
                    )
                );

            $(confirm).modal( {
                containerId: 'courseDeleteContainer',
                persist: true
            });
            return false;
        });
    };

    self.addSelectAllLink = function() {

        $( '.courseBrowser table thead th' ).attr({
            rowspan: 2
        }).attr('rowSpan', 2);
        $( '.courseBrowser table thead th[class=\'select\']' )
        .attr({
            rowspan: 1
        }).attr('rowSpan', 1)
        .prev().attr({
            rowspan:1
        }).attr('rowSpan', 1);

        var tr = $( '<tr></tr>' )
        .addClass( 'selectAll' )
        .append(
            $('<th></th>')
            .html( oLocale.getTranslation('CourseBrowser','tblSelectAll') )
            .addClass( 'label' )
            );
        $( 'th[class=\'select\']' ).each(function(i,column) {

            var td = $( '<th></th>' ).append(
                $( '<input type="checkbox"></input>' )
                .attr({
                    name: 'courseBrowserSelectAll'
                })
                .click(function(){
                    $( ":input[type='checkbox']" )
                    .attr({
                        checked: $(this).is(':checked')
                    });
                })
                ).addClass('select').appendTo( tr );
        });
        $( '.courseBrowser table thead' ).append( tr );
    };

    self.addHover = function() {
        $('.sortableHeader').live('mouseover', function() {
            $(this).addClass('sortHover');
        }).live('mouseout', function() {
            $(this).removeClass('sortHover');
        });
    };

    /**
     * Adding confirmation dialogs when the course browser is in "safe mode".
     * "Safe mode" is when a user can change the status of a course that
     * will affect their collaborative offer at post 16.  For example,
     * if they edit the course, then they will need to resubmit it for approval.
     *
     */
    self.addEditConfirmationForPost16 = function() {

        $('form.safeMode').each( function() {

            $(this).submit(function() {
                var answer = confirm(oLocale.getTranslation('CourseBrowser','msgConfirmEdit'));
                return answer;
            });

            $('a.actionEdit').click(function() {
                var answer = confirm(oLocale.getTranslation('CourseBrowser','msgConfirmEdit'));
                return answer;
            });
        });
    };

    self.addNetworkApprovalLightbox = function() {
        self.submitForm             = false;
        var providerListLoaded      = false;
        var providerLightboxTimeout = null;

        if( $('#submitforClusterApproval', $(this.block)).length == 0 ) {
            return;
        }
        var url = self.getBlockJsonUrl({
            action: 'getPartnershipJsonList'
        });

        $.post(url, function(json) {
            self.providerPartnershipSets = eval('(' + json + ')');

            try{
                if (self.providerPartnershipSets.length == 1) {
                    $('.courseBrowser form#coursebrowser-courses').append('<input type="hidden" name="Module[' + self.getInstanceId() + '][partnershipSetId]" value="' + self.providerPartnershipSets[0][0] + '" />');
                    self.submitForm = true;
                }
                providerListLoaded = true;
            } catch(e){}
        });

        $('#submitforClusterApproval', $(this.block)).bind('click', function(){
            if ($('.courseBrowser table input[type=checkbox]:checked').length == 0){
                $('.actionDispatcherMessages').replaceWith(Common_makeMessage( 'error', oLocale.getTranslation('CourseBrowser','msgNoCoursesSelected')));
                return false;
            } else {
                $('.actionDispatcherMessages').addClass('hidden');
            }

            if (self.submitForm === true){
                return true;
            }

            if (providerListLoaded === false) {
                if (providerLightboxTimeout !== null) {
                    window.clearTimeout(providerLightboxTimeout);
                }

                var thisLink = $(this);
                providerLightboxTimeout = window.setTimeout(function () {
                    thisLink.click();
                }, 100);

                return false;
            }

            self.originatingFormButton = this;

            var container = $('<div class="lightboxContainer providerSelectionLightbox" />');
            container.append('<h2>' + oLocale.getTranslation('CourseBrowser', 'sendForNetworkApproval') + '</h2>');

            var innerContainer = $('<div class="innerContainer" />');
            container.append(innerContainer);
            innerContainer.append('<p>' + oLocale.getTranslation('CourseBrowser', 'sendForNetworkApprovalDescription') + '</p>');
            innerContainer.append('<p>' + oLocale.getTranslation('CourseBrowser', 'sendForNetworkApprovalDesc2'), '</p>');

            var formContainer = $('<div class="form" />');

            $(self.providerPartnershipSets).each(function () {
                var partnershipSetId = null;
                var partnershipSetName = null;

                for (var currentPartnershipDetailsIndex in this) {
                    if (this.hasOwnProperty(currentPartnershipDetailsIndex)) {
                        partnershipSetId = currentPartnershipDetailsIndex;
                        partnershipSetName = this[currentPartnershipDetailsIndex];
                    }
                }

                formContainer.append(
                    $('<div class="formRow" />').append(
                        '<input type="checkbox" name="Module[' + self.getInstanceId() + '][partnershipSetIds][]" value="' + partnershipSetId + '" id="'+self.getInstanceId()+'_partnership_'+partnershipSetId+'" />'
                    ).append(
                        '<label for="'+self.getInstanceId()+'_partnership_'+partnershipSetId+'">'+ partnershipSetName +'</label>'
                    )
                );
            });

            var localeId = oLocale.getFieldValue( 'id' );

            var submitRow = $('<div class="submitRow" />');
            submitRow.css({'padding-bottom':'5px'});
            formContainer.append(submitRow);

            submitRow.append(
                $('<img class="button" src="custom/careers_wales/img/buttons/button_save_' + localeId + '.gif"/>').click(function () {
                    self.submitSendToNetworkForApproval();
                })
            );

            var closeLink = $('<div class="close" style="margin:0;">' + oLocale.getTranslation('CourseBrowser', 'or') + '</div>');
            var cancelTxt = $('<span class="cancel">' + oLocale.getTranslation('CourseBrowser', 'cancel') + '</span>');
            closeLink.append(cancelTxt);
            cancelTxt.bind('click', function(){
                $.modal.close();
            });


            submitRow.append(closeLink);
            innerContainer.append(formContainer);

            $.modal(container, {
                autoPosition: {
                    horizontal:true,
                    vertical:true
                },
                containerCss: {
                    width: '434px'
                }
            });

            $('#simplemodal-container').css({height:'auto'});
            return false;
        });
    };

    self.submitSendToNetworkForApproval = function() {
        $('.providerSelectionLightbox input[type=checkbox]:checked').each(function () {
            $(self.originatingFormButton).parent().append(
                $('<input type="hidden" />').attr('name', this.getAttribute('name')).attr('value', this.getAttribute('value'))
            );
        });

        self.submitForm = true;
        self.originatingFormButton.click();
    };

    self.addDynamicSearch = function(block) {
        var table = $('table tbody', block);

        $('.search input', block).keyup(function() {
            var searchPhrase = $(this).val().toLowerCase();
            var hasSearchPhrase = searchPhrase.length > 0;

            $('tr div:pos(2) a', table).each(function(index) {
                var anchor = $(this);
                var tr = anchor.parent().parent().parent();

                !hasSearchPhrase || anchor.text().toLowerCase().indexOf(searchPhrase) >= 0
                    ? tr.show()
                    : tr.hide();
            });
        });
    };
};
/* UserManager.js (151) */
var userManager = function() {

    var self = this;

    self.initialise = function( block ) {
        var blockId = $( block )
                            .attr( 'id' )
                            .match( /^block_(\d+)$/ )[ 1 ];

        self.initNewProviderForm( block, blockId );
        self.initDeleteProviderForm( block, blockId );
        self.initEditProviderForm( block, blockId );
		
    	Common_initTableZebraStripe(block);
        Common_initSortableTable( null, { 
        	2: { sorter: false },
            3: { sorter: false },
            4: { sorter: false },
            5: { sorter: false },
            6: { sorter: false },
            7: { sorter: false },
            8: { sorter: false },
            9: { sorter: false },
            10: {sorter:false }
        });
        self.addMessages();
        self.addHover();
    };

    self.initTableFilterer = function() {

        var div = $( '<div></div>' )
            .css({ 'margin-bottom': '8px' });
        var input = $( '<input type="text" />' )
            .attr({ id: 'TableFilterInput' })
            .keyup( self.doTableFilter )
            .prependTo( div );
        var label = $( '<label></label>' )
            .html( oLocale.getTranslation('UserManager','lblSearch') + ': &nbsp;' )
            .prependTo( div );

        div.prependTo( $('#preTableDiv') );

    };
    
    self.addMessages = function() {
    	
    	self.confirmAction('Delete');
    	self.confirmAction('ResetPassword');
	self.confirmAction('ResetAllPasswords');
    };
    
    self.confirmAction = function($action) {
    	$('.action'+$action).click(function() {
    		var answer = confirm(oLocale.getTranslation('UserManager','lblUser'+$action));
    		return answer;
    	});
    };
	
    self.addHover = function() {
            $('.sortableHeader').hover(
                    function() {
                            $(this).addClass('sortHover');
                    },
                    function() {
                            $(this).removeClass('sortHover');
                    }
            );
    };

    /**
     *  NB! @todo: this is half done
     *
     *  this function users a text input box that the user can type
     *  into and dynamically filter out table rows that don't match
     *
     *  it works a little bit, but wasn't playing nicely with the table
     *  sorting and stuff...  should finish sometime.
     *
     */

    self.doTableFilter = function() {

        var searchStr = document.getElementById( 'TableFilterInput' ).value.toLowerCase();

        $( '.sortableTable tbody tr' ).each(function(i,row){
            var html = $( row ).html();
            var text = html.replace( /(<.*?>)/g, '' ).toLowerCase();
            $( row ).css({
                visibility: (searchStr == '') || (text.indexOf(searchStr) > 0)
                    ? 'visible' : 'hidden'
            });
        });

    };
	
    /**
     *  add handles the editing of form groups
     *
     *  @param HTMLElement block
     *  @param int blockId
     *
     */
    self.initEditProviderForm = function( block, blockId ) {
		
        // When the user clicks the edit symbol in the table
        $( 'form.updateProviderForm' ).submit( function() {

            // Get the values of the form
            var formTitle     = $(this).parent().prev().text();
            var formId        = $('input[name*="formGroupId"]', $(this)).val();
            var formContainer = $('div.updateFormGroup');
            var form		  = $('#updateProviderForm');

            // Update form values to be the current form to be edited.
            $('input[name*="formGroupId"]', form).val(formId);
            $('input[name*="oldFormGroupName"]', form).val(formTitle);
            $('input[name*="formGroupName"]', form).val(formTitle);

            // If the user clicks cancel, hide the form and remove all errors
            $('a.cancel', formContainer).click(function(){
                formContainer.fadeOut();
                $('div.actionDispatcherMessages', formContainer).remove();
                return false;
            });

            // User is attempting to update the conFormGroup
            $(form).submit(function() {
                // Remove previous errors
                $('div.actionDispatcherMessages', formContainer).fadeOut().remove();

                var newFormName = $('input[name*="formGroupName"]', form);
                var oldFormName = $('input[name*="oldFormGroupName"]', form);

                // Do we have any value?
                if( newFormName.val() == '') {
                    Common_makeMessage( 'error', oLocale.getTranslation('ProviderAdmin','errNoProviderFormName') )
                       .hide()
                       .insertBefore( form )
                       .fadeIn();
                    return false;
                }

                // Has the title changed?
                if( newFormName.val() == oldFormName.val() ) {
                    Common_makeMessage( 'error', oLocale.getTranslation('ProviderAdmin','providerFormNoChange') )
                       .hide()
                       .insertBefore( form )
                       .fadeIn();
                    return false;
                }
                // Validate update, submit
                Common_makeMessage( 'information', oLocale.getTranslation('ProviderAdmin','saving') )
                       .hide()
                       .insertBefore( form )
                       .fadeIn();
            });
            // Show form and prevent default behaviour
            formContainer.slideDown();
            $('input[name*="formGroupName"]', form).focus();
            return false;
        });
    };
	
    /**
     *  adds handlers to provider form delete links to do ajax delete
     *
     *  @param HTMLElement block
     *  @param int blockId
     *
     */
    self.initDeleteProviderForm = function( block, blockId ) {

        $( 'form.deleteProviderForm' ).each(function() {

            var submitUrl = $( this ).attr( 'action' ) +'?jsonOutput=' +blockId;

            $( this ).submit(function() {
                    if( confirm(oLocale.getTranslation('ProviderAdmin','msgDelete')) ) {
                            var tBody = $( this ).parent().parent().parent();
                        $( this ).parent().parent().remove();

                        // Check whether there are any forms left
                        if ( tBody.children().length <= 1 ) {
                            tBody.parent().addClass('hidden');
                            Common_makeMessage( 'error', oLocale.getTranslation('ProviderAdmin','providerNoFormGroups') )
                                            .hide()
                                            .insertAfter( tBody.parent() )
                                            .fadeIn();

                        }
                        $( this ).ajaxSubmit({
                            url: submitUrl
                        });
                    }
                return false;
            });

        });

    };
	
    /**
     *  hijacks the new provider form to do it ajax styleee
     *
     *  @param HTMLElement block
     *  @param int blockId
     *
     */
    self.initNewProviderForm = function(block, blockId){

        $('form#newProviderForm').each(function(){

            var form = $(this);
            var submitUrl = form.attr('action') + '?jsonOutput=' + blockId;
            var error = Common_makeMessage('error', oLocale.getTranslation('ProviderAdmin', 'errNoProviderFormName')).hide().insertBefore(form);

            form.submit(function(){

                if ($('#formGroupName').val() == '') {
                        error.fadeIn();
                        return false;
                }
                error.slideUp();
                var feedback = Common_makeMessage('information', oLocale.getTranslation('ProviderAdmin', 'saving')).hide().insertBefore(form).fadeIn();

                $(this).ajaxSubmit({
                    url: submitUrl,
                    success: function(responseText){
                        eval('var json = ' + responseText);
                        var module = json.Module;

                        if (module.numErrors == 0) {

                                // Build form elements
                                var deleteForm = $('td.delete:first').show().clone(true);

                                var editForm = $('td.edit:first').show().clone(true);

                                // remove feedback
                                feedback.slideUp(function(){
                                        $(this).remove();
                                });

                                var formId = module.oConFormGroup[0].oContent.aField.contentId;
                                var formTitle = module.aRequestVariable.formGroupName;

                                // set form group id to delete and edit
                                $('input.formGroup', editForm).val(formId);
                                $('input.formGroup', deleteForm).val(formId);

                                // add item to list
                                var tr = $('<tr />').append($('<td />').html(formTitle).addClass('formTitle')).append(editForm).append(deleteForm);

                                // Remove any feedback and show the table if it was hidden
                                $('table', block).next('.actionDispatcherMessages').slideUp().remove();
                                $('table', block).removeClass('hidden').append(tr);

                                // Clear old value from form
                                $("input[type ='text']", form).val("");
                        }

                        else {
                                var errors = [];
                                for (var i = 0; i < module.aMessage.length; i++) {
                                        var message = module.aMessage[i];
                                        if (message.type == 3) {
                                                errors.push(' - ' + message.message);
                                        }
                                }
                                alert('Errors:\n' + errors.join('\n'));
                                
                                // remove feedback
                                feedback.slideUp(function(){
                                        $(this).remove();
                                });
                        }
                    }
                });
                return false; // cancel normal submit
            });

        });
    };

};
/* OptionBlockAdmin.js (124) */
var optionBlockAdmin = function() {

    var self = this;

    self.editBlocksReset = function() {
        document.getElementById( 'OptionBlockAdmin_editBlockCourses' ).reset();
        return false;
    };

    self.editBlocksSubmit = function() { return true; };

    self.initialise = function( block ) {
        Common_initTableZebraStripe( block );
        Common_replaceFormButtons( 'OptionBlockAdmin', 'replaceButtons', self.editBlocksReset, self.editBlocksSubmit );
        Common_addCalendarControls( 'dateControlField', 'OptionBlockAdmin_calenderDiv' );
        Common_addColorPicker( '#programmeColorField' );

        // add handlers for the block/course selection page
        self.addBlockSelectionCallback();

        self.updateDoubleAwardRestrictions();
        self.createAddCoursePicker();

        // add validation hooks
        $( 'form#OptionBlockAdmin_editProgramme' ).submit(function() {
            return self.validateEditProgramme();
        });
        $( 'form#OptionBlockAdmin_editBlockCourses' ).submit(function() {
            return self.validateEditBlockCourses();
        });

        Common_initSortableTable();

    };

    /**
     *  creates the 'add course' picker functionality
     *
     */

    self.createAddCoursePicker = function() {
		
        var self = this;
        $('#editBlocks').each( function() {
            var langId = oLocale.getFieldValue( 'id' );

            self.createCoursePicker();

            $( '<a/>' )
                .attr({ href: 'javascript:;' })
                .append(
                    $( '<img>' )
                        .attr({ src: SITE_WEB_ROOT+ 'custom/careers_wales/img/buttons/button_addCourses_' +langId+ '.gif' })
                )
                .click(function( evt ) {
                    $('#addCoursePopup')
                        .css({
                            left: (evt.pageX+4)+ 'px',
                            top: (evt.pageY+4)+ 'px'
                        })
                        .fadeIn('fast');
                })
            .insertBefore( $('form#addCourseToProgramme') );
        });
    };
    
    /**
     *	Add the popup to page before it is requested as IE doesn't load the input buttons
     *  If the popup is added to the page.  This also eliminates the problem with having
     *  multiple popups opened.  Also has the benefit of remember what the user selected
     *  if they were to close the dialog without clicking save.
     */
    self.createCoursePicker = function() {
    	
    	var langId = oLocale.getFieldValue( 'id' );
    	
    	// create popup element
        var popup = $( '<div>' )
                    	.addClass( 'addCoursePopup' )
                    	.attr('id', 'addCoursePopup' )
                    	.css({
                        	position: 'absolute'
                    	});

		// add courses to the popup
        $.each( providerCourses, function(i,course) {
        	var courseSelect = i % 2 == 0? 'even' : 'odd';
            var courseStatus = course.status == '4' ? 'liveCourse' : 'draftCourse';
                	
            $( '<div>' )
            	.addClass( 'course' )
                .addClass( courseSelect )
                .addClass( courseStatus )
                .append(
                	$( '<input type="checkbox">' )
                    	.attr({ value: course.id })
                        .attr({ id: course.id })
                        .click( function () {
                        	if ( $(this).is(':checked')) {
                            	$(this).parent().addClass('selected');
                            }else{
                            $(this).parent().removeClass('selected');
                            }
                        })
				)
                .append(
                	$( '<label/>' )
                    	.html( course.title )
                        .attr("for", course.id)
                )
                .mouseover( function() { $(this).addClass('over');})
            	.mouseout( function() { $(this).removeClass('over');})
        		.appendTo( popup );
		});

		// add buttons then whack on the page
        popup
        	.append(
            	$( '<div>' )
                	.addClass( 'buttons' )
                    .append(
                    	$( '<input type="image">' )
                        	.attr({ value: oLocale.getTranslation('OptionBlockAdmin','btnSave') })
                            .attr({ alt : oLocale.getTranslation('OptionBlockAdmin','btnSave') })
                            .attr({ src : SITE_WEB_ROOT+'/custom/careers_wales/img/buttons/button_save_'+langId+'.gif' })
                            .click(function() {
                            	var courseIds = '';
                                $( 'input:checked', popup )
                                	.each(function() {
                                    	courseIds += $(this).val() + ',';
                                });
                               	$( '#addCourseIdsToProgramme' )
                                	.val( courseIds )
                                    .parent()
                                    .submit();
                                    popup.hide();
                            	})
 						)
                       	.append(
                        	$( '<input type="image">' )
                            	.attr({ value: oLocale.getTranslation('OptionBlockAdmin','btnCancel') })
                            	.attr({ alt : oLocale.getTranslation('OptionBlockAdmin','btnCancel') })
                            	.attr({ src : SITE_WEB_ROOT+'/custom/careers_wales/img/buttons/button_cancel_'+langId+'.gif' })
                            	.click(function() { popup.hide(); })
            			)
			)
            .hide()
            .appendTo( $('body') 
    	);
    };

    /**
     *  adds the handler for when a block is selected
     *
     */

    self.addBlockSelectionCallback = function() {

        // double award subject selections
        $( "input[type=checkbox]" )
            .click( self.updateDoubleAwardRestrictions );

    };

    /**
     *  double award courses can't be selected in the last option block, so
     *  if any are selected disable the last option block for that course
     *
     */

    self.updateDoubleAwardRestrictions = function() {

        // enable all
        $( "input[name^=ob-]" )
            .attr({ disabled: false } );

        // then loop double award subjects, we need to disable the last option
        // block, and options one block AFTER selected blocks.
        $( "input[name^=doubleaward][checked]" ).each(function(){

            var id = $(this).attr('name')
                .match( /^doubleaward\[(\d+)\]$/ )[1];
            var options = $( "input[name^=ob-" +id+ "-]" );

            // disable those AFTER ones selected
            $.each( options, function(i,option) {
                if ( $(option).attr('checked') && (i+1<options.length) )
                    $(options[i+1]).attr({ disabled: true, checked: false });
            });

            // then disable last one
            $( options[options.length-1] )
                .attr({ disabled: true, checked: false });

        });

    };

    /**
     *  searches the array for the given element, if it's found then
     *  it returns the FIRST index it's at, otherwise returns -1
     *
     *  @param array the array to search
     *  @param element element to match
     *  @return integer index of element if found, false otherwise
     *
     */

    self.indexOf = function( array, element ) {
        for ( var i=0; i<array.length; i++ )
            if ( array[i] == element )
                return i;
        return -1;
    };

    /**
     *  validates that the option blocks form looks ok, checks things
     *  like each block having at least 1 course, etc...
     *
     *  @return boolean true if all ok, false otherwise
     *
     */

    self.validateEditBlockCourses = function() {

        // get unique block ids (we're assuming that they're gonna be in the
        // correct order from left to right)
        var blockIds = new Array();
        var blockCounts = new Array();
        $( "input[name^=ob-]" ).each(function() {
            var info = $(this).attr('name').match( /-(\d+)$/ );
            var blockId = info[ 1 ];
            if ( self.indexOf(blockIds,blockId) == -1 ) {
                blockIds.push( blockId );
                blockCounts[ blockId ] = 0;
            }
        });

        // add up selection counts for each block
        $.each( blockIds, function(i,blockId) {
            // loop through the options for this block, check if they're
            // selected, and if they're a double option they'll also
            // effect the next block.
            $( "input[name$=-"+blockId+"]" ).each(function() {
                if ( $(this).attr('checked') ) {
                    var info = $(this).attr('name').match( /-(\d+)-\d+$/ );
                    var courseId = info[ 1 ];
                    blockCounts[ blockId ]++;
                    if ( $(".doubleAward-"+courseId).attr('checked') )
                        blockCounts[ blockIds[i+1] ]++;
                }
            });
        });
		
		$('.optionBlockAdmin form .actionDispatcherMessages').remove();
		var errEmptyBlocks = Common_makeMessage( 'error', oLocale.getTranslation('OptionBlockAdmin','emptyOptionBlock') )
        						.hide()
        						.insertBefore($('.optionBlockAdmin table'));
                               
        for ( var id in blockCounts ) {
            if ( blockCounts[id] == 0 ) {
                errEmptyBlocks.fadeIn();
                return false;
            }
		}
		errEmptyBlocks.fadeOut();
        return true;

    };

    /**
     *  returns a date object for the value in the input field with the specified ID.
     *  if the input field doesn't contain a valid date then null is returned.
     *
     *  @param String inputId
     *
     *  @return Date
     *
     */

    self.getDate = function( inputId ) {

        var theDate = new Date();
        var dateStr = $( '#' +inputId ).val();
        var parts = dateStr.split( '/' );

        if ( parts.length != 3 ) return null;

        theDate.setDate( parts[0] );
        theDate.setMonth( parts[1] - 1 );
        theDate.setFullYear( parts[2] );

        return theDate;

    };

    /**
     *  performs validation checks for the main edit programme form (with the details
     *  like publish/deadline date, blocks, etc...)
     *
     *  @return boolean
     *
     */

    self.validateEditProgramme = function() {

        // check publish date is before deadline date
        var publishDate = self.getDate( 'publishDate' );
        var deadlineDate = self.getDate( 'deadlineDate' );

        if ( publishDate && deadlineDate && (deadlineDate.getTime() < publishDate.getTime()) ) {
            alert( oLocale.getTranslation('OptionBlockAdmin','deadlineBeforePublish') );
            return false;
        }

        return true;

    };

};
/* AssignProsToLearners.js (134) */
var assignProsToLearners = function() {

    var self = this;
	
    self.initialise = function( block ) {
        self.addSelectAllLinks(block);
        self.addFixedHeaders(block);
    };
    
    /**
     *  add "select all" links to column titles
     *
     */

    self.addSelectAllLinks = function() {

        $( 'th[id^=Pro]' ).each(function(i,column) {
            var id = column.id.match( /^Pro-(\d+)$/ )[ 1 ];
            $('<input type="checkbox"></input>')
                .attr({
                    'name' : 'assignProsToLearners',
                    'class': 'prof-' + id
                }).appendTo(this);
        });
    };
    
    /**
     * 
     */
    self.addFixedHeaders = function(block) {
        $('table', block).fixedHeaderTable({
            fixedColumn: true,
            width: '100%',
            height: '700px',
            themeClass: 'styled',
            altClass: 'odd',
            create : function() {
                $('.fht-fixed-body th input', block).click(function() {
                    var id = $(this).attr('class').match(/^prof-(\d+)$/)[1];
                    $(".fht-tbody input[id$=_" +id+ "]" ).attr({ checked: $(this).is(':checked') });
                });
                $(".fht-tbody tr", block)
                    .mouseover(function() {$(this).addClass("over");})
                    .mouseout(function() {$(this).removeClass("over");});
            }
        });
    };
};
/* AssignLearnersToProgs.js (137) */
var assignLearnersToProgs = function() {

    var self = this;

    self.initialise = function( block ) {
        self.addFixedHeaders(block);
    };

    /**
     *
     */
    self.addFixedHeaders = function(block) {
        $('table#allLearnersTable', block).fixedHeaderTable({
            fixedColumn: true,
            width: '100%',
            height: '700px',
            themeClass: 'styled',
            altClass: 'odd',
            create : function() {
                // Call as part of callback to avert IE issues
                self.addSelectAllLinks();

                // As we have just added a row and the fixed height was worked out without this row, we need to adjust
                $('.fht-table-wrapper').height($('.fht-table-wrapper').height() + 30);

                $('tr.selectAll th input', block).click(function() {
                    var id = $(this).attr('class').match(/^prog-(\d+)$/)[1];
                    $(".fht-tbody input[id$=_" +id+ "]" ).attr({ checked: $(this).is(':checked') });
                });
                $("#allLearnersTable tr", block)
                    .mouseover(function() {$(this).addClass("over");})
                    .mouseout(function() {$(this).removeClass("over");});
            }
        });
    };

    /**
     *  add "select all" links to column titles
     *
     */
    self.addSelectAllLinks = function() {

        var tr = $( '<tr />' )
            .addClass( 'selectAll' )
            .append(
                $('<th />')
                    .html( oLocale.getTranslation('AssignLearnersToProgs','tickAllLearners') )
                    .addClass( 'label' )
        );

        $( 'th[id^=ProgRow]' ).each(function(i,column) {
            var id = column.id.match( /^ProgRow-(\d+)$/ )[ 1 ];
            $( '<th />' ).append(
                $( '<input type="checkbox" />' )
                    .attr({
                        'name'  : 'assignLearnersToProgsSelectAll',
                        'class' : 'prog-' + id
                    })
            ).appendTo(tr);
        });
        $( '.fht-thead table.fht-table thead' ).append(tr);
    };

};
/* FreeChoicePollAdmin.js (82) */
var freeChoicePollAdmin = function() {

    var self = this;

    self.initialise = function( block ) {
		Common_initTableZebraStripe(block);
        Common_addCalendarControls( 'dateControlField', 'FreeChoicePollAdmin_calenderDiv' );
        Common_initSortableTable();
        self.addSelectAllLinks();

    };
	
	self.addSelectAllLinks = function() {

        var tr = $( '<tr />' ).addClass( 'selectAll' );

        $( 'th' ).each(function(i,column) {
			var td = $('<th />');
					
			if( $(this).attr('id') == 'remove' ) {
					
			    td.addClass('remove')
			    	.append(
			        	$( '<input type="checkbox"></input>' )
			            	.attr({ name: 'freeChoicePollAdmin' })
			                .click(function(){
			                	$( "table input[type$=checkbox]" )
			                    	.attr({ checked: $(this).is(':checked') });
			    	}));
			}
		    td.appendTo( tr );
        });
        $('.freeChoicePollAdmin table.styled thead' ).append( tr );
        $('table th input').parent().prev().html(oLocale.getTranslation('FreeChoicePollAdmin','tickAll')).css('text-align', 'right');
    };
};
/* OptionBlock.js (93) */
/**
 *  an option block rule
 *
 *  @param int from from block course id
 *  @param int to to course id
 *  @param String type rule type (as defined by option block object)
 *
 */

function OptionBlock_CourseRule( from, to, type ) {
    this.from = from;
    this.to = to;
    this.type = type;
}

/**
 *  a block in an options block
 *
 *  @param int id
 *  @param int numberOfChoices
 *  @param boolean hasDoubleAward
 *
 */

function OptionBlock_Block( id, numberOfChoices, hasDoubleAward ) {
    this.id = id;
    this.numberOfChoices = numberOfChoices;
    this.hasDoubleAward = ( hasDoubleAward == '1' ) ? true : false;
}

/**
 *  a domain of study
 *
 *  @param int id
 *  @param String name
 *  @param int numberOfOptions
 *
 */

function OptionBlock_Domain( id, name, numberOfOptions ) {
    this.id = id;
    this.name = name;
    this.numberOfOptions = numberOfOptions;
    this.cats = new Array();
}

/**
 *  a block course is a course assigned to a particular block
 *
 *  @param int id
 *  @param String name
 *  @param int weighting
 *  @param int blockId
 *  @param int courseId
 *  @param boolean isCompulsory
 *
 */

function OptionBlock_BlockCourse( id, name, weighting, blockId, courseId, isCompulsory ) {
    this.id = id;
    this.name = name;
    this.isDoubleAward = ( weighting == '2' ) ? true : false;
    this.blockId = blockId;
    this.courseId = courseId;
    this.isCompulsory = ( isCompulsory == '1' ) ? true : false;
    this.domains = new Array();
}

/**
 *  a course (not attached to any option block)
 *
 *  @param int id
 *  @param String name
 *  @param boolean isCompulsory
 *  @param boolean isDoubleAward
 *  @param int blockCourseId
 *
 */

function OptionBlock_Course( id, name, isCompulsory, isDoubleAward, blockCourseId ) {
    this.id = id;
    this.name = name;
    this.isCompulsory = isCompulsory;
    this.isDoubleAward = isDoubleAward;
    this.blockCourseId = blockCourseId;
}

/**
 *  information for a course
 *
 *  @param int id
 *  @param String text
 *
 */

function OptionBlock_CourseInfo( id, text ) {
    this.id = id;
    this.text = text;
    this.cats = new Array();
}

/**
 *  this represents an option block, which is a group of blocks with courses
 *  that the user can select from.
 *
 *  @param int id
 *
 */

function OptionBlock( id, name ) {

    this.id = id;
    this.name = name;

    // course rule types
    this.CANT_SELECT = '1';
    this.MUST_SELECT = '2';
    this.ONLY_SELECT_IF = '3';

    // info stores
    this.rules = new Array();
    this.blocks = new Array();
    this.domains = new Array();
    this.blockCourses = new Array();
    this.courseInfo = new Array();

    // properties
    this.locale = 'OptionBlock';

    // elements
    this.tooltip = null;
    this.feedback = null;

};

/**
 *  adds a rule to the options block
 *
 *  @param OptionBlock_Rule rule
 *
 */

OptionBlock.prototype.addRule = function( rule ) {
    this.rules.push( rule );
};

/**
 *  adds a block to the options block
 *
 *  @param OptionBlock_Block rule
 *
 */

OptionBlock.prototype.addBlock = function( block ) {
    this.blocks.push( block );
};

/**
 *  adds a domain to the options block
 *
 *  @param OptionBlock_Domain rule
 *
 */

OptionBlock.prototype.addDomain = function( domain ) {
    this.domains.push( domain );
};

/**
 *  adds a 'block course' to the options block
 *
 *  @param OptionBlock_BlockCourse rule
 *
 */

OptionBlock.prototype.addBlockCourse = function( blockCourse ) {
    this.blockCourses.push( blockCourse );
};

/**
 *  adds a course info object to the options block
 *
 *  @param OptionBlock_CourseInfo rule
 *
 */

OptionBlock.prototype.addCourseInfo = function( courseInfo ) {
    this.courseInfo.push( courseInfo );
};

OptionBlock.prototype.init = function() {

    var self = this;

    self.tooltip = $( '<div></div>' )
        .css({ position: 'absolute' })
        .addClass( 'optTooltip' )
        .prependTo( '#OptionBlock_' +this.id )
        .hide();
    self.feedback = $( '<ul></ul>' )
        .addClass( 'feedbackInfo' )
        .appendTo( '#OptionBlock_' +this.id );

    // add click handlers to the option checkboxes
    $( ".optinput[type='checkbox'][name^=ob-" +this.id+ "-]" )
        .click(function(evt){
            self.optionClicked( evt );
        });
        
    self.applyRules();
    self.updateFeedback();

};

/**
 *  decodes some xml entities and replaces with with their
 *  normal characters
 *
 *  @param str the string to do replacements in
 *  @return decoded string
 *
 */

OptionBlock.prototype.decodeXmlEntities = function( str ) {

    var entities = new Array(
        '&lt;', '<',
        '&gt;', '>',
        '&amp;', '&',
        '&quot;', '"'
    );

    for ( var i=0; i<entities.length; i+=2 ) {
        str = str.replace( new RegExp(entities[i],'g'), entities[i+1] );
    }
    return str;

};

/**
 *  hides the course information tooltip
 *
 */

OptionBlock.prototype.courseHoverOut = function() {

    var self = this;

    self.tooltip.fadeOut( 'fast' );

};

/**
 *  returns the course info object for a course id
 *
 *  @param courseId {integer} i of course to fetch
 *  @return OptionBlock_CourseInfo
 *
 */

OptionBlock.prototype.getCourseInfo = function( courseId ) {
    for ( var i=0; i<this.courseInfo.length; i++ )
        if ( this.courseInfo[i].id == courseId )
            return this.courseInfo[i];

    return null;

};

/**
 *  if all is ok and we're going to go ahead and submit the form then
 *  we need to enable the selected options incase they're disabled
 *  (if they're disabled then they won't be submitted in the request)
 *
 */

OptionBlock.prototype.enableCheckboxes = function() {

    $( "OptionBlock_" +this.id+ " .optinput[checked]" )
        .attr({ disabled: false });

};

/**
 *  the reset button on the form has been pressed
 *
 */
OptionBlock.prototype.resetClicked = function() {

    var self = this;
    document.getElementById( 'OBForm' ).reset();

    self.applyRules();
    self.updateFeedback();

    // stop form resetting itself
    return false;
};

/**
 *  returns a block course for a specific ID
 *
 *  @param blockCourseId {integer} id of course to fetch
 *  @returns OptionBlock_Course (null if not found)
 *
 */
OptionBlock.prototype.getBlockCourse = function( blockCourseId ) {

    for ( var i=0; i<this.blockCourses.length; i++ ) {
        if ( this.blockCourses[i].id == blockCourseId ) {
            return this.blockCourses[i];
        }
    }
    return null;
};

/**
 *  returns an array of unique courses that this set of options uses.  a
 *  course may be on two different blocks so we have the BlockCourse object
 *  which represents this.  this function extracts unique courses from these
 *
 *  @returns {Array} array of Course objects
 *
 */

OptionBlock.prototype.getCourses = function() {

    var courses = new Array();
    var added = new Array();

    $.each( this.blockCourses, function(i,blockCourse) {
        if ( !added[blockCourse.courseId] ) {
            courses.push( new OptionBlock_Course(
                blockCourse.courseId, blockCourse.name,
                blockCourse.isCompulsory, blockCourse.isDoubleAward,
                blockCourse.blockCourseId
            ));
            added[ blockCourse.courseId ] = true;
        }
    });

    return courses;
};

/**
 *  applies any rules we have about courses to the forms current selection
 *
 */

OptionBlock.prototype.applyRules = function(clickedOption, isChecked) {

    var self = this;

    if (typeof isChecked == "undefined"){
            isChecked = true;
    }

    if (typeof clickedOption == "undefined"){
            clickedOption = 0;
    }

    // enable everything first
    $( ".optinput[type='checkbox']" )
        .attr( 'disabled', '' );    
                
    var unCheckedCourses = new Array();   
    
    $.each( self.rules, function(i,rule) {
		
        var fromChoice = self.isChecked( rule.from );                
                        
        switch ( rule.type ) {

            case self.MUST_SELECT:
                if ( fromChoice ) {

                    var fromBlockCourse = self.getBlockCourse( rule.from );
                    var toBlockCourse = self.getBlockCourse( rule.to );
                    var toChoice = fromChoice;
                    var toDisable = $( ".optinput[name^=ob-" +self.id+ "-" +rule.to+ "-]" );                                            
					
					if (!isChecked && clickedOption == toBlockCourse.id) {
						//self.checkDependentMustChooseRule(toBlockCourse);
						//need to deselect the dependent course
						$(".optinput[name^=ob-" + self.id + "-" + fromBlockCourse.id + "-" + toChoice + "-]").attr('checked', false);                        
                        
                        // Keep a record of courses we have unchecked
                        unCheckedCourses.push(fromBlockCourse.id);
					} else {                        
					
						// if courses are in the same block, need to select a different choice
						// to the current one (cause eg. you can't have 2 first choices)
						if (fromBlockCourse.blockId == toBlockCourse.blockId) {
							toChoice = toChoice < self.getBlock(toBlockCourse.blockId).numberOfChoices ? toChoice + 1 : toChoice - 1;
						}
						// if rule is across blocks, constrain vertically aswell
						//else 
							toDisable = toDisable.add(".optinput[name$=-" + toChoice + "-" + toBlockCourse.blockId + "]");
						
						// disable restricted options
						toDisable.attr({
							disabled: true
						});
						
						// need to look for associated double award courses
						// @todo [AR] This is causing problems with double award subjects
						//				that are in the middle!!
						var blocks = self.getAssociatedBlocks(toBlockCourse.blockId);
						$.each(blocks, function(i, block){
							$.each(self.blockCourses, function(j, blockCourse){
								if (blockCourse.blockId == block.id && blockCourse.isDoubleAward) 
									$(".optinput[name^=ob-" + self.id + "-" + block.id + "-" + toChoice + "-]").attr({
										disabled: true
									});
							});
						});
						
						//we need to make sure that the current option choice is not disabled,
						//the user will have no way of deselecting it
						$(".optinput[name^=ob-" + self.id + "-" + fromBlockCourse.id + "-" + toChoice + "-]").attr({
							disabled: false
						});
						$(".optinput[name^=ob-" + self.id + "-" + toBlockCourse.id + "-" + toChoice + "-]").attr({
							disabled: false
						});
						
                        /**
                         * Need to check a course hasn't been unticked from within this
                         * loop.  Items were getting unticked, then the fromChoice 
                         * conditional above was then equating to false and hitting this.
                         */
                        var canAdd = true;
                        $.each(unCheckedCourses, function() {
                            if (this == toBlockCourse.id) {
                                canAdd = false;
                                return false;
                            }
                        });					
                        
                        if (canAdd) {
                            self.selectOption(toBlockCourse.id, toChoice, toBlockCourse.blockId, true, true);
                        }
					}
                    
                }
                break;

            case self.CANT_SELECT:
            	
                if ( fromChoice )
                    $( ".optinput[name^=ob-" +self.id+ "-" +rule.to+ "-" +fromChoice+ "-]" )
                        .attr({ disabled: true })
                        .attr({ checked: false });
                break;

            case self.ONLY_SELECT_IF:

                var toChoice = self.isChecked( rule.to );
                var fromBlockCourse = self.getBlockCourse( rule.from );
                var toBlockCourse = self.getBlockCourse( rule.to );
                var toSelect = ".optinput[name^=ob-" +self.id+ "-" +rule.from+ "-" +toChoice+ "]";
                var isFromChecked = $( toSelect ).attr( 'checked' );
                var isToChecked = $( ".optinput[name^=ob-" +self.id+ "-" +rule.to+ "-" +toChoice+ "]" ).attr( 'checked' );

                $( ".optinput[name^=ob-" +self.id+ "-" +rule.from+ "]" )
                    .attr({ disabled: true });

                // behaviour depends on whether or not courses are in the same block.
                if ( isToChecked && (fromBlockCourse.blockId == toBlockCourse.blockId) ) {
                    // *should* be able to do in 1 jquery this with a .not()...
                    $( ".optinput[name^=ob-" +self.id+ "-" +rule.from+ "]" )
                        .attr({ disabled: false });
                    $( ".optinput[name^=ob-" +self.id+ "-" +rule.from+ "-" +toChoice+ "-]" )
                        .attr({ disabled: true });
                }
                else $( toSelect )
                    .attr({ disabled: false })
                    .attr({ checked: isFromChecked });
                break;

        }
    });

};

/**
 *  if a checkbox for a course is selected, returns the choice
 *  which is checked.  if none then returns false
 *
 *  @param blockCourseId {integer} course id to check
 *  @returns {mixed} integer of choice if selected, false otherwise
 *
 */

OptionBlock.prototype.isChecked = function( blockCourseId ) {

    var boxes = $( ".optinput[name^=ob-" +this.id+ "-" +blockCourseId+ "]" );
    
    for ( var i=0; i<boxes.length; i++ ) {
        if ( boxes[i].checked ) {           
            return i + 1;
        }
    }

    return null;

};

/**
 *  this function finds out if a COURSE is checked.  remember a course is
 *  not the same as a "block course".
 *
 *  @param courseId {integer} course id to check
 *  @returns {boolean} true if it is, false otherwise
 *
 */

OptionBlock.prototype.isCourseChecked = function( courseId ) {

    var isChecked = false;
    var self = this;

    $.each( this.blockCourses, function(i,blockCourse) {
        if ( blockCourse.courseId == courseId && self.isChecked(blockCourse.id) )
            isChecked = true;
    });

    return isChecked;

};

/**
 *  returns any blocks that are associated with the specified block by
 *  double award courses.
 *
 *  @param blockId {integer} block id of current block
 *  @returns {array} associated blocks
 *
 */

OptionBlock.prototype.getAssociatedBlocks = function( blockId ) {

    var self = this;
    var associatedBlocks = new Array();

    // include this block
    $.each( self.blocks, function(i,block) {
        if ( block.id == blockId ) {
            associatedBlocks.push( block );
            //  if this block is double include next block
            if ( block.hasDoubleAward && i<self.blocks.length )
                associatedBlocks.push( self.blocks[i+1] );
            // if prev block has double award include that
            if ( i>0 && self.blocks[i-1].hasDoubleAward )
                associatedBlocks.push( self.blocks[i-1] );
        }
    });

    return associatedBlocks;

};

/**
 *  enforms radio group style functionality horizontally
 *
 *  @param blockCourseId {integer} course to constrain
 *  @param ignoreMustSelect (see selectOption)
 *
 */

OptionBlock.prototype.constrainHorizontally = function( blockCourseId, ignoreMustSelect ) {

    var self = this;

    $( ".optinput[name^=ob-" +this.id+ "-" +blockCourseId+ "]" ).each(function(i,checkbox) {
        self.selectCheckbox( checkbox, false, ignoreMustSelect );
    });

};

/**
 *  enforms radio group style functionality vertically
 *
 *  @param choice {integer} the column
 *  @param blockId {integer} the block id
 *  @param ignoreMustSelect (see selectOption)
 *
 */

OptionBlock.prototype.constrainVertically = function( choice, blockId, ignoreMustSelect ) {

    var self = this;

    $( ".optinput[name$=-" +choice+ "-" +blockId+ "]" ).each(function(i,checkbox) {
        self.selectCheckbox( checkbox, false, ignoreMustSelect );
    });

};

/**
 *  this is a wrapper around selectOption(), so you can just pass it
 *  a checkbox and it'll extract the information from it's .name and
 *  then call selectOption().
 *
 *  @param checkbox option checkbox
 *  @param isChecked boolean indicating if you want the checkbox checked or not
 *  @param ignoreMustSelect (see selectOption)
 *
 */

OptionBlock.prototype.selectCheckbox = function( checkbox, isChecked, ignoreMustSelect ) {

    var self = this;
    var info = checkbox.name.match( /^ob-\d+-(\d+)-(\d+)-(\d+)$/ );
    var blockCourseId = info[ 1 ];
    var choice = info[ 2 ];
    var blockId = info[ 3 ];

    self.selectOption( blockCourseId, choice, blockId, isChecked, ignoreMustSelect );

};

/**
 *  selects an option for a course, enforcing radio style functionality
 *  both horizontally (for the course) and possibly vertically.  also checks
 *  for dependent must have constraints (unless ignoreMustSelect is set to true)
 *  and takes into account double award courses in adjacent blocks that may
 *  be affected (phew!)
 *
 *  @param blockCourseId
 *  @param choice
 *  @param blockId
 *  @param isChecked
 *  @param ignoreMustSelect
 *
 */

OptionBlock.prototype.selectOption = function( blockCourseId, choice, blockId, isChecked, ignoreMustSelect ) {

    var self = this;
    var course = self.getBlockCourse( blockCourseId );

    // we only need to wother about enforcing selection constraints
    // if this option is actually going to be checked.
    if ( isChecked ) {

        // find this block...
        $.each( self.blocks, function(blockIndex,block) {
            if ( block.id == blockId ) {

                // check double award subjects from previous block
                if ( blockIndex > 0 ) {
                    var prevBlock = self.blocks[ blockIndex - 1 ];
                    $.each( self.blockCourses, function(i,blockCourse) {
                        if ( blockCourse.blockId == prevBlock.id && blockCourse.isDoubleAward ) {
                            self.selectOption( blockCourse.id, choice, prevBlock.id, false, ignoreMustSelect );
                        }
                    });
                }

                // check this block
                self.constrainHorizontally( blockCourseId, ignoreMustSelect );
                self.constrainVertically( choice, blockId, ignoreMustSelect );

                // if it's a double award then check the next block
                if ( course.isDoubleAward ) {
                    var nextBlock = self.blocks[ blockIndex + 1 ];
                    $( ".optinput[name$=-" +choice+ "-" +nextBlock.id+ "]" ).each(function(i,checkbox){
                        self.selectCheckbox( checkbox, false, ignoreMustSelect );
                    });
                }

           }
        });

    }

    else if ( !ignoreMustSelect ) self.checkDependentMustChooseRule( blockCourseId );

    $( ".optinput[name^=ob-" +this.id+ "-" +blockCourseId+ "-" +choice+ "-]" )
        .attr({ checked: isChecked });

};

/**
 *  if there is a two-way "must-have" relation between two courses
 *  then if this course is part of the relation and unchecked we
 *  need to deselect the other part of the relation, otherwise
 *  there'll be a locked dependency betweent them
 *
 *  @param blockCourseId
 *
 */

OptionBlock.prototype.checkDependentMustChooseRule = function( blockCourseId ) {

    var self = this;

    $.each( self.rules, function(i,rule) {
        if ( rule.from == blockCourseId && rule.type == self.MUST_SELECT ) {
            $( ".optinput[name^=ob-" +this.id+ "-" +rule.to+ "-]" )
                .attr({ checked: false });
        }
    });

};

/**
 *  an option checkbox has been clicked
 *
 */

OptionBlock.prototype.optionClicked = function( evt ) {

    var self = this;
    var source = evt.target;
    var info = source.name.match( /^ob-\d+-(\d+)-(\d+)-(\d+)$/ );
    var isChecked = source.checked;
    var blockCourseId = info[ 1 ];
    var choice = info[ 2 ];
    var blockId = info[ 3 ];
    var blockCourse = self.getBlockCourse( blockCourseId );

    // if we're selecting a course, apply the restriction that
    // any other matching courses IN THE SAME OPTIONS COLUMN
    // can't be selected.
    if ( isChecked )
        $.each( self.blockCourses, function(i,otherBlockCourse) {
             if ( blockCourse.courseId == otherBlockCourse.courseId ) {
                $( "input[name^=ob-" +this.id+ "-" +otherBlockCourse.id+ "-" +choice+ "-]" )
                    .attr({ checked: false });
             }
        });

    self.selectOption( blockCourseId, choice, blockId, isChecked );
    self.applyRules(blockCourseId,isChecked);
    self.updateFeedback();

};

/**
 *  this function updates the "feedback" element below the option blocks
 *  to inform the user with text what their current option selections are
 *
 **/

OptionBlock.prototype.updateFeedback = function() {

    var self = this;
    var checkedOptions = self.getCheckedOptions();

    // clear old text
    self.feedback.empty();

    $.each( checkedOptions, function(i,option) {

        var info = option.name.match( /ob-\d+-(\d+)-\d+-(\d+)/ );
        var blockCourseId = info[ 1 ];
        var blockId = info[ 2 ];
        var blockCourse = self.getBlockCourse( blockCourseId );

        // find the block this course is for (we need it's index in
        // the blocks array to say 'Option Block 1', etc...
        $.each( self.blocks, function(j,block) {
            if ( block.id == blockId )
                $( '<li></li>' )
                    .html( self.getTranslation('youSelectedCourse',new Array(blockCourse.name,j+1)) )
                    .appendTo( self.feedback );
        });

    });

};

/**
 *  returns all the currently checked option checkbox elements
 *
 *  @return {array} selected checkboxes
 *
 */

OptionBlock.prototype.getCheckedOptions = function() {

    return $( ".optinput[name^=ob-" +this.id+ "-]" )
        .filter(function(){ return this.checked; });

};

/**
 *  checks the selected options to make sure they conform to all the
 *  rules before submission.  if everything is ok then this will
 *  return true, otherwise error messages will be displayed and
 *  false is returned.
 *
 *  @return {boolean} true if all ok, false otherwise
 *  
 */

OptionBlock.prototype.validateOptions = function() {

    var errors = new Array();
    var self = this;

    // check option block selection counts are ok
    $.each( self.blocks, function(i,block) {
        var blocks = self.getAssociatedBlocks( block.id );
        var selectedCount = 0;
        $.each( blocks, function(j,assocBlock) {
            var options = $( ".optinput[name$=-" +assocBlock.id+ "]" )
                .filter(function(){ return this.checked; });
            $.each( options, function(i,option) {
                var info = option.name.match( /^ob-\d+-(\d+)-(\d+)-\d+$/ );
                var courseId = info[ 1 ];
                var choice = info[ 2 ];
                var blockCourse = self.getBlockCourse( courseId );
                // count the course if a) it's in this block, or b) it's a double
                // award course from the previous block.
                if ( (blockCourse.blockId == block.id || (blockCourse.blockId < block.id && blockCourse.isDoubleAward)) && (choice <= block.numberOfChoices) )
                    selectedCount++;
            });
        });
        if ( selectedCount != block.numberOfChoices )
            errors.push( self.getTranslation('errOptionBlockChoices',new Array(block.numberOfChoices,i+1))  );
    });

    // check compulsory subjects
    $.each( self.getCourses(), function(i,course) {
        if ( course.isCompulsory && !self.isCourseChecked(course.id) )
            errors.push( self.getTranslation('errCompulsoryCourse',new Array(course.name)) );
    });

    // check domains are represented
    var checkedOptions = self.getCheckedOptions();
    $.each( self.domains, function(i,domain) {
        var counted = new Array();
        var optionCount = 0;
        // go through the checked options, and work out what domain it is
        // in, only count it if we haven't counted that COURSE before.
          
        $.each( checkedOptions, function(i,option) {
            var info = option.name.match( /ob-\d+-(\d+)-.*/ );
            var blockCourse = self.getBlockCourse( info[1] );
            var courseInfo = self.getCourseInfo( blockCourse.courseId );
            
            // courseInfo being null was causing support issue 14757
            if (courseInfo !== null) {
                $.each( domain.cats, function(i,domainCat) {
                    $.each( courseInfo.cats, function(i,courseCat) {
                        if ( courseCat == domainCat && !counted[blockCourse.courseId] ) {
                            counted[ blockCourse.courseId ] = true;
                            optionCount++;
                        }
                    });
                });
            }

        });
        if ( optionCount != domain.numberOfOptions )
            errors.push( self.getTranslation('errDomainChoices',new Array(domain.numberOfOptions,domain.name)) );
    });

    // display errors if there were any
    if ( errors.length > 0 ) {

        var errDiv = $( '<ul/>' );

        for ( var i=0; i<errors.length; i++ )
            errDiv.append( $('<li/>').html(errors[i]) );

        $( '#OBFormErrors' )
            .append( $('<h3/>').html(this.name) )
            .append( errDiv );

    }

    return ( errors.length == 0 );

};

/**
 *  a thin wrapper to the locale objects getTranslation method
 *
 *  @param message {string} the message to format
 *  @param options {array} array of replacements
 *  @returns {string} the formatted message
 *
 */

OptionBlock.prototype.getTranslation = function( message, options ) {

    var self = this;

    return oLocale.getTranslation( self.locale, message, options );

};

/**
 *  returns a block for specified id, if it's not found you'll get false
 *
 *  @param blockId block id to fetch
 *
 */

OptionBlock.prototype.getBlock = function( blockId ) {

    var self = this;

    for ( var i=0; i<self.blocks.length; i++ )
        if ( self.blocks[i].id == blockId )
            return self.blocks[i];

    return false;

};

/**
 *  validates the given option blocks and sets error messages
 *  if there are any.  returns true if all ok, false otherwise
 *
 *  @param array optionBlocks
 *
 *  @return boolean
 *
 */

function OptionBlock_validateBlocks( optionBlocks ) {

    var isValid = true;

    // clear errors
    var errDiv = $( "#OBFormErrors" ).empty();

    // check for errors
    $.each( optionBlocks, function(i,optionBlock) {
        if ( !optionBlock.validateOptions() )
            isValid = false;
    });

    // if the form is valid then we need to enable any disabled
    // checkboxes so they get submitted in the request.
    if ( isValid ) {
        errDiv.slideUp();
        $.each( optionBlocks, function(i,optionBlock) {
            optionBlock.enableCheckboxes();
        });
    }

    else errDiv.prepend(
        $( '<h2/>' ).html( oLocale.getTranslation('OptionBlock','invalidOptions') )
    )
    .slideDown();

    return isValid;

};

/**
 *  general init of options block stuff
 *
 */

$(function() {

    $( '#optionBlockTabs' ).tabs();

});
/* UserAccount.js (65) */
/**
 * Based on the code at http://phiras.wordpress.com/2007/04/08/password-strength-meter-a-jquery-plugin, written by
 * Firas Kassem <phiras@gmail.com> [2007.04.05] and modified by Amin Rajaee <rajaee@gmail.com> [2009.07.26]
 *
 * Mostly rewritten to correct errors and allow customisation
 *
 * @author Dan Bettles <dan.bettles@boxuk.com>
 */
var PasswordStrengthMeter = {

    /**
     * Returns the number of occurrences of the pattern in the string
     *
     * @param {RegExp|String} p_regexp
     * @param {String} p_string
     * @return {Number}
     */
    countOccurrences: function (p_regexp, p_string) {
        var aMatch = p_string.match(p_regexp);

        if (aMatch === null) {
            return 0;
        }

        return aMatch.length;
    },

    /**
     * @param {Number} pLen
     * @param {String} str
     * @return {String}
     */
    _checkRepetition: function (pLen, str) {
        var res = '', repeated = true, i, j;

        for (i = 0; i < str.length; i++) {
            repeated = true;

            for (j = 0; j < pLen && (j + i + pLen) < str.length; j++) {
                repeated = repeated && (str.charAt(j + i) == str.charAt(j + i + pLen));
            }

            repeated = (j < pLen) ? false : repeated;

            if (repeated) {
                i += pLen - 1;
                repeated = false;
            }
            else {
                res += str.charAt(i);
            }
        }

        return res;
    },

    /**
     * Returns the percentage strength of the password
     *
     * @param {String} password
     * @param {String} username
     * @return {Number}
     */
    strengthPercent: function (password, username) {

        if (password.length < 8) {
            return 0;
        }

        if (password.toLowerCase() == username.toLowerCase()) {
            return 1;
        }

        var reSymbol = '[\\!,@#\\$%\\^&\\*\\?_~]',
            score = 0,
            i,
            numDigits = this.countOccurrences(/([0-9])/, password),
            numSymbols = this.countOccurrences('/('+reSymbol+')/', password),
            numLowercase = this.countOccurrences(/([a-z])/, password),
            numUppercase = this.countOccurrences(/([A-Z])/, password),
            numAlpha = numLowercase + numUppercase;

        //password length
        score += password.length * 4;

        for (i = 1; i <= 4; i++) {
            score += this._checkRepetition(i, password).length - password.length;
        }

        //password has 3 numbers
        score += numDigits >= 3 ? 5 : 0;

        //password has 2 symbols
        score += numSymbols >= 2 ? 5 : 0;

        //password has Upper and Lower chars
        score += numLowercase && numUppercase ? 10 : 0;

        //password has number and chars
        score += numAlpha && numDigits ? 15 : 0;

        //password has number and symbol
        score += numSymbols && numDigits ? 15 : 0;

        //password has char and symbol
        score += numSymbols && numAlpha ? 15 : 0;

        //password is just numbers or just chars
        score -= (numAlpha == password.length) || (numDigits == password.length) ? 10 : 0;

        //verifing 0 < score < 100
        if (score < 0) {
            score = 0;
        }
        else if (score > 100) {
            score = 100;
        }

        return score;
    },

    /**
     * Returns an integer between 1 and 5 indicating the strength of the password
     *
     * @param {String} password
     * @param {String} username
     * @return {Number}
     */
    strengthGrade: function (p_score) {
        var oStrengths = {
            shortPass: 1,  /*Too Short Password*/
            badPass: 2,  /*Weak; Use letters & numbers*/
            goodPass: 3,  /*Medium; Use special charecters*/
            strongPass: 4,  /*Strong Password*/
            sameAsUsername: 5  /*Password is the same as username.*/
        };

        if (p_score === 0) {
            return oStrengths.shortPass;
        }
        else if (p_score === 1) {
            return oStrengths.sameAsUsername;
        }
        else if (p_score < 34) {
            return oStrengths.badPass;
        }
        else if (p_score < 68) {
            return oStrengths.goodPass;
        }

        return oStrengths.strongPass;
    },

    /**
     * Returns an integer between 1 and 5 indicating the strength of the password
     *
     * @param {String} password
     * @param {String} username
     * @return {Number}
     */
    strength: function (password, username) {
        return this.strengthGrade(this.strengthPercent(password, username));
    }
};

/*--------------------------------------------------------------------------------------------------------------------*/

var UserAccountUtils = {

    /**
     * @param string p_regexp
     * @param string p_string
     * @return string
     */
    _firstSubmatch: function (p_regexp, p_string) {
        var aMatch = p_string.match(p_regexp);
        return aMatch === null ? false : aMatch[1];
    },

    /**
     * Trims leading and trailing whitespace
     *
     * @param {String} p_string
     * @return {String}
     */
    trim: function (p_string) {
        return p_string.replace(/^\s+|\s+$/, '');
    },

    /**
     *  uses the house number and postcode values from the form to try and look up an address
     *
     *  @param {Object} p_oFormElem the form the fields are in
     */
    doPostcodeLookup: function (p_oFormElem) {
        var oThrobberEl = jQuery('div.pcl-button img'),
            oLocale = window.oLocale,
            urlCurrent = window.location.href,
            navCat = this._firstSubmatch(/show=nav.([0-9a-z]+)/, urlCurrent),
            change = this._firstSubmatch(/change=(\w+)/, urlCurrent),
            /*blockId = this._firstSubmatch(/blockId=(\w+)/, urlCurrent),  *//*Remember: block IDs can be alphanumeric*/
            postcode = p_oFormElem['formField[postCode]'].value,
            houseNum = p_oFormElem['formField[houseNameNumber]'].value,
            urlRequest;

        if (houseNum.length < 1) {
            window.alert(oLocale.getTranslation('UserAccount', 'pcl_invalidHouseNameNumber'));
            return false;
        }

        if (postcode.length < 1) {
            window.alert(oLocale.getTranslation('UserAccount', 'pcl_invalidPostcode'));
            return false;
        }

        oThrobberEl.show();

        urlRequest = (
            'server.php?' +
            ( navCat === false ? '' : 'show=nav.' + navCat + '&' ) +
            ( change === false ? '' : 'change=' + change + '&' ) +
            'templateLayout=1&' +
            'action=getAddress&' +
            'outputFormat=ajax&' +
            'outputMime=application/json&' +
            'postCode=' + escape(postcode) + '&' +
            'houseNum=' + escape(houseNum)
        );

        jQuery.ajax({
            type: 'GET',
            url: urlRequest,
            dataType: 'json',
            success: function (response, status) {
                oThrobberEl.hide();
                UserAccountUtils.handlePostcodeLookupResponse(p_oFormElem, response, status);
            },
            error: function() {
                oThrobberEl.hide();
                window.alert(oLocale.getTranslation('UserAccount', 'pcl_unspecifiedError'));
            }
        });

        return true;
    },

    /**
     *  handles the returns of the query to look up the address from the postcode and house number
     *
     *  @param response {Object} the response object
     */
    handlePostcodeLookupResponse: function (p_oFormElem, response, status) {
        if (! (jQuery.isArray(response) && (response.length > 0))) {
            window.alert(window.oLocale.getTranslation('UserAccount', 'pcl_failedToFindAddress'));
            return false;
        }

        var aAddress = response,
            numAddresses = aAddress.length,
            addressChooserId = 'addressChooser',
            oAddressChooserEl,
            i,
            oSelectEl,
            paddingPels = 20,
            reportedSelectWidth;

        if (numAddresses == 1) {
            UserAccountUtils.setAddressFields(p_oFormElem, aAddress[0]);
            return true;
        }

        oAddressChooserEl = jQuery('<form><div><label>'+
            '<span>'+window.oLocale.getTranslation('UserAccount', 'pcl_howToSelect')+'</span><select/>'+
            '</label></div></form>')
            .appendTo('body')
            .attr('id', addressChooserId)
            .css('padding', paddingPels + 'px')
            .submit(function () { return false; });

        oSelectEl = oAddressChooserEl.find('select')
            .attr({
                multiple: 'multiple',
                size: 10
            })
            .dblclick(function () {
                var aSeldAddress = jQuery(this).val();
                UserAccountUtils.setAddressFields(p_oFormElem, aSeldAddress[0]);
                jQuery.cwmodal.close();
            });

        for (i = 0; i < numAddresses; i++) {
            oSelectEl.append('<option value="'+aAddress[i]+'">'+aAddress[i]+'</option>');
        }

        //todo: width() returns a value much greater than the observable width of the SELECT.  I don't know where the
        //extra width comes from, so I can't do anything about it directly.  What I can do, however, is set the width of
        //the dialog to the reported width and force the SELECT to fit to that.  It's not ideal, but it avoids a whole
        //load of 'unsightly' whitespace.
        reportedSelectWidth = oSelectEl.width();
        oSelectEl.css('width', '100%');

        oAddressChooserEl.cwmodal({
            persist: true,
            containerCss: {
                width: (reportedSelectWidth + (paddingPels * 2)) + 'px',
                height: oAddressChooserEl.height() + 'px'
            },
            autoPosition: true
        });

        return true;
    },

    setAddressFields: function (p_oFormElem, p_address) {
        var aAddressPartMatch = p_address.match(/^([^,]+),\s*(.*)/),
            addressRemaining = '',
            numAddressParts = 0;

        /*todo: What to do...*/
        if (aAddressPartMatch === null) {
            return false;
        }

        p_oFormElem['formField[houseNameNumber]'].value = this.trim(aAddressPartMatch[1]);

        addressRemaining = aAddressPartMatch[2];
        aAddressPartMatch = addressRemaining.split(',');

        //We know there will definitely be a postcode
        p_oFormElem['formField[postCode]'].value = this.trim(aAddressPartMatch.pop());

        numAddressParts = aAddressPartMatch.length;

        if (numAddressParts > 0) {
            if (numAddressParts == 1) {
                p_oFormElem['formField[address]'].value = this.trim(aAddressPartMatch.pop());
            }
            else {
                p_oFormElem['formField[county]'].value = this.trim(aAddressPartMatch.pop());
                p_oFormElem['formField[address]'].value = this.trim(aAddressPartMatch.join(','));
            }
        }

        return true;
    },

    /**
     * Updates the password strength meter associated with the element
     *
     * @param {jQuery|DomElement|string} p_oInputElem
     */
    updatePasswordStrengthMeter: function (p_oInputElem) {
        var oLocale = window.oLocale,
            aGradeDescription = [
                '',
                oLocale.getTranslation('UserAccount', 'psm_shortPass'),
                oLocale.getTranslation('UserAccount', 'psm_badPass'),
                oLocale.getTranslation('UserAccount', 'psm_goodPass'),
                oLocale.getTranslation('UserAccount', 'psm_strongPass'),
                oLocale.getTranslation('UserAccount', 'psm_sameAsUsername')
            ],
            aStrengthColour = [
                '',
                '#f00',
                '#f00',  /*Red*/
                '#dd7500',  /*Amber*/
                '#008b00',  /*Green*/
                '#f00'
            ],
            oThisEl = jQuery(p_oInputElem),
            password = oThisEl.val(),
            username = oThisEl.closest('form').find('input#username,input#registrationForm-username').val(),
            percent = window.PasswordStrengthMeter.strengthPercent(password, username),
            grade = window.PasswordStrengthMeter.strengthGrade(percent),
            barWidth = (grade == 1) || (grade == 5) ? 100 : percent;

        oThisEl.siblings('div.psm-outer')
            .find('span.description')
                .text(aGradeDescription[grade])
            .end()
            .find('div.bar')
                .css({ width: barWidth + '%', 'background-color': aStrengthColour[grade] })
            .end();
    },

    /**
     * Attaches a password strength meter to the element
     *
     * @param {jQuery|DomElement|string} p_oInputElem
     */
    displayPasswordStrengthMeter: function (p_oInputElem) {
        var oInputEl = jQuery(p_oInputElem),
            oAttachEl = oInputEl,
            oTooltip = oAttachEl.siblings('div.toolTip');

        if (oTooltip.length) {
            oAttachEl = oTooltip;
        }

        oAttachEl
            .parent()
            .prepend(
                '<div class="psm-outer"><div class="psm-inner">'+
                '<p>'+window.oLocale.getTranslation('UserAccount', 'psm_passwordStrength')+': <span class="description"/></p>'+
                '<div class="barContainer" style="width: 170px">' +
                '<div class="bar">&nbsp;</div>'+
                '</div></div></div>'
            );

        oInputEl
            .keyup(function () {
                UserAccountUtils.updatePasswordStrengthMeter(this);
            });
    }
};

/*--------------------------------------------------------------------------------------------------------------------*/

jQuery(function () {
    var oLocale = window.oLocale,
        oLocaleId = oLocale.getFieldValue('id'),
        src = 'custom/careers_wales/img/selfreg/findaddress_'+window.SITE_CODE+'_'+oLocaleId+'.png',
        oToolTipEl = jQuery('div.userAccount input#postCode + div.toolTip');  /*Was after input#postCode*/

    // Set the body height to 100% to resolve any IE6 issues related to the user account lightbox
    jQuery('body').addClass('hijaxed').css('height', '100%');

    jQuery('div.userAccount p.forgottenlinks a.iframelightbox').click(function () {
        /*frameborder must be specified in the markup - and not in the list of attributes - or else IE renders a border*/
        var oIframe = jQuery('<iframe frameborder="0"/>')
            .attr({
                id: 'lightbox-iframe',
                src: jQuery(this).attr('href'),
                width: '100%',
                height: '100%'
            })
            .load(function () {
                var testFrame = jQuery('#lightbox-iframe'),  /*todo: Is there a reason we don't use jQuery(this)?*/
                    oIframeContents = testFrame.contents(),
                    oCwModal = jQuery.cwmodal,
                    blkBdy = oIframeContents.find('.blkBdy'),
                    cellOne = oIframeContents.find('.cellOne'),
                    container = testFrame.parent().parent(),
                    // Calculate the height of the container based on the height of the 'blkBdy' div, and the vertical padding of the 'cellOne' div
                    newHeight = blkBdy.height() +
                    parseInt(cellOne.css('padding-top').replace('px', '')) +
                    parseInt(cellOne.css('padding-bottom').replace('px', '')),
                    oIframeHeading = oIframeContents.find('div.userAccount h1'),
                    oIframeLastRow = oIframeContents.find('div.userAccount div.poslast');

                /*I _was_ using jQuery::appendTo(), which resulted in cleaner code, but this wasn't supported in IE*/
                oIframeHeading
                    .prepend('<span class="button-close"><img src="custom/careers_wales/img/selfreg/lightbox-close.gif"/></span>')
                    .find('span')
                        .click(function () { oCwModal.close(); });

                /*I _was_ using jQuery::appendTo(), which resulted in cleaner code, but this wasn't supported in IE*/
                 oIframeLastRow
                    .append('<span class="closelink">Or <a href="#">Cancel</a> to close</span>')
                    .find('a')
                        .click(function () { oCwModal.close(); });

                container.animate(
                    { height: newHeight },
                    'slow',
                    function(){
                        // Calling window.resize() resets cwmodal's auto positioning
                        jQuery(window).resize();
                    }
                );
            })
            .cwmodal({
                persist: true,
                containerCss: { width: '600px', background: 'none' },
                minHeight: 300,
                autoPosition: true
            });

        return false;
    });

    jQuery('div.userAccount input#houseNameNumber')
        .parent()
        .prepend('<div class="help help-address">'+oLocale.getTranslation('UserAccount', 'houseNameNumberHelpText')+'</div>');

    if (! oToolTipEl.length) {
        oToolTipEl = jQuery('div.userAccount input#postCode');
    }

    jQuery(
        '<div class="pcl-button">'+
        '<input type="image" class="imageButton" src="'+src+'" alt="'+oLocale.getTranslation('UserAccount', 'find')+'"/>'+
        '<img src="custom/careers_wales/img/selfreg/throbber-landinglights.gif" style="display: none"/>'+
        '</div>'
    )
        .insertAfter(oToolTipEl)
        .find('input')
            .click(function () {
                window.UserAccountUtils.doPostcodeLookup(jQuery(this).closest('form').get(0));
                return false;
            });

    window.UserAccountUtils.displayPasswordStrengthMeter(jQuery('div.userAccount input#password1'));

    /*Don't submit if the passwords don't match*/
    jQuery('div.userAccount form')
        .submit(function () {
            if(jQuery('.password1').length && jQuery('.password2').length) {
                // Passwords exist
                return window.UserAccountUtils.validatePasswords(this);
            }

            return true;
        });

    $('select[name=formField\\[dob_month\\]], select[name=formField\\[dob_year\\]]').change(
        function() {
            year = $('select[name=formField\\[dob_year\\]]').val();
            month = $('select[name=formField\\[dob_month\\]]').val();

            days = $('select[name=formField\\[dob_day\\]] > option');

            days.show();

            lastDay = 31;

            aShortMonth = ['September', 'April', 'June', 'November'];

            for (i = 0; i < aShortMonth.length; i++) {
                if (month == aShortMonth[i]) {
                    lastDay = 30;
                }
            }

            if (month == 'February') {
                lastDay = new Date(year, 1, 29).getDate() == 29 ? 29 : 28;
            }

            $(days).each(
                function () {
                    if ($(this).val() > lastDay) {
                        $(this).hide();
                        if ($(this).attr('selected')) {
                            $(days[lastDay]).attr('selected', true);
                        }
                    }
                }
            );
        }
    );
});
/* FreeChoicePoll.js (73) */
function FreeChoicePoll_Rule( fromCourseId, toCourseId, ruleType ) {
    this.fromCourseId = fromCourseId;
    this.toCourseId = toCourseId;
    this.ruleType = ruleType;
}

function FreeChoicePoll_Course( id, credits ) {
    this.id = id;
    this.credits = credits;
}

var FreeChoicePoll = {

    MAX_CREDITS: null,

    MUST_SELECT: 2,
    CANT_SELECT: 1,
    ONLY_SELECT: 3,

    courses: new Array(),
    rules: new Array(),
    errorDiv: null,
    locale: 'FreeChoicePoll',
    
    init: function() {
        var self = this; 
        $( ".fcinput[type=checkbox]" ).click( self.optionClicked );

        var ulDiv = $( '<div></div>' )
            .addClass( 'actionDispatcherMessages' );
        self.errorDiv = $( '<ul></ul>' )
            .hide()
            .appendTo( ulDiv );
        ulDiv.prependTo( '#FCForm' );
        self.applyConstraints();
		
		var localeId = oLocale.getFieldValue('id');
        $( ".buttons :input" )
            .remove();
        // reset button
        $( '<input type="image" />' )
            .attr({ value: self.getTranslation('btnReset'),
                src: 'custom/careers_wales/img/buttons/button_reset_' +localeId+ '.gif' })
            .click( self.resetClicked )
            .appendTo( '.FCForm .buttons' );
        // submit button
        $( '<input type="image" />' )
            .attr({ value: self.getTranslation('btnSave'),
                src: 'custom/careers_wales/img/buttons/button_save_' +localeId+ '.gif' })
            .click( self.submitClicked )
            .appendTo( '.FCForm .buttons' );
		
    },

    applyConstraints: function() {

        var self = this;

        self.applyRules();
        self.applyCreditLimit();

    },

    setLocale: function( locale ) {
        this.locale = locale;
    },

    resetClicked: function() {

        var self = FreeChoicePoll;

        document.getElementById( 'FCForm' ).reset();

        self.applyConstraints();

        return false;

    },

    submitClicked: function() {

        var self = FreeChoicePoll;

        return self.isFormValid();

    },
    
    getCourse: function( courseId ) {

        var self = this;

        for (  var i=0; i<self.courses.length; i++ )
            if ( self.courses[i].id == courseId )
                return self.courses[i];

        return null;

    },
    
    /**
     *  callback for when poll options are clicked
     *
     */
    
    optionClicked: function( evt ) {

        var self = FreeChoicePoll;
        var source = evt.target;
        var isChecked = source.checked;
        var info = source.name.match( /fcp-(\d+)-(\d+)/ );
        var courseId = info[ 1 ];
        var choice = info[ 2 ];

        self.selectChoice( courseId, choice, isChecked );
        self.applyConstraints();

    },
    
    /**
     *  uses the MAX_CREDITS var to disable any courses that if selected would
     *  take the user over the maximum number of credits they're allowed.
     *
     */
    
    applyCreditLimit: function() {

        var self = this;
        var credits = self.getSelectedCreditsCount();

        $.each( self.courses, function(i,course) {
            // if selecting courses will take us over (and they're not part of
            // the current selection) disable them.
            if ( (credits + course.credits > self.MAX_CREDITS) && !self.getSelectedChoice(course.id) )
                $( ":input[name^=fcp-" +course.id+ "-]" )
                    .attr({ disabled: true, checked: false });
        });

    },
    
    /**
     *  returns all the selected options in the poll
     *
     *  @returns array of selected checkboxes
     *
     */
    
    getSelectedOptions: function() {

        return $( ".fcinput[name^=fcp-]" )
            .filter( function(){return this.checked} );

    },
    
    /**
     *  applies the currently defined rules to the free choice options
     *
     */
    
    applyRules: function() {

        var self = this;
        var selectedOptions = self.getSelectedOptions();

        // enable all to start with
        $( ".fcinput" )
            .attr({ disabled: false });

        // then apply rules defined for this poll
        $.each( self.rules, function(i,rule) {
            switch ( rule.ruleType ) {

                case self.MUST_SELECT:
                    // if fromCourseId is selected, then also select AN option
                    // in the toCourse, but not the same one as in fromCourse
                    var fromChoice = self.getSelectedChoice( rule.fromCourseId );
                    if ( fromChoice ) {
                        $( ":input[name^=fcp-" +rule.toCourseId+ "-" +fromChoice+ "]" )
                            .attr({ disabled: true });
                        if ( !self.getSelectedChoice(rule.toCourseId) )
                            self.selectChoice( rule.toCourseId, fromChoice+1, true );
                    }
                    break;

                case self.CANT_SELECT:
                    // easy rule, if fromCourse is selected, disable toCourse
                    var fromChoice = self.getSelectedChoice( rule.fromCourseId );
                    if ( fromChoice )
                        $( ":input[name^=fcp-" +rule.toCourseId+ "-]" )
                            .attr({ checked: false, disabled: true });
                    break;

                case self.ONLY_SELECT:
                    var toChoice = self.getSelectedChoice( rule.toCourseId );
                    if ( !toChoice )
                        $( ":input[name^=fcp-" +rule.fromCourseId+ "-]" )
                            .attr({ checked: false, disabled: true });
                    // if it is selected then disable the selected choice on
                    // that course, cause that doesn't make sense?
                    else
                        $( ":input[name=fcp-" +rule.fromCourseId+ "-" +toChoice+ "]" )
                            .attr( { checked: false, disabled: true });
                    break;

            }
        });

    },
    
    /**
     *  selects an option, applying selection constraints
     *
     *  @param courseId the course to select
     *  @param choice the choice to select for that course
     *
     */
    
    selectChoice: function( courseId, choice, isChecked ) {

        $( ":input[name^=fcp-" +courseId+ "]" )
            .add( ":input[name$=-" +choice+ "]" )
            .attr({ checked: false });

        $( ":input[name=fcp-" +courseId+ "-" +choice+ "]" )
            .attr({ checked: isChecked, disabled: false });

    },
    
    /**
     *  this method checks to see if a course is selected, and if it is returns
     *  the "choice" number that is selected.  if nothing is selcted then it
     *  will return false
     *
     *  @param courseId id of course to check
     *
     */
    
    getSelectedChoice: function( courseId ) {

        var options = $( ":input[name^=fcp-" +courseId+ "]" );

        for ( var i=0; i<options.length; i++ )
            if ( $(options[i]).attr('checked') )
                return i+1;

        return false;

    },

    /**
     *  returns the number of selected credits according to the weightings
     *  of the courses on the poll
     *
     */

    getSelectedCreditsCount: function() {

        var self = this;
        var selectedOptions = self.getSelectedOptions();
        var credits = 0;

        $.each( selectedOptions, function(i,option) {

            var info = option.name.match( /fcp-(\d+)-.*/ );
            var courseId = info[ 1 ];
            var course = self.getCourse( courseId );

            credits += course.credits;

        });

        return credits;

    },
    
    /**
     *  checks if the poll form is valid, if it isn't then error messages
     *  are displayed and it'll return false.  otherwise it'll return true
     *
     */
    
    isFormValid: function() {

        var self = FreeChoicePoll;
        var errors = new Array();
        var credits = self.getSelectedCreditsCount();

        if ( credits != self.MAX_CREDITS )
            errors.push( self.getTranslation('wrongNumCredits') );

        // display errors if there are any
        self.errorDiv.empty();
        if ( errors.length > 0 ) {
            $.each( errors, function(i,message) {
                $( '<li></li>' )
                    .addClass( 'message errorMessage' )
                    .html( '<span class="message">' +message+ '</span>' )
                    .appendTo( self.errorDiv );
            });
            self.errorDiv.fadeIn();
        }
        else self.errorDiv.fadeOut();

        return ( errors.length == 0 );

    },

    /**
     *  returns a locale translation for this block
     *
     *  @param message the translation key
     *  @param options an array of replacements
     *
     */

    getTranslation: function( message, options ) {
        var self = this;
        return oLocale.getTranslation( self.locale, message, options );
    }
    
};
/* LearningPathwayPlan.js (81) */
/**
 * Lowercases the first character of the string p_string
 *
 * @author Dan Bettles <dan.bettles@boxuk.com>
 */
function lcfirst (p_string) {
    return p_string.toString().substring(0,1).toLowerCase() + 
           p_string.toString().substring(1);
}


/**
 * Does a confirm() with the translation identified by p_componentId and 
 * p_localeKey
 *
 * @author Dan Bettles <dan.bettles@boxuk.com>
 */
function confirmLocale (p_componentId, p_localeKey) {
    if (window.confirm (oLocale.getTranslation (p_componentId, p_localeKey))) {
        return true;
    }
    else {
        return false;
    }
}


/**
 * Prepares the block
 *
 * @author Dan Bettles <dan.bettles@boxuk.com>
 */
$(document).ready (function() {

    var componentId = 'LearningPathwayPlan';
    var selectorBlock = 'div.' + lcfirst (componentId);

/******************************************************************************/

    /*
     * Hide all 'toggle-able' forms
     */

    $(selectorBlock + ' div.studentMilestones div.deleteForm').toggleClass (
        'hidden'
    );

    $(selectorBlock + ' div.studentMilestones div.updateForm').toggleClass (
        'hidden'
    );

/******************************************************************************/

    /*
     * @todo Make this more robust?
     */
    var oCourseFilterForm = $(selectorBlock + ' div.courseFilterForm form')
                            .slice (0, 1);

    /*
     * Course filter.  Hide the "Filter Courses" button.
     */
    $('input[type=image]', oCourseFilterForm).toggleClass ('hidden');

    oCourseFilterForm.append (
        '<input type="hidden" name="outputFormat" value="ajax" />'
    );

    /*
     * Course filter.  Changing value submits the form.
     */
    $('select.filter', oCourseFilterForm).change (
        function() {
            if ($(this).val.toString().length > 0) {
                var oCourses = $(
                    selectorBlock + ' div.createForm select.courses'
                );

                var oThrobber = $(
                    'span.throbber', 
                    oCourses.parent ('dd.control')
                );

                if (oThrobber.length) {
                    oThrobber.attr ('style', 'visibility: visible');
                }
                else {
                    oThrobber = $('<span class="throbber">&nbsp;</span>')
                                .appendTo (oCourses.parent());
                }

                var oOptions = {
                    dataType: 'html',

                    beforeSubmit: function() {
                        oCourses.html (
                            '<option value="">' +
                            oLocale.getTranslation (
                                componentId, 
                                'labelPleaseWait'
                            ) +
                            '</option>'
                        );

                        oCourses.attr ('disabled', 'disabled');
                    },

                    success: function (p_response) {
                        oCourses.html (p_response);
                        oCourses.attr ('disabled', '');
                        oThrobber.attr ('style', 'visibility: hidden');
                    },

                    error: function() {
                        alert (oLocale.getTranslation (
                            componentId, 
                            'alertJavascriptError'
                        ));

                        oThrobber.attr ('style', 'visibility: hidden');
                    }
                };

                $(this.form).ajaxSubmit (oOptions);
            }
        }
    );

/******************************************************************************/

    /*
     * Delete button (links).  Add delete functionality.
     */
    $(selectorBlock + ' div.studentMilestones ul a.delete').click (
        function (p_oEvent) {
            if (confirmLocale (componentId, 'confirmDelete')) {
                $('form', $(this).parent().siblings('div.deleteForm'))[0].submit();
            }
            return false;
        }
    );

    /*
     * Update button (links).  Add toggle functionality.
     */
    $(selectorBlock + ' div.studentMilestones ul a.update').click (
        function (p_oEvent) {
            $(this).parent().siblings('div.updateForm').toggleClass('hidden'); 
            return false;
        }
    );

/******************************************************************************/

    /*
     * Location drop-downs.  When the value of a drop-down is changed, copy the 
     * new value into the adjacent text field.
     */
    $(selectorBlock + ' div.createForm select.location').each (
        function() {
            $(this).change (function() {
                $(this).siblings('input.location').slice(0,1).val (this.value);
            });
        }
    );

    /*
     * Delete buttons.  Ask the user before deleting data.
     */
    $(selectorBlock + ' input.deleteButton').click (
        function (p_oEvent) {
            return confirmLocale (componentId, 'confirmDelete');
        }
    );

    /*
     * Milestone Tools.  Un-hide (!)
     */
    $(selectorBlock + ' div.studentMilestones p.tools').toggleClass ('hidden');
});
/* jqform.js (106) */
/***
 * jQuery Form Plugin
 * version: 2.36 (07-NOV-2009)
 * @requires jQuery v1.2.6 or later
 *
 * Examples and documentation 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
 */
;(function($) {

/*
	Usage Note:
	-----------
	Do not use both ajaxSubmit and ajaxForm on the same form.  These
	functions are intended to be exclusive.  Use ajaxSubmit if you want
	to bind your own submit handler to the form.  For example,

	$(document).ready(function() {
		$('#myForm').bind('submit', function() {
			$(this).ajaxSubmit({
				target: '#output'
			});
			return false; // <-- important!
		});
	});

	Use ajaxForm when you want the plugin to manage all the event binding
	for you.  For example,

	$(document).ready(function() {
		$('#myForm').ajaxForm({
			target: '#output'
		});
	});

	When using ajaxForm, the ajaxSubmit function will be invoked for you
	at the appropriate time.
*/

/**
 * ajaxSubmit() provides a mechanism for immediately submitting
 * an HTML form using AJAX.
 */
$.fn.ajaxSubmit = function(options) {
	// fast fail if nothing selected (http://dev.jquery.com/ticket/2752)
	if (!this.length) {
		log('ajaxSubmit: skipping submit process - no element selected');
		return this;
	}

	if (typeof options == 'function')
		options = { success: options };

	var url = $.trim(this.attr('action'));
	if (url) {
		// clean url (don't include hash vaue)
		url = (url.match(/^([^#]+)/)||[])[1];
   	}
   	url = url || window.location.href || '';

	options = $.extend({
		url:  url,
		type: this.attr('method') || 'GET',
		iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'
	}, options || {});

	// hook for manipulating the form data before it is extracted;
	// convenient for use with rich editors like tinyMCE or FCKEditor
	var veto = {};
	this.trigger('form-pre-serialize', [this, options, veto]);
	if (veto.veto) {
		log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
		return this;
	}

	// provide opportunity to alter form data before it is serialized
	if (options.beforeSerialize && options.beforeSerialize(this, options) === false) {
		log('ajaxSubmit: submit aborted via beforeSerialize callback');
		return this;
	}

	var a = this.formToArray(options.semantic);
	if (options.data) {
		options.extraData = options.data;
		for (var n in options.data) {
		  if(options.data[n] instanceof Array) {
			for (var k in options.data[n])
			  a.push( { name: n, value: options.data[n][k] } );
		  }
		  else
			 a.push( { name: n, value: options.data[n] } );
		}
	}

	// give pre-submit callback an opportunity to abort the submit
	if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
		log('ajaxSubmit: submit aborted via beforeSubmit callback');
		return this;
	}

	// fire vetoable 'validate' event
	this.trigger('form-submit-validate', [a, this, options, veto]);
	if (veto.veto) {
		log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
		return this;
	}

	var q = $.param(a);

	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) {
			$(options.target).html(data).each(oldSuccess, arguments);
		});
	}
	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].apply(options, [data, status, $form]);
	};

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

	var multipart = false;
//	var mp = 'multipart/form-data';
//	multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);

	// options.iframe allows user to force iframe mode
	// 06-NOV-09: now defaulting to iframe mode if file input is detected
   if ((files.length && options.iframe !== false) || options.iframe || found || multipart) {
	   // hack to fix Safari hang (thanks to Tim Molendijk for this)
	   // see:  http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
	   if (options.closeKeepAlive)
		   $.get(options.closeKeepAlive, fileUpload);
	   else
		   fileUpload();
	   }
   else
	   $.ajax(options);

	// fire 'notify' event
	this.trigger('form-submit-notify', [this, options]);
	return this;


	// private function for handling file uploads (hat tip to YAHOO!)
	function fileUpload() {
		var form = $form[0];

		if ($(':input[name=submit]', form).length) {
			alert('Error: Form elements must not be named "submit".');
			return;
		}

		var opts = $.extend({}, $.ajaxSettings, options);
		var s = $.extend(true, {}, $.extend(true, {}, $.ajaxSettings), opts);

		var id = 'jqFormIO' + (new Date().getTime());
		var $io = $('<iframe id="' + id + '" name="' + id + '" src="'+ opts.iframeSrc +'" />');
		var io = $io[0];

		$io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });

		var xhr = { // mock object
			aborted: 0,
			responseText: null,
			responseXML: null,
			status: 0,
			statusText: 'n/a',
			getAllResponseHeaders: function() {},
			getResponseHeader: function() {},
			setRequestHeader: function() {},
			abort: function() {
				this.aborted = 1;
				$io.attr('src', opts.iframeSrc); // abort op in progress
			}
		};

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

		if (s.beforeSend && s.beforeSend(xhr, s) === false) {
			s.global && $.active--;
			return;
		}
		if (xhr.aborted)
			return;

		var cbInvoked = 0;
		var timedOut = 0;

		// add submitting element to data if we know it
		var sub = form.clk;
		if (sub) {
			var n = sub.name;
			if (n && !sub.disabled) {
				options.extraData = options.extraData || {};
				options.extraData[n] = sub.value;
				if (sub.type == "image") {
					options.extraData[name+'.x'] = form.clk_x;
					options.extraData[name+'.y'] = form.clk_y;
				}
			}
		}

		// take a breath so that pending repaints get some cpu time before the upload starts
		setTimeout(function() {
			// make sure form attrs are set
			var t = $form.attr('target'), a = $form.attr('action');

			// update form attrs in IE friendly way
			form.setAttribute('target',id);
			if (form.getAttribute('method') != 'POST')
				form.setAttribute('method', 'POST');
			if (form.getAttribute('action') != opts.url)
				form.setAttribute('action', opts.url);

			// ie borks in some cases when setting encoding
			if (! options.skipEncodingOverride) {
				$form.attr({
					encoding: 'multipart/form-data',
					enctype:  'multipart/form-data'
				});
			}

			// support timout
			if (opts.timeout)
				setTimeout(function() { timedOut = true; cb(); }, opts.timeout);

			// add "extra" data to form if provided in options
			var extraInputs = [];
			try {
				if (options.extraData)
					for (var n in options.extraData)
						extraInputs.push(
							$('<input type="hidden" name="'+n+'" value="'+options.extraData[n]+'" />')
								.appendTo(form)[0]);

				// add iframe to doc and submit the form
				$io.appendTo('body');
				io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false);
				form.submit();
			}
			finally {
				// reset attrs and remove "extra" input elements
				form.setAttribute('action',a);
				t ? form.setAttribute('target', t) : $form.removeAttr('target');
				$(extraInputs).remove();
			}
		}, 10);

		var domCheckCount = 50;

		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;

				var isXml = opts.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);
				log('isXml='+isXml);
				if (!isXml && (doc.body == null || doc.body.innerHTML == '')) {
				 	if (--domCheckCount) {
						// in some browsers (Opera) the iframe DOM is not always traversable when
						// the onload callback fires, so we loop a bit to accommodate
						cbInvoked = 0;
						setTimeout(cb, 100);
						return;
					}
					log('Could not access iframe DOM after 50 tries.');
					return;
				}

				xhr.responseText = doc.body ? doc.body.innerHTML : null;
				xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
				xhr.getResponseHeader = function(header){
					var headers = {'content-type': opts.dataType};
					return headers[header];
				};

				if (opts.dataType == 'json' || opts.dataType == 'script') {
					// see if user embedded response in textarea
					var ta = doc.getElementsByTagName('textarea')[0];
					if (ta)
						xhr.responseText = ta.value;
					else {
						// account for browsers injecting pre around json response
						var pre = doc.getElementsByTagName('pre')[0];
						if (pre)
							xhr.responseText = pre.innerHTML;
					}
				}
				else if (opts.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) {
					xhr.responseXML = toXml(xhr.responseText);
				}
				data = $.httpData(xhr, opts.dataType);
			}
			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;
		};
	};
};

/**
 * 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.
 *
 * 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.
 */
$.fn.ajaxForm = function(options) {
	return this.ajaxFormUnbind().bind('submit.form-plugin', function() {
		$(this).ajaxSubmit(options);
		return false;
	}).bind('click.form-plugin', function(e) {
		var target = e.target;
		var $el = $(target);
		if (!($el.is(":submit,input:image"))) {
			// is this a child element of the submit el?  (ex: a span within a button)
			var t = $el.closest(':submit');
			if (t.length == 0)
				return;
			target = t[0];
		}
		var form = this;
		form.clk = target;
		if (target.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 = $el.offset();
				form.clk_x = e.pageX - offset.left;
				form.clk_y = e.pageY - offset.top;
			} else {
				form.clk_x = e.pageX - target.offsetLeft;
				form.clk_y = e.pageY - target.offsetTop;
			}
		}
		// clear form vars
		setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100);
	});
};

// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
$.fn.ajaxFormUnbind = function() {
	return this.unbind('submit.form-plugin click.form-plugin');
};

/**
 * 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.
 */
$.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, value: $(el).val()});
				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 it here
		var $input = $(form.clk), input = $input[0], n = input.name;
		if (n && !input.disabled && input.type == 'image') {
			a.push({name: n, value: $input.val()});
			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
 */
$.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
 */
$.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.
 */
$.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.
 */
$.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) {
				var v = op.value;
				if (!v) // extra pain for IE...
					v = (op.attributes && op.attributes['value'] && !(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
 */
$.fn.clearForm = function() {
	return this.each(function() {
		$('input,select,textarea', this).clearFields();
	});
};

/**
 * Clears the selected form elements.
 */
$.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.
 */
$.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();
	});
};

/**
 * Enables or disables any matching elements.
 */
$.fn.enable = function(b) {
	if (b == undefined) b = true;
	return this.each(function() {
		this.disabled = !b;
	});
};

/**
 * Checks/unchecks any matching checkboxes or radio buttons and
 * selects/deselects and matching option elements.
 */
$.fn.selected = function(select) {
	if (select == undefined) select = true;
	return this.each(function() {
		var t = this.type;
		if (t == 'checkbox' || t == 'radio')
			this.checked = select;
		else if (this.tagName.toLowerCase() == 'option') {
			var $sel = $(this).parent('select');
			if (select && $sel[0] && $sel[0].type == 'select-one') {
				// deselect all other options
				$sel.find('option').selected(false);
			}
			this.selected = select;
		}
	});
};

// helper fn for console logging
// set $.fn.ajaxSubmit.debug to true to enable debug logging
function log() {
	if ($.fn.ajaxSubmit.debug && window.console && window.console.log)
		window.console.log('[jquery.form] ' + Array.prototype.join.call(arguments,''));
};

})(jQuery);
/* CalenderPopup.js (119) */
/***
// ===================================================================
// Author: Matt Kruse <matt@mattkruse.com>
// WWW: http://www.mattkruse.com/
//
// NOTICE: You may use this code for any purpose, commercial or
// private, without any further permission from the author. You may
// remove this notice from your final code if you wish, however it is
// appreciated by the author if at least my web site address is kept.
//
// You may *NOT* re-distribute this code in any way except through its
// use. That means, you can include it in your product, or your web
// site, or any other form where the code is actually being used. You
// may not put the plain javascript up on your site for download or
// include it in your javascript libraries for download. 
// If you wish to share this code with others, please just point them
// to the URL instead.
// Please DO NOT link directly to my .js files from your site. Copy
// the files to your server and use them there. Thank you.
// ===================================================================
 */

/* SOURCE FILE: AnchorPosition.js */

/* 
AnchorPosition.js
Author: Matt Kruse
Last modified: 10/11/02

DESCRIPTION: These functions find the position of an <A> tag in a document,
so other elements can be positioned relative to it.

COMPATABILITY: Netscape 4.x,6.x,Mozilla, IE 5.x,6.x on Windows. Some small
positioning errors - usually with Window positioning - occur on the 
Macintosh platform.

FUNCTIONS:
getAnchorPosition(anchorname)
  Returns an Object() having .x and .y properties of the pixel coordinates
  of the upper-left corner of the anchor. Position is relative to the PAGE.

getAnchorWindowPosition(anchorname)
  Returns an Object() having .x and .y properties of the pixel coordinates
  of the upper-left corner of the anchor, relative to the WHOLE SCREEN.

NOTES:

1) For popping up separate browser windows, use getAnchorWindowPosition. 
   Otherwise, use getAnchorPosition

2) Your anchor tag MUST contain both NAME and ID attributes which are the 
   same. For example:
   <A NAME="test" ID="test"> </A>

3) There must be at least a space between <A> </A> for IE5.5 to see the 
   anchor tag correctly. Do not do <A></A> with no space.
   
4) Andrew Roberts - As a workaround for a bug in Internet Explorer 6 (possibly 7)
   all select boxes are hidden when the calender is displayed, whether it is a DIV
   or a new window. The selects are shown again when the calender is hidden.
*/ 

// getAnchorPosition(anchorname)
//   This function returns an object having .x and .y properties which are the coordinates
//   of the named anchor, relative to the page.
function getAnchorPosition(anchorname) {
	// This function will return an Object with x and y properties
	var useWindow=false;
	var coordinates=new Object();
	var x=0,y=0;
	// Browser capability sniffing
	var use_gebi=false, use_css=false, use_layers=false;
	if (document.getElementById) { use_gebi=true; }
	else if (document.all) { use_css=true; }
	else if (document.layers) { use_layers=true; }
	// Logic to find position
 	if (use_gebi && document.all) {
		x=AnchorPosition_getPageOffsetLeft(document.all[anchorname]);
		y=AnchorPosition_getPageOffsetTop(document.all[anchorname]);
		}
	else if (use_gebi) {
		var o=document.getElementById(anchorname);
		x=AnchorPosition_getPageOffsetLeft(o);
		y=AnchorPosition_getPageOffsetTop(o);
		}
 	else if (use_css) {
		x=AnchorPosition_getPageOffsetLeft(document.all[anchorname]);
		y=AnchorPosition_getPageOffsetTop(document.all[anchorname]);
		}
	else if (use_layers) {
		var found=0;
		for (var i=0; i<document.anchors.length; i++) {
			if (document.anchors[i].name==anchorname) { found=1; break; }
			}
		if (found==0) {
			coordinates.x=0; coordinates.y=0; return coordinates;
			}
		x=document.anchors[i].x;
		y=document.anchors[i].y;
		}
	else {
		coordinates.x=0; coordinates.y=0; return coordinates;
		}
	coordinates.x=x;
	coordinates.y=y;
	return coordinates;
	}

// getAnchorWindowPosition(anchorname)
//   This function returns an object having .x and .y properties which are the coordinates
//   of the named anchor, relative to the window
function getAnchorWindowPosition(anchorname) {
	var coordinates=getAnchorPosition(anchorname);
	var x=0;
	var y=0;
	if (document.getElementById) {
		if (isNaN(window.screenX)) {
			x=coordinates.x-document.body.scrollLeft+window.screenLeft;
			y=coordinates.y-document.body.scrollTop+window.screenTop;
			}
		else {
			x=coordinates.x+window.screenX+(window.outerWidth-window.innerWidth)-window.pageXOffset;
			y=coordinates.y+window.screenY+(window.outerHeight-24-window.innerHeight)-window.pageYOffset;
			}
		}
	else if (document.all) {
		x=coordinates.x-document.body.scrollLeft+window.screenLeft;
		y=coordinates.y-document.body.scrollTop+window.screenTop;
		}
	else if (document.layers) {
		x=coordinates.x+window.screenX+(window.outerWidth-window.innerWidth)-window.pageXOffset;
		y=coordinates.y+window.screenY+(window.outerHeight-24-window.innerHeight)-window.pageYOffset;
		}
	coordinates.x=x;
	coordinates.y=y;
	return coordinates;
	}

// Functions for IE to get position of an object
function AnchorPosition_getPageOffsetLeft (el) {
	var ol=el.offsetLeft;
	while ((el=el.offsetParent) != null) { ol += el.offsetLeft; }
	return ol;
	}
function AnchorPosition_getWindowOffsetLeft (el) {
	return AnchorPosition_getPageOffsetLeft(el)-document.body.scrollLeft;
	}	
function AnchorPosition_getPageOffsetTop (el) {
	var ot=el.offsetTop;
	while((el=el.offsetParent) != null) { ot += el.offsetTop; }
	return ot;
	}
function AnchorPosition_getWindowOffsetTop (el) {
	return AnchorPosition_getPageOffsetTop(el)-document.body.scrollTop;
	}

/* SOURCE FILE: date.js */

// HISTORY
// ------------------------------------------------------------------
// May 17, 2003: Fixed bug in parseDate() for dates <1970
// March 11, 2003: Added parseDate() function
// March 11, 2003: Added "NNN" formatting option. Doesn't match up
//                 perfectly with SimpleDateFormat formats, but 
//                 backwards-compatability was required.

// ------------------------------------------------------------------
// These functions use the same 'format' strings as the 
// java.text.SimpleDateFormat class, with minor exceptions.
// The format string consists of the following abbreviations:
// 
// Field        | Full Form          | Short Form
// -------------+--------------------+-----------------------
// Year         | yyyy (4 digits)    | yy (2 digits), y (2 or 4 digits)
// Month        | MMM (name or abbr.)| MM (2 digits), M (1 or 2 digits)
//              | NNN (abbr.)        |
// Day of Month | dd (2 digits)      | d (1 or 2 digits)
// Day of Week  | EE (name)          | E (abbr)
// Hour (1-12)  | hh (2 digits)      | h (1 or 2 digits)
// Hour (0-23)  | HH (2 digits)      | H (1 or 2 digits)
// Hour (0-11)  | KK (2 digits)      | K (1 or 2 digits)
// Hour (1-24)  | kk (2 digits)      | k (1 or 2 digits)
// Minute       | mm (2 digits)      | m (1 or 2 digits)
// Second       | ss (2 digits)      | s (1 or 2 digits)
// AM/PM        | a                  |
//
// NOTE THE DIFFERENCE BETWEEN MM and mm! Month=MM, not mm!
// Examples:
//  "MMM d, y" matches: January 01, 2000
//                      Dec 1, 1900
//                      Nov 20, 00
//  "M/d/yy"   matches: 01/20/00
//                      9/2/00
//  "MMM dd, yyyy hh:mm:ssa" matches: "January 01, 2000 12:30:45AM"
// ------------------------------------------------------------------

var MONTH_NAMES = oLocale.getAllMonthNames();
var DAY_NAMES = oLocale.getAllDayNames();
function LZ(x) {return(x<0||x>9?"":"0")+x}

// ------------------------------------------------------------------
// isDate ( date_string, format_string )
// Returns true if date string matches format of format string and
// is a valid date. Else returns false.
// It is recommended that you trim whitespace around the value before
// passing it to this function, as whitespace is NOT ignored!
// ------------------------------------------------------------------
function isDate(val,format) {
	var date=getDateFromFormat(val,format);
	if (date==0) { return false; }
	return true;
	}

// -------------------------------------------------------------------
// compareDates(date1,date1format,date2,date2format)
//   Compare two date strings to see which is greater.
//   Returns:
//   1 if date1 is greater than date2
//   0 if date2 is greater than date1 of if they are the same
//  -1 if either of the dates is in an invalid format
// -------------------------------------------------------------------
function compareDates(date1,dateformat1,date2,dateformat2) {
	var d1=getDateFromFormat(date1,dateformat1);
	var d2=getDateFromFormat(date2,dateformat2);
	if (d1==0 || d2==0) {
		return -1;
		}
	else if (d1 > d2) {
		return 1;
		}
	return 0;
	}

// ------------------------------------------------------------------
// formatDate (date_object, format)
// Returns a date in the output format specified.
// The format string uses the same abbreviations as in getDateFromFormat()
// ------------------------------------------------------------------
function formatDate(date,format) {
	format=format+"";
	var result="";
	var i_format=0;
	var c="";
	var token="";
	var y=date.getYear()+"";
	var M=date.getMonth()+1;
	var d=date.getDate();
	var E=date.getDay();
	var H=date.getHours();
	var m=date.getMinutes();
	var s=date.getSeconds();
	var yyyy,yy,MMM,MM,dd,hh,h,mm,ss,ampm,HH,H,KK,K,kk,k;
	// Convert real date parts into formatted versions
	var value=new Object();
	if (y.length < 4) {y=""+(y-0+1900);}
	value["y"]=""+y;
	value["yyyy"]=y;
	value["yy"]=y.substring(2,4);
	value["M"]=M;
	value["MM"]=LZ(M);
	value["MMM"]=MONTH_NAMES[M-1];
	value["NNN"]=MONTH_NAMES[M+11];
	value["d"]=d;
	value["dd"]=LZ(d);
	value["E"]=DAY_NAMES[E+7];
	value["EE"]=DAY_NAMES[E];
	value["H"]=H;
	value["HH"]=LZ(H);
	if (H==0){value["h"]=12;}
	else if (H>12){value["h"]=H-12;}
	else {value["h"]=H;}
	value["hh"]=LZ(value["h"]);
	if (H>11){value["K"]=H-12;} else {value["K"]=H;}
	value["k"]=H+1;
	value["KK"]=LZ(value["K"]);
	value["kk"]=LZ(value["k"]);
	if (H > 11) { value["a"]="PM"; }
	else { value["a"]="AM"; }
	value["m"]=m;
	value["mm"]=LZ(m);
	value["s"]=s;
	value["ss"]=LZ(s);
	while (i_format < format.length) {
		c=format.charAt(i_format);
		token="";
		while ((format.charAt(i_format)==c) && (i_format < format.length)) {
			token += format.charAt(i_format++);
			}
		if (value[token] != null) { result=result + value[token]; }
		else { result=result + token; }
		}
	return result;
	}
	
// ------------------------------------------------------------------
// Utility functions for parsing in getDateFromFormat()
// ------------------------------------------------------------------
function _isInteger(val) {
	var digits="1234567890";
	for (var i=0; i < val.length; i++) {
		if (digits.indexOf(val.charAt(i))==-1) { return false; }
		}
	return true;
	}
function _getInt(str,i,minlength,maxlength) {
	for (var x=maxlength; x>=minlength; x--) {
		var token=str.substring(i,i+x);
		if (token.length < minlength) { return null; }
		if (_isInteger(token)) { return token; }
		}
	return null;
	}
	
// ------------------------------------------------------------------
// getDateFromFormat( date_string , format_string )
//
// This function takes a date string and a format string. It matches
// If the date string matches the format string, it returns the 
// getTime() of the date. If it does not match, it returns 0.
// ------------------------------------------------------------------
function getDateFromFormat(val,format) {
	val=val+"";
	format=format+"";
	var i_val=0;
	var i_format=0;
	var c="";
	var token="";
	var token2="";
	var x,y;
	var now=new Date();
	var year=now.getYear();
	var month=now.getMonth()+1;
	var date=1;
	var hh=now.getHours();
	var mm=now.getMinutes();
	var ss=now.getSeconds();
	var ampm="";
	
	while (i_format < format.length) {
		// Get next token from format string
		c=format.charAt(i_format);
		token="";
		while ((format.charAt(i_format)==c) && (i_format < format.length)) {
			token += format.charAt(i_format++);
			}
		// Extract contents of value based on format token
		if (token=="yyyy" || token=="yy" || token=="y") {
			if (token=="yyyy") { x=4;y=4; }
			if (token=="yy")   { x=2;y=2; }
			if (token=="y")    { x=2;y=4; }
			year=_getInt(val,i_val,x,y);
			if (year==null) { return 0; }
			i_val += year.length;
			if (year.length==2) {
				if (year > 70) { year=1900+(year-0); }
				else { year=2000+(year-0); }
				}
			}
		else if (token=="MMM"||token=="NNN"){
			month=0;
			for (var i=0; i<MONTH_NAMES.length; i++) {
				var month_name=MONTH_NAMES[i];
				if (val.substring(i_val,i_val+month_name.length).toLowerCase()==month_name.toLowerCase()) {
					if (token=="MMM"||(token=="NNN"&&i>11)) {
						month=i+1;
						if (month>12) { month -= 12; }
						i_val += month_name.length;
						break;
						}
					}
				}
			if ((month < 1)||(month>12)){return 0;}
			}
		else if (token=="EE"||token=="E"){
			for (var i=0; i<DAY_NAMES.length; i++) {
				var day_name=DAY_NAMES[i];
				if (val.substring(i_val,i_val+day_name.length).toLowerCase()==day_name.toLowerCase()) {
					i_val += day_name.length;
					break;
					}
				}
			}
		else if (token=="MM"||token=="M") {
			month=_getInt(val,i_val,token.length,2);
			if(month==null||(month<1)||(month>12)){return 0;}
			i_val+=month.length;}
		else if (token=="dd"||token=="d") {
			date=_getInt(val,i_val,token.length,2);
			if(date==null||(date<1)||(date>31)){return 0;}
			i_val+=date.length;}
		else if (token=="hh"||token=="h") {
			hh=_getInt(val,i_val,token.length,2);
			if(hh==null||(hh<1)||(hh>12)){return 0;}
			i_val+=hh.length;}
		else if (token=="HH"||token=="H") {
			hh=_getInt(val,i_val,token.length,2);
			if(hh==null||(hh<0)||(hh>23)){return 0;}
			i_val+=hh.length;}
		else if (token=="KK"||token=="K") {
			hh=_getInt(val,i_val,token.length,2);
			if(hh==null||(hh<0)||(hh>11)){return 0;}
			i_val+=hh.length;}
		else if (token=="kk"||token=="k") {
			hh=_getInt(val,i_val,token.length,2);
			if(hh==null||(hh<1)||(hh>24)){return 0;}
			i_val+=hh.length;hh--;}
		else if (token=="mm"||token=="m") {
			mm=_getInt(val,i_val,token.length,2);
			if(mm==null||(mm<0)||(mm>59)){return 0;}
			i_val+=mm.length;}
		else if (token=="ss"||token=="s") {
			ss=_getInt(val,i_val,token.length,2);
			if(ss==null||(ss<0)||(ss>59)){return 0;}
			i_val+=ss.length;}
		else if (token=="a") {
			if (val.substring(i_val,i_val+2).toLowerCase()=="am") {ampm="AM";}
			else if (val.substring(i_val,i_val+2).toLowerCase()=="pm") {ampm="PM";}
			else {return 0;}
			i_val+=2;}
		else {
			if (val.substring(i_val,i_val+token.length)!=token) {return 0;}
			else {i_val+=token.length;}
			}
		}
	// If there are any trailing characters left in the value, it doesn't match
	if (i_val != val.length) { return 0; }
	// Is date valid for month?
	if (month==2) {
		// Check for leap year
		if ( ( (year%4==0)&&(year%100 != 0) ) || (year%400==0) ) { // leap year
			if (date > 29){ return 0; }
			}
		else { if (date > 28) { return 0; } }
		}
	if ((month==4)||(month==6)||(month==9)||(month==11)) {
		if (date > 30) { return 0; }
		}
	// Correct hours value
	if (hh<12 && ampm=="PM") { hh=hh-0+12; }
	else if (hh>11 && ampm=="AM") { hh-=12; }
	var newdate=new Date(year,month-1,date,hh,mm,ss);
	return newdate.getTime();
	}

// ------------------------------------------------------------------
// parseDate( date_string [, prefer_euro_format] )
//
// This function takes a date string and tries to match it to a
// number of possible date formats to get the value. It will try to
// match against the following international formats, in this order:
// y-M-d   MMM d, y   MMM d,y   y-MMM-d   d-MMM-y  MMM d
// M/d/y   M-d-y      M.d.y     MMM-d     M/d      M-d
// d/M/y   d-M-y      d.M.y     d-MMM     d/M      d-M
// A second argument may be passed to instruct the method to search
// for formats like d/M/y (european format) before M/d/y (American).
// Returns a Date object or null if no patterns match.
// ------------------------------------------------------------------
function parseDate(val) {
	var preferEuro=(arguments.length==2)?arguments[1]:false;
	generalFormats=new Array('y-M-d','MMM d, y','MMM d,y','y-MMM-d','d-MMM-y','MMM d');
	monthFirst=new Array('M/d/y','M-d-y','M.d.y','MMM-d','M/d','M-d');
	dateFirst =new Array('d/M/y','d-M-y','d.M.y','d-MMM','d/M','d-M');
	var checkList=new Array('generalFormats',preferEuro?'dateFirst':'monthFirst',preferEuro?'monthFirst':'dateFirst');
	var d=null;
	for (var i=0; i<checkList.length; i++) {
		var l=window[checkList[i]];
		for (var j=0; j<l.length; j++) {
			d=getDateFromFormat(val,l[j]);
			if (d!=0) { return new Date(d); }
			}
		}
	return null;
	}

/* SOURCE FILE: PopupWindow.js */

/* 
PopupWindow.js
Author: Matt Kruse
Last modified: 02/16/04

DESCRIPTION: This object allows you to easily and quickly popup a window
in a certain place. The window can either be a DIV or a separate browser
window.

COMPATABILITY: Works with Netscape 4.x, 6.x, IE 5.x on Windows. Some small
positioning errors - usually with Window positioning - occur on the 
Macintosh platform. Due to bugs in Netscape 4.x, populating the popup 
window with <STYLE> tags may cause errors.

USAGE:
// Create an object for a WINDOW popup
var win = new PopupWindow(); 

// Create an object for a DIV window using the DIV named 'mydiv'
var win = new PopupWindow('mydiv'); 

// Set the window to automatically hide itself when the user clicks 
// anywhere else on the page except the popup
win.autoHide(); 

// Show the window relative to the anchor name passed in
win.showPopup(anchorname);

// Hide the popup
win.hidePopup();

// Set the size of the popup window (only applies to WINDOW popups
win.setSize(width,height);

// Populate the contents of the popup window that will be shown. If you 
// change the contents while it is displayed, you will need to refresh()
win.populate(string);

// set the URL of the window, rather than populating its contents
// manually
win.setUrl("http://www.site.com/");

// Refresh the contents of the popup
win.refresh();

// Specify how many pixels to the right of the anchor the popup will appear
win.offsetX = 50;

// Specify how many pixels below the anchor the popup will appear
win.offsetY = 100;

NOTES:
1) Requires the functions in AnchorPosition.js

2) Your anchor tag MUST contain both NAME and ID attributes which are the 
   same. For example:
   <A NAME="test" ID="test"> </A>

3) There must be at least a space between <A> </A> for IE5.5 to see the 
   anchor tag correctly. Do not do <A></A> with no space.

4) When a PopupWindow object is created, a handler for 'onmouseup' is
   attached to any event handler you may have already defined. Do NOT define
   an event handler for 'onmouseup' after you define a PopupWindow object or
   the autoHide() will not work correctly.
*/ 

// Set the position of the popup window based on the anchor
function PopupWindow_getXYPosition(anchorname) {
	var coordinates;
	if (this.type == "WINDOW") {
		coordinates = getAnchorWindowPosition(anchorname);
		}
	else {
		coordinates = getAnchorPosition(anchorname);
		}
	this.x = coordinates.x;
	this.y = coordinates.y;
	}
// Set width/height of DIV/popup window
function PopupWindow_setSize(width,height) {
	this.width = width;
	this.height = height;
	}
// Fill the window with contents
function PopupWindow_populate(contents) {
	this.contents = contents;
	this.populated = false;
	}
// Set the URL to go to
function PopupWindow_setUrl(url) {
	this.url = url;
	}
// Set the window popup properties
function PopupWindow_setWindowProperties(props) {
	this.windowProperties = props;
	}
// Refresh the displayed contents of the popup
function PopupWindow_refresh() {
	if (this.divName != null) {
		// refresh the DIV object
		if (this.use_gebi) {
			document.getElementById(this.divName).innerHTML = this.contents;
			}
		else if (this.use_css) { 
			document.all[this.divName].innerHTML = this.contents;
			}
		else if (this.use_layers) { 
			var d = document.layers[this.divName]; 
			d.document.open();
			d.document.writeln(this.contents);
			d.document.close();
			}
		}
	else {
		if (this.popupWindow != null && !this.popupWindow.closed) {
			if (this.url!="") {
				this.popupWindow.location.href=this.url;
				}
			else {
				this.popupWindow.document.open();
				this.popupWindow.document.writeln(this.contents);
				this.popupWindow.document.close();
			}
			this.popupWindow.focus();
			}
		}
	}
// Position and show the popup, relative to an anchor object
function PopupWindow_showPopup(anchorname) {
	this.getXYPosition(anchorname);
	this.x += this.offsetX;
	this.y += this.offsetY;
	
	// hide all selects
	$( 'select' ).css({ visibility: 'hidden' });
	
	if (!this.populated && (this.contents != "")) {
		this.populated = true;
		this.refresh();
		}
	if (this.divName != null) {
		// Show the DIV object
		if (this.use_gebi) {
			document.getElementById(this.divName).style.left = this.x + "px";
			document.getElementById(this.divName).style.top = this.y + "px";
			document.getElementById(this.divName).style.visibility = "visible";
			}
		else if (this.use_css) {
			document.all[this.divName].style.left = this.x;
			document.all[this.divName].style.top = this.y;
			document.all[this.divName].style.visibility = "visible";
			}
		else if (this.use_layers) {
			document.layers[this.divName].left = this.x;
			document.layers[this.divName].top = this.y;
			document.layers[this.divName].visibility = "visible";
			}
		}
	else {
		if (this.popupWindow == null || this.popupWindow.closed) {
			// If the popup window will go off-screen, move it so it doesn't
			if (this.x<0) { this.x=0; }
			if (this.y<0) { this.y=0; }
			if (screen && screen.availHeight) {
				if ((this.y + this.height) > screen.availHeight) {
					this.y = screen.availHeight - this.height;
					}
				}
			if (screen && screen.availWidth) {
				if ((this.x + this.width) > screen.availWidth) {
					this.x = screen.availWidth - this.width;
					}
				}
			var avoidAboutBlank = window.opera || ( document.layers && !navigator.mimeTypes['*'] ) || navigator.vendor == 'KDE' || ( document.childNodes && !document.all && !navigator.taintEnabled );
			this.popupWindow = window.open(avoidAboutBlank?"":"about:blank","window_"+anchorname,this.windowProperties+",width="+this.width+",height="+this.height+",screenX="+this.x+",left="+this.x+",screenY="+this.y+",top="+this.y+"");
			}
		this.refresh();
		}
	}
// Hide the popup
function PopupWindow_hidePopup() {
	
	// show all selects
	$( 'select' ).css({ visibility: 'visible' });

	if (this.divName != null) {
		if (this.use_gebi) {
			document.getElementById(this.divName).style.visibility = "hidden";
			}
		else if (this.use_css) {
			document.all[this.divName].style.visibility = "hidden";
			}
		else if (this.use_layers) {
			document.layers[this.divName].visibility = "hidden";
			}
		}
	else {
		if (this.popupWindow && !this.popupWindow.closed) {
			this.popupWindow.close();
			this.popupWindow = null;
			}
		}
	}
// Pass an event and return whether or not it was the popup DIV that was clicked
function PopupWindow_isClicked(e) {
	if (this.divName != null) {
		if (this.use_layers) {
			var clickX = e.pageX;
			var clickY = e.pageY;
			var t = document.layers[this.divName];
			if ((clickX > t.left) && (clickX < t.left+t.clip.width) && (clickY > t.top) && (clickY < t.top+t.clip.height)) {
				return true;
				}
			else { return false; }
			}
		else if (document.all) { // Need to hard-code this to trap IE for error-handling
			var t = window.event.srcElement;
			while (t.parentElement != null) {
				if (t.id==this.divName) {
					return true;
					}
				t = t.parentElement;
				}
			return false;
			}
		else if (this.use_gebi && e) {
			var t = e.originalTarget;
			while (t.parentNode != null) {
				if (t.id==this.divName) {
					return true;
					}
				t = t.parentNode;
				}
			return false;
			}
		return false;
		}
	return false;
	}

// Check an onMouseDown event to see if we should hide
function PopupWindow_hideIfNotClicked(e) {
	if (this.autoHideEnabled && !this.isClicked(e)) {
		this.hidePopup();
		}
	}
// Call this to make the DIV disable automatically when mouse is clicked outside it
function PopupWindow_autoHide() {
	this.autoHideEnabled = true;
	}
// This global function checks all PopupWindow objects onmouseup to see if they should be hidden
function PopupWindow_hidePopupWindows(e) {
	for (var i=0; i<popupWindowObjects.length; i++) {
		if (popupWindowObjects[i] != null) {
			var p = popupWindowObjects[i];
			p.hideIfNotClicked(e);
			}
		}
	}
// Run this immediately to attach the event listener
function PopupWindow_attachListener() {
	if (document.layers) {
		document.captureEvents(Event.MOUSEUP);
		}
	window.popupWindowOldEventListener = document.onmouseup;
	if (window.popupWindowOldEventListener != null) {
		document.onmouseup = new Function("window.popupWindowOldEventListener(); PopupWindow_hidePopupWindows();");
		}
	else {
		document.onmouseup = PopupWindow_hidePopupWindows;
		}
	}
// CONSTRUCTOR for the PopupWindow object
// Pass it a DIV name to use a DHTML popup, otherwise will default to window popup
function PopupWindow() {
	if (!window.popupWindowIndex) { window.popupWindowIndex = 0; }
	if (!window.popupWindowObjects) { window.popupWindowObjects = new Array(); }
	if (!window.listenerAttached) {
		window.listenerAttached = true;
		PopupWindow_attachListener();
		}
	this.index = popupWindowIndex++;
	popupWindowObjects[this.index] = this;
	this.divName = null;
	this.popupWindow = null;
	this.width=0;
	this.height=0;
	this.populated = false;
	this.visible = false;
	this.autoHideEnabled = false;
	
	this.contents = "";
	this.url="";
	this.windowProperties="toolbar=no,location=no,status=no,menubar=no,scrollbars=auto,resizable,alwaysRaised,dependent,titlebar=no";
	if (arguments.length>0) {
		this.type="DIV";
		this.divName = arguments[0];
		}
	else {
		this.type="WINDOW";
		}
	this.use_gebi = false;
	this.use_css = false;
	this.use_layers = false;
	if (document.getElementById) { this.use_gebi = true; }
	else if (document.all) { this.use_css = true; }
	else if (document.layers) { this.use_layers = true; }
	else { this.type = "WINDOW"; }
	this.offsetX = 0;
	this.offsetY = 0;
	// Method mappings
	this.getXYPosition = PopupWindow_getXYPosition;
	this.populate = PopupWindow_populate;
	this.setUrl = PopupWindow_setUrl;
	this.setWindowProperties = PopupWindow_setWindowProperties;
	this.refresh = PopupWindow_refresh;
	this.showPopup = PopupWindow_showPopup;
	this.hidePopup = PopupWindow_hidePopup;
	this.setSize = PopupWindow_setSize;
	this.isClicked = PopupWindow_isClicked;
	this.autoHide = PopupWindow_autoHide;
	this.hideIfNotClicked = PopupWindow_hideIfNotClicked;
	}

/* SOURCE FILE: CalendarPopup.js */

// HISTORY
// ------------------------------------------------------------------
// Feb 7, 2005: Fixed a CSS styles to use px unit
// March 29, 2004: Added check in select() method for the form field
//      being disabled. If it is, just return and don't do anything.
// March 24, 2004: Fixed bug - when month name and abbreviations were
//      changed, date format still used original values.
// January 26, 2004: Added support for drop-down month and year
//      navigation (Thanks to Chris Reid for the idea)
// September 22, 2003: Fixed a minor problem in YEAR calendar with
//      CSS prefix.
// August 19, 2003: Renamed the function to get styles, and made it
//      work correctly without an object reference
// August 18, 2003: Changed showYearNavigation and 
//      showYearNavigationInput to optionally take an argument of
//      true or false
// July 31, 2003: Added text input option for year navigation.
//      Added a per-calendar CSS prefix option to optionally use 
//      different styles for different calendars.
// July 29, 2003: Fixed bug causing the Today link to be clickable 
//      even though today falls in a disabled date range.
//      Changed formatting to use pure CSS, allowing greater control
//      over look-and-feel options.
// June 11, 2003: Fixed bug causing the Today link to be unselectable
//      under certain cases when some days of week are disabled
// March 14, 2003: Added ability to disable individual dates or date
//      ranges, display as light gray and strike-through
// March 14, 2003: Removed dependency on graypixel.gif and instead 
///     use table border coloring
// March 12, 2003: Modified showCalendar() function to allow optional
//      start-date parameter
// March 11, 2003: Modified select() function to allow optional
//      start-date parameter
/* 
DESCRIPTION: This object implements a popup calendar to allow the user to
select a date, month, quarter, or year.

COMPATABILITY: Works with Netscape 4.x, 6.x, IE 5.x on Windows. Some small
positioning errors - usually with Window positioning - occur on the 
Macintosh platform.
The calendar can be modified to work for any location in the world by 
changing which weekday is displayed as the first column, changing the month
names, and changing the column headers for each day.

USAGE:
// Create a new CalendarPopup object of type WINDOW
var cal = new CalendarPopup(); 

// Create a new CalendarPopup object of type DIV using the DIV named 'mydiv'
var cal = new CalendarPopup('mydiv'); 

// Easy method to link the popup calendar with an input box. 
cal.select(inputObject, anchorname, dateFormat);
// Same method, but passing a default date other than the field's current value
cal.select(inputObject, anchorname, dateFormat, '01/02/2000');
// This is an example call to the popup calendar from a link to populate an 
// input box. Note that to use this, date.js must also be included!!

<A HREF="#" onClick="cal.select(document.forms[0].date,'anchorname','MM/dd/yyyy'); return false;">Select</A>

// Set the type of date select to be used. By default it is 'date'.
cal.setDisplayType(type);

// When a date, month, quarter, or year is clicked, a function is called and
// passed the details. You must write this function, and tell the calendar
// popup what the function name is.
// Function to be called for 'date' select receives y, m, d
cal.setReturnFunction(functionname);
// Function to be called for 'month' select receives y, m
cal.setReturnMonthFunction(functionname);
// Function to be called for 'quarter' select receives y, q
cal.setReturnQuarterFunction(functionname);
// Function to be called for 'year' select receives y
cal.setReturnYearFunction(functionname);

// Show the calendar relative to a given anchor
cal.showCalendar(anchorname);

// Hide the calendar. The calendar is set to autoHide automatically
cal.hideCalendar();

// Set the month names to be used. Default are English month names
cal.setMonthNames("January","February","March",...);

// Set the month abbreviations to be used. Default are English month abbreviations
cal.setMonthAbbreviations("Jan","Feb","Mar",...);

// Show navigation for changing by the year, not just one month at a time
cal.showYearNavigation();

// Show month and year dropdowns, for quicker selection of month of dates
cal.showNavigationDropdowns();

// Set the text to be used above each day column. The days start with 
// sunday regardless of the value of WeekStartDay
cal.setDayHeaders("S","M","T",...);

// Set the day for the first column in the calendar grid. By default this
// is Sunday (0) but it may be changed to fit the conventions of other
// countries.
cal.setWeekStartDay(1); // week is Monday - Sunday

// Set the weekdays which should be disabled in the 'date' select popup. You can
// then allow someone to only select week end dates, or Tuedays, for example
cal.setDisabledWeekDays(0,1); // To disable selecting the 1st or 2nd days of the week

// Selectively disable individual days or date ranges. Disabled days will not
// be clickable, and show as strike-through text on current browsers.
// Date format is any format recognized by parseDate() in date.js
// Pass a single date to disable:
cal.addDisabledDates("2003-01-01");
// Pass null as the first parameter to mean "anything up to and including" the
// passed date:
cal.addDisabledDates(null, "01/02/03");
// Pass null as the second parameter to mean "including the passed date and
// anything after it:
cal.addDisabledDates("Jan 01, 2003", null);
// Pass two dates to disable all dates inbetween and including the two
cal.addDisabledDates("January 01, 2003", "Dec 31, 2003");

// When the 'year' select is displayed, set the number of years back from the 
// current year to start listing years. Default is 2.
// This is also used for year drop-down, to decide how many years +/- to display
cal.setYearSelectStartOffset(2);

// Text for the word "Today" appearing on the calendar
cal.setTodayText("Today");

// The calendar uses CSS classes for formatting. If you want your calendar to
// have unique styles, you can set the prefix that will be added to all the
// classes in the output.
// For example, normal output may have this:
//     <SPAN CLASS="cpTodayTextDisabled">Today<SPAN>
// But if you set the prefix like this:
cal.setCssPrefix("Test");
// The output will then look like:
//     <SPAN CLASS="TestcpTodayTextDisabled">Today<SPAN>
// And you can define that style somewhere in your page.

// When using Year navigation, you can make the year be an input box, so
// the user can manually change it and jump to any year
cal.showYearNavigationInput();

// Set the calendar offset to be different than the default. By default it
// will appear just below and to the right of the anchorname. So if you have
// a text box where the date will go and and anchor immediately after the
// text box, the calendar will display immediately under the text box.
cal.offsetX = 20;
cal.offsetY = 20;

NOTES:
1) Requires the functions in AnchorPosition.js and PopupWindow.js

2) Your anchor tag MUST contain both NAME and ID attributes which are the 
   same. For example:
   <A NAME="test" ID="test"> </A>

3) There must be at least a space between <A> </A> for IE5.5 to see the 
   anchor tag correctly. Do not do <A></A> with no space.

4) When a CalendarPopup object is created, a handler for 'onmouseup' is
   attached to any event handler you may have already defined. Do NOT define
   an event handler for 'onmouseup' after you define a CalendarPopup object 
   or the autoHide() will not work correctly.
   
5) The calendar popup display uses style sheets to make it look nice.

*/ 

// CONSTRUCTOR for the CalendarPopup Object
function CalendarPopup() {
	var c;
	if (arguments.length>0) {
		c = new PopupWindow(arguments[0]);
		}
	else {
		c = new PopupWindow();
		c.setSize(150,175);
		}
	c.offsetX = -152;
	c.offsetY = 25;
	c.autoHide();
	// Calendar-specific properties
	c.monthNames = oLocale.getMonthNames();
	c.monthAbbreviations = oLocale.getMonthAbbrevNames();
	c.dayHeaders = oLocale.getDayLetters();
	c.returnFunction = "CP_tmpReturnFunction";
	c.returnMonthFunction = "CP_tmpReturnMonthFunction";
	c.returnQuarterFunction = "CP_tmpReturnQuarterFunction";
	c.returnYearFunction = "CP_tmpReturnYearFunction";
	c.weekStartDay = 0;
	c.isShowYearNavigation = false;
	c.displayType = "date";
	c.disabledWeekDays = new Object();
	c.disabledDatesExpression = "";
	c.yearSelectStartOffset = 2;
	c.currentDate = null;
	c.todayText=oLocale.getTodayTitle();
	c.cssPrefix="";
	c.isShowNavigationDropdowns=false;
	c.isShowYearNavigationInput=false;
	window.CP_calendarObject = null;
	window.CP_targetInput = null;
	window.CP_dateFormat = "MM/dd/yyyy";
	// Method mappings
	c.copyMonthNamesToWindow = CP_copyMonthNamesToWindow;
	c.setReturnFunction = CP_setReturnFunction;
	c.setReturnMonthFunction = CP_setReturnMonthFunction;
	c.setReturnQuarterFunction = CP_setReturnQuarterFunction;
	c.setReturnYearFunction = CP_setReturnYearFunction;
	c.setMonthNames = CP_setMonthNames;
	c.setMonthAbbreviations = CP_setMonthAbbreviations;
	c.setDayHeaders = CP_setDayHeaders;
	c.setWeekStartDay = CP_setWeekStartDay;
	c.setDisplayType = CP_setDisplayType;
	c.setDisabledWeekDays = CP_setDisabledWeekDays;
	c.addDisabledDates = CP_addDisabledDates;
	c.setYearSelectStartOffset = CP_setYearSelectStartOffset;
	c.setTodayText = CP_setTodayText;
	c.showYearNavigation = CP_showYearNavigation;
	c.showCalendar = CP_showCalendar;
	c.hideCalendar = CP_hideCalendar;
	c.getStyles = getCalendarStyles;
	c.refreshCalendar = CP_refreshCalendar;
	c.getCalendar = CP_getCalendar;
	c.select = CP_select;
	c.setCssPrefix = CP_setCssPrefix;
	c.showNavigationDropdowns = CP_showNavigationDropdowns;
	c.showYearNavigationInput = CP_showYearNavigationInput;
	c.copyMonthNamesToWindow();
	// Return the object
	return c;
	}
function CP_copyMonthNamesToWindow() {
	// Copy these values over to the date.js 
	if (typeof(window.MONTH_NAMES)!="undefined" && window.MONTH_NAMES!=null) {
		window.MONTH_NAMES = new Array();
		for (var i=0; i<this.monthNames.length; i++) {
			window.MONTH_NAMES[window.MONTH_NAMES.length] = this.monthNames[i];
		}
		for (var i=0; i<this.monthAbbreviations.length; i++) {
			window.MONTH_NAMES[window.MONTH_NAMES.length] = this.monthAbbreviations[i];
		}
	}
}
// Temporary default functions to be called when items clicked, so no error is thrown
function CP_tmpReturnFunction(y,m,d) { 
	if (window.CP_targetInput!=null) {
		var dt = new Date(y,m-1,d,0,0,0);
		if (window.CP_calendarObject!=null) { window.CP_calendarObject.copyMonthNamesToWindow(); }
		window.CP_targetInput.value = formatDate(dt,window.CP_dateFormat);
		}
	else {
		alert('Use setReturnFunction() to define which function will get the clicked results!'); 
		}
	}
function CP_tmpReturnMonthFunction(y,m) { 
	alert('Use setReturnMonthFunction() to define which function will get the clicked results!\nYou clicked: year='+y+' , month='+m); 
	}
function CP_tmpReturnQuarterFunction(y,q) { 
	alert('Use setReturnQuarterFunction() to define which function will get the clicked results!\nYou clicked: year='+y+' , quarter='+q); 
	}
function CP_tmpReturnYearFunction(y) { 
	alert('Use setReturnYearFunction() to define which function will get the clicked results!\nYou clicked: year='+y); 
	}

// Set the name of the functions to call to get the clicked item
function CP_setReturnFunction(name) { this.returnFunction = name; }
function CP_setReturnMonthFunction(name) { this.returnMonthFunction = name; }
function CP_setReturnQuarterFunction(name) { this.returnQuarterFunction = name; }
function CP_setReturnYearFunction(name) { this.returnYearFunction = name; }

// Over-ride the built-in month names
function CP_setMonthNames() {
	for (var i=0; i<arguments.length; i++) { this.monthNames[i] = arguments[i]; }
	this.copyMonthNamesToWindow();
	}

// Over-ride the built-in month abbreviations
function CP_setMonthAbbreviations() {
	for (var i=0; i<arguments.length; i++) { this.monthAbbreviations[i] = arguments[i]; }
	this.copyMonthNamesToWindow();
	}

// Over-ride the built-in column headers for each day
function CP_setDayHeaders() {
	for (var i=0; i<arguments.length; i++) { this.dayHeaders[i] = arguments[i]; }
	}

// Set the day of the week (0-7) that the calendar display starts on
// This is for countries other than the US whose calendar displays start on Monday(1), for example
function CP_setWeekStartDay(day) { this.weekStartDay = day; }

// Show next/last year navigation links
function CP_showYearNavigation() { this.isShowYearNavigation = (arguments.length>0)?arguments[0]:true; }

// Which type of calendar to display
function CP_setDisplayType(type) {
	if (type!="date"&&type!="week-end"&&type!="month"&&type!="quarter"&&type!="year") { alert("Invalid display type! Must be one of: date,week-end,month,quarter,year"); return false; }
	this.displayType=type;
	}

// How many years back to start by default for year display
function CP_setYearSelectStartOffset(num) { this.yearSelectStartOffset=num; }

// Set which weekdays should not be clickable
function CP_setDisabledWeekDays() {
	this.disabledWeekDays = new Object();
	for (var i=0; i<arguments.length; i++) { this.disabledWeekDays[arguments[i]] = true; }
	}
	
// Disable individual dates or ranges
// Builds an internal logical test which is run via eval() for efficiency
function CP_addDisabledDates(start, end) {
	if (arguments.length==1) { end=start; }
	if (start==null && end==null) { return; }
	if (this.disabledDatesExpression!="") { this.disabledDatesExpression+= "||"; }
	if (start!=null) { start = parseDate(start); start=""+start.getFullYear()+LZ(start.getMonth()+1)+LZ(start.getDate());}
	if (end!=null) { end=parseDate(end); end=""+end.getFullYear()+LZ(end.getMonth()+1)+LZ(end.getDate());}
	if (start==null) { this.disabledDatesExpression+="(ds<="+end+")"; }
	else if (end  ==null) { this.disabledDatesExpression+="(ds>="+start+")"; }
	else { this.disabledDatesExpression+="(ds>="+start+"&&ds<="+end+")"; }
	}
	
// Set the text to use for the "Today" link
function CP_setTodayText(text) {
	this.todayText = text;
	}

// Set the prefix to be added to all CSS classes when writing output
function CP_setCssPrefix(val) { 
	this.cssPrefix = val; 
	}

// Show the navigation as an dropdowns that can be manually changed
function CP_showNavigationDropdowns() { this.isShowNavigationDropdowns = (arguments.length>0)?arguments[0]:true; }

// Show the year navigation as an input box that can be manually changed
function CP_showYearNavigationInput() { this.isShowYearNavigationInput = (arguments.length>0)?arguments[0]:true; }

// Hide a calendar object
function CP_hideCalendar() {
	if (arguments.length > 0) { window.popupWindowObjects[arguments[0]].hidePopup(); }
	else { this.hidePopup(); }
	}

// Refresh the contents of the calendar display
function CP_refreshCalendar(index) {
	var calObject = window.popupWindowObjects[index];
	if (arguments.length>1) { 
		calObject.populate(calObject.getCalendar(arguments[1],arguments[2],arguments[3],arguments[4],arguments[5]));
		}
	else {
		calObject.populate(calObject.getCalendar());
		}
	calObject.refresh();
	}

// Populate the calendar and display it
function CP_showCalendar(anchorname) {
	if (arguments.length>1) {
		if (arguments[1]==null||arguments[1]=="") {
			this.currentDate=new Date();
			}
		else {
			this.currentDate=new Date(parseDate(arguments[1]));
			}
		}
	this.populate(this.getCalendar());
	this.showPopup(anchorname);
	}

// Simple method to interface popup calendar with a text-entry box
function CP_select(inputobj, linkname, format) {
	var selectedDate=(arguments.length>3)?arguments[3]:null;
	if (!window.getDateFromFormat) {
		alert("calendar.select: To use this method you must also include 'date.js' for date formatting");
		return;
		}
	if (this.displayType!="date"&&this.displayType!="week-end") {
		alert("calendar.select: This function can only be used with displayType 'date' or 'week-end'");
		return;
		}

	if (inputobj.disabled) { return; } // Can't use calendar input on disabled form input!
	window.CP_targetInput = inputobj;
	window.CP_calendarObject = this;
	this.currentDate=null;
	var time=0;
	if (selectedDate!=null) {
		time = getDateFromFormat(selectedDate,format)
		}
	else if (inputobj.value!="") {
		time = getDateFromFormat(inputobj.value,format);
		}
	if (selectedDate!=null || inputobj.value!="") {
		if (time==0) { this.currentDate=null; }
		else { this.currentDate=new Date(time); }
		}
	window.CP_dateFormat = format;
	this.showCalendar(linkname);
	}
	
// Get style block needed to display the calendar correctly
function getCalendarStyles() {
	var result = "";
	var p = "";
	if (this!=null && typeof(this.cssPrefix)!="undefined" && this.cssPrefix!=null && this.cssPrefix!="") { p=this.cssPrefix; }
	result += "<STYLE>\n";
	result += "."+p+"cpYearNavigation,."+p+"cpMonthNavigation { background-color:#C0C0C0; text-align:center; vertical-align:center; text-decoration:none; color:#000000; font-weight:bold; }\n";
	result += "."+p+"cpDayColumnHeader, ."+p+"cpYearNavigation,."+p+"cpMonthNavigation,."+p+"cpCurrentMonthDate,."+p+"cpCurrentMonthDateDisabled,."+p+"cpOtherMonthDate,."+p+"cpOtherMonthDateDisabled,."+p+"cpCurrentDate,."+p+"cpCurrentDateDisabled,."+p+"cpTodayText,."+p+"cpTodayTextDisabled,."+p+"cpText { font-family:arial; font-size:8pt; }\n";
	result += "TD."+p+"cpDayColumnHeader { text-align:right; border:solid thin #C0C0C0;border-width:0px 0px 1px 0px; }\n";
	result += "."+p+"cpCurrentMonthDate, ."+p+"cpOtherMonthDate, ."+p+"cpCurrentDate  { text-align:right; text-decoration:none; }\n";
	result += "."+p+"cpCurrentMonthDateDisabled, ."+p+"cpOtherMonthDateDisabled, ."+p+"cpCurrentDateDisabled { color:#D0D0D0; text-align:right; text-decoration:line-through; }\n";
	result += "."+p+"cpCurrentMonthDate, .cpCurrentDate { color:#000000; }\n";
	result += "."+p+"cpOtherMonthDate { color:#808080; }\n";
	result += "TD."+p+"cpCurrentDate { color:white; background-color: #C0C0C0; border-width:1px; border:solid thin #800000; }\n";
	result += "TD."+p+"cpCurrentDateDisabled { border-width:1px; border:solid thin #FFAAAA; }\n";
	result += "TD."+p+"cpTodayText, TD."+p+"cpTodayTextDisabled { border:solid thin #C0C0C0; border-width:1px 0px 0px 0px;}\n";
	result += "A."+p+"cpTodayText, SPAN."+p+"cpTodayTextDisabled { height:20px; }\n";
	result += "A."+p+"cpTodayText { color:black; }\n";
	result += "."+p+"cpTodayTextDisabled { color:#D0D0D0; }\n";
	result += "."+p+"cpBorder { border:solid thin #808080; }\n";
	result += "</STYLE>\n";
	return result;
	}

// Return a string containing all the calendar code to be displayed
function CP_getCalendar() {
	var now = new Date();
	// Reference to window
	if (this.type == "WINDOW") { var windowref = "window.opener."; }
	else { var windowref = ""; }
	var result = "";
	// If POPUP, write entire HTML document
	if (this.type == "WINDOW") {
		result += "<HTML><HEAD><TITLE>Calendar</TITLE>"+this.getStyles()+"</HEAD><BODY MARGINWIDTH=0 MARGINHEIGHT=0 TOPMARGIN=0 RIGHTMARGIN=0 LEFTMARGIN=0>\n";
		result += '<CENTER><TABLE WIDTH=100% BORDER=0 BORDERWIDTH=0 CELLSPACING=0 CELLPADDING=0>\n';
		}
	else {
		result += '<TABLE CLASS="'+this.cssPrefix+'cpBorder" WIDTH=144 BORDER=1 BORDERWIDTH=1 CELLSPACING=0 CELLPADDING=1>\n';
		result += '<TR><TD ALIGN=CENTER>\n';
		result += '<CENTER>\n';
		}
	// Code for DATE display (default)
	// -------------------------------
	if (this.displayType=="date" || this.displayType=="week-end") {
		if (this.currentDate==null) { this.currentDate = now; }
		if (arguments.length > 0) { var month = arguments[0]; }
			else { var month = this.currentDate.getMonth()+1; }
		if (arguments.length > 1 && arguments[1]>0 && arguments[1]-0==arguments[1]) { var year = arguments[1]; }
			else { var year = this.currentDate.getFullYear(); }
		var daysinmonth= new Array(0,31,28,31,30,31,30,31,31,30,31,30,31);
		if ( ( (year%4 == 0)&&(year%100 != 0) ) || (year%400 == 0) ) {
			daysinmonth[2] = 29;
			}
		var current_month = new Date(year,month-1,1);
		var display_year = year;
		var display_month = month;
		var display_date = 1;
		var weekday= current_month.getDay();
		var offset = 0;
		
		offset = (weekday >= this.weekStartDay) ? weekday-this.weekStartDay : 7-this.weekStartDay+weekday ;
		if (offset > 0) {
			display_month--;
			if (display_month < 1) { display_month = 12; display_year--; }
			display_date = daysinmonth[display_month]-offset+1;
			}
		var next_month = month+1;
		var next_month_year = year;
		if (next_month > 12) { next_month=1; next_month_year++; }
		var last_month = month-1;
		var last_month_year = year;
		if (last_month < 1) { last_month=12; last_month_year--; }
		var date_class;
		if (this.type!="WINDOW") {
			result += '<TABLE WIDTH="180" BORDER=0 BORDERWIDTH=0 CELLSPACING=0 CELLPADDING=0>';
			}
		result += '<TR>\n';
		var refresh = windowref+'CP_refreshCalendar';
		var refreshLink = 'javascript:' + refresh;
		if (this.isShowNavigationDropdowns) {
			result += '<TD CLASS="'+this.cssPrefix+'cpMonthNavigation" WIDTH="78" COLSPAN="3"><select CLASS="'+this.cssPrefix+'cpMonthNavigation" name="cpMonth" onChange="'+refresh+'('+this.index+',this.options[this.selectedIndex].value-0,'+(year-0)+');">';
			for( var monthCounter=1; monthCounter<=12; monthCounter++ ) {
				var selected = (monthCounter==month) ? 'SELECTED' : '';
				result += '<option value="'+monthCounter+'" '+selected+'>'+this.monthNames[monthCounter-1]+'</option>';
				}
			result += '</select></TD>';
			result += '<TD CLASS="'+this.cssPrefix+'cpMonthNavigation" WIDTH="10">&nbsp;</TD>';

			result += '<TD CLASS="'+this.cssPrefix+'cpYearNavigation" WIDTH="56" COLSPAN="3"><select CLASS="'+this.cssPrefix+'cpYearNavigation" name="cpYear" onChange="'+refresh+'('+this.index+','+month+',this.options[this.selectedIndex].value-0);">';
			for( var yearCounter=year-this.yearSelectStartOffset; yearCounter<=year+this.yearSelectStartOffset; yearCounter++ ) {
				var selected = (yearCounter==year) ? 'SELECTED' : '';
				result += '<option value="'+yearCounter+'" '+selected+'>'+yearCounter+'</option>';
				}
			result += '</select></TD>';
			}
		else {
			if (this.isShowYearNavigation) {
				result += '<TD CLASS="'+this.cssPrefix+'cpMonthNavigation" WIDTH="10"><A CLASS="'+this.cssPrefix+'cpMonthNavigation" HREF="'+refreshLink+'('+this.index+','+last_month+','+last_month_year+');">&lt;</A></TD>';
				result += '<TD CLASS="'+this.cssPrefix+'cpMonthNavigation" WIDTH="110"><SPAN CLASS="'+this.cssPrefix+'cpMonthNavigation">'+this.monthNames[month-1]+'</SPAN></TD>';
				result += '<TD CLASS="'+this.cssPrefix+'cpMonthNavigation" WIDTH="10"><A CLASS="'+this.cssPrefix+'cpMonthNavigation" HREF="'+refreshLink+'('+this.index+','+next_month+','+next_month_year+');">&gt;</A></TD>';
				result += '<TD CLASS="'+this.cssPrefix+'cpMonthNavigation" WIDTH="10">&nbsp;</TD>';

				result += '<TD CLASS="'+this.cssPrefix+'cpYearNavigation" WIDTH="10"><A CLASS="'+this.cssPrefix+'cpYearNavigation" HREF="'+refreshLink+'('+this.index+','+month+','+(year-1)+');">&lt;</A></TD>';
				if (this.isShowYearNavigationInput) {
					result += '<TD CLASS="'+this.cssPrefix+'cpYearNavigation" WIDTH="36"><INPUT NAME="cpYear" CLASS="'+this.cssPrefix+'cpYearNavigation" SIZE="4" MAXLENGTH="4" VALUE="'+year+'" onBlur="'+refresh+'('+this.index+','+month+',this.value-0);"></TD>';
					}
				else {
					result += '<TD CLASS="'+this.cssPrefix+'cpYearNavigation" WIDTH="36"><SPAN CLASS="'+this.cssPrefix+'cpYearNavigation">'+year+'</SPAN></TD>';
					}
				result += '<TD CLASS="'+this.cssPrefix+'cpYearNavigation" WIDTH="10"><A CLASS="'+this.cssPrefix+'cpYearNavigation" HREF="'+refreshLink+'('+this.index+','+month+','+(year+1)+');">&gt;</A></TD>';
				}
			else {
				result += '<TD CLASS="'+this.cssPrefix+'cpMonthNavigation" WIDTH="22"><A CLASS="'+this.cssPrefix+'cpMonthNavigation" HREF="'+refreshLink+'('+this.index+','+last_month+','+last_month_year+');">&lt;&lt;</A></TD>\n';
				result += '<TD CLASS="'+this.cssPrefix+'cpMonthNavigation" WIDTH="100"><SPAN CLASS="'+this.cssPrefix+'cpMonthNavigation">'+this.monthNames[month-1]+' '+year+'</SPAN></TD>\n';
				result += '<TD CLASS="'+this.cssPrefix+'cpMonthNavigation" WIDTH="22"><A CLASS="'+this.cssPrefix+'cpMonthNavigation" HREF="'+refreshLink+'('+this.index+','+next_month+','+next_month_year+');">&gt;&gt;</A></TD>\n';
				}
			}
		result += '</TR></TABLE>\n';
		result += '<TABLE WIDTH=120 BORDER=0 CELLSPACING=0 CELLPADDING=1 ALIGN=CENTER>\n';
		result += '<TR>\n';
		for (var j=0; j<7; j++) {

			result += '<TD CLASS="'+this.cssPrefix+'cpDayColumnHeader" WIDTH="14%"><SPAN CLASS="'+this.cssPrefix+'cpDayColumnHeader">'+this.dayHeaders[(this.weekStartDay+j)%7]+'</TD>\n';
			}
		result += '</TR>\n';
		for (var row=1; row<=6; row++) {
			result += '<TR>\n';
			for (var col=1; col<=7; col++) {
				var disabled=false;
				if (this.disabledDatesExpression!="") {
					var ds=""+display_year+LZ(display_month)+LZ(display_date);
					eval("disabled=("+this.disabledDatesExpression+")");
					}
				var dateClass = "";
				if ((display_month == this.currentDate.getMonth()+1) && (display_date==this.currentDate.getDate()) && (display_year==this.currentDate.getFullYear())) {
					dateClass = "cpCurrentDate";
					}
				else if (display_month == month) {
					dateClass = "cpCurrentMonthDate";
					}
				else {
					dateClass = "cpOtherMonthDate";
					}
				if (disabled || this.disabledWeekDays[col-1]) {
					result += '	<TD CLASS="'+this.cssPrefix+dateClass+'"><SPAN CLASS="'+this.cssPrefix+dateClass+'Disabled">'+display_date+'</SPAN></TD>\n';
					}
				else {
					var selected_date = display_date;
					var selected_month = display_month;
					var selected_year = display_year;
					if (this.displayType=="week-end") {
						var d = new Date(selected_year,selected_month-1,selected_date,0,0,0,0);
						d.setDate(d.getDate() + (7-col));
						selected_year = d.getYear();
						if (selected_year < 1000) { selected_year += 1900; }
						selected_month = d.getMonth()+1;
						selected_date = d.getDate();
						}
					result += '	<TD CLASS="'+this.cssPrefix+dateClass+'"><A HREF="javascript:'+windowref+this.returnFunction+'('+selected_year+','+selected_month+','+selected_date+');'+windowref+'CP_hideCalendar(\''+this.index+'\');" CLASS="'+this.cssPrefix+dateClass+'">'+display_date+'</A></TD>\n';
					}
				display_date++;
				if (display_date > daysinmonth[display_month]) {
					display_date=1;
					display_month++;
					}
				if (display_month > 12) {
					display_month=1;
					display_year++;
					}
				}
			result += '</TR>';
			}
		var current_weekday = now.getDay() - this.weekStartDay;
		if (current_weekday < 0) {
			current_weekday += 7;
			}
		result += '<TR>\n';
		result += '	<TD COLSPAN=7 ALIGN=CENTER CLASS="'+this.cssPrefix+'cpTodayText">\n';
		if (this.disabledDatesExpression!="") {
			var ds=""+now.getFullYear()+LZ(now.getMonth()+1)+LZ(now.getDate());
			eval("disabled=("+this.disabledDatesExpression+")");
			}
		if (disabled || this.disabledWeekDays[current_weekday+1]) {
			result += '		<SPAN CLASS="'+this.cssPrefix+'cpTodayTextDisabled">'+this.todayText+'</SPAN>\n';
			}
		else {
			result += '		<A CLASS="'+this.cssPrefix+'cpTodayText" HREF="javascript:'+windowref+this.returnFunction+'(\''+now.getFullYear()+'\',\''+(now.getMonth()+1)+'\',\''+now.getDate()+'\');'+windowref+'CP_hideCalendar(\''+this.index+'\');">'+this.todayText+'</A>\n';
			}
		result += '		<BR>\n';
		result += '	</TD></TR></TABLE></CENTER></TD></TR></TABLE>\n';
	}

	// Code common for MONTH, QUARTER, YEAR
	// ------------------------------------
	if (this.displayType=="month" || this.displayType=="quarter" || this.displayType=="year") {
		if (arguments.length > 0) { var year = arguments[0]; }
		else { 
			if (this.displayType=="year") {	var year = now.getFullYear()-this.yearSelectStartOffset; }
			else { var year = now.getFullYear(); }
			}
		if (this.displayType!="year" && this.isShowYearNavigation) {
			result += "<TABLE WIDTH=144 BORDER=0 BORDERWIDTH=0 CELLSPACING=0 CELLPADDING=0>";
			result += '<TR>\n';
			result += '	<TD CLASS="'+this.cssPrefix+'cpYearNavigationBack" WIDTH="22"><A CLASS="'+this.cssPrefix+'cpYearNavigation" HREF="javascript:'+windowref+'CP_refreshCalendar('+this.index+','+(year-1)+');">&lt;&lt;</A></TD>\n';
			result += '	<TD CLASS="'+this.cssPrefix+'cpYearNavigation" WIDTH="100">'+year+'</TD>\n';
			result += '	<TD CLASS="'+this.cssPrefix+'cpYearNavigationNext" WIDTH="22"><A CLASS="'+this.cssPrefix+'cpYearNavigation" HREF="javascript:'+windowref+'CP_refreshCalendar('+this.index+','+(year+1)+');">&gt;&gt;</A></TD>\n';
			result += '</TR></TABLE>\n';
			}
		}
		
	// Code for MONTH display 
	// ----------------------
	if (this.displayType=="month") {
		// If POPUP, write entire HTML document
		result += '<TABLE WIDTH=120 BORDER=0 CELLSPACING=1 CELLPADDING=0 ALIGN=CENTER class="calMonths">\n';
		for (var i=0; i<4; i++) {
			result += '<TR>';
			for (var j=0; j<3; j++) {
				var monthindex = ((i*3)+j);
				result += '<TD WIDTH=33% ALIGN=CENTER><A CLASS="'+this.cssPrefix+'cpText" HREF="javascript:'+windowref+this.returnMonthFunction+'('+year+','+(monthindex+1)+');'+windowref+'CP_hideCalendar(\''+this.index+'\');" CLASS="'+date_class+'">'+this.monthAbbreviations[monthindex]+'</A></TD>';
				}
			result += '</TR>';
			}
		result += '</TABLE></CENTER></TD></TR></TABLE>\n';
		}
	
	// Code for QUARTER display
	// ------------------------
	if (this.displayType=="quarter") {
		result += '<BR><TABLE WIDTH=120 BORDER=1 CELLSPACING=0 CELLPADDING=0 ALIGN=CENTER>\n';
		for (var i=0; i<2; i++) {
			result += '<TR>';
			for (var j=0; j<2; j++) {
				var quarter = ((i*2)+j+1);
				result += '<TD WIDTH=50% ALIGN=CENTER><BR><A CLASS="'+this.cssPrefix+'cpText" HREF="javascript:'+windowref+this.returnQuarterFunction+'('+year+','+quarter+');'+windowref+'CP_hideCalendar(\''+this.index+'\');" CLASS="'+date_class+'">Q'+quarter+'</A><BR><BR></TD>';
				}
			result += '</TR>';
			}
		result += '</TABLE></CENTER></TD></TR></TABLE>\n';
		}

	// Code for YEAR display
	// ---------------------
	if (this.displayType=="year") {
		var yearColumnSize = 4;
		result += "<TABLE WIDTH=144 BORDER=0 BORDERWIDTH=0 CELLSPACING=0 CELLPADDING=0>";
		result += '<TR>\n';
		result += '	<TD CLASS="'+this.cssPrefix+'cpYearNavigation" WIDTH="50%"><A CLASS="'+this.cssPrefix+'cpYearNavigation" HREF="javascript:'+windowref+'CP_refreshCalendar('+this.index+','+(year-(yearColumnSize*2))+');">&lt;&lt;</A></TD>\n';
		result += '	<TD CLASS="'+this.cssPrefix+'cpYearNavigation" WIDTH="50%"><A CLASS="'+this.cssPrefix+'cpYearNavigation" HREF="javascript:'+windowref+'CP_refreshCalendar('+this.index+','+(year+(yearColumnSize*2))+');">&gt;&gt;</A></TD>\n';
		result += '</TR></TABLE>\n';
		result += '<TABLE WIDTH=120 BORDER=0 CELLSPACING=1 CELLPADDING=0 ALIGN=CENTER>\n';
		for (var i=0; i<yearColumnSize; i++) {
			for (var j=0; j<2; j++) {
				var currentyear = year+(j*yearColumnSize)+i;
				result += '<TD WIDTH=50% ALIGN=CENTER><A CLASS="'+this.cssPrefix+'cpText" HREF="javascript:'+windowref+this.returnYearFunction+'('+currentyear+');'+windowref+'CP_hideCalendar(\''+this.index+'\');" CLASS="'+date_class+'">'+currentyear+'</A></TD>';
				}
			result += '</TR>';
			}
		result += '</TABLE></CENTER></TD></TR></TABLE>\n';
		}
	// Common
	if (this.type == "WINDOW") {
		result += "</BODY></HTML>\n";
		}
	return result;
	}
/* jAutocomplete.js (120) */
/***
 * jQuery Autocomplete plugin 1.1
 *
 * Copyright (c) 2009 JÃ¶rn Zaefferer
 *
 * 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: jquery.autocomplete.js 15 2009-08-22 10:30:27Z joern.zaefferer $
 */

;(function($) {

$.fn.extend({
	autocomplete: function(urlOrData, options) {
		var isUrl = typeof urlOrData == "string";
		options = $.extend({}, $.Autocompleter.defaults, {
			url: isUrl ? urlOrData : null,
			data: isUrl ? null : urlOrData,
			delay: isUrl ? $.Autocompleter.defaults.delay : 10,
			max: options && !options.scroll ? 10 : 150
		}, options);

		// if highlight is set to false, replace it with a do-nothing function
		options.highlight = options.highlight || function(value) { return value; };

		// if the formatMatch option is not specified, then use formatItem for backwards compatibility
		options.formatMatch = options.formatMatch || options.formatItem;

		return this.each(function() {
			new $.Autocompleter(this, options);
		});
	},
	result: function(handler) {
		return this.bind("result", handler);
	},
	search: function(handler) {
		return this.trigger("search", [handler]);
	},
	flushCache: function() {
		return this.trigger("flushCache");
	},
	setOptions: function(options){
		return this.trigger("setOptions", [options]);
	},
	unautocomplete: function() {
		return this.trigger("unautocomplete");
	}
});

$.Autocompleter = function(input, options) {

	var KEY = {
		UP: 38,
		DOWN: 40,
		DEL: 46,
		TAB: 9,
		RETURN: 13,
		ESC: 27,
		COMMA: 188,
		PAGEUP: 33,
		PAGEDOWN: 34,
		BACKSPACE: 8
	};

	// Create $ object for input element
	var $input = $(input).attr("autocomplete", "off").addClass(options.inputClass);

	var timeout;
	var previousValue = "";
	var cache = $.Autocompleter.Cache(options);
	var hasFocus = 0;
	var lastKeyPressCode;
	var config = {
		mouseDownOnSelect: false
	};
	var select = $.Autocompleter.Select(options, input, selectCurrent, config);

	var blockSubmit;

	// prevent form submit in opera when selecting with return key
	$.browser.opera && $(input.form).bind("submit.autocomplete", function() {
		if (blockSubmit) {
			blockSubmit = false;
			return false;
		}
	});

	// only opera doesn't trigger keydown multiple times while pressed, others don't work with keypress at all
	$input.bind(($.browser.opera ? "keypress" : "keydown") + ".autocomplete", function(event) {
		// a keypress means the input has focus
		// avoids issue where input had focus before the autocomplete was applied
		hasFocus = 1;
		// track last key pressed
		lastKeyPressCode = event.keyCode;
		switch(event.keyCode) {

			case KEY.UP:
				event.preventDefault();
				if ( select.visible() ) {
					select.prev();
				} else {
					onChange(0, true);
				}
				break;

			case KEY.DOWN:
				event.preventDefault();
				if ( select.visible() ) {
					select.next();
				} else {
					onChange(0, true);
				}
				break;

			case KEY.PAGEUP:
				event.preventDefault();
				if ( select.visible() ) {
					select.pageUp();
				} else {
					onChange(0, true);
				}
				break;

			case KEY.PAGEDOWN:
				event.preventDefault();
				if ( select.visible() ) {
					select.pageDown();
				} else {
					onChange(0, true);
				}
				break;

			// matches also semicolon
			case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA:
			case KEY.TAB:
			case KEY.RETURN:
				if( selectCurrent() ) {
					// stop default to prevent a form submit, Opera needs special handling
					event.preventDefault();
					blockSubmit = true;
					return false;
				}
				break;

			case KEY.ESC:
				select.hide();
				break;

			default:
				clearTimeout(timeout);
				timeout = setTimeout(onChange, options.delay);
				break;
		}
	}).focus(function(){
		// track whether the field has focus, we shouldn't process any
		// results if the field no longer has focus
		hasFocus++;
	}).blur(function() {
		hasFocus = 0;
		if (!config.mouseDownOnSelect) {
			hideResults();
		}
	}).click(function() {
		// show select when clicking in a focused field
		if ( hasFocus++ > 1 && !select.visible() ) {
			onChange(0, true);
		}
	}).bind("search", function() {
		// TODO why not just specifying both arguments?
		var fn = (arguments.length > 1) ? arguments[1] : null;
		function findValueCallback(q, data) {
			var result;
			if( data && data.length ) {
				for (var i=0; i < data.length; i++) {
					if( data[i].result.toLowerCase() == q.toLowerCase() ) {
						result = data[i];
						break;
					}
				}
			}
			if( typeof fn == "function" ) fn(result);
			else $input.trigger("result", result && [result.data, result.value]);
		}
		$.each(trimWords($input.val()), function(i, value) {
			request(value, findValueCallback, findValueCallback);
		});
	}).bind("flushCache", function() {
		cache.flush();
	}).bind("setOptions", function() {
		$.extend(options, arguments[1]);
		// if we've updated the data, repopulate
		if ( "data" in arguments[1] )
			cache.populate();
	}).bind("unautocomplete", function() {
		select.unbind();
		$input.unbind();
		$(input.form).unbind(".autocomplete");
	});


	function selectCurrent() {
		var selected = select.selected();
		if( !selected )
			return false;

		var v = selected.result;
		previousValue = v;

		if ( options.multiple ) {
			var words = trimWords($input.val());
			if ( words.length > 1 ) {
				var seperator = options.multipleSeparator.length;
				var cursorAt = $(input).selection().start;
				var wordAt, progress = 0;
				$.each(words, function(i, word) {
					progress += word.length;
					if (cursorAt <= progress) {
						wordAt = i;
						return false;
					}
					progress += seperator;
				});
				words[wordAt] = v;
				// TODO this should set the cursor to the right position, but it gets overriden somewhere
				//$.Autocompleter.Selection(input, progress + seperator, progress + seperator);
				v = words.join( options.multipleSeparator );
			}
			v += options.multipleSeparator;
		}

		$input.val(v);
		hideResultsNow();
		$input.trigger("result", [selected.data, selected.value]);
		return true;
	}

	function onChange(crap, skipPrevCheck) {
		if( lastKeyPressCode == KEY.DEL ) {
			select.hide();
			return;
		}

		var currentValue = $input.val();

		if ( !skipPrevCheck && currentValue == previousValue )
			return;

		previousValue = currentValue;

		currentValue = lastWord(currentValue);
		if ( currentValue.length >= options.minChars) {
			$input.addClass(options.loadingClass);
			if (!options.matchCase)
				currentValue = currentValue.toLowerCase();
			request(currentValue, receiveData, hideResultsNow);
		} else {
			stopLoading();
			select.hide();
		}
	};

	function trimWords(value) {
		if (!value)
			return [""];
		if (!options.multiple)
			return [$.trim(value)];
		return $.map(value.split(options.multipleSeparator), function(word) {
			return $.trim(value).length ? $.trim(word) : null;
		});
	}

	function lastWord(value) {
		if ( !options.multiple )
			return value;
		var words = trimWords(value);
		if (words.length == 1)
			return words[0];
		var cursorAt = $(input).selection().start;
		if (cursorAt == value.length) {
			words = trimWords(value)
		} else {
			words = trimWords(value.replace(value.substring(cursorAt), ""));
		}
		return words[words.length - 1];
	}

	// fills in the input box w/the first match (assumed to be the best match)
	// q: the term entered
	// sValue: the first matching result
	function autoFill(q, sValue){
		// autofill in the complete box w/the first match as long as the user hasn't entered in more data
		// if the last user key pressed was backspace, don't autofill
		if( options.autoFill && (lastWord($input.val()).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != KEY.BACKSPACE ) {
			// fill in the value (keep the case the user has typed)
			$input.val($input.val() + sValue.substring(lastWord(previousValue).length));
			// select the portion of the value not typed by the user (so the next character will erase)
			$(input).selection(previousValue.length, previousValue.length + sValue.length);
		}
	};

	function hideResults() {
		clearTimeout(timeout);
		timeout = setTimeout(hideResultsNow, 200);
	};

	function hideResultsNow() {
		var wasVisible = select.visible();
		select.hide();
		clearTimeout(timeout);
		stopLoading();
		if (options.mustMatch) {
			// call search and run callback
			$input.search(
				function (result){
					// if no value found, clear the input box
					if( !result ) {
						if (options.multiple) {
							var words = trimWords($input.val()).slice(0, -1);
							$input.val( words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator : "") );
						}
						else {
							$input.val( "" );
							$input.trigger("result", null);
						}
					}
				}
			);
		}
	};

	function receiveData(q, data) {
		if ( data && data.length && hasFocus ) {
			stopLoading();
			select.display(data, q);
			autoFill(q, data[0].value);
			select.show();
		} else {
			hideResultsNow();
		}
	};

	function request(term, success, failure) {
		if (!options.matchCase)
			term = term.toLowerCase();
		var data = cache.load(term);
		// recieve the cached data
		if (data && data.length) {
			success(term, data);
		// if an AJAX url has been supplied, try loading the data now
		} else if( (typeof options.url == "string") && (options.url.length > 0) ){

			var extraParams = {
				timestamp: +new Date()
			};
			$.each(options.extraParams, function(key, param) {
				extraParams[key] = typeof param == "function" ? param() : param;
			});

			$.ajax({
				// try to leverage ajaxQueue plugin to abort previous requests
				mode: "abort",
				// limit abortion to this input
				port: "autocomplete" + input.name,
				dataType: options.dataType,
				url: options.url,
				data: $.extend({
					q: lastWord(term),
					limit: options.max
				}, extraParams),
				success: function(data) {
					var parsed = options.parse && options.parse(data) || parse(data);
					cache.add(term, parsed);
					success(term, parsed);
				}
			});
		} else {
			// if we have a failure, we need to empty the list -- this prevents the the [TAB] key from selecting the last successful match
			select.emptyList();
			failure(term);
		}
	};

	function parse(data) {
		var parsed = [];
		var rows = data.split("\n");
		for (var i=0; i < rows.length; i++) {
			var row = $.trim(rows[i]);
			if (row) {
				row = row.split("|");
				parsed[parsed.length] = {
					data: row,
					value: row[0],
					result: options.formatResult && options.formatResult(row, row[0]) || row[0]
				};
			}
		}
		return parsed;
	};

	function stopLoading() {
		$input.removeClass(options.loadingClass);
	};

};

$.Autocompleter.defaults = {
	inputClass: "ac_input",
	resultsClass: "ac_results",
	loadingClass: "ac_loading",
	minChars: 1,
	delay: 400,
	matchCase: false,
	matchSubset: true,
	matchContains: false,
	cacheLength: 10,
	max: 100,
	mustMatch: false,
	extraParams: {},
	selectFirst: true,
	formatItem: function(row) { return row[0]; },
	formatMatch: null,
	autoFill: false,
	width: 0,
	multiple: false,
	multipleSeparator: ", ",
	highlight: function(value, term) {
		return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
	},
    scroll: true,
    scrollHeight: 180
};

$.Autocompleter.Cache = function(options) {

	var data = {};
	var length = 0;

	function matchSubset(s, sub) {
		if (!options.matchCase)
			s = s.toLowerCase();
		var i = s.indexOf(sub);
		if (options.matchContains == "word"){
			i = s.toLowerCase().search("\\b" + sub.toLowerCase());
		}
		if (i == -1) return false;
		return i == 0 || options.matchContains;
	};

	function add(q, value) {
		if (length > options.cacheLength){
			flush();
		}
		if (!data[q]){
			length++;
		}
		data[q] = value;
	}

	function populate(){
		if( !options.data ) return false;
		// track the matches
		var stMatchSets = {},
			nullData = 0;

		// no url was specified, we need to adjust the cache length to make sure it fits the local data store
		if( !options.url ) options.cacheLength = 1;

		// track all options for minChars = 0
		stMatchSets[""] = [];

		// loop through the array and create a lookup structure
		for ( var i = 0, ol = options.data.length; i < ol; i++ ) {
			var rawValue = options.data[i];
			// if rawValue is a string, make an array otherwise just reference the array
			rawValue = (typeof rawValue == "string") ? [rawValue] : rawValue;

			var value = options.formatMatch(rawValue, i+1, options.data.length);
			if ( value === false )
				continue;

			var firstChar = value.charAt(0).toLowerCase();
			// if no lookup array for this character exists, look it up now
			if( !stMatchSets[firstChar] )
				stMatchSets[firstChar] = [];

			// if the match is a string
			var row = {
				value: value,
				data: rawValue,
				result: options.formatResult && options.formatResult(rawValue) || value
			};

			// push the current match into the set list
			stMatchSets[firstChar].push(row);

			// keep track of minChars zero items
			if ( nullData++ < options.max ) {
				stMatchSets[""].push(row);
			}
		};

		// add the data items to the cache
		$.each(stMatchSets, function(i, value) {
			// increase the cache size
			options.cacheLength++;
			// add to the cache
			add(i, value);
		});
	}

	// populate any existing data
	setTimeout(populate, 25);

	function flush(){
		data = {};
		length = 0;
	}

	return {
		flush: flush,
		add: add,
		populate: populate,
		load: function(q) {
			if (!options.cacheLength || !length)
				return null;
			/*
			 * if dealing w/local data and matchContains than we must make sure
			 * to loop through all the data collections looking for matches
			 */
			if( !options.url && options.matchContains ){
				// track all matches
				var csub = [];
				// loop through all the data grids for matches
				for( var k in data ){
					// don't search through the stMatchSets[""] (minChars: 0) cache
					// this prevents duplicates
					if( k.length > 0 ){
						var c = data[k];
						$.each(c, function(i, x) {
							// if we've got a match, add it to the array
							if (matchSubset(x.value, q)) {
								csub.push(x);
							}
						});
					}
				}
				return csub;
			} else
			// if the exact item exists, use it
			if (data[q]){
				return data[q];
			} else
			if (options.matchSubset) {
				for (var i = q.length - 1; i >= options.minChars; i--) {
					var c = data[q.substr(0, i)];
					if (c) {
						var csub = [];
						$.each(c, function(i, x) {
							if (matchSubset(x.value, q)) {
								csub[csub.length] = x;
							}
						});
						return csub;
					}
				}
			}
			return null;
		}
	};
};

$.Autocompleter.Select = function (options, input, select, config) {
	var CLASSES = {
		ACTIVE: "ac_over"
	};

	var listItems,
		active = -1,
		data,
		term = "",
		needsInit = true,
		element,
		list;

	// Create results
	function init() {
		if (!needsInit)
			return;
		element = $("<div/>")
		.hide()
		.addClass(options.resultsClass)
		.css("position", "absolute")
		.appendTo(document.body);

		list = $("<ul/>").appendTo(element).mouseover( function(event) {
			if(target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') {
	            active = $("li", list).removeClass(CLASSES.ACTIVE).index(target(event));
			    $(target(event)).addClass(CLASSES.ACTIVE);
	        }
		}).click(function(event) {
			$(target(event)).addClass(CLASSES.ACTIVE);
			select();
			// TODO provide option to avoid setting focus again after selection? useful for cleanup-on-focus
			input.focus();
			return false;
		}).mousedown(function() {
			config.mouseDownOnSelect = true;
		}).mouseup(function() {
			config.mouseDownOnSelect = false;
		});

		if( options.width > 0 )
			element.css("width", options.width);

		needsInit = false;
	}

	function target(event) {
		var element = event.target;
		while(element && element.tagName != "LI")
			element = element.parentNode;
		// more fun with IE, sometimes event.target is empty, just ignore it then
		if(!element)
			return [];
		return element;
	}

	function moveSelect(step) {
		listItems.slice(active, active + 1).removeClass(CLASSES.ACTIVE);
		movePosition(step);
        var activeItem = listItems.slice(active, active + 1).addClass(CLASSES.ACTIVE);
        if(options.scroll) {
            var offset = 0;
            listItems.slice(0, active).each(function() {
				offset += this.offsetHeight;
			});
            if((offset + activeItem[0].offsetHeight - list.scrollTop()) > list[0].clientHeight) {
                list.scrollTop(offset + activeItem[0].offsetHeight - list.innerHeight());
            } else if(offset < list.scrollTop()) {
                list.scrollTop(offset);
            }
        }
	};

	function movePosition(step) {
		active += step;
		if (active < 0) {
			active = listItems.size() - 1;
		} else if (active >= listItems.size()) {
			active = 0;
		}
	}

	function limitNumberOfItems(available) {
		return options.max && options.max < available
			? options.max
			: available;
	}

	function fillList() {
		list.empty();
		var max = limitNumberOfItems(data.length);
		for (var i=0; i < max; i++) {
			if (!data[i])
				continue;
			var formatted = options.formatItem(data[i].data, i+1, max, data[i].value, term);
			if ( formatted === false )
				continue;
			var li = $("<li/>").html( options.highlight(formatted, term) ).addClass(i%2 == 0 ? "ac_even" : "ac_odd").appendTo(list)[0];
			$.data(li, "ac_data", data[i]);
		}
		listItems = list.find("li");
		if ( options.selectFirst ) {
			listItems.slice(0, 1).addClass(CLASSES.ACTIVE);
			active = 0;
		}
		// apply bgiframe if available
		if ( $.fn.bgiframe )
			list.bgiframe();
	}

	return {
		display: function(d, q) {
			init();
			data = d;
			term = q;
			fillList();
		},
		next: function() {
			moveSelect(1);
		},
		prev: function() {
			moveSelect(-1);
		},
		pageUp: function() {
			if (active != 0 && active - 8 < 0) {
				moveSelect( -active );
			} else {
				moveSelect(-8);
			}
		},
		pageDown: function() {
			if (active != listItems.size() - 1 && active + 8 > listItems.size()) {
				moveSelect( listItems.size() - 1 - active );
			} else {
				moveSelect(8);
			}
		},
		hide: function() {
			element && element.hide();
			listItems && listItems.removeClass(CLASSES.ACTIVE);
			active = -1;
		},
		visible : function() {
			return element && element.is(":visible");
		},
		current: function() {
			return this.visible() && (listItems.filter("." + CLASSES.ACTIVE)[0] || options.selectFirst && listItems[0]);
		},
		show: function() {
			var offset = $(input).offset();
			element.css({
				width: typeof options.width == "string" || options.width > 0 ? options.width : $(input).width(),
				top: offset.top + input.offsetHeight,
				left: offset.left
			}).show();
            if(options.scroll) {
                list.scrollTop(0);
                list.css({
					maxHeight: options.scrollHeight,
					overflow: 'auto'
				});

                if($.browser.msie && typeof document.body.style.maxHeight === "undefined") {
					var listHeight = 0;
					listItems.each(function() {
						listHeight += this.offsetHeight;
					});
					var scrollbarsVisible = listHeight > options.scrollHeight;
                    list.css('height', scrollbarsVisible ? options.scrollHeight : listHeight );
					if (!scrollbarsVisible) {
						// IE doesn't recalculate width when scrollbar disappears
						listItems.width( list.width() - parseInt(listItems.css("padding-left")) - parseInt(listItems.css("padding-right")) );
					}
                }

            }
		},
		selected: function() {
			var selected = listItems && listItems.filter("." + CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);
			return selected && selected.length && $.data(selected[0], "ac_data");
		},
		emptyList: function (){
			list && list.empty();
		},
		unbind: function() {
			element && element.remove();
		}
	};
};

$.fn.selection = function(start, end) {
	if (start !== undefined) {
		return this.each(function() {
			if( this.createTextRange ){
				var selRange = this.createTextRange();
				if (end === undefined || start == end) {
					selRange.move("character", start);
					selRange.select();
				} else {
					selRange.collapse(true);
					selRange.moveStart("character", start);
					selRange.moveEnd("character", end);
					selRange.select();
				}
			} else if( this.setSelectionRange ){
				this.setSelectionRange(start, end);
			} else if( this.selectionStart ){
				this.selectionStart = start;
				this.selectionEnd = end;
			}
		});
	}
	var field = this[0];
	if ( field.createTextRange ) {
		var range = document.selection.createRange(),
			orig = field.value,
			teststring = "<->",
			textLength = range.text.length;
		range.text = teststring;
		var caretAt = field.value.indexOf(teststring);
		field.value = orig;
		this.selection(caretAt, caretAt + textLength);
		return {
			start: caretAt,
			end: caretAt + textLength
		}
	} else if( field.selectionStart !== undefined ){
		return {
			start: field.selectionStart,
			end: field.selectionEnd
		}
	}
};

})(jQuery);
/* common.js (126) */
/**
 *  represents a ProviderCourse
 *
 *  @param int id
 *  @param String title
 *
 */

function ProviderCourse( id, title, courseStatus ) {

    this.id = id;
    this.title = title;
    this.status = courseStatus;

}

/**
 *  Determine the strength of password by set rules
 *
 *  @param String password
 *
 *  @return int
 *
 */

function Common_getPasswordStrength( password ) {

    var score = 0;

    // Check the length of the password
    if ( password.length >= 6 ) {
        score += 10;
    }

    // Check whether the password contains one numbers
    if ( password.match(/(.*[0-9])/) ) {
        score += 10;
    }

    // Check whether the password has both upper and lower case letters
    //if ( password.match(/([a-z].*[A-Z])|([A-Z].*[a-z])/) ) score += 10;

    // Check whether the password password has numbers and letters
    if ( password.match(/([a-zA-Z])/) && password.match(/([0-9])/) ) {
        score += 10;
    }

    return score;

}

/**
 *  Get the 'traffic light' color for the password strength (0-40)
 *
 *  @param String strength
 *
 *  @return String
 *
 */

function Common_getPasswordColor( strength ) {

    switch( strength ) {
        /*case 40:
            return '#91FF3F';
            break;*/
        case 30:
            return '#C7FF3F';

        case 20:
            return '#FFDD3F';

        case 10:
            return '#FFA73F';

        default:
            return '#FF5F3F';
    }
}

/**
 *  jQuery plugin to toggle the value of a checkbox
 *
 *  @return jQuery
 *
 */

jQuery.fn.toggleChecked = function() {

    this.attr({
        checked: !this.attr( 'checked' )
    });

    return this;

};

/**
 *  a jquery plugin to height an error has occurred in an input field
 *
 *  @return jQuery
 *
 */

jQuery.fn.highlightError = function() {

    var input = this;
    var red = 'rgb(255,100,100)';
    var white = 'white';

    $.each( [red,white,red,white], function(i,color) {
        input.animate({
            backgroundColor: color
        }, 200 );
    });

    return this;

};

/**
 *  addition to String to allow them to be trimmed
 *
 */

String.prototype.trim = function() {

    return this.replace( /^\s*(.*?)\s*$/, '$1' );

};

/**
 *  jQuery plugin to add password strength functionality to password fields
 *
 *  @return jQuery
 *
 */

jQuery.fn.passwordStrength = function() {

    $( this )
        .keyup(function( event ) {
            var strength = Common_getPasswordStrength( $(this).val() );
            $( this )
                .css({
                    backgroundColor: Common_getPasswordColor( strength )
                });
        })
        .trigger( 'keyup' );

    return this;

};

/**
 *  returns a element for displaying action dispatcher style messages
 *
 *  @param String messageClass
 *  @param String messageText
 *
 *  @return jQuery
 *
 */

function Common_makeMessage( messageClass, messageText ) {

    return $( '<div>' )
            .addClass( 'actionDispatcherMessages' )
            .append(
                $( '<ul>' ).append(
                    $('<li>')
                        .addClass( 'message ' +messageClass )
                        .addClass( messageClass + 'Message' )
                        .append(
                            $( '<span/>' )
                                .html( messageText )
                                .addClass('message')
                        )
                )
            );

}

/**
 *  pads a number with a leading 0 if it's less than 10
 *
 *  @param natural num
 *
 *  @return String
 *
 */

function Common_padTens( num ) {
    return (num < 10) ? '0' + num : num;
}

/**
 *  converts the specified fields matched by the jquery selector
 *  to use a color picker instead of input box
 *
 *  @param selector a jquery selector string
 *
 */

function Common_addColorPicker( selector ) {

    var colors = ['0ff','00f','f0f','888','080','800','880','808','f00','088'];

    $( selector ).each(function(i,input) {

        var selectedColor = input.value.replace( /^\s*/, '' );
        var controls = $( '<div></div>' )
            .addClass( 'controls colorPicker' );

        $.each( colors, function(j,color) {
            var control =  $('<a></a>')
                .css({
                    display: 'block',
                    'float': 'left',
                    width: '20px',
                    height: '20px',
                    'background-color': '#'+color,
                    'text-decoration': 'none'
                })
                .click(function() {
                    $( '.colorPicker a' ).removeClass( 'selectedColor' );
                    $( this ).addClass( 'selectedColor' );
                    input.value = color;
                    input.focus(); // just makes it look a lil nicer, doesn't matter if it doesn't work
                })
                .attr({href: 'javascript:;'})
                .html( '&nbsp;' );

            if ( color == selectedColor ) {
                control.addClass( 'selectedColor' );
            }

            controls.append( control );
        });

        $( input )
            .css({display: 'none'})
            .after( controls );

    });
}

/**
 *  this function will replace standards correct "reset" and "submit" buttons
 *  with nice graphical versions set to the correct locale
 *
 *  @param locale the name of the block
 *  @param buttonsDivClass the class of the div containing the form buttons
 *  @param resetAction function callback for reset clicked
 *  @param submitAction function callback for submit clicked
 *
 */

function Common_replaceFormButtons( locale, buttonsDivClass, resetAction, submitAction ) {

    var localeId = oLocale.getFieldValue( 'id' );

    $( '.' + buttonsDivClass + " :input" )
        .remove();

    // reset button
    $( '<input type="image" />' )
        .attr({value: oLocale.getTranslation(locale,'btnReset'),
            src: 'custom/careers_wales/img/buttons/button_resetToLastSave_' +localeId+ '.gif'})
        .click( resetAction )
        .appendTo( '.' + buttonsDivClass );

    // submit button
    $( '<input type="image" />' )
        .attr({value: oLocale.getTranslation(locale,'btnSave'),
            src: 'custom/careers_wales/img/buttons/button_save_' +localeId+ '.gif'})
        .click( submitAction )
        .appendTo( '.' + buttonsDivClass );
}

/**
 *  adds calender controls for the specified date control fields
 *
 *  @param dateFieldClass class of fields to add controls to
 *  @param calDivId id for calender popup div
 *
 */

function Common_addCalendarControls( dateFieldClass, calDivId, context ) {

    // create calender div
    $( '<div></div>' )
        .attr({id: calDivId})
        .addClass( 'calenderPopup' )
        .css({position: 'absolute'})
        .appendTo( document.body );

    if (context === undefined) {
        context = 'body';
    }

    // attach calender picker to date fields
    $.each( $('.'+dateFieldClass, context), function(i,field) {
        var name = calDivId + i;
        var picker = $( '<a></a>' )
            .attr({href: '#', id: name})
            .addClass('calenderPicker')
            .css({'float': 'left', 'margin-right': '5px'})
            .append(
                $('<img />')
                    .attr({src: 'custom/careers_wales/img/icons/datepicker.gif', alt: oLocale.getTranslation('GlobaleLocale', 'datePicker')})
            )
            .click( function() {
                var cal = new CalendarPopup( calDivId );
                cal.setDisplayType( 'date' );
                cal.showYearNavigation();
                cal.select( field, name, 'dd/MM/yyyy' );
                return false;
            })

            .insertAfter( $(field) );

        $( field ).keypress( function(){return false;} );

    });

}

/**
 *  uses the jquery tablesorter to make a table sortable.  for some tables
 *  there are anchor links to do sorting by reloading the page, so these
 *  are replaced if they're found.
 *
 *  NB! currently "headers" defaults to the 7th column being disabled cause
 *  it's often an edit link column
 *
 *  @param tableSelector the "selector" name to identify the table
 *  @param headers (optional) how to sort table headers
 *
 */

function Common_initSortableTable( tableSelector, headers ) {

    if ( tableSelector === null ) {
        tableSelector = '.sortableTable';
    }


    if ( headers === null ) {
        headers = {
            7: {sorter: false}
        };
    }
    // sortable tables are done standard style with anchor links
    // by default, so remove those cause they're not needed now
    $( tableSelector + ' th' ).each(function(){
        var elems = $(this).find( 'span' );
        if ( elems.length > 0 ) {
            var name = $(elems[0]).html();
            $(this).empty().html( name );
        }
    });

    $( tableSelector ).tablesorter({
        headers: headers,
        cssAsc: 'sortableHeaderSortUp',
        cssDesc: 'sortableHeaderSortDown',
        cssHeader: 'sortableHeader'
    });
}

/**
 * Use jQuery zebra striping of tables
 *
 *
 */
function Common_initTableZebraStripe(block) {
	$("table.stripe tbody tr", block)
		.live('mouseover', function() {$(this).addClass("over");})
		.live('mouseout', function() {$(this).removeClass("over");});

	$("table.stripe tbody tr:even").addClass("odd");
}

/**
 * Write cookie to current domain
 *
 * @param string name
 * @param string value
 * @param int days
 */
function Common_createCookie(name,value,days) {
    var expires = '';

    if (days) {
        var date = new Date();
        date.setTime(date.getTime()+(days*24*60*60*1000));
        expires = "; expires="+date.toGMTString();
    } else {
        expires = "";
    }

    document.cookie = name+"="+value+expires+"; path="+SITE_WEB_ROOT;
}

/**
 * Read cookie
 *
 * @see http://www.quirksmode.org/js/cookies.html
 * @param string name
 */
function Common_readCookie(name) {
    var nameEQ = name + "=";
    var ca     = document.cookie.split(';');
    for(var i=0;i < ca.length;i++) {
        var c = ca[i];
        while (c.charAt(0)==' ') { 
            c = c.substring(1,c.length);
        }
        if (c.indexOf(nameEQ) == 0) {
            return c.substring(nameEQ.length,c.length);
        }
    }
    return null;
}

/**
 * Site-wide on DOM ready changes
 *
 */
$(document).ready(function () {

    // Update font-size
    $('a.sizeOption').click(function(){
        var currentStyle = Common_getCurrentStyle();
        $('body')
            .removeClass()
            .addClass(currentStyle)
            .addClass($(this).attr('id'));
        Common_createCookie('fontSize', $(this).attr('id'), 365);
        return false;
    });

    // Update style for Myfuture
    $('#styleChangeBlock')
        .find('a.button')
        .click(function() {
            var currentSize = Common_getCurrentSize();
            $('body')
                .removeClass()
                .addClass(currentSize)
                .addClass($(this).attr('id'));
            $('#styleChangeBlock').find('a.button').removeClass('selected');
            $(this).addClass('selected');
            Common_createCookie('myfutureStyle', $(this).attr('id'), 365);
            return false;
        }
    );

    // Handle media files, these aren't block / template specific
    Common_updateFlash();
    Common_flashVideo();

    // Tooltip display
    CW.toolTips.initialise();
    CW.betaAdvert();
});

function Common_getCurrentStyle() {
	var currentBodyClass = $('body').attr('class');
	var newBodyClass = currentBodyClass.replace(/small|normal|large/gi, '');
	return newBodyClass;
}

function Common_getCurrentSize( ) {
	var currentBodyClass = $('body').attr('class');
	var newBodyClass = currentBodyClass.replace(/colour|text|hiRes/gi, '');
	return newBodyClass;
}

function Common_updateFlash () {
    $(function() {
        $(".singleContent .conMediaFile, .advertSetVert .conMediaFile").each(function() {
            var mediaFileId = $(this).attr('id');

            $("div[id^='swf-']", $(this)).each(function() {
                var id        = $(this).attr("id");
                var aSwfVideo = id.split("-");
                var fileName  = aSwfVideo[1];
                var width     = aSwfVideo[2] <= 0? '200': aSwfVideo[2];
                var height    = aSwfVideo[3] <= 0? '200': aSwfVideo[3];

                //If in IE6, we need reduce the size a bit
                if (/MSIE 6/i.test(navigator.userAgent)){
                    width  = width - 9;
                    height = height -9;
                }
                setTimeout(function(){swfobject.embedSWF(SITE_WEB_ROOT + "upload/swf/"+fileName, id, width, height, "8", "", {}, {'wmode' : 'transparent'})}, 100);
            });
        });
    });
}

function Common_flashVideo() {

    $(function() {
        $(".singleContent .conMediaFile").each(function() {
            $("div[id^='video-']", $(this)).each(function() {
                var aSwfVideo = $(this).attr("id").split("_");
                var blockId   = aSwfVideo[1];
                var contentId = aSwfVideo[2];
                var flv_file  = aSwfVideo[3];
                var width     = aSwfVideo[4];
                var height    = aSwfVideo[5];
                var currLang  = aSwfVideo[6];

                FlashVideo.init(currLang, blockId, contentId, flv_file, width, height);
            });
        });
    });
}

/**
 *  hijax code stuff...
 *
 */

var oControllerRegistry = {
    aoController : {},

    add : function (p_componentId, p_controller) {
        if (!this.aoController[p_componentId]) {
            this.aoController[p_componentId] = p_controller;
        }
    },

    get : function (p_componentId) {
        if (this.aoController[p_componentId]) {
            return this.aoController[p_componentId];
        }
        return null;
    },

    getAll : function () {
        return this.aoController;
    },

    getObject : function (p_componentId) {
        var oObject = this.get(p_componentId);
        if (oObject) {
            return new oObject();
        }

        return null;
    }

};


function hijax (p_aModule) {
    var oModule;
    for (var i = 0; oModule = p_aModule[i]; i++) {
        if (window[oModule] && window[oModule] instanceof Function) {
            oControllerRegistry.add(oModule, window[oModule]);
        }
    }

    for (var sClassName in oControllerRegistry.getAll()) {
        var oClass = oControllerRegistry.get(sClassName);
        var oController = new oClass();

        var aoEvent = getControllerEvents(oController);

        var aBlocks = $('div.' + sClassName);
        if (aBlocks.length) {
            aBlocks.each(function(bIndex) {
                var oBlock = this;

                this._componentId = sClassName;
                this._instanceId = oBlock.id.split('_')[1];

                if (oController.initialise) {
                    prepareController(oController, oBlock, null);

                    oController.initialise($(oBlock));
                }

                if (aoEvent.length) {
                    bindControllerEvents(aoEvent, oBlock);
                }
            });
        } else {
            if (oController.initialise) {
                prepareController(oController, null, null);

                oController.initialise(null);
            }
        }

    }
}


function handleEvent (p_oEvent)
{
    var oElement = getEventTarget(p_oEvent);
    if (!oElement) {
        return true;
    }

    var oBlock = oElement._oBlock;
    var oController = oControllerRegistry.getObject(oBlock._componentId);

    if (oController) {
        var sFunctionName = 'on' + p_oEvent.type;
        if (oController[sFunctionName]) {
            prepareController(oController, oBlock, p_oEvent);
            return oController[sFunctionName] (p_oEvent);
        }
    }
    return true;
}


function prepareController (p_oController, p_oBlock, p_oEvent)
{
    if (p_oEvent) {
        p_oController.oElement = $(getEventTarget(p_oEvent));
        p_oController.oBlock = $(p_oController.oElement[0]._oBlock);
    } else if (p_oBlock) {
        p_oController.oBlock = $(p_oBlock);
    }

    p_oController.getComponentId = function() {
        return this.oBlock[0]._componentId;
    };

    p_oController.getInstanceId = function() {
        return this.oBlock[0]._instanceId;
    };

    p_oController.replaceBlockContents = function(html) {
        var fragment = document.createElement('span');
        fragment.innerHTML = html;

        this.oBlock.find('div.blkBdy').html(
            $('div.blkBdy', fragment).html()
        );

        if (p_oController.initialise)
            p_oController.initialise(this.oBlock);

        var aoEvents = getControllerEvents(this);
        if (aoEvents.length) {
            bindControllerEvents(aoEvents, this.oBlock[0]);
        }
    };

    p_oController.getPageUrl = function() {
        return window.location.href.split('#')[0];
    };

    p_oController.getPageAjaxUrl = function(aParam) {
        var sParams = this.createRequestVarString(aParam);
        var url = this.getPageUrl();

        // Correctly prepend the following query string arguments
        if (url.indexOf('?') == -1) {
            url += '?';
        } else {
            url += '&';
        }

        if (sParams != '' ) {
            url += sParams;
        }

        url += '&outputFormat=ajax';
        return url;
    };

    p_oController.getBlockAjaxUrl = function(aParam) {
        var sParams = this.createRequestVarString(aParam);
        return 'server.php?show=block.' + this.getInstanceId() + sParams + '&outputFormat=ajax';
    };

    p_oController.getLinkAjaxUrl = function(aParam) {
        var sParams = this.createRequestVarString(aParam);
        var url = this.oElement.attr('href').split('#')[0];
        if (url.substr(0, 7) == 'http://') {
            var parts = url.substr(8, url.length).split('/');
            var url = url.substr(8 + parts[0].length, url.length);
        }
        return url + sParams + '&outputFormat=ajax';
    };

    p_oController.getApiUrl = function(aParam) {
        var sParams = this.createRequestVarString(aParam);
        return 'api.php?do=block.' + this.getInstanceId() + sParams;
    };

     p_oController.getBlockJsonUrl = function(aParam) {
        var sParams = this.createRequestVarString(aParam);
        var url = this.getPageUrl();

        // Correctly prepend the following query string arguments
        if (sParams != '') {
        if (url.indexOf('?') == -1) {
            url += '?';
            }
            else {
            url += '&';
        }
            url += sParams;
        }
        if (url.indexOf('?') == -1) {
            url += '?';
        }
        else {
            url += '&';
        }
        url += 'jsonOutput=' + this.getInstanceId();
        return url;
    };

    p_oController.createRequestVarString = function (aParam) {
        var sParams = '';
        if (aParam) {
            for (var key in aParam) {
                sParams += '&Module[' + this.getInstanceId() + '][' + key + ']=' + aParam[key];
            }
        }
        return sParams;
    };

    p_oController.getModuleFieldTitle = function( key ) {
        return 'Module['+this.getInstanceId()+']['+key+']';
    };

    p_oController.getTranslation = function(key) {
        if (!(typeof(key) == 'string' || typeof(key) == 'number')) {
            return '';
        }

        return oLocale.getTranslation(this.getLocaleCompontentId(), key);
    };

    p_oController.getLocaleCompontentId = function() {
        var componentId = this.getComponentId();
        return (componentId.substr(0, 1).toUpperCase())+(componentId.substr(1));
    };

}


function parseEventString(string) {
    //converts the string "tag.className#id::eventType" into an object
    //todo: regex
    var oEvent = {};

    var nameAndType = string.split('::');
    if (nameAndType.length != 2) {
        return null;
    }

    oEvent.selector = oEvent.tagName = nameAndType[0];
    oEvent.type = nameAndType[1];

    var tagAndClass = oEvent.tagName.split('.');
    if (tagAndClass[1]) {
        oEvent.tagName = tagAndClass[1];
        oEvent.className = tagAndClass[1];
    }
    var tagAndId = oEvent.tagName.split('#');
    if (tagAndId[1]) {
        oEvent.tagName = tagAndId[0];
        oEvent.id = tagAndId[1];
    }
    return oEvent;
}


function getEventTarget(p_oEvent) {
    if (p_oEvent.srcElement) {
        var currentTarget = p_oEvent.srcElement;
        while (!currentTarget._oBlock && currentTarget) {
            currentTarget = currentTarget.parentNode;
        }
        if (currentTarget) {
            return currentTarget;
        }

        return null;
    }
    return p_oEvent.currentTarget;
}


function getControllerEvents(p_oController) {
    var aoEvent = [];
    if (p_oController.handles) {
        var aEvent = p_oController.handles;
        var n = 0;
        for (var i = 0; i < aEvent.length; i++) {
            var oEvent = parseEventString(aEvent[i]);
            if (oEvent) {
                aoEvent[n++] = oEvent;
            }
        }
    }
    return aoEvent;
}


function bindControllerEvents(p_aoEvent, p_oContainer) {
    for (var i = 0; i < p_aoEvent.length; i++) {
        var oEvent = p_aoEvent[i];
        $(oEvent.selector, p_oContainer)
            .bind(oEvent.type, handleEvent)
            .each(function(eIndex){
                this._oBlock = p_oContainer;
            })
        ;
    }
}

/**
 * AMAXUS global object
 * -> nicely wraps up common methods without painfully polluting the global namespace
 */
if (typeof(AMAXUS) == 'undefined') {
    AMAXUS = {
    };
}

/**
 * A few developer hooks
 */
AMAXUS.developer = {
    /**
     * Are we currently working from a development domain?
     * -> are we /not/ working from a live site?
     *
     * @return bool
     */
    isDevelopmentDomain:function(){
        return (window.location.host.indexOf('.') == -1);
    }
};

/**
 * Log content to the JavaScrit console
 * -> works with Firebug, Safari/Chrome and IE consoles
 * -> pass in any number of arguments, all of which will get logged (apart from in Safari/Chrome, when only the first is used)
 *
 * /@/param object
 */
AMAXUS.log = function() {
    var isConsoleOverride = (window.location.search.indexOf('forceconsole') > -1);
    if (!AMAXUS.developer.isDevelopmentDomain() && !isConsoleOverride) {
        return true;
    }

    try {
        // Adds console.XXX methods for Opera, if not present
        // -> maps all to opera.postError for logging in Dragonfly (Opera 9.5-ish onwards)
        if (window.opera && !window.console) {
            window.console = {};

            var fn = function() {
                opera.postError(arguments);
            };

            ['log', 'debug', 'info', 'warn', 'error', 'assert', 'dir', 'dirxml', 'group', 'groupEnd',
            'time', 'timeEnd', 'count', 'trace', 'profile', 'profileEnd'].forEach(function(name) {
                window.console[name] = fn;
            });
        }

        // For poor Safari, who has a console.log() method that only takes one
        // argument ever and throws a type error if you try to give it more
        if(navigator.userAgent.toLowerCase().indexOf("applewebkit") != -1) {
            console.log(arguments[0]);
        } else {
            console.log.apply(this,arguments);
        }
    } catch (error) {
        return true;
    }

    return true;
};

/**
* Define console (and console.log) if not present
* -> defensive technique for preventing 'console is not defined' failures in IE
* -> can eventually build on this to apply a console layer for IE
*    -> something like a 100%-width, x-height panel fixed to the top/left/bottom/right that we can pop content into
*/
if (!window.console) {
    window.console = {
        log:function(){}
    };
}

/**
 * Wrapper class for jQuery.ajax, adding support for retrying a request X times before failing
 *
 * @constructor
 */
AMAXUS.ajaxRequestHandler = function() {
    var requestPool = {};   // Holds one request per URL

    var issueRequest = function(settings) {
        settings.dataType = (typeof(settings.dataType) == 'undefined') ? null : settings.dataType;
        settings.sentCount = (typeof(settings.sentCount) == 'number') ? settings.sentCount : 0;

        settings.sentCount++;

        return $.ajax({
            url:settings.url,
            dataType:settings.dataType,
            error:function(XMLHttpRequest, textStatus, errorThrown) {   // http://docs.jquery.com/Ajax/jQuery.ajax#options :: error
                switch (errorThrown) {
                case 'timeout':
                    // -> for the time being we just try again on the offchance the error was a fluke
                    handleError(this, settings, XMLHttpRequest, textStatus, errorThrown);
                    break;

                case 'error':
                    // HTTP error (status 40X, 50X)
                    // -> for the time being we just try again on the offchance the error was a fluke
                    handleError(this, settings, XMLHttpRequest, textStatus, errorThrown);
                    break;

                case 'notmodified':
                    // Never ever seen this happen in practice
                    // We should eventuallly:
                    //  1. cache response data
                    //  2. get server to return a 304 status when this is truly appropriate
                    //  3. and just return the cached value
                    // -> for the time being we just try again on the offchance the error was a fluke
                    handleError(this, settings, XMLHttpRequest, textStatus, errorThrown);
                    break;

                case 'parsererror':
                    // Data returned cannot be parsed as the expected data type
                    // -> for the time being we just try again on the offchance the error was a fluke
                    handleError(this, settings, XMLHttpRequest, textStatus, errorThrown);
                    break;
                }

                handleError(this, settings, XMLHttpRequest, textStatus, errorThrown);
            },
            success:settings.success,
            timeout:settings.timeout
        });
    };

    var handleError = function(request, settings, XMLHttpRequest, textStatus, errorThrown) {
        if ((typeof(settings.retryLimit) == 'number')) {
            if (settings.sentCount < settings.retryLimit) {
                requestPool[settings.url] = issueRequest(settings);
                return false;
            }
        }

        if (typeof(settings.error) == 'function') {
            requestPool[settings.url].abort();
            delete(requestPool[settings.url]);
            settings.error(XMLHttpRequest, textStatus, errorThrown);
         }

        return false;
    };

    /**
     * Remove a request from the request pool
     * -> you need to do this if you want to re-run a completed request
     *
     * @param url The URL to remove from the request pool     *
     */
    this.clearRequest = function (url) {
        if (typeof(requestPool[url]) == 'undefined') {
            return true;
        }

        requestPool[url] = null;
        return true;
    };

    /**
     * Extension of jQuery.ajax, adding support for retrying a failed request
     *
     * @param options object See http://docs.jquery.com/Ajax/jQuery.ajax#options,
     *                       {retryLimit:Number of times to try this request before giving up}
     */
    this.get = function(options) {
        var defaults = {
            url:'',             // http://docs.jquery.com/Ajax/jQuery.ajax#options :: url
            dataType:'json',    // http://docs.jquery.com/Ajax/jQuery.ajax#options:: dataType
            retryLimit:3,       // Number of times to try this request before giving up
            timeout:3000        // Timeout in milliseconds
        };

        var settings = $.extend(defaults, options);
        if (typeof(requestPool[settings.url]) == 'undefined' || requestPool[settings.url] === null) {
            requestPool[settings.url] = issueRequest(settings);
        }

        return requestPool[settings.url];
    };
};

AMAXUS.math = {
    /**
     * Return the magnitude of a number
     *
     * @return number
     */
    magnitude:function(num1, num2) {
        if (typeof num1 != 'number' || typeof num1 != 'number') {
            return 0;
        }

        if (num1 > num2) {
            return num1 - num2;
        }

        if (num2 > num1) {
            return num2 - num1;
        }

        return 0;
    }
};

AMAXUS.dimensions = {
    element:{
        edges:function(element) {
            if (!(element instanceof jQuery)) {
                element = $(element);
            }

            var topEdge = element.offset().top;
            var bottomEdge = topEdge + element.innerHeight();
            var leftEdge = parseInt(element.css('left'), 10);
            var rightEdge = leftEdge + parseInt(element.width(), 10);

            return {
                top:topEdge,
                right:rightEdge,
                bottom:bottomEdge,
                left:leftEdge
            };
        },

        isBelowTheFold:function(options) {
            var defaults = {
                selector:null,
                topEdge:true,
                bottomEdge:false,
                offset:0
            };

            var settings = $.extend(defaults, options);

            var element = $(settings.selector);
            var topEdge = element.offset().top;
            var bottomEdge = element.offset().top + element.innerHeight();

            var isBottomEdgeBelow = ((bottomEdge+settings.offset) >= $(window).height());
            var isTopEdgeBelow = ((topEdge+settings.offset) >= $(window).height());

            var topEdgeComparator = options.topEdge ? '1' : '0';
            var bottomEdgeComparator = options.bottomEdge ? '1' : '0';

            switch (topEdgeComparator+''+bottomEdgeComparator) {
            case '01': // Is bottom edge off?
                return isBottomEdgeBelow;

            case '10': // Is top edge off?
            case '11': // Are both top and bottom edges off?
                return isTopEdgeBelow;

            default:
                return false;
            }
        }
    }
};

AMAXUS.validate = {
    REGEX:{
        EMAIL:/[^@]+@[^\.]+\.[^\.]+/
    },

    isInt:function(value) {
        if (isNaN(value)) {
            return false;
        }

        if (typeof(value) != 'string' && typeof(value) != 'number') {
            return false;
        }

        return parseInt(value, 10) == value;
    },

    isIntInRange:function(inputValue, options) {
        // Do we have an integer value to check?
        if (!AMAXUS.validate.isInt(inputValue)) {
            return false;
        }

        // Check options are safe
        if (typeof(options.min) == 'undefined') {
            options.min = null;
        }

        if (typeof(options.max) == 'undefined') {
            options.max = null;
        }

        var value = parseInt(inputValue, 10);

        // Less than minimum?
        if (AMAXUS.validate.isInt(options.min)) {
            var min = parseInt(options.min, 10);
            if (value < min) {
                  return false;
            }
        }

        // Greater than maximum?
         if (AMAXUS.validate.isInt(options.max)) {
            var max = parseInt(options.max, 10);
            if (value > max) {
                return false;
            }
        }

        return true;
    },

    isPositiveInteger:function(value) {
        return AMAXUS.validate.isIntInRange(value, {min:0, max:null});
    },

    isNegativeInteger:function(value) {
        return AMAXUS.validate.isIntInRange(value, {min:null, max:-1});
    },

    isBlankString:function(value) {
        if (typeof value != 'string') {
            return true;
        }

        value = $.trim(value);
        return value == '';
    },

    isValidEmail:function(value) {
        return AMAXUS.validate.REGEX.EMAIL.test(value);
    }
};

AMAXUS.errorList = {};

/**
 * Get list of error messages from within JSON-representation of module
 *
 * @param module {}
 * @return errors []
 */
AMAXUS.errorList.getFromModule = function (module) {
    var errors = [];
    var messageCount = module.aMessage.length;

    if ( messageCount > 0 ) {
        var currentMessage = null;

        for ( var i=0; i<messageCount; i++ ) {
            currentMessage = module.aMessage[ i ];
            if ( currentMessage.type == 3 ) {
                errors.push( currentMessage );
            }
        }
    }

    return errors;
};

AMAXUS.google = {

};

AMAXUS.google.maps = {

};

AMAXUS.google.maps.constants = {
    SCRIPT_ELEMENT_ID: 'google.maps.script',
    API_URL: 'http://maps.google.com/maps/api/js?sensor=false'
};

/**
 * Dynamically add Google Maps API <script> element
 *
 */
AMAXUS.google.maps.insertApiScript = function (callbackFunctionName) {
    var apiSrc = AMAXUS.google.maps.constants.API_URL;
    if (callbackFunctionName) {
        apiSrc += '&callback=' + callbackFunctionName;
    }

    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = apiSrc;
    document.body.appendChild(script);
};

AMAXUS.google.maps.geocoder = {

};

AMAXUS.google.maps.geocoder.get = function (requestOptions, callback) {
    var geocoder = new google.maps.Geocoder();
    geocoder.geocode(requestOptions, callback);
};

/**
 * Careers Wales global object
 */
CW = {};

CW.errorList = {};
/**
 *  Create an unordered list of error messages
 *
 *  @param errors []
 *  @param options {}
 *  @return String
 */
CW.errorList.makeHTML = function (errors, options) {
    var defaults = {
        liClasses:'message errorMessage',
        spanClasses:'message'
    };

    var settings = $.extend({}, defaults, options);

    if (!(errors instanceof Array)) {
        errors = [];
    }

    var html = '<ul>';
    $.each( errors, function(i,error) {
        html += '<li class="'+settings.liClasses+'"><span class="'+settings.spanClasses+'">' +error.message+ '</span></li>';
    });

    return html + '</ul>';
};

/**
 * Address lookup tool
 * -> apply postode-to-address lightbox lookup to a form
 *
 * @constructor
 */
CW.addressLookup = function (options) {
    // See CW.addressLookup.initialise() for options choices and the defaults
    // -> at the very end of this class

    /**
     * Class for modelling an address
     *
     * @constructor (for CW.addressLookup.address)
     */
    var address = function(address) {
        var fields = {
            moniker: null,
            numberOrName:null,
            line1:null,
            line2:null,
            line3:null,
            postcode:null
        };

        this.numberOrName = function(normalised) {
            var numberOrName = fields.numberOrName;
            var normalise = function (numberOrName) {
                var normalisedNumberOrName = '';

                if (typeof numberOrName  != 'string') {
                    return normalisedNumberOrName;
                }

                normalisedNumberOrName = numberOrName.replace(/[:space:]/, '');
                return (normalisedNumberOrName == '') ? '' : normalisedNumberOrName.toLowerCase();
            };

            return (normalised === true) ? normalise(numberOrName) : numberOrName;
        };

        this.line1 = function() {
            return fields.line1;
        };

        this.line2 = function() {
            return fields.line2;
        };

        this.line3 = function() {
            return fields.line3;
        };

        this.postcode = function() {
            return fields.postcode;
        };

        this.moniker = function(){
            return fields.moniker;
        };

        this.toString = function() {
            var removeDoubleSpaces = function (value) {
                var newValue = '';

                for (var index = 0; index < value.length; index++) {
                    var currentCharacter = value.charAt(index);
                    var nextCharacter = value.charAt(index + 1);

                    if (currentCharacter == ' ' && nextCharacter == ' ') {
                        newValue += '';
                    } else {
                        newValue += currentCharacter;
                    }
                }

                return newValue;
            };

            var stringRepresentation = '';

            for (var fieldIndex in fields) {
                if (fields.hasOwnProperty(fieldIndex)) {
                    if ((typeof fields[fieldIndex] == 'string' || typeof fields[fieldIndex] == 'number') && fieldIndex != 'moniker') {
                        stringRepresentation += fields[fieldIndex];

                        if (fieldIndex == 'numberOrName') {
                            stringRepresentation += ' ';
                        }

                        if (!(fieldIndex == 'numberOrName' || fieldIndex == 'postcode') && fields[fieldIndex].length > 1) {
                            stringRepresentation += ', ';
                        }
                    }
                }
            }

            return removeDoubleSpaces(stringRepresentation);
        };

        var initialise = function (address) {
            for (var fieldIndex in fields) {
                if (fields.hasOwnProperty(fieldIndex)) {
                    fields[fieldIndex] = $.trim(address[fieldIndex]);
                }
            }
        };

        initialise(address);

    };
    /* end address class defintion */


    /*
     * Class, for an object representing the button that is clicked to start the whole process off
     * @constructor (for CW.addressLookup.lookupButton)
     */
    var lookupButton = function(options) {
        var defaults = {
            id:'findAddressButton',
            src:'',
            alt:''
        };

        var settings = $.extend({}, defaults, options);
        settings.id = (settings.id === null) ? '' : settings.id;
        settings.src = (settings.src === null) ? '' : settings.src;
        settings.alt = (settings.alt === null) ? '' : settings.alt;

        /**
         * Create and return the button element for popping into the DOM
         *
         * @return object jQuery object for the button
         */
        var element = function() {
            return $('<img />').attr(
                       'id', settings.id
                   ).attr(
                       'src', settings.src
                   ).attr(
                       'alt', settings.alt
                   ).css({
                       cursor:'pointer'
                   }).click(function(){
                       performLookup();
                   });
        };

        this.clone = function () {
            return element();
        };

        this.reference = function() {
            return $('#'+settings.id);
        };

        /**
         * Have this button sit next to an input field
         *
         * @param targetSelector string jQuery selector for field to which this button should next to sit
         * @return bool Did the button manage to get sat next to the target element?
         */
        this.sitNextTo = function(targetSelector) {
            var target = $(targetSelector);
            if (target.length === 0) {
                return false;
            }

            target.after(element());
            return true;
        };
    };

    /**
     * CW.addressLookup class properties
     *
     */
    var settings = {};
    var button = null;  // lookupButton

    /**
     * Get current relevant postcode value
     * -> either the field in the orignial form, or the field in the lightbox, depending on current state
     *
     * @return string postcode
     */
    var postcode = function (normalised) {
        var selector = null;
        var normalise = function (postcode) {
            var normalisedPostcode = '';

            if (typeof postcode  !== 'string') {
                return normalisedPostcode;
            }

            var postcodePattern = /[A-Z0-9]/i;
            var postcodeMatcher = new RegExp(postcodePattern);

            var postcodeLength = postcode.length;
            for (var characterIndex = 0; characterIndex < postcodeLength; characterIndex++) {
                var currentCharacter = postcode.charAt(characterIndex);
                if (postcodeMatcher.test(currentCharacter)) {
                    normalisedPostcode += currentCharacter;
                }
            }

            return normalisedPostcode.toLowerCase();
        };

        if ($('#postcoderelookup'+settings.instanceId).length) {
            selector = '#postcoderelookup'+settings.instanceId;
        } else {
            selector = settings.selectors.lookupPostcodeField;
        }

        var rawValue = $(selector).val();
        if (rawValue == '') {
            return '';
        }

        return (normalised === false) ? rawValue : normalise(rawValue);
    };

    /**
     * Get current relevant house number/name
     * -> either the field in the orignial form, or the field in the lightbox, depending on current state
     *
     * @return string postcode
     */
    var numberOrName = function (normalised) {
        var selector = null;
        var normalise = function (numberOrName) {
            var normalisedNumberOrName = '';

            if (typeof numberOrName  != 'string') {
                return normalisedNumberOrName;
            }

            normalisedNumberOrName = numberOrName.replace(/[:space:]/, '');
            return (normalisedNumberOrName == '') ? '' : normalisedNumberOrName.toLowerCase();
        };

        if ($('#numberornamerelookup'+settings.instanceId).length) {
            selector = '#numberornamerelookup'+settings.instanceId;
        } else {
            selector = settings.selectors.lookupNumberOrNameField;
        }

        var rawValue = $(selector).val();
        if (rawValue == '') {
            return '';
        }

        return (normalised === false) ? rawValue : normalise(rawValue);
    };

    /**
     * Copy the label for the house number/name field from the orignal form
     *
     * @return {} jQuery object representing the label for the house number/name field from the original form
     */
    var getNumberOrNameLabel = function () {
        var inputId = $(settings.selectors.lookupNumberOrNameField).attr('id');
        var label = $('label[for='+inputId+']');

        return label.clone();
    };

    /**
     * Copy the input for the house number/name field from the orignal form
     *
     * @return {} jQuery object representing the house number/name input from the original form
     */
    var getNumberOrNameField = function() {
        return $(settings.selectors.lookupNumberOrNameField).clone();
    };

    /**
     * Copy the label for the postcode field from the orignal form
     *
     * @return {} jQuery object representing the label for the postcode field from the original form
     */
    var getPostcodeLabel = function () {
        var inputId = $(settings.selectors.lookupPostcodeField).attr('id');
        var label = $('label[for='+inputId+']');

        return label.clone();
    };

    /**
     * Copy the input for the postcode field from the orignal form
     *
     * @return {} jQuery object representing the postcode input from the original form
     */
    var getPostcodeField = function() {
        return $(settings.selectors.lookupPostcodeField).clone();
    };

    /* Basic state management */
    var states = {
        START:0,                // Starting state, no lookup request yet made
        LIGHTBOX_PREPARING:1,   // Lightbox open, preparing to display either address choice or 'no results - try again' content
        LIGHTBOX_RESULTS:2,     // Lightbox open, displaying results of address lookup (when choices are available)
        LIGHTBOX_NORESULTS:3,   // Lightbox open, displaying 'no results - try again' content
        LIGHTBOX_LOADING_FORMATTED_ADDRESS:4

    };

    var currentState = null;
    var defaultState = null;
    var requestUrl = null;

    var isStateValid = function (newState) {
        for (var stateName in states) {
            if (states.hasOwnProperty(stateName)) {
                if (states[stateName] == newState) {
                    return true;
                }
            }
        }

        return false;
    };

    /**
     * Set the current state, but don't react to the state change at all
     *
     */
    var setState = function (newState) {
        if (!isStateValid(newState)) {
            newState = defaultState;
        }

        currentState = newState;
    };

    /**
     * Set the current state AND then update the interface accordingly
     *
     */
    var updateState = function (newState) {
        setState(newState);
        updateInterface();
    };

    var getState = function () {
        return currentState;
    };

    this.getState = function () {
        return getState();
    };

    this.states = function() {
        return states;
    };

    var resetState = function () {
        setState();
    };

    this.resetState = function () {
        resetState();
    };

    var getStateName = function () {
        for (var key in states) {
            if (states.hasOwnProperty(key)) {
                if (states[key] == getState()) {
                    return key;
                }
            }
        }

        return false;
    };
    /* /Basic state management */

    /* Class properties */
    var addressLookupBusy = [];
    var addresses = {
        '':{}   // Default address set for no postcode
    };

    var ajaxRequestHandler = null;  // Instantiated as new AMAXUS.ajaxRequestHandler in initialise()

    /**
     * Form URL for postcode lookup
     * -> nothing much more than appending the postcode value to the end of the given requestUrl
     *
     * @return string the Ajax request URL
     */
    var postcodeLookupUrl = function () {
        var requestUrl = settings.ajax.url;
        var moduleKey = /Module\[[0-9]+\]/.exec(requestUrl);
        var moduleId = moduleKey[0].replace('Module', '').replace('[', '').replace(']', '');

        requestUrl += (requestUrl.indexOf('?') == -1) ? '?' : '&';
        requestUrl += 'Module['+moduleId+'][postcode]='+postcode();

        return requestUrl;
    };

    /**
     * Get set of addresses for given postcode.
     * Uses locally-stored address set if present,
     * otherwise fires off Ajax request to get data
     *
     * Returns false if there are no addresses stored locally for the
     * given postcode, which then lets you know that a remote postcode
     * lookup will follow.
     *
     * Return an empty array if there are no addresses for a given postcode.
     *
     * @return mixed {} or false
     */
    var getAddressSet = function () {
        var addressSet = [];
        var currentPostcode = postcode();

        if (currentPostcode == '') {
            return addressSet;
        }

        if (typeof(addresses[currentPostcode]) == 'undefined') {
            if (addressLookupBusy[currentPostcode] === true) {
                return false;
            }

            addressLookupBusy[currentPostcode] = true;

            ajaxRequestHandler.get({
                url:postcodeLookupUrl(),
                error:function() {
                    addressLookupBusy[currentPostcode] = false;

                    if (typeof settings.events.onFailure == 'function') {
                        settings.events.onFailure();
                        return true;
                    }

                    $.cwmodal.close();
                    return true;
                },
                success:function(responseData) {
                    var returnedAddresses = [];

                    for (var addressIndex in responseData) {
                        if (responseData.hasOwnProperty(addressIndex)) {
                            var addressData = responseData[addressIndex].address.split(',');
                            
                            var numberOrName = addressData[0];
                            var postcodeIndex = addressData.length - 1;
                            
                            var line1 = '';
                            var line2 = '';
                            var line3 = '';

                            var moniker = responseData[addressIndex].moniker;
                            
                            for (var addressDataIndex = 1; addressDataIndex < postcodeIndex; addressDataIndex++) {
                                switch (addressDataIndex) {
                                    case 1:
                                        line1 = addressData[1];
                                        break;

                                    case 2:
                                        line2 = addressData[2];
                                        break;

                                    default:
                                        line3 += addressData[addressDataIndex];
                                        if (addressDataIndex < postcodeIndex - 1) {
                                            line3 += ', ';
                                        }
                                        break;
                                }
                            }

                            returnedAddresses[addressIndex] = new address({
                                'moniker': moniker,
                                'numberOrName':numberOrName,
                                'line1':line1,
                                'line2':line2,
                                'line3':line3,
                                'postcode':addressData[postcodeIndex]
                            });
                        }
                    }

                    addresses[currentPostcode] = returnedAddresses;
                    addressLookupBusy[currentPostcode] = false;

                    if (addresses[currentPostcode].length) {
                        setState(states.LIGHTBOX_RESULTS);
                    } else {
                        setState(states.LIGHTBOX_NORESULTS);
                    }

                    updateInterface();
                },
                timeout:settings.ajax.timeout,
                retryLimit:settings.ajax.retryLimit,
                dataType:'json'
            });

            return false;
        }

        var currentNumberOrName = numberOrName();

        addressSet = addresses[currentPostcode];
        if (typeof currentNumberOrName == 'string' && currentNumberOrName != '') {
            var filteredAddressSet = [];
            var addressSetIndex = 0;
            var currentAddress = null;

            for (var addressIndex in addressSet) {
                if (addressSet.hasOwnProperty(addressIndex)) {
                    currentAddress = addressSet[addressIndex];

                    if (currentNumberOrName == currentAddress.numberOrName(true)) {
                        filteredAddressSet[addressSetIndex] = currentAddress;
                        addressSetIndex++;
                    }
                }
            }

            addressSet = filteredAddressSet;
        }

        return addressSet;
    };

    /**
     * Update what is displayed on screen based on the current state
     *
     *
     **/
    var updateInterface = function () {
/*
        START:0,                // Starting state, no lookup request yet made
        LIGHTBOX_PREPARING:1,   // Lightbox open, preparing to display either address choice or 'no results - try again' content
        LIGHTBOX_RESULTS:2,     // Lightbox open, displaying results of address lookup (when choices are available)
        LIGHTBOX_NORESULTS:3    // Lightbox open, displaying 'no results - try again' content
        LIGHTBOX_LOADING_FORMATTED_ADDRESS:4 // as it says
*/

        var isLightboxState = function() {
            switch (getState()) {
                case states.LIGHTBOX_PREPARING:
                case states.LIGHTBOX_RESULTS:
                case states.LIGHTBOX_NORESULTS:
                case states.LIGHTBOX_LOADING_FORMATTED_ADDRESS:
                    return true;
            }

            return false;
        };

        var populateAddressForm = function (address) {
            // Populate always-present fields
            $(settings.selectors.lookupNumberOrNameField).val(address.numberOrName());
            $(settings.selectors.lookupPostcodeField).val(address.postcode());
            $(settings.selectors.manualNumberOrNameField).val(address.numberOrName());
            $(settings.selectors.manualPostcodeField).val(address.postcode());

            // Populate address lines
            if (typeof settings.selectors.manualLine1Field == 'undefined' || settings.selectors.manualLine1Field == '') {
                return true;
            }

            var line1 = '';
            var line2 = '';
            var line3 = '';

            line1 = address.line1();

            if (typeof settings.selectors.manualLine2Field == 'undefined' || settings.selectors.manualLine2Field == '') {
                if (line2 != '') {
                    line1 += ', ';
                }

                line1 += address.line2();
            } else {
                line2 = address.line2();
            }

            if (typeof settings.selectors.manualLine3Field == 'undefined' || settings.selectors.manualLine3Field == '') {
                if (typeof settings.selectors.manualLine2Field == 'undefined' || settings.selectors.manualLine2Field == '') {
                    if (line3 != '') {
                        line1 += ', ';
                    }

                    line1 += address.line3();
                } else {
                    if (line3 != '') {
                        line2 += ', ';
                    }

                    line2 += address.line3();
                }
            } else {
                line3 = address.line3();
            }

            if (line1 != '') {
                $(settings.selectors.manualLine1Field).val(line1);
            }

            if (line2 != '') {
                $(settings.selectors.manualLine2Field).val(line2);
            }

            if (line3 != '') {
                $(settings.selectors.manualLine3Field).val(line3);
            }

            return true;
        };


        var getFormattedAddressUrl = function(moniker){
            var requestUrl = settings.ajax.url;
            var moduleKey = /Module\[[0-9]+\]/.exec(requestUrl);
            var moduleId = moduleKey[0].replace('Module', '').replace('[', '').replace(']', '');

            requestUrl += (requestUrl.indexOf('?') == -1) ? '?' : '&';
            requestUrl += 'Module['+moduleId+'][moniker]='+moniker;

            return requestUrl;
        };

        var getFormattedAddress = function(oAddress){
            setState(states.LIGHTBOX_LOADING_FORMATTED_ADDRESS);
            updateInterface();
            //we need to go back to the server to get the formatted address.
            // We will only need to pass in the moniker
            ajaxRequestHandler.get({
                url:getFormattedAddressUrl(oAddress.moniker()),
                error:function() {
                    //There was an error, attempt to output the
                    // unformatted address

                    populateAddressForm(oAddress);
                    $.cwmodal.close();
                    return true;
                },
                success:function(responseData) {
                    ajaxRequestHandler.clearRequest(getFormattedAddressUrl(oAddress.moniker()));
                    
                    // Populate always-present fields
                    $(settings.selectors.lookupNumberOrNameField).val(responseData.nameNumber);
                    $(settings.selectors.lookupPostcodeField).val(responseData.postcode);
                    $(settings.selectors.manualNumberOrNameField).val(responseData.nameNumber);
                    $(settings.selectors.manualPostcodeField).val(responseData.postcode);

                    $(settings.selectors.manualLine1Field).val(responseData.street);
                    $(settings.selectors.manualLine2Field).val(responseData.town);
                    $(settings.selectors.manualLine3Field).val(responseData.county);
                    
                    $.cwmodal.close();
                    return true;
                },
                timeout:settings.ajax.timeout,
                retryLimit:settings.ajax.retryLimit,
                dataType:'json'
            });
        };

        var lightbox = {
            content: {
                PREPARING: {
                    title:settings.content.lightbox.PREPARING.title
                },
                RESULTS: {
                    title:settings.content.lightbox.RESULTS.title,
                    content:function(){
                        var addressSet = getAddressSet();
                        var addessSetLength = addressSet.length;
                        var currentAddress = null;

                        var resultList = $('<ul />');
                        for (var addressIndex = 0; addressIndex < addessSetLength; addressIndex ++) {
                            try{
                                currentAddress = addressSet[addressIndex];

                                var listItem = $('<li />').hover(function(){
                                    $(this).addClass('over');
                                }, function(){
                                    $(this).removeClass('over');
                                }).html(currentAddress+'').attr(
                                    'id',
                                    currentAddress.moniker()
                                );

                                resultList.append(listItem);
                            } catch(e){}
                        }

                        resultList.children().filter(':last').addClass('last');
                        resultList.mouseout(function(){
                            $('li', this).removeClass('over');
                        });

                        resultList.click(function(event){
                            var selectedAddress = $(event.target).text();
                            var selectedAddressIndex = null;

                            for (var addressIndex = 0; addressIndex < addessSetLength; addressIndex ++) {
                                try{
                                    currentAddress = addressSet[addressIndex];
                                
                                    if (currentAddress.toString() == selectedAddress) {
                                        selectedAddressIndex = addressIndex;
                                        break;
                                    }
                                }catch(e){}
                            }

                            getFormattedAddress(addressSet[selectedAddressIndex]);

                            //populateAddressForm(addressSet[selectedAddressIndex]);
                            //$.cwmodal.close();
                        });

                        // 'See all addresses for POSTCODE' content
                        // -> included if there is a house number/name selected
                        var seeAllAction = null;
                        if (numberOrName().length) {
                            seeAllAction = $('<a />').text(
                                settings.content.lightbox.RESULTS.seeAllAddresses+' '+postcode(false)
                            ).css({
                                cursor:'pointer'
                            }).click(function() {
                                $(settings.selectors.lookupNumberOrNameField).val('');
                                performLookup(false);
                            }).append(
                                $('<br />')
                            );
                        } else {
                            seeAllAction = $('<br />');
                        }

                        var enterManuallyAction = $('<a />').text(
                            settings.content.lightbox.RESULTS.enterYourAddressManually
                        ).click(function() {
                            $.cwmodal.close();
                            $(settings.selectors.manualNumberOrNameField).focus();
                        }).css(
                            'cursor', 'pointer'
                        );

                        return $('<div />').append(
                            $('<div />').addClass('address-list').append(
                                resultList
                            )
                        ).append(
                            $('<div />').addClass('address-list-actions').append(
                                seeAllAction
                            ).append(
                                settings.content.lightbox.RESULTS.or
                            ).append(
                                enterManuallyAction
                            )
                        );
                    }
                },
                NORESULTS: {
                    title:function () {
                        var title = null;
                        var currentNumberOrName = numberOrName(false);
                        var currentPostcode = postcode(false);

                        var numberOrNameFilled = (currentNumberOrName == '') ? 'numberOrNameBlank' : 'numberOrNameFilled';
                        var postcodeFilled = (currentPostcode == '') ? 'postcodeBlank' : 'postcodeFilled';

                        switch (numberOrNameFilled+':'+postcodeFilled) {
                            case 'numberOrNameBlank:postcodeBlank':
                                title = settings.content.lightbox.NORESULTS.title;
                                break;

                            case 'numberOrNameBlank:postcodeFilled':
                                title = settings.content.lightbox.NORESULTS.title+settings.content.lightbox.NORESULTS['for']+' <u>'+currentPostcode+'</u>';
                                break;

                            case 'numberOrNameFilled:postcodeBlank':
                                title = settings.content.lightbox.NORESULTS.title+settings.content.lightbox.NORESULTS['for']+' <u>'+currentNumberOrName+'</u>';
                                break;

                            case 'numberOrNameFilled:postcodeFilled':
                                title = settings.content.lightbox.NORESULTS.title+settings.content.lightbox.NORESULTS['for']+' <u>'+currentNumberOrName+', '+currentPostcode+'</u>';
                                break;
                        }

                        return title;
                    },
                    content:function () {

                        return $('<div />').append(
                            $('<h3 />').text(
                                settings.content.lightbox.NORESULTS.tryAgain
                            )
                        ).append(
                            $('<form />').append(
                                $('<div />').addClass(
                                    'formRow'
                                ).append(
                                    getNumberOrNameLabel().attr(
                                        'for', 'numberornamerelookup'+settings.instanceId
                                    )
                                ).append(
                                    getNumberOrNameField().attr(
                                        'id', 'numberornamerelookup'+settings.instanceId
                                    ).change(function(){
                                        $(settings.selectors.lookupNumberOrNameField).val(
                                            $('#numberornamerelookup'+settings.instanceId).val()
                                        );
                                    })
                                )
                            ).append(
                                $('<div />').addClass(
                                    'formRow'
                                ).append(
                                    getPostcodeLabel().attr(
                                        'for', 'postcoderelookup'+settings.instanceId
                                    )
                                ).append(
                                    getPostcodeField().attr(
                                        'id', 'postcoderelookup'+settings.instanceId
                                    ).change(function(){
                                        $(settings.selectors.lookupPostcodeField).val(
                                            $('#postcoderelookup'+settings.instanceId).val()
                                        );
                                    })
                                ).append(
                                    button.clone()
                                )
                            )
                        ).append(
                            $('<h3 />').text(
                                settings.content.lightbox.NORESULTS.or
                            )
                        ).append(
                            $('<a />').text(
                                settings.content.lightbox.NORESULTS.enterYourAddressManually
                            ).click(function(){
                                $.cwmodal.close();
                                $(settings.selectors.manualNumberOrNameField).focus();
                            }).css(
                                'cursor', 'pointer'
                            )
                        );

                    }
                },
                LOADING_FORMATTED_ADDRESS:{
                    title:settings.content.lightbox.PREPARING.title,
                    content: ''
                }
            },

            getContent:function () {
                var lightboxState = getStateName().replace('LIGHTBOX_', '');

                var title = (typeof lightbox.content[lightboxState].title == 'function') ? lightbox.content[lightboxState].title() : lightbox.content[lightboxState].title;
                var content = (typeof lightbox.content[lightboxState].content == 'function') ? lightbox.content[lightboxState].content() : lightbox.content[lightboxState].content;

                return $('<div />').append(
                    $('<div />').addClass(
                        'content '+lightboxState
                    ).append(
                        $('<h2 />').append(title)
                    ).append(
                        $('<div />').addClass(
                            'inner'
                        ).append(
                            content
                        )
                    )
                );
            },

            addClasses:function (selector, classes) {
                if (typeof classes != 'string') {
                    return false;
                }

                var target = $(selector);
                if (target.length === 0) {
                    return false;
                }

                target.addClass(classes);
                return true;
            }
        };

        if (isLightboxState()) {
            $.cwmodal.close();

            lightbox.getContent().cwmodal({
                containerId:settings.lightbox.containerId
            });

            lightbox.addClasses('#'+settings.lightbox.containerId, settings.lightbox.containerClasses);
            lightbox.addClasses('#simplemodal-data', settings.lightbox.dataClasses);
        }

        switch (getState()) {
            case states.LIGHTBOX_PREPARING:
                break;

            case states.LIGHTBOX_RESULTS:
                break;

            case states.LIGHTBOX_NORESULTS:
                break;

            default:
                break;
        }
    };

    /**
     * Get the address lookup's 'Find Address' button
     *
     * @return CW.addressLookup.lookupButton
     */
    this.getButton = function () {
        return button;
    };

    /**
     * Are we performing a re-lookup (trying again from the lightbox form)?
     *
     * @return bool
     */
    var isRelookup = function() {
        return $('#'+settings.lightbox.containerId).length > 0;
    };

    /**
     * Perform the actual address lookup, which basically involves displaying
     * a lightbox with a set of address choices based on the name/number and postcode entered
     *
     */
    var performLookup = function (delayed) {
        if (typeof settings.events.preLookup == 'function') {
            settings.events.preLookup();
        }

        resetState();
        updateState(states.LIGHTBOX_PREPARING);

        var returnedAddresses = getAddressSet();        // Will change state, and update interface when done, if remote lookup is required
        if (returnedAddresses === false ) {
            updateState(states.LIGHTBOX_PREPARING);
            return true;
        }

        // Special case: when trying again from within the lightbox, display the 'Loading' state
        // for a fixed peroid instead of switching state straight away
        // -> otherwise the change from 'loading' to 'results/noresults' is /too/ fastyy
        if (isRelookup() && delayed !== false) {
            window.setTimeout(function(){
                performLookup(false);
            }, settings.tryAgainDelay);

            return true;
        }

        if (returnedAddresses.length) {
            setState(states.LIGHTBOX_RESULTS);
        } else {
            setState(states.LIGHTBOX_NORESULTS);
        }

        updateInterface();
        return true;
    };
    this.perform = performLookup;

    /**
     * Tidy up settings that, when wrong, can cause things to fail
     *
     */
    var setMissingSettings = function (defaults) {
        // Form field selector that, if not correctly specified, make things fail
        if (typeof settings.selectors.manualNumberOrNameField == 'undefined') {
            settings.selectors.manualNumberOrNameField = settings.selectors.lookupNumberOrNameField;
        }

        if (typeof settings.selectors.manualPostcodeField == 'undefined') {
            settings.selectors.manualPostcodeField = settings.selectors.lookupPostcodeField;
        }

        // Content that can be passed in as null but which causes things to fail if so
        if (typeof settings.content.lightbox.PREPARING.title != 'string') {
            settings.content.lightbox.PREPARING.title = defaults.content.lightbox.PREPARING.title;
        }

        if (typeof settings.content.lightbox.RESULTS.title != 'string') {
            settings.content.lightbox.RESULTS.title = defaults.content.lightbox.RESULTS.title;
        }

        if (typeof settings.content.lightbox.RESULTS.seeAllAddresses != 'string') {
            settings.content.lightbox.RESULTS.seeAllAddresses = defaults.content.lightbox.RESULTS.seeAllAddresses;
        }

        if (typeof settings.content.lightbox.RESULTS.enterYourAddressManually != 'string') {
            settings.content.lightbox.RESULTS.enterYourAddressManually = defaults.content.lightbox.RESULTS.enterYourAddressManually;
        }

        if (typeof settings.content.lightbox.NORESULTS.title != 'string') {
            settings.content.lightbox.NORESULTS.title = defaults.content.lightbox.NORESULTS.title;
        }

        if (typeof settings.content.lightbox.NORESULTS['for'] != 'string') {
            settings.content.lightbox.NORESULTS['for']  = defaults.content.lightbox.NORESULTS['for'];
        }

        if (typeof settings.content.lightbox.NORESULTS.tryAgain != 'string') {
            settings.content.lightbox.NORESULTS.tryAgain = defaults.content.lightbox.NORESULTS.tryAgain;
        }

        if (typeof settings.content.lightbox.NORESULTS.or != 'string') {
            settings.content.lightbox.NORESULTS.or = defaults.content.lightbox.NORESULTS.or;
        }

        if (typeof settings.content.lightbox.NORESULTS.enterYourAddressManually != 'string') {
            settings.content.lightbox.NORESULTS.enterYourAddressManually = defaults.content.lightbox.NORESULTS.enterYourAddressManually;
        }

    };

    /**
     * Initialise (called by constructor, no need to call directly)
     *
     * @param options {} as passed by constructor
     */
    var initialise = function (options) {
        var defaults = {
            instanceId:0,   // Block instance ID
            selectors: {    // jQuery selectors for relevant elements
                lookupNumberOrNameField:'input[class=addressLookup_numberOrName]',    // jQuery selector for house number/name form field relevant to lookup
                lookupPostcodeField:'input[class=addressLookup_postcode]',            // jQuery selector for postcode form field relevant to lookup
                manualNumberOrNameField:'',     // selector for number/name field for manual entry (if blank, assumed same as lookupNumberOrNameField
                manualLine1Field:'',            // selector for line1 of address
                manualLine2Field:'',            // selector for line2 of address (if blank, line2 address data will be concatenated with line1)
                manualLine3Field:'',            // selector for line3 of adderss (if blank, line3 address data will be concatenated with line2)
                manualPostcodeField:''          // selector for postcode field for manual entry (if blank, assumed same as lookupPostcodeField)
            },
            button: {                    // 'Find address' button (auto-generated and added next to postcode form field)
                id:'findAddressButton', // Button HTML id value
                src:'',                 // Button image HTML src value
                alt:''                  // Button image HTML alt value
            },
            ajax: {                                      // Options for remote Ajax request
                url:'http://example.com/incorrectUrl/', // Request URL
                timeout:5000,                           // Timeout (milliseconds)
                retryLimit:3                           // Number of times to retry if request fails
            },
            lightbox: {
                containerId:'addressLookup_lightbox',   // HTML id to apply to the lightbox container
                containerClasses:''                     // Additional CSS classes to apply to the lighbox container
            },
            events: {                                   // Functions to call when certain events happen
                onFailure:function(){},                 // ... when Ajax request fails (after having retried the specified number of times)
                preLookup:function(){}                  // ... before each lookup is performed. Is run after the 'Find address' button is clicked and before anything else happens
            },
            content: {
                lightbox: {
                    PREPARING: {
                        title:'Loading address list &hellip'
                    },
                    RESULTS: {
                        title:'Address list:',
                        seeAllAddresses:'See all addresses for',
                        enterYourAddressManually:'enter your address manually'
                    },
                    NORESULTS: {
                        title:'Sorry, nothing found ',
                        'for':'for',
                        tryAgain:'Try again',
                        or:'Or,',
                        enterYourAddressManually:'enter your address manually'
                    }
                }
            },
            tryAgainDelay:500                           // Number of milliseconds to automatically wait when trying again (smooths things out for searches that didn't have results the first time and won't have them when trying again)
        };

        settings = $.extend({}, defaults, options);
        setMissingSettings(defaults);

        button = new lookupButton(settings.button);
        button.sitNextTo(settings.selectors.lookupPostcodeField);

        ajaxRequestHandler = new AMAXUS.ajaxRequestHandler();

        resetState();
    };

    initialise(options);
};
/* end CW.addressLookup class */

/**
 * Class for checking if user CV total has been exceeded
 * @constructor
 */
CW.userCvTotalChecker = function (options) {
    var states = {
        WAITING:0,      // Default state, waiting to start
        CHECKING:1,     // In the process of checking user CV total
        EXCEEDED:2,     // Finished checking user CV total and succeeeded
        NOTEXCEEDED:3,  // Finished checking user CV total and succeeeded
        FAILED:4        // Finished checking user CV total and failed
    };

    var currentState = null;
    var defaultState = null;
    var ajaxRequestHandler = null;
    var requestUrl = null;
    var settings = null;

    var isStateValid = function (newState) {
        for (var stateName in states) {
            if (states.hasOwnProperty(stateName)) {
                if (states[stateName] == newState) {
                    return true;
                }
            }
        }

        return false;
    };

    var setState = function (newState) {
        if (!isStateValid(newState)) {
            newState = defaultState;
        }

        currentState = newState;
    };

    this.getState = function () {
        return currentState;
    };

    this.states = function() {
        return states;
    };

    this.reset = function () {
        setState();
    };

    /**
     * Has the user's CV total been exceeded?
     * -> user is allowed to store only X CVs         *
     *
     * /@/return sets state based on result
     *
     **/
    this.isExceeded = function () {
        if (currentState == states.WAITING) {
            ajaxRequestHandler.get({
                url:requestUrl,
                error:function() {
                    ajaxRequestHandler.clearRequest(requestUrl);
                    setState(states.FAILED);
                },
                success:function(responseData) {
                    ajaxRequestHandler.clearRequest(requestUrl);
                    if (responseData === false) {
                        setState(states.NOTEXCEEDED);
                    } else {
                        setState(states.EXCEEDED);
                    }
                },
                timeout:settings.ajaxRequestTimeout,
                retryLimit:settings.ajaxRequestRetryLimit,
                dataType:'json'
            });

            setState(states.CHECKING);
        }
    };

    var initialise = function (options) {
        defaultState = states.WAITING;
        setState();
        ajaxRequestHandler = new AMAXUS.ajaxRequestHandler();
        requestUrl = options.url;
        settings = options;

    };

    initialise(options);
};

/**
 * A jquery plugin to 
 *
 * @return jQuery
 */
jQuery.fn.replaceFileInput = function(options)
{    
    this.css({
        'opacity': 0,
        'position': 'absolute',
        'top': '0px',
        'right': '0px',
        'font-size': '50px',
        'cursor': 'pointer',
        'filter': 'alpha(opacity=0)',
        '-ms-filter': 'alpha(opacity=0)', 
	'-khtml-opacity': 0, 
	'-moz-opacity': 0
    });
    
    var textInput = $('<input />')
        .attr({
            'id': options['textInputId'],
            'className': options['textInputClass'],
            'type': 'text',
            'readonly': 'readonly'
        })
        .css({
            'float': 'left'
        });

    this.before(textInput);

    textInput.css({
        'margin-top': (options['imgHeight'].replace('px', '') - textInput.outerHeight()) / 2 + 'px'
    });
    
    this.change(
        function() {
            textInput.val(
                $(this).val()
            );
        }
    );
    
    var parent = this.parent();
    
    var label = $('label', parent);
    label.css('float', 'left');

    var wrapper = $('<div />').css({
        'position': 'relative',
        'overflow': 'hidden',     
        'width': options['imgWidth'],
        'height': options['imgHeight']
    });
    
    this.wrap(wrapper);
    
    var browseImg = $('<img />')
        .attr({
            'id': options['browseImgId'],
            'class': options['browseImgClass'],
            'src': options['src'],
            'alt': options['alt'],
            'title': options['title']
        })
        .css({
            'position': 'absolute',
            'top': '0px'
        });
        
    this.before(browseImg);
};

/**
 * Common tooltip handling
 *
 */
CW.toolTips = {};
CW.toolTips.initialise = function (context) {
    var tooltipContext = (context === undefined) ? document.body : context;

    // (?) form field tool tips
    $('.toolTip', tooltipContext).qToolTip();

    // Action icons (add/edit/delete)
    //  + remove the title attribute as this will cause IE to add it's own
    //    tooltip over this one.
    $('ul li form .toolTip', tooltipContext).qToolTip({
        selectors:{
            icon: 'input',
            content: '.content'
        },
        style: {
             classes:{
                'tooltip': 'toolTipForm'
            }
        }
    });

    $('ul li form .toolTipForm input', tooltipContext).attr('title', '');
};

/**
 * Bar to advertise new beta site
 */
CW.betaAdvert = function() {
    
    /**
     * Handle closing of the advert
     */
    function close() {
       Common_createCookie('betabannerhide', 'close', 360);
       $('#beta-advert').slideUp();
    }
    
    /**
     * Returns content for advert
     * 
     * @return jQuery
     */
    function getContent() {
        return $('<div />').attr('id', 'beta-advert').append(
            $('<div />').attr('id', 'beta-container').append(
                $('<div />').addClass('beta-wrapper').append(
                    $('<p />').text(oLocale.getTranslation('GlobaleLocale','bannercontent') + ' ').append(
                        $('<a />').attr('href', 'http://beta.careerswales.com').text('beta.careerswales.com').click(function() {
                            $('#beta-advert').slideUp();
                        })
                    ).addClass('content')   
                ).append(
                    $('<p />').append(
                        $('<a />').click(function(evt) {
                             close();
                             evt.preventDefault();
                        }).attr('href', '#')
                        .text(oLocale.getTranslation('GlobaleLocale', 'bannerClose'))
                    ).addClass('close')
                )
            )
        ).hide();
    }
    
    /**
     * Check whether the user has previously visited the page
     */
    function hasPreviouslyClosed() {
        return Common_readCookie('betabannerhide');
    }
    
    /**
     * Check whether we are on the beta site
     */ 
    function isBetaSite() {
        return SITE_CODE == 'cp';
    }
    
    /**
     * Initialise advert
     */
    function initialise() {
        var body    = $('body');
        var content = getContent();
        content.prependTo(body);
        content.slideDown();
    }
    
    if(hasPreviouslyClosed() || isBetaSite()) {
        return;
    }
    initialise();
};



/**
 * Learning Pathways grey text function.  Moved here as this code was littered
 * throughout all the modules.
 * 
 */
LearningPathways = {
    initDefaultTextHandler : function(block) {
        $('textarea.defaultGreyText', $(block)).bind('focus.learning-pathways-grey', function(){
            $(this).val('');
            $(this).attr('class', '');
            $(this).unbind('focus.learning-pathways-grey');
        });
    }
};
/* ConProviderCourse.js (153) */
var conProviderCourse = {

    self: this,

    initialize: function() {
        // add rounded corners to the details section
        $( '#courseDetailsWrap' ).corner();
    }

};

// @TODO: change this to use hijax
$(function(){ conProviderCourse.initialize(); });
/* CertificatesAndCourses.js (332) */
/**
 * @package private_output_careers_wales_learningpathways
 * @version $Id: CertificateAndCourses.js 8432 2008-05-23 14:09:25Z jamesrc $
 * @copyright Copyright (c) 2008 Box UK Ltd. All rights reserved.
 *
 * Adds tool tips and lightbox functionality to block.
 *
 * @audit
 * - 2009-08-11  JRC  Created file.
 */
var certificatesAndCourses = function() {

    var self = this;

    self.initialise = function( block ) {
         Common_addCalendarControls( 'calendar', 'certificateAndCoursesCal', block );
         $(block).tooglePathways({
            'content' : '.certificate',
            'module'  : 'CertificatesAndCourses'
         });
         $(".action .delete form").lightBoxDelete();
         $('.certificate', block).editInPlace({
            'selectors': {
                'form' : '.edit form',
                'editForm' : 'form.new'
            },
            'instanceId' : self.getInstanceId(),
            'module': 'CertificatesAndCourses',
            'action': 'editCertificate',
            'name'  : 'certificate',
            'aField': new Array('title', 'date', 'description')
         });

         LearningPathways.initDefaultTextHandler(block);
    };
};
/* WorkExperience.js (333) */
/**
 * @package private_output_careers_wales_learningpathways
 * @version $Id: WorkExperience.js 8432 2008-05-23 14:09:25Z jamesrc $
 * @copyright Copyright (c) 2008 Box UK Ltd. All rights reserved.
 *
 * Adds tool tips and lightbox functionality to block.
 *
 * @audit
 * - 2009-08-11  JRC  Created file.
 */
var workExperience = function() {

    var self = this;

    self.initialise = function( block ) {
        Common_addCalendarControls( 'calendar', 'workExperienceCal', block );
        $(block).tooglePathways({
            'content' : '.experience',
            'module'  : 'WorkExperience'
         });
         $(".action .delete form").lightBoxDelete({
             'module': 'WorkExperience'
         });

         $('.experience', block).editInPlace({
            'selectors': {
                'form' : '.edit form',
                'editForm' : 'form.new'
            },
            'instanceId' : self.getInstanceId(),
            'module': 'WorkExperience',
            'action': 'editExperience',
            'name'  : 'experience',
            'aField': new Array('title', 'location', 'startDate', 'endDate', 'description')
         });

         LearningPathways.initDefaultTextHandler(block);
    };
};
/* AchievementsAndExperience.js (334) */
/**
 * @package private_output_careers_wales_learningpathways
 * @version $Id: AchievementsAndExperience.js 8432 2008-05-23 14:09:25Z jamesrc $
 * @copyright Copyright (c) 2008 Box UK Ltd. All rights reserved.
 *
 * Adds tool tips and lightbox functionality to block.
 *
 * @audit
 * - 2009-08-11  JRC  Created file.
 */
var achievementsAndExperience = function() {

    var self = this;

    self.initialise = function( block ) {
         $(block).tooglePathways({
            'content' : '.achievement',
            'module'  : 'AchievementsAndExperience'
         });
         $('.action .delete form').lightBoxDelete({
             'module': 'AchievementsAndExperience'
         });
         $('.achievement', block).editInPlace({
            'selectors': {
                'form' : '.edit form',
                'editForm' : 'form.new'
            },
            'instanceId' : self.getInstanceId(),
            'module': 'AchievementsAndExperience',
            'action': 'editAchievement',
            'name'  : 'achievement',
            'aField': new Array('title', 'description')
         });

         LearningPathways.initDefaultTextHandler(block);
    };
};
/* Research.js (335) */
/**
 * @package private_output_careers_wales_learningpathways
 * @version $Id: Research.js 8432 2008-05-23 14:09:25Z jamesrc $
 * @copyright Copyright (c) 2008 Box UK Ltd. All rights reserved.
 *
 * Adds tool tips and lightbox functionality to block.
 *
 * @audit
 * - 2009-08-11  JRC  Created file.
 */
var research = function() {

    var self = this;

    self.initialise = function( block ) {
        $(".action .delete form").lightBoxDelete({
             'module': 'Research'
        });
    };
};
/* Qualifications.js (336) */
/**
 * @package private_output_careers_wales_learningpathways
 * @version $Id: Qualification.js 8432 2008-05-23 14:09:25Z jamesrc $
 * @copyright Copyright (c) 2008 Box UK Ltd. All rights reserved.
 *
 * Adds tool tips and lightbox functionality to block.
 *
 * @audit
 * - 2009-08-11  JRC  Created file.
 */
var qualifications = function() {

    var self        = this;

    self.initialise = function( block ) {           
        $(block).tooglePathways({
            'content' : '.qualification',
            'module'  : 'Qualifications'
        });
        $(".qualifications table td.delete form").lightBoxDelete({
             'module': 'Qualifications'
        });

        self.attachTitleChange( 'select[name="'+self.getModuleFieldTitle('courseId')+'"]', $('form.new'), true );

        $(".qualifications .content tr.qualification").lightBoxEdit({
            'instanceId' : self.getInstanceId(),
            'module': 'Qualifications',
            'action': 'editQualification',
            'containerId' : 'editQualification',
            'name' : 'qual',
            'formClass': 'qualification',
            'aField': new Array('title', 'qualification', 'qualificationStatus', 'grade'),
            'preLoadAction' : function( parameters ) {
               var aParams = {
                    'action': 'getDetails',
                    'format': 'json',
                    'qual'  : parameters.id
                };
                parameters.callBack();  
                //$('.toolTip', '#editQualification').qToolTip();
                CW.toolTips.initialise('#editQualification');
                $.ajax({
                    'url' : self.getApiUrl(aParams),
                    'dataType' : 'json',
                    'success' : function ( data, textStatus ) {
                        var oQualification = data.Module.oQualification.aField;
                        var form = parameters.form;

                        $('input[name="'+self.getModuleFieldTitle('provider')+'"]', form).attr('value', oQualification.provider);
                        $('input[name="'+self.getModuleFieldTitle('qualification')+'"]', form).attr('value', oQualification.qualification);
                        $('input[name="'+self.getModuleFieldTitle('awardingBody')+'"]', form).attr('value', oQualification.awardingBody);
                        $('input[name="'+self.getModuleFieldTitle('status')+'"]', form).attr('value', oQualification.qualificationStatus);
                        $('input[name="'+self.getModuleFieldTitle('startDate')+'"]', form).attr('value', oQualification.startDate);
                        $('input[name="'+self.getModuleFieldTitle('endDate')+'"]', form).attr('value', oQualification.endDate);
                        $('textarea[name="'+self.getModuleFieldTitle('description')+'"]', form).attr('value', oQualification.description);
                        

                        $('select[name="'+self.getModuleFieldTitle('courseId')+'"]', form).each(function() {
                            $('option:first', $(this)).remove();
                            $('option[value="'+oQualification.courseId+'"]', $(this)).attr('selected', 'selected');
                        });
                        self.attachTitleChange('select[name="'+self.getModuleFieldTitle('courseId')+'"]', form, false);
                        parameters.callBack();                        
                    }
                });

            }
        });

        LearningPathways.initDefaultTextHandler(block);

        /*If the user is running a very low res, lightboxes won't be entirely visible if they're placed as they would
        normally.  By highlighting the fact the res is low, we can easily do something about it.*/
        if (jQuery(window).height() <= 800) {
            jQuery('body').addClass('lowres');
        }
    };

    self.attachTitleChange = function( element, form, showLoader ) {
        $(element, form).each( function() {

            var element = $(this);

            element.change(function() {
                showLoader ? self.showLoadingQualificationDialog() : self.showLoadingQualificationMessage(form);
                
                var value = element.attr('value');
                
                var aParams = {
                    'action': 'getCourseDetails',
                    'format': 'json',
                    'course': value
                };

                $.ajax({
                    'url' : self.getApiUrl(aParams),
                    'cache' : true,
                    'dataType' : 'json',
                    'success' : function ( data, textStatus ) {
                        var module = data.Module;

                        if( module.oCourse ) {
                            var oCourse = module.oCourse.oContent;
                            var oMetadata = module.oCourse.oMetadataManager.oMetadata;
                            var aoQualifications = oCourse.aoQualifications;

                            $('input[name="'+self.getModuleFieldTitle('title')+'"]', form).attr('value', oMetadata.aField.title);
                            $('input[name="'+self.getModuleFieldTitle('startDate')+'"]', form).attr('value', oCourse.aField.dateStartFormatted);
                            $('input[name="'+self.getModuleFieldTitle('endDate')+'"]', form).attr('value', oCourse.aField.dateEndFormatted);

                            if( aoQualifications && aoQualifications !== 'null' ) {
                                var type = '';
                                var awardingBody = '';

                                var awardingBodyRoot = Amaxus.settings.aMetaRoots.awardingBody;
                                var qualificationRoot = Amaxus.settings.aMetaRoots.qualification;

                                // Loop over each qualification
                                for( var i = 0; i < aoQualifications.length; i++ ) {
                                    var aoCategories = aoQualifications[i].oMetadataManager.aoCategory;

                                    // Loop over each category for that qualification
                                    for ( var j = 0; j < aoCategories.length; j++ ) {
                                        var categoryId = aoCategories[j].aField.categoryId;
                                        var name       = aoCategories[j].aField.name;

                                        // Select the awarding body
                                        if ( categoryId.match(qualificationRoot)) {
                                            type += name;
                                            
                                            if( !(i == aoQualifications.length - 1) ) {
                                                type+= ', ';
                                            }
                                        }

                                        // Select the qualification title
                                        if ( categoryId.match(awardingBodyRoot)) {
                                            awardingBody += name;
                                            
                                            if( !(i == aoQualifications.length - 1) ) {
                                                awardingBody+= ', ';
                                            }
                                        }
                                    }
                                }

                                $('input[name="'+self.getModuleFieldTitle('qualification')+'"]', form).attr('value', type);
                                $('input[name="'+self.getModuleFieldTitle('awardingBody')+'"]', form).attr('value', awardingBody);
                            }
                        }
                        showLoader ? self.removeLoadingQualificationDialog() : self.removeLoadingQualificationMessage(form);
                    }
                });
            });
        });
    };

    /**
     * Shows a dialog notifying that user that the qualification is being
     * loaded
     */
    self.showLoadingQualificationDialog = function() {

        var content = self.getLoadMessage("<br />");
        content.cwmodal({
            overlayId  : 'QualLoader',
            containerId: 'QualContainer',
            maxHeight  : '80px'
        });
    };

    /**
     * Removes dialog notifying the user that the course is being loaded
     */
    self.removeLoadingQualificationDialog = function() {
        $.modal.close();
    };

    /**
     * Adds messages to edit lightbox
     */
    self.showLoadingQualificationMessage = function(form) {

        $('<div />').addClass('actionDispatcherMessages')
            .append(
                $('<ul />').append(
                    $('<li />').addClass('informationMessage').html(self.getLoadMessage(" - "))
                )
            )
            .insertBefore($('fieldset', form));
    };

    /**
     * Removes the messages from edit lightbox
     */
    self.removeLoadingQualificationMessage = function(form) {
        $('.actionDispatcherMessages', form).fadeOut(function() {
            $(this).remove();
        });
    };

    /**
     * Return message for loading content
     */
    self.getLoadMessage = function(seperator) {
        return $('<div />')
            .append(
                $('<img />')
                    .attr({
                        'src' : SITE_WEB_ROOT+ 'custom/careers_wales/img/ajax/spinner.gif',
                        'alt' : oLocale.getTranslation('Qualifications', 'labelLoadingQualification')
                    })
            )
            .append(
                $('<p />').html(
                    '<strong>'+oLocale.getTranslation('Qualifications', 'labelLoadingQualification')+'</strong>'+
                    seperator +
                    oLocale.getTranslation('Qualifications', 'labelPleaseWait')
                )
            );
    };
};
/* SupportTeam.js (337) */
/**
 * @package private_output_careers_wales_learningpathways
 * @version $Id: SupportTeam.js 8432 2008-05-23 14:09:25Z jamesrc $
 * @copyright Copyright (c) 2008 Box UK Ltd. All rights reserved.
 *
 * Adds tool tips and lightbox functionality to block.
 *
 * @audit
 * - 2009-08-11  JRC  Created file.
 */
var supportTeam = function() {

    var self = this;

    self.initialise = function( block ) {

        $(block).tooglePathways({
            'content' : '.member',
            'module'  : 'SupportTeam'
        });
        $(".action .delete form").lightBoxDelete({
             'module': 'SupportTeam'
        });

        $(".members .member").lightBoxEdit({
            'instanceId' : self.getInstanceId(),
            'module': 'SupportTeam',
            'aField': ['title', 'titleOther', 'name', 'contact'],
            'preLoadAction': function( parameters ) {                
                parameters.callBack();
                $('.toolTip', '#editContainer').qToolTip();
                self.initOtherJobRoleField($('#editContainer'));
            }
        });

        self.initOtherJobRoleField(block);
    };

    self.initOtherJobRoleField = function(block) {
        $('.titleOtherField', $(block)).hide();

        if ($('select', $(block)).val() == 'Other' || $('select', $(block)).val() == 'Arall') {
            $('.titleOtherField', $(block)).show();
        }

        $('select', $(block)).change(function() {
            if ($(this).val() == 'Other' || $('select', $(block)).val() == 'Arall') {
                $('.titleOtherField', $(block)).show();
            } else {
                $('.titleOtherField', $(block)).hide();
            }
        });
        
    };
};
/* LearningPathways.js (338) */
/**
 * @package private_output_careers_wales_learningpathways
 * @version $Id: LearningPathways.js 8432 2008-05-23 14:09:25Z jamesrc $
 * @copyright Copyright (c) 2008 Box UK Ltd. All rights reserved.
 *
 *
 * @audit
 * - 2009-08-11  JRC  Created file.
 */

/**
 * 
 * @param {object} localeText
 *
 * @constructor
 */
var lppDocumentChooser = function (localeText, type) {
    
    var actionAlignment = 'center';
    
    var formAction = 'server.php';

    var lightboxType = type;

    var content = function () {       

        var sectionList = $('#documentChooser').html();

        var formActions = $('<div class="actions ' + actionAlignment +' " />');
        var formActionIndex = 0;
        for (formActionIndex = 0; formActionIndex < actions.length; formActionIndex++) {
            formActions.append(
                $('<input type="' + actions[formActionIndex].type + '" name="' + actions[formActionIndex].name + '" src="' + actions[formActionIndex].src + '" value="' + actions[formActionIndex].value + '" alt="' + actions[formActionIndex].alt + '" />')
            );
        }
        
        var cancelLink = $('<div class="cancelLink" />').append(
            $('<p>' + oLocale._aTranslation.LearningPathways.or + ', <a href="#">' + oLocale._aTranslation.LearningPathways.cancel + '</a> ' + oLocale._aTranslation.LearningPathways.toCloseThisSection + '</p>').click(function() {
                $.modal.close();
                return false;
            })
        );

        var container = $('<div />');
        var form = $('<form method="get" action="' + formAction + '" target="_blank" />');
        form.addClass(lightboxType);
        
        form.append(sectionList).append(formActions).append(cancelLink);

        if (lightboxType=='download'){
            $('h2', $('#lppDocumentChooser')).html(oLocale._aTranslation.LearningPathways.chooserDownloadHeading);
        } else {
            $('h2', $('#lppDocumentChooser')).html(oLocale._aTranslation.LearningPathways.chooserPrintHeading);
        }


        return container.append(form);
    };

    var actions = [];

    this.addAction = function (actionOptions) {
        actions.push(actionOptions);
        return this;
    };

    this.launch = function () {                
        content().cwmodal({
            persist: false,
            containerId: 'lppDocumentChooser',
            containerCss: {height:'500px'}
        });
        
        // Swap out standard checkboxes for fancified ones
        $('input[type=checkbox]').each(function(){
            new replacementCheckbox(this);
        });        
    };

    this.setActionAlignment = function (alignmentChoice) {
        actionAlignment = alignmentChoice;
        return this;
    };
    
    this.setFormAction = function(theAction) {
        formAction = theAction;
        return this;
    };
};

var learningPathways = function() {

    var self = this;

    self.initialise = function( block ) {
                
        var downloadChooser = new lppDocumentChooser(oLocale._aTranslation.LearningPathways, 'download').addAction({
            'type': 'image',
            'src': '../custom/careers_wales/img/buttons/button_year10and11_Saveaspdf_' + oLocale.getFieldValue('id') + '.png',
            'name': 'saveAsPdf',
            'alt': oLocale._aTranslation.LearningPathways.buttonSaveAsPdf,
            'value': 1
        }).addAction({
            'type': 'image',
            'src': '../custom/careers_wales/img/buttons/button_year10and11_Saveasword_' + oLocale.getFieldValue('id') + '.png',
            'name': 'saveAsWord',
            'alt': oLocale._aTranslation.LearningPathways.buttonSaveAsWord,
            'value': 1
        }).addAction({
           'type':'hidden',
           'name':'change',
           'value':'LearningPathwaysDocument'
        }).addAction({
            'type':'hidden',
            'name':'filename',
            'value':'Learning Pathway Plan'
        }).addAction({
            'type':'hidden',
            'name':'forceDownload',
            'value':'true'
        }).setActionAlignment('center').setFormAction('custom/careers_wales/server_process.php');
        
        var printChooser = new lppDocumentChooser(oLocale._aTranslation.LearningPathways, 'print').addAction({
            'type':'image',
            'src': '../custom/careers_wales/img/buttons/button_year10and11_ViewPlan_' + oLocale.getFieldValue('id') + '.png',
            'name': 'viewPlan',
            'alt': oLocale._aTranslation.LearningPathways.buttonViewPlan,
            'value': 1
        }).addAction({
           'type':'hidden',
           'name':'change',
           'value':'LearningPathwaysDocument'
        }).setActionAlignment('right').setFormAction('server.php');
     
        $('.download a', block).click(function () {
            downloadChooser.launch();
            return false;
        });

        $('.print a', block).click(function () {
            printChooser.launch();
            return false;
        });

        //$('.download a').lightBoxDownload();
        Common_addCalendarControls( 'calendar', 'confirmCalendar' );
        self.attachPrintButton();
        
        // Download page
        // Swap out standard checkboxes for fancified ones
        $('#downloadDocumentChooser input[type=checkbox][class!=replaced]').each(function(){
            new replacementCheckbox(this);
        });          
    };
    
    self.getLocaleId = function () {
        return oLocale.getFieldValue('id');
    };    

    /**
     * Attachs a print button to the top of the page for printing a learning pathways
     * document
     * 
     */
    self.attachPrintButton = function() {

        // Check whether print is available or whether the user is confirming
        // If either are true, don't attach the print button.
        if( !window.print || $('.learningPathwaysDocument .confirm').length > 0 ) {
            return;
        }
        
        $('.learningPathwaysDocument .document').each( function() {
            $(this).css('position', 'relative');
            $(this).append(
                $('<div />')
                    .css({
                        'position' : 'absolute',
                        'top'      : '20px',
                        'right'    : '20px'
                    })
                    .addClass('printButton')
                    .append(
                        $('<a />')
                            .click(function() {
                                window.print();
                            })
                            .text(oLocale.getTranslation('LearningPathways', 'labelPrint'))
                    )
            );
        });
    };
};

/**
 * Class representing a fancified checkbox that is used to replace the browser default
 *
 * @constructor
 */
var replacementCheckbox = function (inboundCheckbox, inboundCallbacks) {
    var checkbox = null;        // The checkbox we're replacing (jQuery object)
    var replacement = null;
    var callbacks = {};

    var isChecked = function () {
        if (checkbox === null) {
            return true;
        }

        return checkbox.is(':checked');
    };

    this.isChecked = function () {
        return isChecked();
    };

    var check = function () {
        if (checkbox === null) {
            return true;
        }

        // Update actual checkbox
        checkbox.attr('checked', 'checked');

        // Update replacement checkbox imagery
        $('span', replacement).addClass('checkbox-checked');
        $('span', replacement).removeClass('checkbox-unchecked');

        return true;
    };

    this.check = function () {
        return check();
    };

    var uncheck = function () {
        if (checkbox === null) {
            return true;
        }

        // Update actual checkbox
        checkbox.attr('checked', '');

        // Update replacement checkbox imagery
        $('span', replacement).addClass('checkbox-unchecked');
        $('span', replacement).removeClass('checkbox-checked');
        return true;
    };

    this.uncheck = function () {
        return uncheck();
    };

    var toggle = function () {
        if (isChecked()) {
            uncheck();

            if (typeof callbacks.off == 'function') {
                callbacks.off();
            }

        } else {
            check();

           if (typeof callbacks.on == 'function') {
                callbacks.on();
           }
        }

        return true;
    };

    var initialise = function (inboundCheckbox, inboundCallbacks) {
        // Keep original checkbox
        checkbox = $(inboundCheckbox);

        // Check and store callback options
        if (typeof inboundCallbacks == 'object') {
            callbacks = inboundCallbacks;
        }

        // Swap out checkbox with replacement imagery
        if (!checkbox.is('replaced')) {
            checkbox.addClass('replaced');
        }

        replacement = $('<span />').addClass('checkarea').append('<span class="checkbox" />').click(function () {
            toggle();
            return false;
        });

        replacement.attr('title', checkbox.attr('title'));

        var existingReplacement = checkbox.next('span.checkarea');
        if (existingReplacement.length) {
            existingReplacement.remove();
        }

        checkbox.after(replacement);

        // Set initial checked/unchecked state of replacement
        if (isChecked()) {
            $('span', replacement).addClass('checkbox-checked');
        } else {
            $('span', replacement).addClass('checkbox-unchecked');
        }

        // Find label associated with checkbox (if present) and make that work with replacement
        var checkboxId = checkbox.attr('id');
        if (checkboxId.length) {
            var label = $('label[for='+checkboxId+']');
            label.click(function(){
                toggle();
                return false;
            });
        }

        return true;

    };

    initialise(inboundCheckbox, inboundCallbacks);
};
/* end replacementCheckbox class */
/* RelatedEClipsLeaflets.js (220) */
/**
 * Attached functionality to hide related leaflets if there are more
 * than ten of them.  Show / hide switch is added to to block.
 *
 * @author James Cryer
 * 
 */
var relatedEClipsLeaflets = function() {
	
    var self = this;
    var locale = 'RelatedEClipsLeaflets';

    self.initialise = function( block ) {
        
        // The block is not available if there is no related content
        if(block == null) {
            return;
        }
        self.hideLeaflets(block);
    };

    self.hideLeaflets = function(block) {
        

        $('ul.more-leaflets', block).each(function(i) {
            var list = $(this).slideUp();
            var actionLink = self.getActionLink()
                                .insertAfter(list).wrap($('<p />')
                                .addClass('view-more-container'));
            
            actionLink.toggle(
                function() {
                    list.slideDown();
                    $(this).text(oLocale.getTranslation( locale, 'hideMore'));
                },
                function () {
                    list.slideUp();
                    $(this).text(oLocale.getTranslation( locale, 'viewMore'));
                }
            );
        });
    };

    /**
     * Returns the link that the user can click to show more
     * related leaflets
     */
    self.getActionLink = function() {
        return $('<a />').addClass('viewMore')
                    .attr('href', '')
                    .text(oLocale.getTranslation( locale, 'viewMore'));
                    
    };
};
/* ConMediaFile.js (223) */
/************************************/
/*	ConMediaFile.js.223.allsites.js	*/
/************************************/

var FlashVideo = {
	
    langId	   : null,
    blockId	   : null,
    contentId  : null,
    file	   : null,
    width	   : null,
    height     : null,
    altContent : null,
    conSelector: null,
    vidSelector: null,
    fileType   : null,
    flvPlayer  : null,
    imageLoading: 'custom/careers_wales/img/year9/lightbox-ico-loading_',
    imageBtnPrev: 'custom/careers_wales/img/year9/lightbox-btn-prev_',
    imageBtnNext: 'custom/careers_wales/img/year9/lightbox-btn-next_',
    imageBtnClose: 'custom/careers_wales/img/year9/lightbox-btn-close_',
    imageBlank:	  'custom/careers_wales/img/year9/lightbox-blank_',
    imageExt:	  '.gif',
	
    init: function($langId, $blockId, $contentId, $file, $width, $height) {
		
        var self		 = this;

        // Pass values from Block
        self.langId		 = $langId;
        self.file		 = $file;
        self.width		 = $width;
        self.height		 = $height;
        self.blockId	 = $blockId;
        self.contentId	 = $contentId;
		
        // Determine whether we are using the old media player or the new media player
        tmp = self.file.split('.');
        self.fileType = tmp[tmp.length-1];
        self.flvPlayer   = self.fileType == 'flv' ? 'upload/videoplayer.swf' : 'http://62.128.130.234/images/video/videoplayer.swf';
		
        tmp2 = self.file.split('/');
        self.file = self.fileType == 'flv'? self.file: 'resources/'+tmp2[tmp2.length-1];
		
        // Selectors and HTML content
        self.conSelector = "#video_"+self.blockId;
        self.vidSelector = "flashVideo_"+self.contentId;
        self.altContent  = $(self.conSelector).html();
		
        if(self.checkFlashEnabled()) {
            if ( !(self.width > 470) ) {
                swfobject.embedSWF(
                    self.flvPlayer,
                    self.vidSelector,
                    self.width,
                    self.height,
                    "9.0.0",
                    '',
                    {   //  Flash variables
                        gXMLFilename:self.file,
                        file:self.file
                    },
                    {   // Param variables (<object><param name="$key" value="$value" /> ....</object>
                        'wmode':'transparent'
                    },
                    {

                    });
			
            }else {
                /*  The video is too large to fit into the content area.
					Add lightbox to the video instead! */
                self.imageLoading = self.imageLoading + $langId + self.imageExt;
                self.imageBtnPrev = self.imageBtnPrev + $langId + self.imageExt;
                self.imageBtnNext = self.imageBtnNext + $langId + self.imageExt;
                self.imageBtnClose= self.imageBtnClose + $langId + self.imageExt;
                self.imageBlank   =	self.imageBlank + $langId + self.imageExt;
				
                $("#"+self.vidSelector).wrap('<a id="'+self.contentId+'" href="'+self.file+'"></a>');
                $('#'+self.contentId).lightBox({
                    fixedNavigation:false,
                    imageLoading: self.imageLoading,
                    imageBtnPrev: self.imageBtnPrev,
                    imageBtnNext: self.imageBtnNext,
                    imageBtnClose:self.imageBtnClose,
                    imageBlank: self.imageBlank,
												
                    type     : 'flashVideo',
                    file	 : self.file,
                    width    : self.width,
                    height   : self.height,
                    flvPlayer: self.flvPlayer,
                    languageId: self.langId
                });
            }
            /* Need to remove support text */
            $("#support_"+self.blockId).hide();
        }
    },
	
    checkFlashEnabled: function() {

        var isInstalled = false;
        var version = null;
        if (window.ActiveXObject) {
            var control = null;
            try {
                control = new ActiveXObject('ShockwaveFlash.ShockwaveFlash');
            } catch (e) {
                return false;
            }
            if (control) {
                isInstalled = true;
                version = control.GetVariable('$version').substring(4);
                version = version.split(',');
                version = parseFloat(version[0] + '.' + version[1]);
            }
        } else {
            var plugin = (navigator.mimeTypes && navigator.mimeTypes["application/x-shockwave-flash"]) ? navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin : 0;
            if ( plugin ) {
                var words = navigator.plugins["Shockwave Flash"].description.split(" ");
                for (var i = 0; i < words.length; ++i) {
                    if (isNaN(parseInt(words[i]))){
                        continue;
                    }
                    var MM_PluginVersion = words[i];
                }
                isInstalled = MM_PluginVersion? true :false ;
            }
        }
        return isInstalled;
    }
};
/* MySiteAdmin.js (168) */
function setPosition(obj) {
    var aTargetArea = obj.id.split("_");
    $('#' + obj.id).children(".mySiteBox").each(function(inc) {
        var children = $(this).children();
        for (i = 0; i < children.length; i++) {
            if (children[i].name !== undefined) {
                if (children[i].name.search(/priority/) != -1) {
                    children[i].value = (inc + 1);
                }
                if (children[i].name.search(/targetArea/) != -1) {
                    children[i].value = (aTargetArea[1]);
                }
            }
        }
    });
}

/**
 *  creates a new MySiteAdmin administration
 *
 *  @param String blockName
 *
 */

function MySiteAdmin() {

    this.lightboxOverlay = null;
    this.lightboxContent = null;

}

/**
 *  called when block loads
 *
 *  @param block
 *
 */

MySiteAdmin.prototype.initialise = function( block ) {

    var blockId = $( block ).attr( 'id' ).match( /^block_(\d+)$/ )[ 1 ];

    this.blockId = blockId;
    this.hideAllForms();
    this.initEditInPlace( block, blockId );
    this.addAddBoxItemLinks();
    this.addDeleteItemLinks();
    this.addDeleteImageLinks();
    this.addCancelEditButtons();
    this.addClearUploadFieldFunctionality();
    this.initLightbox();
    this.addLightboxToEditFormSubmits();
    this.initSortablePublishing();
    this.initColorPickers();
    this.initSortableBoxItems( blockId );
    this.initHelpDocLightbox( block );
    this.initLoadingImage( block );
    this.initAddItemValidation( block );
    this.initRemoveImagesForTextOnly( block );
    this.initFlashItems();
    this.replaceFileInput();

    // publishing (only do on publishing page, obviously...)
    if ( $('div.mySiteAdmin form.publishing').length > 0 ) {
        this.addPublishingToggleLinks();
    }

};


/**
 * replaceFileInput
 */
MySiteAdmin.prototype.replaceFileInput = function( block ) {
    
    
    var customDir    = 'custom/careers_wales/';
    var buttonDir    = 'img/sen/buttons/';
    var removeButton = 'button_browse_';
    
    if (self.siteCode == 'sen') {
        removeButton += 'sen';
    }
    removeButton += oLocale.getFieldValue('id') + '.gif';
    
    $('#mySiteFileUpload').replaceFileInput({
        'textInputId': '',
        'textInputClass': 'textInput',
        'browseImgId': '',
        'browseImgClass': 'browseImg',
        'src': customDir + buttonDir + removeButton,
        'alt': 'Browse',
        'title': 'Browse',
        'imgWidth': '100px',
        'imgHeight': '29px'            
    });

};


/**
 *  adds submission validation to the new item forms
 *
 *  @param HTMLElement block
 *
 */

MySiteAdmin.prototype.initAddItemValidation = function( block ) {

    $( 'div.mySiteBoxItemFormNew form', block ).submit(function() {
        // If tinyMCE is being used, copy the contents over to the textarea for saving
        if (window.tinyMCE) {
            tinyMCE.triggerSave();
        }

        var isValidForm = true;
        var titleInput = $( 'input[type=text]', this )[ 1 ];
        var bodyInput = $( 'textarea', this )[ 1 ];

        if ( titleInput.value.trim() == '' ) {
            $( titleInput ).highlightError();
            isValidForm = false;
        }

        if ( bodyInput.value.trim() == '' ) {
            // As we use TinyMCE currently, the textarea isn't displayed
            // jQuery crashed when trying to animate the background colour
            // of iframe body tag, so overlay a div then remove it.
            
            var errorDiv = $('<div />')
                                .attr('class', 'errorDiv')
                                .css({
                                    'background' : 'red',
                                    'display'    : 'block',
                                    'position'   : 'absolute'
                                }).highlightError();
                                
            $(bodyInput).parent().append(errorDiv);

            $(errorDiv).fadeOut(
                'slow',
                function() {
                    $(this).remove();
                }
            );
            isValidForm = false;
        }
        return isValidForm;
    });
};

/**
 *  this makes sure the loading gif is loaded in the browser so it can be shown
 *  in the lightbox when saving.  this solves a problem with firefox where (i think)
 *  because it's loading a new page it won't make a request to fetch the image
 *  if it's not already loaded?  maybe... ?
 *
 *  @param HTMLElement block
 *
 */

MySiteAdmin.prototype.initLoadingImage = function( block ) {

    $( '<img/>' )
        .css({ display: 'none' })
        .attr({ src: SITE_WEB_ROOT+ 'custom/careers_wales/img/mysitesen/loading.gif' })
        .appendTo( block );

};

/**
 * Returns a unique string id for the wysiwyg
 *
 * @return string
 */
MySiteAdmin.prototype.getUniqueWysiwygId = function () {
    // ensure a completely unique id for each field, so no clashes occur
    // Number(new Date())   - returns the current timestamp
    // Math.random() * 100  - returns a random int between 0 and 100
    return 'wysiwyg-' + (Number(new Date()) % 100) + '-' + parseInt(Math.random() * 100, 10);
};

/**
 *  inits the "edit in place" functionality for box items
 *
 *  @param HTMLElement block
 *  @param int blockId
 *
 */

MySiteAdmin.prototype.initEditInPlace = function( block, blockId ) {

    var self = this;

    $( 'div.boxContent' ).each(function() {

        var boxContent = $( this );
        var langId = oLocale.getFieldValue( 'id' );

        // disable status fields
        $( 'select.status', boxContent )
            .attr({ disabled: true });

        // add delete image field (default to false)
        var deleteImageField = $( '<input type="hidden"/>' )
                                    .attr({
                                        name: 'Module[' +blockId+ '][item][deleteImage]',
                                        value: ''
                                    })
                                    .appendTo( $('form.editForm fieldset.hidden',boxContent) );

        function makeEditable() {

            var anchor = $( this )
                            .unbind( 'click' );
            var images = $( '.thumbnail img', boxContent ); // should be just one
            var image = null;
            var deleteImageLink = null;

            // if there's an image currently set, then we need to add the ability to delete it.

            if ( images.length > 0 ) {
                image = $( images[0] );
                deleteImageLink = $( '<a/>' )
                    .append(
                        $( '<img/>' ).attr({ src: SITE_WEB_ROOT+'custom/careers_wales/img/icons/delete.gif' })
                    )
                    .css({
                        position: 'absolute',
                        top: (image.position().top+8) + 'px',
                        left: (image.position().left+8) + 'px',
                        visibility: 'visible'
                    })
                    .click(function() {
                        deleteImageField.attr({ value: '1' });
                        image
                            .add( deleteImageLink )
                            .parent().parent().css({ display: 'none' }); // hide .thumbnail element
                        return false;
                    })
                    .insertAfter( image );
            }

            // add the image upload field
            var thumbnail = $( '<span/>' )
                .addClass( 'thumbnail' )
                .append(
                    $( '<label>' ).html( oLocale.getTranslation('MySiteAdmin','imageFilename') )
                )
                .append(
                    $( '<input type="file">' )
                        .attr({ name: 'mediaFile' })
                )
                .appendTo( $('.conMySiteBoxItem',boxContent) );

            // change title to text input
            var itemTitle = $( 'h4', boxContent )[ 0 ];
            var itemTitleElement =  $( '<input type="text">' )
                                        .addClass( 'itemTitle' )
                                        .attr({ name: 'Module[' +blockId+ '][item][title]' })
                                        .val( $(itemTitle).html() );
            $( itemTitle ).replaceWith( itemTitleElement );

            // change bodyText to a textarea
            var itemBody = $( 'div.bodyText', boxContent )[ 0 ];
            var itemBodyElement = $( '<textarea>' )
                                        .addClass( 'itemBodyText' )
                                        .attr({
                                            name: 'Module[' +blockId+ '][item][bodyText]',
                                            id:   self.getUniqueWysiwygId()
                                        })
                                        .val( $(itemBody).html() );
            $( itemBody ).replaceWith( itemBodyElement );

            tinyMCE.execCommand('mceAddControl', false, $(itemBodyElement).attr('id'));

            // editify the status select
            $( 'select.status', boxContent )
                .toggleClass( 'edit' )
                .attr({ disabled: false });

            var buttons = $( '<fieldset>' )
                .addClass( 'submitButtons' )
                .append(
                    $( '<input type="image">' )
                        .addClass( 'itemSubmit' )
                        .attr({ src: SITE_WEB_ROOT+ 'custom/careers_wales/img/buttons/button_save_' +langId+ '.gif' })
                        .click(function() {
                            // Quick fix for 17423, remove validation on title and description when editing
                            return true;
                        })
                )
                .append(
                    $( '<input type="image">' )
                        .addClass( 'itemCancel' )
                        .attr({ src: SITE_WEB_ROOT+ 'custom/careers_wales/img/buttons/button_cancel_' +langId+ '.gif' })
                        .click(function() {
                            // remove elements we've added
                            $( '.thumbnail', boxContent )
                                .css({ display: 'block' });
                            images
                                .unbind( 'mouseover' )
                                .unbind( 'mouseout' );
                            if ( deleteImageLink ) {
                                deleteImageLink.remove();
                            }
                            deleteImageField.attr({ value: '' });
                            buttons.remove();
                            thumbnail.remove();
                            // change form items back to their markup
                            $( 'input.itemTitle', boxContent ).each(function() {
                                $( this ).replaceWith( '<h4>' +$(this).val()+ '</h4>' );
                            });
                            $( 'textarea.itemBodyText', boxContent ).each(function() {
                                $( this ).replaceWith( '<div class="bodyText">' +$(this).val()+ '</div>' );
                            });
                            $( 'select.status', boxContent )
                                .attr({ disabled: true })
                                .toggleClass( 'edit' );
                            $('.mceEditorContainer', boxContent).remove();
                            anchor.click( makeEditable );
                            return false;
                        })
                )
                .appendTo( $('.conMySiteBoxItem',boxContent) );

            return false;

        }
        $( 'a.editLink', boxContent ).click( makeEditable );

    });

};

/**
 *  this makes the box items on the main content pages sortable, and when they're
 *  moved sends updates to the server
 *
 */

MySiteAdmin.prototype.initSortableBoxItems = function( blockId ) {

    var self = this;

    $( 'div.tabPage div.mySiteBoxItems' ).each(function(){

        // add drag handles to items
        self.addDragHandle($( 'div.mySiteBoxItem', this ));

        // populated before a drag starts, so when it finishes we
        // can check if anything has actually moved.
        var startBoxItemIds = null;

        // then init sortablility of container
        $( this )
            .sortable({
                handle: 'img.dragHandle',
                axis: 'y',
                items: 'div.mySiteBoxItem',
                start: function( e, ui ) {
                    startBoxItemIds = self.getBoxItemIds( $('.mySiteBoxItem',this) );
                },
                stop: function() {

                    var boxItems = this;
                    var newBoxItemIds = self.getBoxItemIds( $('.mySiteBoxItem',this) );

                    // lets check if anything has moved...
                    if ( newBoxItemIds != startBoxItemIds ) {

                        var url = SITE_WEB_ROOT+ 'api.php';
                        var boxBlockId = $( this ).attr( 'id' ).match( /mySiteBox_(\d+)/ )[ 1 ];
                        var feedback = Common_makeMessage(
                                'savingMessage',
                                oLocale.getTranslation('MySiteAdmin','savingFeedback')
                            )
                            .hide()
                            .appendTo( boxItems )
                            .fadeIn();

                        // make api call to update items
                        $.post( url,
                            {
                                'do': 'block.' +blockId,
                                'func': 'updateBoxItemPriorities',
                                'mySiteBox': boxBlockId,
                                'mySiteBoxItems': newBoxItemIds
                            },
                            function( responseText ) {
                                feedback.slideUp(function(){
                                    $(this).remove();
                                });
                                // if there was an error show an alert...
                                if ( responseText != 'true' ) {
                                    alert( responseText );
                                }
                            }
                        );

                    }

                }
            });

    });

};

/**
 *  adds a drag handle to the specified elements
 *
 *  @param HTMLElement element
 *
 */

MySiteAdmin.prototype.addDragHandle = function( items ) {

    $( items ).each(function(){
        $( '<img/>' )
            .attr({
                src: SITE_WEB_ROOT+ 'custom/careers_wales/img/ajax/dragHandle.gif'
            })
            .addClass( 'dragHandle' )
            .prependTo( this );
    });

};

/**
 *  returns a string of commer seperated ids for the items
 *  with mySiteBoxItem_\d+ matching id's
 *
 *  @param Array items
 *
 *  @return String
 *
 */

MySiteAdmin.prototype.getBoxItemIds = function( items ) {

    // when sorting stops there's still an old copy of the item we're
    // moving left in the DOM for a moment, so we need to check we don't
    // include the same ID's twice.
    var seenId = [];
    var itemIds = '';

    // work out the id's of all the box items
    $( items ).each(function() {

        var parts = $( this )
                        .attr( 'id' )
                        .match( /mySiteBoxItem_(\d+)/ );

        if ( parts && !seenId[parts[1]] ) {

            if ( itemIds != '' ) {
                itemIds += ',';
            }
            itemIds += parts[1];
            seenId[ parts[1] ] = true;

        }

    });

    return itemIds;

};

/**
 *  makes the list of items on the publish page sortable
 *
 */

MySiteAdmin.prototype.initSortablePublishing = function() {

    $("#publishingArea_1").sortable({
        connectWith: ['#publishingArea_2'],
        handle: 'h3',
        cursor: 'pointer',
        scroll: 'true',
        scrollSensitivity: 50,
        placeholder: 'publishPlaceholder',
        change: function(e, ui) {
            setPosition(this);
        }
    });
    $("#publishingArea_2").sortable({
        connectWith: ['#publishingArea_1'],
        handle: 'h3',
        cursor: 'pointer',
        scroll: 'true',
        scrollSensitivity: 50,
        placeholder: 'publishPlaceholder',
        change: function(e, ui) {
            setPosition(this);
        }
    });

};

/**
 * Creates the jquery color pickers on publish page
 */
MySiteAdmin.prototype.initColorPickers = function() {
    var colors = ['d40606', 'ff6600', 'ffff00', '99cc33',
                  '009900', '00becc', '003399', '670099',
                  'b10c68', 'cccccc', '808080', '000000'];
    $('.simple_color').simpleColor({
        cellWidth: 25,
        cellHeight: 25,
        border: '1px solid #333333',
        buttonClass: 'colourButton',
        colors: colors,
        boxWidth: 310,
        boxheight: 25,
        columns:4
    });
};

/**
 *  on the publishing page, hides the standard checkboxes and
 *  adds show/hide links for more intuitive editing of what
 *  content is going to be published.
 *
 */

MySiteAdmin.prototype.addPublishingToggleLinks = function() {

    // set all the checkboxes to checked as all the
    // boxes will be open initially.
    $( 'div.mySiteAdmin form.publishing div.toggler input[type=checkbox]' )
        .attr({ checked: true });

    $( 'div.mySiteAdmin form.publishing div.toggler' ).each(function(i,toggler) {

        var checkbox = $( 'input', toggler );
        var span = $( 'span', toggler );
        var mySiteBox = $( toggler ).parent().parent();

        // hide checkbox (it's still used though!)
        checkbox.css({ display: 'none' });
        // add new toggle show/hide link
        span.empty().append(
            $('<a/>')
                .attr({ href: 'javascript:;' })
                .html( oLocale.getTranslation('MySiteAdmin','toggleLink') )
                .click(function(){
                    // when the user toggles the section, we need to update the (hidden)
                    // checkbox, and also show/hide the box items
                    var isChecked = checkbox.attr( 'checked' );
                    checkbox.attr({ checked: !isChecked });
                    $( '.conMySiteBoxItem', mySiteBox )
                        .slideToggle();
                })
        );

    });
    
    // Hide the edit, save, and delete links.
    $('a.addText').hide();

};

/**
 *  init the lightbox ready to be shown with whatever content
 *
 */

MySiteAdmin.prototype.initLightbox = function() {

    var self = this;

    self.lightboxOverlay = $('<div></div>')
                    .addClass( 'mySiteAdmin-lightboxOverlay')
                    .css({
                        position: 'absolute',
                        top: 0,
                        left: 0,
                        opacity: '0.7'
                    })
                    .hide();
    self.lightboxContent = $( '<div></div>' )
                    .addClass( 'mySiteAdmin-lightboxContent')
                    .css({
                        position: 'absolute'
                    })
                    .hide();

    $( 'body' )
        .append( self.lightboxOverlay )
        .append( self.lightboxContent );

};

/**
 *  resizes the lightbox to fill the screen
 *
 */

MySiteAdmin.prototype.positionLightbox = function( pageSize, width, height ) {

    if( $.browser.msie && $.browser.version.substr(0,1)< 7 ) {
        this.lightboxOverlay.css({
            width: pageSize[0],
            height: pageSize[1]
        });
    }
    else {
        this.lightboxOverlay.css({
            width: '100%',
            height: '100%',
            position: 'fixed',
            top: 0,
            left: 0
        });
    }

    var top  = ((pageSize[3] / 2) + $(document).scrollTop()) - (height / 2);
    var left = (pageSize[2] / 2) - (width / 2);

    this.lightboxContent.css({
        width: width + 'px',
        left: left + 'px',
        top: top + 'px'
    });

};

/**
 *  shows the loading message in the lightbox
 *
 */

MySiteAdmin.prototype.showLightboxLoading = function() {

    var self = this;
    var content = $(
        '<div class="saving">' +
            '<h3>' +oLocale.getTranslation('MySiteAdmin','lightboxTitle')+ '</h3>' +
            '<div><img src="' +SITE_WEB_ROOT+ 'custom/careers_wales/img/mysitesen/loading.gif" /></div>' +
            '<p>' +oLocale.getTranslation('MySiteAdmin','lightboxMessage')+ '</p>' +
        '</div>'
    );

    self.showLightbox( content, 220, 100 );

};

/**
 *  shows the lightbox with some arbitrary content in it
 *
 *  @param HTMLElement content
 *  @param int width
 *  @param int height
 *
 */

MySiteAdmin.prototype.showLightbox = function( content, width, height, allowCancel, scrollContent ) {

    var self = this;
    var pageSize = this.getPageSize();

    self.lightboxContent
        .empty()
        .append(
            $( '<div>' )
                .addClass( 'mySiteAdminMain' )
                .append( content )
        );

    // hide some objects to stop problems in IE
    $( 'embed, object, select' )
        .not( $('*',content) )
        .hide();

    self.positionLightbox( pageSize, width, height );

    self.lightboxOverlay.fadeIn(function() {

        // turn on scrolling if we've been asked to
        var scrollClass = 'mySiteAdmin-lightboxContent-scroll';
        if ( scrollContent ) {
            self.lightboxContent.addClass( scrollClass ).append(self.getCloseButton());
        }
        else {
            self.lightboxContent.removeClass( scrollClass );
        }

        self.lightboxContent.show(50, function(){
            // auto focus the first text input field as IE8 was producing a bug
            // whereby you could not select it.
            $('input[type=text]', this).focus();
        });
        self.lightboxOverlay
            .unbind( 'click' )
            .click(function() {
                if ( allowCancel ) {
                    self.hideLightbox();
                }
            });

    });

};

/**
 *  hides the lightbox
 *
 */

MySiteAdmin.prototype.hideLightbox = function() {

    this.lightboxContent.hide();
    this.lightboxOverlay.fadeOut();

    // show some objects that were hidden to stop problems in IE
    $( 'embed, object, select' ).show();

};

/**
 *  returns an array of page width and height
 *  (from quirksmode.com)
 *
 *  @return Array( width, height )
 *
 */

MySiteAdmin.prototype.getPageSize = function() {
    var xScroll, yScroll;
    if (window.innerHeight && window.scrollMaxY) {
        xScroll = window.innerWidth + window.scrollMaxX;
        yScroll = window.innerHeight + window.scrollMaxY;
    } else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
        xScroll = document.body.scrollWidth;
        yScroll = document.body.scrollHeight;
    } else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
        xScroll = document.body.offsetWidth;
        yScroll = document.body.offsetHeight;
    }
    var windowWidth, windowHeight;
    if (this.innerHeight) { // all except Explorer
        if(document.documentElement.clientWidth){
            windowWidth = document.documentElement.clientWidth;
        } else {
            windowWidth = this.innerWidth;
        }
        windowHeight = this.innerHeight;
    } else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
        windowWidth = document.documentElement.clientWidth;
        windowHeight = document.documentElement.clientHeight;
    } else if (document.body) { // other Explorers
        windowWidth = document.body.clientWidth;
        windowHeight = document.body.clientHeight;
    }
    // for small pages with total height less then height of the viewport
    if(yScroll < windowHeight){
        pageHeight = windowHeight;
    } else {
        pageHeight = yScroll;
    }
    // for small pages with total width less then width of the viewport
    if(xScroll < windowWidth){
        pageWidth = xScroll;
    } else {
        pageWidth = windowWidth;
    }
    arrayPageSize = new Array(pageWidth,pageHeight,windowWidth,windowHeight);
    return arrayPageSize;
};

/**
 *  when any form is submitted, this show a lightbox style prompt
 *  informing the user something is going on
 *
 */

MySiteAdmin.prototype.addLightboxToEditFormSubmits = function() {

    var self = this;

    $( 'div.mySiteAdmin form.editForm' ).submit(function(){
        self.showLightboxLoading();
        return true;
    });

};

/**
 *  hides all the forms for editing box items
 *
 */

MySiteAdmin.prototype.hideAllForms = function() {

    $( 'div.mySiteAdmin div.mySiteBoxItemForm' )
        .hide();

};

/**
 *  changes all the add box item links to show only the form associated with
 *  that box item in a lightbox.
 *
 */

MySiteAdmin.prototype.addAddBoxItemLinks = function() {

    var self = this;

    $( 'p.addLink a' ).click(function() {
        // Get the (hidden) form, deep clone and show it
        var $formId = $(this).attr('href');
        var $form = $($formId).clone(true).show();

        // Apply an id to the textarea for wysiwyg conversion
        var $wysiwygId = self.getUniqueWysiwygId();
        $('textarea', $form).attr({
            id: $wysiwygId
        });

        // and now show it
        self.showLightbox($form, 600, 300, true );

        // Add tinyMCE functionality to it - this has to be done after the item is displayed
        tinyMCE.execCommand('mceAddControl', false, $wysiwygId);

        return false;
    });

};

MySiteAdmin.prototype.addDeleteItemLinks = function() {

    var self = this;

    $( 'a.deleteLink').click(function(){

        var contentId = $( this ).attr( 'href' ).substring( 1 );

        $( '#deleteItem_contentId' )
            .val( contentId );

        self.showLightbox(
            $( '#deleteForm' )
                .clone( true )
                .show(),
            300, 60, true
        );

        return false;

    });

};

MySiteAdmin.prototype.addDeleteImageLinks = function() {

    var self = this;

    $( 'a.deleteImage').click(function(){

        var contentId = $( this ).attr( 'href' ).substring( 1 );

        $( '#deleteImage_contentId' )
            .val( contentId );

        self.showLightbox(
            $( '#deleteImageForm' )
                .clone( true )
                .show(),
            300, 60, true
        );
        return false;
    });
};

/**
 *  adds buttons to the edit forms so the user can "cancel" out and
 *  get back to viewing all their boxes
 *
 */

MySiteAdmin.prototype.addCancelEditButtons = function() {

    var self = this;
    var langId = oLocale.getFieldValue( 'id' );
	var addImagePath = SITE_CODE == 'sen' ? 'myfuture_' : '';

    $( 'p.submissionControls' ).each(function() {
        $( this ).append(
            $( '<input type="image" />' )
                .attr({
                    value: oLocale.getTranslation('MySiteAdmin','cancelButton'),
                    src: SITE_WEB_ROOT+ 'custom/careers_wales/img/buttons/button_'+ addImagePath +'cancel_' +langId+ '.gif'
                })
                .click(function() {
                    self.hideLightbox();
                    return false;
                })
        );
    });

};

/**
 *  adds functionality to the upload cancel links
 *
 */

MySiteAdmin.prototype.addClearUploadFieldFunctionality = function() {

    $( 'div.mySiteAdmin p.fileUploader a.reset, div.mySiteAdminMain p.uploadText a.reset').click(
        function() {
            var uploadsDiv = $( this ).parent().parent();
            $( 'input.file', uploadsDiv ).val( '' );
            return false;
        }
    );

};

/**
 *  if there is a help document on the page then creates a link to show
 *  it in a lightbox.
 *
 *  @param HTMLElement block
 *
 */

MySiteAdmin.prototype.initHelpDocLightbox = function( block ) {

    var self = this;
	var localeId = oLocale.getFieldValue( 'id' );

    $( 'div#tabHelpDoc').each(function() {

        var helpDoc = $( 'div.content', this )[ 0 ];

        $( '<a/>' )
            .append(
                $( '<img>' )
                    .attr({ src: SITE_WEB_ROOT+ 'custom/careers_wales/img/buttons/button_help_'+ localeId +'.gif'})
            )
            .attr({ href: 'javascript:;' })
            .click(function() {
                self.showLightbox(
                    $( '<div>' )
                        .addClass( 'helpDoc' )
                        .append( $( helpDoc ).clone() ),
                    650,
                    500,
                    true,
                    true
                );
            })
            .appendTo( this );

    });

};

/**
 * Remove images when publishing a text only versions
 *
 */
MySiteAdmin.prototype.initRemoveImagesForTextOnly = function ( block ) {

	var self = this;

	$('form.publishTextOnly div.mySiteBox').each( function() {
		$('.play_audio, .play_video, .thumbnail, div.result img').remove();
	});

};

MySiteAdminMain.prototype = new MySiteAdmin();
MySiteAdminMain.prototype.constructor = MySiteAdminMain;

function MySiteAdminMain() {}

/**
 *  initialiser for this block
 *
 *  @param HTMLElement block
 *
 */

MySiteAdminMain.prototype.initialise = function( block ) {

    // chain constructors...
    MySiteAdmin.prototype.initialise.call( this, block );

    this.initCreateGuestForm( block, this.blockId );
    this.addConfirmDeletePrompts( block );
    this.addDeleteActionToMyLearningTable( 'table#myLearning td.delete', block );
    this.addDeleteActionToMyLearningTable( 'table#myCertifications td.delete', block);
    this.addMyLearningAddNewFeedback( $('table#myLearning',block) );
    this.addMyLearningAddNewFeedback( $('table#myCertifications', block) );
    this.initPublishMyLearning( 'table#publishMyCertification', block );
    this.initPublishMyLearning( 'table#publishMyLearning', block );

    Common_addCalendarControls( 'date', 'MySiteAdmin_calenderDiv' );

};

/**
 *  adds toggle show/hide functionality to the my learning table
 *
 *  @param HTMLElement block
 *
 */

MySiteAdminMain.prototype.initPublishMyLearning = function( table, block ) {

    $( table ).each(function(i,table) {

        $( 'tr' )
            .filter( ':has(input:checked)' )
            .addClass( 'enabled' );

        $( 'input[type=checkbox]', table )
            .click(function() {
                $( this ).parent().parent()
                    .toggleClass( 'enabled' );
            });

    });

};

/**
 *  adds some visual feedback to the 'add new' row of the my learning table.  this
 *  displays some text in the field until it gets focus when it's removed.
 *
 *  @param HTMLTableElement block
 *
 */

MySiteAdminMain.prototype.addMyLearningAddNewFeedback = function( table ) {

    var defaultValue = '...';

    $( 'tr.newitem input.text', table ).each(function() {

        var input = this;

        // add blur/focus handlers to add/remove default
        $( input )
            .val( defaultValue )
            .focus(function() {
                if ( $(input).val() == defaultValue )
                    $( input ).val( '' );
            })
            .blur(function() {
                if ( $(input).val() == '' )
                    $( input ).val( defaultValue );
            });

        // attach clear handler to form submit
        $( this )
            .parent().parent().parent()
            .submit(function() {
                if ( $(input).val() == defaultValue )
                    $( input ).val( '' );
            });

    });

};

/**
 *  adds delete links to the deletable achievements.
 *
 *  this is here because IE doesn't support passing the NAME of image
 *  input's, only the x/y click value.  this means you can only have
 *  1 form action using them.  what a workaround...
 *
 *  @param HTMLElement block
 *
 */

MySiteAdminMain.prototype.addDeleteActionToMyLearningTable = function( table,  block ) {

    $( table ).each(function() {

        var id = $( this )
                    .attr( 'class' )
                    .match( /delete-(\d+)/ )[ 1 ];

        $( this )
            .append(
                $( '<a/>' )
                    .addClass( 'icon' )
                    .append(
                        $( '<img>' )
                            .attr({ src: SITE_WEB_ROOT+ 'custom/careers_wales/img/icons/delete.gif' })
                    )
                    .attr({ href: 'javascript:;' })
                    .click(function() {
                        if ( confirm(oLocale.getTranslation('MySiteAdminMain','supportTeam_confDelete')) ) {
                            $( '#deleteAchievementForm' +id ).submit();
                        }
                    })
            );

    });

};

/**
 *  turns the create guest form into a lightboxified version
 *
 *  @param HTMLElement block
 *
 */

MySiteAdminMain.prototype.initCreateGuestForm = function( block, blockId ) {

    var self = this;

    $( 'form#createGuestForm', block ).each(function() {

        var form = this;
        var langId = oLocale.getFieldValue( 'id' );

        $( '<div/>' )
            .addClass( 'feedback' )
            .hide()
            .appendTo( form );

        //
        //  hijack submit event and send query to amaxus...
        //

        $( form ).submit(function() {

            var subForm = this;

            // hide form, show loading...
            $( 'fieldset', subForm )
                .fadeOut(function() {
                    $( 'div.feedback', subForm )
                        .html( 'Saving...' )
                        .fadeIn();
                });

            // then submit the form
            $( this ).ajaxSubmit({
                url: $( this ).attr( 'action' ) + '?jsonOutput=' +blockId,
                success: function( responseText ) {

                    eval( 'var json = ' +responseText );
                    var module = json.Module;
                    var errors = AMAMXUS.errorList.getFromModule( module );

                    // were there errors?
                    if ( errors.length > 0 ) {

                        $( 'div.feedback', subForm )
                            .empty()
                            .append(
                                $( '<div/>' )
                                    .html( '<p>' +module.aXslText.sorryButErrors+ '</p>' +
                                           CW.errorList.makeHTML(errors, {liClasses:'',spanClasses:''}) )
                            )
                            .append(
                                $( '<a/>' )
                                    .attr({ href: 'javascript:;' })
                                    .html( 'Try again' )
                                    .click(function() {
                                        // try again, re-show the form...
                                        $( 'div.feedback', subForm )
                                            .fadeOut(function() {
                                                $( 'fieldset', subForm )
                                                    .fadeIn();
                                            });
                                    })
                            );

                    }
                    // if not urr... reload the page? :-/
                    else {
                        // @TODO
                        // it would be nice to just hide the lightbox here and
                        // add this info to the table on the page.  no time now...
                        location.reload();
                    }

                }
            });

            // cancel normal form submit
            return false;

        });

        //
        //  add password strength indicators
        //

        $( 'input[type=password]', form ).passwordStrength();

        //
        //  create add link to show the form in a lightbox
        //

        $( '<a/>' )
            .attr({ href: 'javascript:;' })
            .addClass( 'createGuest' )
            .append(
                $( '<img>' )
                    .attr({ src: SITE_WEB_ROOT+ 'custom/careers_wales/img/buttons/button_create_' +langId+ '.gif' })
            )
            .click(function() {
                // show in lightbox
                self.showLightbox(
                    $( form )
                        .clone( true )
                        .show(),
                    500,
                    160,
                    true
                )
            })
            .insertBefore( form );

        //
        //  add cancel link to form
        //

        $( 'fieldset.submit', form )
            .append(
                $( '<input type="image">' )
                    .attr({ src: SITE_WEB_ROOT+ 'custom/careers_wales/img/buttons/button_cancel_' +langId+ '.gif' })
                    .click(function() {
                        self.hideLightbox();
                        return false;
                    })
            );

        //
        //  hide the form
        //

        $( form )
            .css({
                display: 'none'
            });

    });

};

/**
 *  adds confirmation prompts to the links to delete guests
 *
 *  @param HTMLElement block
 *
 */

MySiteAdminMain.prototype.addConfirmDeletePrompts = function( block ) {

    $( 'input.delete', block ).each(function() {
        $( this ).click(function() {
            return confirm( oLocale.getTranslation('MySiteAdminMain','supportTeam_confDelete') );
        });
    });
};

/**
 * returns a close button for lightbox
 *
 */

MySiteAdminMain.prototype.getCloseButton = function() {

    var self = this;

    return $('<div id="btn_close" />')
        .append($('<a />')
            .html(oLocale.getTranslation('MySiteAdminMain','lightboxClose'))
            .attr({ href: 'javascript:;' })
            .addClass('deleteLink')
            .click(function() {
                self.hideLightbox();
                return false;
            })
        );

};

MySiteAdmin.prototype.initFlashItems = function() {
    var self = this;
    
    self.initAddText();
    self.initRemoveFlashItem();
    $('.conMySiteBoxItem .result:even').addClass('odd');
};

MySiteAdmin.prototype.initAddText = function() {
    
    var self = this;
    
    $('.conMySiteBoxItem .result').each(function(i){
        var item = $(this);
        
        $('p.addText', item).show();
        $('textarea.addText, a.save', item).hide();
        
        if (!$('p.addText', item).length > 0){
            $('a.delete', item).hide();
            $('a.edit', item).text(oLocale.getTranslation('MySiteAdminMain', 'add'));
        }
        
        $('a.edit', item).click(function(){
            var parent = $(this).parent().addClass('expanded');
            
            var p = $('p.addText', parent);
            var textarea = $('textarea.addText', parent);

            var elementsToHide = $('a.edit, a.delete', parent).add(p);
            var elementsToShow = $('a.save', parent).add(textarea);

            $(elementsToHide).hide('slow', function(){
                textarea.attr('value', p.html());
                $(elementsToShow).show('slow');
            });
        });
        
        $('a.save', item).click(function(){
            var parent = $(this).parent().removeClass('expanded');

            var p        = $('p.addText', parent);
            var textarea = $('textarea.addText', parent);

            var elementsToHide = $('a.save', parent).add(textarea);
            $('a.edit, a.delete', parent).add(p);
            $('a.edit', parent).text(oLocale.getTranslation('MySiteAdminMain', 'edit'));
            $(elementsToHide).hide('slow', function(){
                p.html(textarea.attr('value'));
                //Sometimes the p el is hidden at this point,
                //so ensure that it is visible
                p.show();

                $('a.edit', parent).show();

                if(p.html().length > 0){
                    $('a.delete', parent).show();
                    p.removeClass('empty');

                }else{
                    //hide the remove link
                    $('a.delete', parent).hide();
                    p.addClass('empty');
                    $('a.edit', parent).text(oLocale.getTranslation('MySiteAdminMain', 'add'));
                }
                self.addText($(this));
            });
        });
        
        $('a.delete', item).click(function(){
            var parent = $(this).parent();
            $('p.addText', parent).html('').addClass('empty');
            $(this).fadeOut(function() {
                $('a.edit', parent)
                    .text(oLocale.getTranslation('MySiteAdminMain', 'add'))
                    .fadeIn();
            });
            self.addText($(this));
        });
    });
};

/**
 * Sent request to update text 
 *
 */
MySiteAdmin.prototype.addText = function(element, textToAdd) {
    var self    = this;
    var blockId = self.getBlockIdentifier(element);
    
    var content = element.parent();
    while(!content.hasClass('conMySiteBoxItem')){
        content = content.parent();
    }
    
    var contentId    = content.attr('id').split('_')[1];
    var bodyText     = self.cleanseContent($('.bodyText', content).clone());
    var actionStr    = 'Module['+blockId+'][action]=addText';
    var contentIdStr = 'Module['+blockId+'][contentId]='+contentId;
    var bodyTextStr  = 'Module['+blockId+'][bodyText]='+bodyText;
    var dataString   = '&'+actionStr+'&'+contentIdStr+'&'+bodyTextStr;
    
    $.ajax({
        'contentType': 'application/x-www-form-urlencoded',
        'type'       : 'POST',
        'url'        : window.location.href.split('&')[0],
        'data'       : dataString
    });
};

/**
 * Handle clicks to remove flash items
 */
MySiteAdmin.prototype.initRemoveFlashItem = function() {
    
    var self = this;
    // don't let users remove items when on publishing forms
    if ( !$('div.mySiteAdmin form.publishing').length > 0 ) {
        $('.conMySiteBoxItem .result').each(function(){
            $('<div />').addClass('removeFlashItem').append(
                $('<a />').text(oLocale.getTranslation('MySiteAdminMain', 'deleteItem')).click(function(evt) {
                    var item = $(this).parent().parent();
                    var box  = item.parent().parent().parent().parent().parent();

                    if(box.find('.result').length == 1) {
                        self.removeBlock(item, box);
                    }
                    else {
                        self.removeItem(item, box);
                    }
                    evt.preventDefault();
                })
            ).insertAfter($('img', $(this)));
        });
    }
};

MySiteAdmin.prototype.removeBlock = function(item, box) {
    var self         = this;
    var id           = box.attr('id').split('_')[1]; 
    var blockId      = self.getBlockIdentifier(box);
    var actionParam  = 'Module['+blockId+'][action]=removeFlashBox';
    var idParam      = 'Module['+blockId+'][contentId]='+id;
    var dataString   = '&'+actionParam+'&'+idParam;
    
    $.ajax({
        'contentType': 'application/x-www-form-urlencoded',
        'type'       : 'POST',
        'url'        : window.location.href.split('&')[0],
        'data'       : dataString
    });
    box.fadeOut(function() {
        box.remove(); 
    });
};

/**
 * Remove an individual Flash item from the flash content
 */
MySiteAdmin.prototype.removeItem = function(item, box) {
    var self = this;
    var id   = box.attr('id').split('_')[1];
    item.fadeOut(function() {
        $(this).remove();
        
        // Setup content
        var content = self.cleanseContent(box.find('.bodyText').clone());

        // Setup request
        var blockId         = self.getBlockIdentifier(box);
        var actionParam     = 'Module['+blockId+'][action]=removeFlashItem';
        var idParam         = 'Module['+blockId+'][contentId]='+id;
        var bodyTextParam   = 'Module['+blockId+'][bodyText]='+content;
        var dataString      = actionParam+'&'+idParam+'&'+bodyTextParam;

        $.ajax({
            'contentType': 'application/x-www-form-urlencoded',
            'type'       : 'POST',
            'url'        : window.location.href.split('&')[0],
            'data'       : dataString
        });
    });
};

/**
 * Return block identifier for current block
 * 
 * @return int
 */
MySiteAdmin.prototype.getBlockIdentifier = function(elem) {
    var block = elem.parent();
    while(!block.hasClass('block')){
        block = block.parent();
    }
    return block.attr('id').split('_')[1];
};

/**
 * Clean the input before posting it to the server
 * 
 */
MySiteAdmin.prototype.cleanseContent = function(content) {
    $('*', content).removeAttr('style');
    
    // IE: Remove jQuery 'sizcache' and 'sizset' attributes from bound elements
    $('*', content).removeAttr('sizcache');
    $('*', content).removeAttr('sizset');
    
    // IE: Unbind jQuery event handlers (remove all attributes with a 'jQuery' prefix
    $('*', content).unbind();
    $(content).unbind();
    
    $('.removeFlashItem', content).remove();
    //$('.addText', content).remove();
    
    /**
     * For some reason, img tags contained in the jQuery .html() attribute of the .bodyText element don't have a slash-close.
     * This seems to be the easiest way to add slash-closes to all img tags
     */
    content = content.html()
        // Remove any slash-closes, just in case
        .replace(/(<img\s+)(.*?)\/>/gi, '$1$2>')
        // Add slash-closes to all img tags
        .replace(/(<img\s+)(.*?)>/gi, '$1$2/>')
        // Don't know why, but IE doesn't enclose all class names in quotes
        .replace(/(\b(class)=(result|addText)\b)/gi, '$2="$3"');
    return content;
};


// objects for hijax

var mySiteAdmin = MySiteAdmin;
var mySiteAdminMain = MySiteAdminMain;
/* EClipsSearch.js (172) */
var eClipsSearch = function() {

    var self = this;

    self.initialise = function( block ) {

        self.hijaxSearch(block);
    };

    /**
     * Checks whether the user has entered enough information to perform a search.
     * Adds error messages to the page if it cannot the form is invalid.
     * Also scroll user to top of page to see results.
     */
    self.hijaxSearch = function( block ) {

        var errors = $('<div />')
        .addClass('actionDispatcherMessages')
        .addClass('search-errors')
        .insertBefore($('form.categorySearch', block));
        
        $('form.categorySearch', block).submit(function() {
            var hasQualification = $('input[name="'+self.getModuleFieldTitle('qualifications')+'"]:checked').length;
            var hasWorkSkill = $('input[name="'+self.getModuleFieldTitle('workskills')+'[]"]:checked').length;

            if(hasWorkSkill && hasQualification) {
                errors.find('ul').fadeOut();
                return true;
            }
            if(!errors.find('ul').length) {
                errors.append(CW.errorList.makeHTML(
                    [{
                        message : self.getTranslation('invalidSearch')
                        }]
                    ));
            }
            $('html, body').animate({
                scrollTop: $('block').offset().top - 50
                }, 500);
            return false;
        });
    };
};
/* ProviderCourseAdmin.js (141) */
var providerCourseAdmin = function() {

    var self = this;

    /**
     *  initialise this block
     *
     *  @param HTMLDivElement block
     *
     */
    self.initialise = function( block ) {
        self.block = block;
        self.initFormFieldClass( block );
        self.initQualifications();
        self.initProvider();
        self.initCourseContentTab();
        self.initDeliveredByProviderDelete();
        self.initFundedCourseSave( block );
        self.hijaxLanguageSwitcher( block );
        
        self.hijaxCollaborativeData(block);
    };

    self.initFormFieldClass = function( block ) {
        $('#courseForm input', block).each(function(i) {
            $(this).addClass('input').addClass($(this).attr('type'));
        });
    };

    /**
     * Adding check for associating qualifications to courses.
     * 
     */
    self.initFundedCourseSave = function () {

        var action = $('input[name="Module['+self.getInstanceId()+'][action]"]').attr('value');
        
        if( action == 'createFundedCourse' || action == 'updateFundedCourse' ) {
            $('#courseForm').submit(function() {
                
                if( $('input[name="Module['+self.getInstanceId()+'][fld_qualifications][]"]').size() === 0 ) {

                    var confirm = $('<div />')
                        .append($('<div />').addClass('outter')
                            .append($('<div />').addClass('mid')
                                .append($('<div />').addClass('inner')
                                    .append($('<h3 />').html(oLocale.getTranslation('ProviderCourseAdmin','msgConfirmQualificationTitle')))
                                    .append($('<p />')
                                        .append($('<h4 />').html(oLocale.getTranslation('ProviderCourseAdmin','msgConfirmQualification')))
                                        .append($('<a href="#" />')
                                            .html(oLocale.getTranslation('ProviderCourseAdmin','labelCancel'))
                                            .click(function() {
                                                $.modal.close();
                                                return false;
                                            })
                                        )
                                    )
                                )
                            )
                        );

                    $(confirm).modal( {
                        overlayId: 'courseDeleteOverlay',
                        containerId: 'courseDeleteContainer',
                        persist: true
                    });
                    return false;
                }
                return true;
            });
        }
    };
    
     /**
     *  initialise this qualification ajax
     *
     *  @param HTMLDivElement block
     *
     */
    self.initQualifications = function() {

        $( '#search' ).associateQualification( {
            'instanceId' : self.getInstanceId(),
            'template'   : 'ProviderCourseAdminDisplay',
            'module'     : 'ProviderCourseAdmin',
            'selector'  : {
                'form'     : '#qualificationForm',
                'field'    : '#fld_approvedCourse',
                'table'    : '#qualificationsTable',
                'feedback' : '#qualFeedback',
                'button'   : '#searchQualification'
            },
            'ndaqUrl'      : 'http://register.ofqual.gov.uk/Qualification/Details/%id%'
        });
    };
    
    self.addProviderToForm = function(list, contentId, title) {
        if($('input[value='+contentId+']', list).length) {
            return;
        }
        var newItem = $('li:hidden', list)
                        .clone()
                        .show()
                        .appendTo(list);
        $('span', newItem).html(title);
        $('input', newItem).attr('value', contentId);
        list.removeClass('empty');
    };
    
    /**
     *  initialise this provider ajax
     *
     *  @param HTMLDivElement block
     *
     */
    self.initProvider = function() {

        $( '#providerSearch' ).associateProvider( {
            'instanceId' : self.getInstanceId(),
            'template'   : 'ProviderCourseAdminDisplay',
            'module'     : 'ProviderCourseAdmin',
            'selector'  : {
                'form'     : '#providerForm',
                'field'    : '#providerQuery',
                'feedback' : '#providerFeedback',
                'searchButton' : '#searchProvider',
                'deliveredByMyProviderButton' : '#deliveredByMyProviderButton',
                'addButton' : '#addProviderButton',
                'letters' : '.enhanced-atoz-selector'                
            },
            'addProviderToUI' : function(contentId, title) {
                if($('#study-at-select:checked').length) {
                    self.addProviderToForm(
                        $('#fld_deliveredByProvider'), 
                        contentId, 
                        title
                    );
                }
                
                if($('#collaborative-provider:checked').length) {
                    self.addProviderToForm(
                        $('#fld_collaborativePartnership'), 
                        contentId, 
                        title
                    );
                }
            }
        });
        
        $('#collaborativeSearch').click(function(e) {
           $('#providerSearch').trigger('click');
           e.preventDefault();
        });
    };


    /**
     * Initialises functionality to enable course content tab
     */
    self.initCourseContentTab = function() {
        // Change the label for the courses tab
        $('#courses ul.tabs li:first a span span').html(
            oLocale.getTranslation('ProviderCourseAdmin', 'labelCourseDetails')
        );

        // Add a details tab
        $('<li/>').html(
            $('<a href="#" />').html(
                $('<span/>').addClass('wrapper').html(
                    $('<span />').addClass('title').html(
                        oLocale.getTranslation('ProviderCourseAdmin', 'labelCourseContent')
                    )
                )
            )
        )
        .insertAfter('#courses ul.tabs li:first');

        // Add in the functionality to make each tab clickable with visual feedback
        $('#courses ul.tabs li:lt(2) a').click(function() {
            $('#courses ul.tabs li').removeClass('selected');
            $(this).parent().addClass('selected');
            return false;
        });

        // Add in the functionality to hide and show
        $('#courses ul.tabs li:first a').click(function() {
            $('#courses #courseContent').fadeOut(function() {
                $('#courses #courseInfo').fadeIn();
            });
        });
        $('#courses ul.tabs li:eq(1) a').click(function() {
            $('#courses #courseInfo').fadeOut(function() {
                $('#courses #courseContent').fadeIn();
            });
        });

        // And hide the initial content
        $('#courses #courseContent').hide();
    };


    /**
     * Enables the delete functionality
     */
    self.initDeliveredByProviderDelete = function() {
        $('#additionalFields img.delete').live('click', function() {
            var list = $(this).parent('li').parent('ul');
            $(this).parent('li').remove();

            if(list.find('li').length == 1) {
                list.addClass('empty');
            }
        });
    };
    
    /**
     * Hijax the language switch to ensure after posting the course creation/edit
     * the user can still switch language and remain on the same course page
     * 
     */
    self.hijaxLanguageSwitcher = function(block) {
        var url = self.getCurrentTabUrl()+ self.getCurrentLangParam();
        $('#langOptions a:last').attr('href', url);
    };
    
    /**
     * Initialise selection of partnerships to populat collaborative list of
     * providers.
     * 
     */
    self.hijaxCollaborativeData = function(block) {
        $('#fld_collaoborativePartners', block).change(function() {
            var selection = $(this);
            
            if(selection.val() == 'NULL') {
                return;
            }
            $('.collaborative-data-set ul#'+selection.val()+' li').each(function() {
                var item = $(this);
                self.addProviderToForm($('#fld_collaborativePartnership'), item.attr('id'), item.text());
            });
        });
    };

    /**
     * Returns the URL for the current tab
     * @return string
     */
    self.getCurrentTabUrl = function (block) {
        return $('ul.tabs li.selected a').attr('href');
    };

    /**
     * Returns the current language parameter
     * @return string
     */
    self.getCurrentLangParam = function() {
        var currUrl = $('#langOptions a:last').attr('href');
        var urlParts = currUrl.split('&');
        return '&' + urlParts[urlParts.length-1];
    };
};

function dateStart_return(y,m){
    $( '#fld_dateStartValid' ).val( Common_padTens(m) + '/' + new String(y).substring(2) );
}

function dateEnd_return(y,m){
    $( '#fld_dateEndValid' ).val( Common_padTens(m) + '/' + new String(y).substring(2) );
}
/* Messaging.js (249) */
var messaging = function(){
	var self=this;
	
	self.keepRecipientValue = false;
	self.aRecipient = new Array();
	self.errorShown = false;
	self.errorShownMain = false;
	self.aCurrentRecipients = new Array();
	
	self.initialise = function(block){
            if (!self.verifyEnvironment()) {
                return false;
            }

		self.initModalRecipientWindow();
		self.initRecipientLink();
		self.initAutoComplete();
		self.initDownloadNotice();
		self.initValidation();

            return true;
	};

        // Verify that the browser environment is in the right state
        // -> may not be if the user is not logged in, or if they don't have the required permissions
        self.verifyEnvironment = function() {
            // Much functionality depends on a select element with an id of 'recipientUserName'
            if ($('#recipientUserName').length === 0) {
                return false;
            }

            return true;
        };
	
	self.initModalRecipientWindow = function(){
		// 1. Create a new element, to be used for the
		// modal popup window
		self.modalWindowElement = $('<div />');

		// 2a. Put in the styling elements
		var outerElement = $('<div />');
		var midElement = $('<div />').attr('class', 'mid');
		var innerElement = $('<div />').attr('class', 'inner');
		innerElement.attr('class', 'inner');
		//innerElement.append(recipientSelectElement);
		midElement.append(innerElement);
		outerElement.append(midElement);
		self.modalWindowElement.append(outerElement);

		// 2b. Put in heading
		innerElement.append($('<h2 />').html(oLocale.getTranslation('Messaging','selectRecipient')));

		//put in the feedback div
		innerElement.append($('<div class="feedbackDiv" />'));

		// 2c. Put in the recipients list - clone it, don't use it as it will break something lower down
                var recipientSelectElement = $('#recipientUserName').clone();

		//Remove all feedback when user selects something
		recipientSelectElement.bind('change',function(){
			self.errorShown = false;
			$('.feedbackDiv').html('');
		});
		recipientSelectElement.attr('id', 'modal_recipients');
		var topForm = $('<div class="topForm" />');
                topForm.append(recipientSelectElement);

		// Include the add button, english and welsh
		var saveButtonElement = $('<img src="custom/careers_wales/img/buttons/button_add_' + oLocale.getFieldValue( 'id' ) + '.gif" alt="Save" />');
		saveButtonElement.bind('click', self.addRecipientToPopup);
		topForm.append(saveButtonElement);
		innerElement.append(topForm);

		//we need a table here to list the
		//recipients the user has selected
		var tblRecipients = $('<table id="selectedRecipients" />');

		innerElement.append(tblRecipients);

		// Include the save button, english and welsh
		var saveButtonElement = $('<img src="custom/careers_wales/img/buttons/button_submit_' + oLocale.getFieldValue( 'id' ) + '.gif" alt="Save" class="save"/>');
		saveButtonElement.bind('click', function(){
			//Copy the correct values to the hidden and visible fields
			if (self.selectRecipient()){
				//Close the window
				$.modal.close();
			}
		});
		innerElement.append(saveButtonElement);


		// 3. Put the element into the DOM
		$('#innercontainer').append(self.modalWindowElement);
		self.modalWindowElement.hide();

                self.modalWindowElement.addClass('hopefully');
	};
	
	self.cloneRecipientList = function(){
		//firstly, create containing element
		var newRecipientList = $('<select id="modal_recipients" />');
		
		//get the original list, currently in the DOM
		var recipientList = $('#recipientUserName');
		
		//copy over the name
		newRecipientList.attr('name', recipientList.attr('name'));
		
		//Find and loop through all the option elements underneath
		//and append them to the parent container - newRecipientList
		$('option', recipientList).each(function(){
			var optionElement = $('<option />');
			optionElement.attr('value', $(this).attr('value'));
			optionElement.text($(this).text());
			newRecipientList.append(optionElement);
		});
		
		//return the element
		return newRecipientList;
	};
	
	self.addRecipientToPopup = function(fullName, username){
		//Add the currently selected recipient to the list
		//get the selected element
		if (typeof username != 'string' || typeof fullName != 'string') {
			var recipientElement = $("#modal_recipients");
			var selectedValueElement = $("option[selected]", recipientElement);
			
			username = selectedValueElement.attr('value');
			fullName = selectedValueElement.text();
			
		}
		if (username=='0'){
			return false;
		}
		//Firstly, ensure the recipient doesn't already exist in the list
		var found = false;
		$(self.aRecipient).each(function(val){
			if (self.aRecipient[val][0] == username){
				found=true;
			}
		});
		
		if (found){
			//alert('This recipient has already been added');
			return false;
		}
		
		//add recipient to the list
		self.aRecipient.push([username,fullName]);
		self.aCurrentRecipients.push([fullName, username]);
		
		//now add it to the table
		var newRow = $('<tr id="' + username + '"/>');
		newRow.append('<td>' + fullName + '</td>');
		var removeCol = $('<td />');
		
		// Include the save button, english and welsh
		var localeId = oLocale.getFieldValue( 'id' );
		var removeButton = $('<img src="custom/careers_wales/img/buttons/button_remove_' + localeId + '.gif" alt="Save" />').attr('style', 'float:left;clear:left;');
		removeButton.bind('click', function(){
			self.removeRecipientFromPopup(username);
		});
		removeCol.append(removeButton);
		newRow.append(removeCol);
		$('#selectedRecipients').append(newRow);
		
	};
	
	self.removeRecipientFromPopup = function(username){
		//remove this from the array
		var arrayIndex=9000; //
		$(self.aRecipient).each(function(val){
			if (self.aRecipient[val][0] == username){
				arrayIndex = val;
			}
		});
		//self.aRecipient[arrayIndex] = [0, 0];
		if (arrayIndex!=9000){
			self.aRecipient.splice(arrayIndex, 1);
		}
		
		//we need to remove it from other array
		arrayIndex = 9000;
		$(self.aCurrentRecipients).each(function(val){
			if (self.aCurrentRecipients[val][1] == username){
				arrayIndex = val;
			}
		});
		
		if (arrayIndex!=9000){
			self.aCurrentRecipients.splice(arrayIndex, 1);
		}
		
		//now remove from the table
		$('#' + username).remove();
	};
	
	self.selectRecipient = function(){
		if (self.aRecipient.length == 0){
			if (!self.errorShown) {
				var elemError = Common_makeMessage('error', oLocale.getTranslation('Messaging', 'youMustSelectARecipient'));
				$('.feedbackDiv').append($(elemError));
				self.errorShown = true;
			}
			return false;
		}
		
		//produce a list of username and names in csv
		var csvRealName = '';
		var csvUsername = '';
		$(self.aRecipient).each(function(val){
			if (val > 0){
				csvRealName = csvRealName + ',';
				csvUsername = csvUsername + ',';
			}
			csvRealName = csvRealName + self.aRecipient[val][1];
			csvUsername = csvUsername + self.aRecipient[val][0];
		});
		
		$('#recipientUserName_1').val(csvRealName);
		$('#recipientUserName').val(csvUsername);
		
		//successfully selected the recipient, return true
		return true;
	};
	
	self.initRecipientLink = function(){
		//change the label to an image
		var localeId = oLocale.getFieldValue( 'id' );
		$('label#recipientSiteUser').html('<img src="custom/careers_wales/img/buttons/button_to_' + localeId + '.png" alt="' + oLocale.getTranslation('Messaging', 'to') + '"/>');
		
		$('label#recipientSiteUser').bind('click', function(){
			self.showRecipientWindow();
		});
	};
	
	self.initAutoComplete = function(){
		if (document.getElementById('recipientUserName')) {
			
			// Before we do anything, we need to check the selected value
			// of the combo and store it so we can later set it as selected
			var selectedUserCombo = $("#recipientUserName");
			var selectedUser = $("option[selected]", selectedUserCombo);
			var selectedUserFullName = selectedUser.text();
			var selectedUserName = selectedUser.attr('value');
			
			//Change the combo into a hidden field
			var elName = document.getElementById('recipientUserName').name;
			
			var hiddenEl = document.createElement('input');
			hiddenEl.setAttribute('type', 'hidden');
			hiddenEl.setAttribute('value', '0');
			hiddenEl.setAttribute('name', elName);
			
			//replace the elements
			document.getElementById('recipientUserName').parentNode.replaceChild(hiddenEl, document.getElementById('recipientUserName'));
			hiddenEl.setAttribute('id', 'recipientUserName');
			
			if (messaging_recipients.length > 1) {
				//this may be more than one recipient and so we must account for that!
				var selectedRecipientUsername = '';
				var selectedRecipientFullname = '';
				var aRecipient = messaging_recipients.split(',');
				$(aRecipient).each(function(index){
					//get the fullname of the user
					var fullName = $("option[value='" + aRecipient[index] + "']", selectedUserCombo);
					if (selectedRecipientUsername){
						selectedRecipientUsername = selectedRecipientUsername + ',';
						selectedRecipientFullname = selectedRecipientFullname + ',';
					}
					selectedRecipientUsername = selectedRecipientUsername + aRecipient[index];
					selectedRecipientFullname = selectedRecipientFullname + fullName.text();
				});
				$('#recipientUserName_1').val(selectedRecipientFullname);
				$('#recipientUserName').val(selectedRecipientUsername);
			}else if (selectedUserName != 0) {
				$('#recipientUserName_1').val(selectedUserFullName);
				$('#recipientUserName').val(selectedUserName);
				self.aCurrentRecipients.push([selectedUserFullName, selectedUserName]);
				self.addRecipientToPopup(selectedUserFullName, selectedUserName);
			}
			
			$("#recipientUserName_1").autocomplete('api.php?do=block.Messaging&call=getRecipients', {
				minChars: 2,
				multiple: true,
				multipleSeparator: ','
			}).result(function(evt, data, formatted){
				//add the recipient to the list
				//self.aCurrentRecipients.push([formatted, data[1]]);
				if ($('#recipientUserName').val()!='0'){
					$('#recipientUserName').val($('#recipientUserName').val() + ',');
				}else {
					$('#recipientUserName').val('');
				}
				$('#recipientUserName').val($('#recipientUserName').val() + data[1]);
				
				//we must maintain compatibility to the recipient pop-up
				self.addRecipientToPopup(formatted, data[1]);
				
				self.keepRecipientValue = true;
			});
			
			// When the user types into the box, we need to recalculate the
            // recipients because it may be
			$("#recipientUserName_1").bind('keydown', null, function(e){
				if (!self.keepRecipientValue) {
					//$('#recipientUserName').val('0');
					
					//we must get all of the recipients in the texbox
					var recipString = $('#recipientUserName_1').val();
					var aRecipientsSelected = recipString.split(',');
					
					//now we need to go through all of the recipients selected and
					//ensure they are still selected, keep building up a list
					//as we go along
					var currentlySelectedUsernames = '';
					var itemsToRemove = new Array();
					
					$(self.aCurrentRecipients).each(function(recipient){
						var stillCurrent = false;
						//go through aRecipientsSelected and only select the ones
						//that match with a user
						//if they don't match - remove them
						$(aRecipientsSelected).each(function(selectedRecipient){
							//alert(aRecipientsSelected[selectedRecipient] + ' : ' + self.aCurrentRecipients[recipient][0] );
							if (aRecipientsSelected[selectedRecipient] == self.aCurrentRecipients[recipient][0]){
								//recipient still selected, add to string
								//alert('found');
								stillCurrent=true;
								if (currentlySelectedUsernames){
									currentlySelectedUsernames = currentlySelectedUsernames + ',';
								}
								currentlySelectedUsernames = currentlySelectedUsernames + self.aCurrentRecipients[recipient][1];
							}
						});
						
						if (!stillCurrent){
							//this item need to be removed!
							//store the index and delete it after the each loop
							itemsToRemove.push(recipient);
						}
						
					});
					
					//now remove the items
					$(itemsToRemove).each(function(index){
						//also remove the user from the popup to remain consistent
						self.removeRecipientFromPopup(self.aCurrentRecipients[itemsToRemove[index]][1]);
						
						//now remove the array
						self.aCurrentRecipients.splice(itemsToRemove[index], 0);
					});

					//if there are no selected recipients set to 0 otherwise put the new list in
					if (currentlySelectedUsernames){
						$('#recipientUserName').val(currentlySelectedUsernames);
					}else {
						$('#recipientUserName').val('0');
					}
				} else {
					self.keepRecipientValue = false;
				}
			});
		}
	};
	
	self.initDownloadNotice = function(){
		$('.attachmentDownload').bind('click', null, function(e){
			return confirm(oLocale.getTranslation('Messaging','downloadNotice'));
		});
	};
	
	self.initValidation = function(){
		//set-up an event handler for the form is submitted
		$('.composeMessage').bind('submit', null,function(e){
			//check that a recipient has been selected
			//this can be mass mail recipients or standard recipient
			
            if (($('.massMailRole').val() == 0 || !$('.massMailRole').val()) &&
                ($('.massMailYear').val() == 0 || !$('.massMailYear').val()) &&
                ($('.massMailFormGroup').val() == 0 || !$('.massMailFormGroup').val()) &&
				($('#recipientUserName').val() == 0 || !$('#recipientUserName').val()) &&
				($('#mdCategories').val() == 0 || !$('#mdCategories').val())){

				if (!self.errorShownMain){
					var elemError = Common_makeMessage('error', oLocale.getTranslation('Messaging', 'youMustSelectARecipient'));
					$('.messaging .actionDispatcherMessages').append($(elemError));
					$('.messaging .actionDispatcherMessages').attr('class', 'actionDispatcherMessages');
					self.errorShownMain = true;
				}
				return false;
			}
			
		});
	};

	self.showRecipientWindow = function(){
		// Use jQuery Modal plugin to make this element a pop-up window
    	$.modal(self.modalWindowElement, {
			overlayId: 'qualificationOverlay',
			containerId: 'qualificationContainer',
			persist: true,
			onOpen: function (dialog) {
				dialog.overlay.fadeIn('fast', function () {
					dialog.container.slideDown('normal', function () {
                        dialog.data.fadeIn('fast');
					});
				});
			},
			onClose: function (dialog) {
 					dialog.data.fadeOut('fast', function () {
					dialog.container.slideUp('normal', function () {
							dialog.overlay.fadeOut('fast', function () {
								$('.modalClose').hide();
							$.modal.close();
						});
					});
				});
			}
		});
	};

};
/* ConEClipsLeafletDisplay.js (351) */
var conEClipsLeafletDisplay = function() {

    if (jQuery.browser.mozilla ) {
        jQuery( 'body' ).addClass( 'isFirefox' );
    }

    var self = this;

    self.initialise = function( block ) {
        self.hideLeafletInfo();
        self.toggleLeafetInfo();
    };

    self.hideLeafletInfo = function() {
        $('#eClipsLeafletBody').hide();
    };

    self.toggleLeafetInfo = function() {

        /* Define text variables for replacement */
        var readMore = oLocale.getTranslation('ConEClipsLeaflet', 'readMore');
        var hideContent = oLocale.getTranslation('ConEClipsLeaflet', 'hideContent');

        /* - Expand and contract content on click 
           - Replace link text */
        $('#eClipsLeafletMore').toggle(
          function() {
              $('#eClipsLeafletBody').slideDown("slow");
              $('#eClipsLeafletMore').html(hideContent);
          },
          function() {
              $('#eClipsLeafletBody').slideUp("slow");
              $('#eClipsLeafletMore').html(readMore);
          }
        );
    };
};
/* ContentTools.js (352) */
var contentTools = function() {

    var self = this;

    self.initialise = function( block ) {
        self.addPrintFunction();
    };

    self.addPrintFunction = function() {
        /*  Create action div and assign to print wrapper */
        var contentHolder = $("#print");
        var wrapper = $('<div />').addClass('action');

        /*  Create icon div  */
        var printIconDiv = $('<div />')
                         .addClass('icon').appendTo(wrapper);

        /*  Add image to icon div  */
        var printIcon =  $('<img />').attr({
                          'src': "custom/careers_wales/img/eclips/icons/print-icon.gif",
                          'width': "26",
                          'height': "27",
                          'alt': "Print this page"
                        }).appendTo(printIconDiv);

        /*  Add button div to wrapper + include JavaScript call  */
        var printButtonDiv = $('<div />')
                            .addClass('button')
                            .appendTo(wrapper)
                            .append($('<p />')
                                      .append($('<a />').attr('href', 'javascript:window.print()')
                                                        .html(oLocale.getTranslation('ContentTools', 'printThisPage'))
                                      )
                            );


        /* Add all contents to print div */
        $(wrapper).appendTo(contentHolder);

    };
};
/* Employment.js (364) */
/**
 * @package private_output_careers_wales_learningpathways
 * @version $Id: WorkExperience.js 8432 2008-05-23 14:09:25Z jamesrc $
 * @copyright Copyright (c) 2008 Box UK Ltd. All rights reserved.
 *
 * Adds tool tips and lightbox functionality to block.
 *
 * @audit
 * - 2009-08-11  JRC  Created file.
 */
var employment = function() {

    var self = this;

    self.initialise = function( block ) {
        Common_addCalendarControls( 'calendar', 'employmentCal', block );
        $(block).tooglePathways({
            'content' : '.userEmployment',
            'module'  : 'Employment'
         });
         $(".action .delete form").lightBoxDelete({
             'module': 'Employment'
         });

         $('.userEmployment', block).editInPlace({
            'selectors': {
                'form' : '.edit form',
                'editForm' : 'form.new'
            },
            'instanceId' : self.getInstanceId(),
            'module': 'Employment',
            'action': 'editEmployment',
            'name'  : 'employment',
            'aField': new Array('title', 'employer', 'location', 'startDate', 'endDate', 'description')
         });

         LearningPathways.initDefaultTextHandler(block);

    };
};
/* DataTransfer.js (366) */
/**
 * @package private_output_careers_wales_learningpathways
 * @version $Id: DataTransfer.js 8432 2008-05-23 14:09:25Z jamesrc $
 * @copyright Copyright (c) 2008 Box UK Ltd. All rights reserved.
 *
 * Adds tool tips and lightbox functionality to block.
 *
 * @audit
 * - 2009-09-24  JRC  Created file.
 */

var dataTransfer = function() {

    var self = this;
    var lightBox = null;
    var form     = null;
    var block    = null;

    /**
     * Initialise block by setting up the lightbox and attaching action.
     *
     * If this is the users first login, then automatically launch the lightbox.
     */
    self.initialise = function(block) {
        self.block = block;
        self.setLightBox(block);
        self.setupEprogressConcertina(block);
        self.setupLppReplacementCheckboxes(block);

        var linkSelector = '.dataTransfer .linkedCategories li a';
        $(linkSelector).click(function() {
            $(self.lightBox).modal({
                persist : false,
                containerId : 'learningPathwaysContainer',
                // r31584 breaks styling of this: this should fix it.
                containerCss : {
                    background : '#fff'
                }
            });
            return false;
        });
        if ($('#firstLogin').size() > 0) {
            $(linkSelector).click();
        }
    };

    /**
     * Produces the mark up for the login lightbox.
     *
     * @param block {jQuery} The block.
     */
    self.setLightBox = function(block) {
        self.lightBox = $('.hidden', block).clone().show().removeClass('hidden');
        $('div.curvedBox', self.lightBox).removeClass('curvedBox');
        self.form = $('form', self.lightBox)
            .append(self.getCancelContent())
            .submit(function() {
              self.sendRequest();
              return false;
            });
        $('.cancel .cancelLightbox', $(self.lightBox)).live('click', function() {
            $.modal.close();
            return false;
        });
    };

    /**
     * Returns cancel links.
     *
     * @returns {jQuery} jQuery object containing HTML for cancel paragraph.
     */
    self.getCancelContent = function() {
        var cancelAnchor = $('<a class="cancelLightbox" href="#" />')
            .append(oLocale.getTranslation('DataTransfer', 'labelCancel'));
        var cancelText = $('<p />')
            .addClass('cancel')
            .append(oLocale.getTranslation('DataTransfer', 'labelOr') + ' ')
            .append(cancelAnchor)
            .append(' ' + oLocale.getTranslation('DataTransfer', 'labelToClose'));
        return cancelText;
    };

    /**
     * Handles sending the request for the data transfer.
     */
    self.sendRequest = function() {
        $('.actionDispatcherMessages', self.lightBox).remove();
        // Check whether the user has completed all the form.
        if (self.hasUsernameAndPassword()) {
            var loader   = $('<div class="ajaxLoader"><img src="/careers_wales/year10and11/custom/careers_wales/img/learningPathways/icons/ajax-loader.gif" alt="" class="ajaxLoader" /></div>');

            // Update interface to notify the user that something is happening.
            self.form.slideUp();
            Common_makeMessage('information', oLocale.getTranslation('DataTransfer', 'msgSearchingForData')).insertBefore(self.form);
            loader.insertBefore(self.form);

            var username = self.getModuleFieldTitle('username');
            var password = self.getModuleFieldTitle('password');
            var action   = self.getModuleFieldTitle('action');
            var blockUrl = self.getBlockJsonUrl({
                username : $('input[name="' + self.getModuleFieldTitle('username') + '"]', self.form).attr('value'),
                password : $('input[name="' + self.getModuleFieldTitle('password') + '"]', self.form).attr('value'),
                action : $('input[name="' + self.getModuleFieldTitle('action') + '"]', self.form).attr('value')
            });

            $.getJSON(
                blockUrl,
                function(json) {
                    $('.actionDispatcherMessages', self.lightBox).remove();
                    loader.remove();

                    // Check to see if there were any errors.
                    var aMessage = AMAXUS.errorList.getFromModule(json.Module);
                    if (aMessage.length > 0) {
                        for (var i = 0; i < aMessage.length; i++) {
                             self.form.prepend(Common_makeMessage('error', aMessage[i].message));
                        }
                        self.form.slideDown();
                        return false;
                    }

                    // The data has been successfully transferred.
                    Common_makeMessage('information', oLocale.getTranslation('DataTransfer', 'successDataTransferred')).insertBefore(self.form);
                    $('<p class="cancel" />')
                        .append(
                            $('<a href="#" class="cancel" />')
                            .append(oLocale.getTranslation('DataTransfer', 'labelClose'))
                            .click(function(){
                                $.modal.close();
                                return false;
                            })
                        ).insertBefore(self.form);
                    self.block.fadeOut();
                }
            );
        }
    };

    /**
     * Checks whether the user has provided a username and password.
     *
     * @return boolean True if the user has a username and password.
     */
    self.hasUsernameAndPassword = function() {
        var username = $('input[name="' + self.getModuleFieldTitle('username') + '"]', self.form).attr('value');
        var password = $('input[name="' + self.getModuleFieldTitle('password') + '"]', self.form).attr('value');
        var isFound  = true;
        if (password === undefined || !password.length > 0) {
            self.form.prepend(Common_makeMessage('error', oLocale.getTranslation('DataTransfer', 'errorEmptyPassword')));
            isFound = false;
        }
        if (username === undefined || !username.length > 0) {
            self.form.prepend(Common_makeMessage('error', oLocale.getTranslation('DataTransfer', 'errorEmptyUsername')));
            isFound = false;
        }
        return isFound;
    };


    /**
     * Sets up the concertina interface for the eProgress section
     *
     * @param block {jQuery} The block.
     */
    self.setupEprogressConcertina = function(block) {
        $('div.eprogress div.expanded', block).hide();

        $('div.eprogress h2', block).click(function () {
            if(!$('div.expanded', $(this).parent()).is(':visible') ) {
                $('div.eprogress div.expanded', block).slideUp(function() {
                    $('span.arrow', block).removeClass('up-arrow').addClass('down-arrow');
                });
            }
            
            $('div.expanded', $(this).parent()).slideToggle('slow', function() {
                if ($(this).is(':visible')) {
                    $('span.arrow', $(this).parent())
                        .removeClass('down-arrow')
                        .addClass('up-arrow');
                } else {
                    $('span.arrow', $(this).parent())
                        .removeClass('up-arrow')
                        .addClass('down-arrow');
                }
            });
        });
    };

    /**
     * Sets up the replacement checkboxes (images) for the Lpp Import screens
     *
     * @param block {jQuery} The block.
     */
    self.setupLppReplacementCheckboxes = function(block) {
        $('div.lppSections input[type=checkbox][class!=replaced]', block).each(function(){
            new replacementCheckbox(this);
        });
    };

    /**
     * Class representing a fancified checkbox that is used to replace the browser default
     * This code has been copied verbatim from BuildYourCV.js (original author: Jon Cram)
     *
     * @constructor
     */
    var replacementCheckbox = function (inboundCheckbox, inboundCallbacks) {
        var checkbox = null;        // The checkbox we're replacing (jQuery object)
        var replacement = null;
        var callbacks = {};

        var isChecked = function () {
            if (checkbox === null) {
                return true;
            }

            return checkbox.is(':checked');
        };

        this.isChecked = function () {
            return isChecked();
        };

        var check = function () {
            if (checkbox === null) {
                return true;
            }

            // Update actual checkbox
            checkbox.attr('checked', 'checked');

            // Update replacement checkbox imagery
            $('span', replacement).addClass('checkbox-checked');
            $('span', replacement).removeClass('checkbox-unchecked');

            return true;
        };

        this.check = function () {
            return check();
        };

        var uncheck = function () {
            if (checkbox === null) {
                return true;
            }

            // Update actual checkbox
            checkbox.attr('checked', '');

            // Update replacement checkbox imagery
            $('span', replacement).addClass('checkbox-unchecked');
            $('span', replacement).removeClass('checkbox-checked');
            return true;
        };

        this.uncheck = function () {
            return uncheck();
        };

        var toggle = function () {
            if (isChecked()) {
                uncheck();

                if (typeof callbacks.off == 'function') {
                    callbacks.off();
                }

            } else {
                check();

               if (typeof callbacks.on == 'function') {
                    callbacks.on();
               }
            }

            return true;
        };

        var initialise = function (inboundCheckbox, inboundCallbacks) {
            // Keep original checkbox
            checkbox = $(inboundCheckbox);

            // Check and store callback options
            if (typeof inboundCallbacks == 'object') {
                callbacks = inboundCallbacks;
            }

            // Swap out checkbox with replacement imagery
            if (!checkbox.is('replaced')) {
                checkbox.addClass('replaced');
            }

            replacement = $('<span />').addClass('checkarea').append('<span class="checkbox" />');

            // add the toggle functionality so long as this record isn't disabled
            if (!checkbox.parent('.lppSectionRecord').is('.disabled')) {
                replacement.click(function () {
                    toggle();
                    return false;
                });
            }

            replacement.attr('title', checkbox.attr('title'));

            var existingReplacement = checkbox.next('span.checkarea');
            if (existingReplacement.length) {
                existingReplacement.remove();
            }

            checkbox.after(replacement);

            // Set initial checked/unchecked state of replacement
            if (isChecked()) {
                $('span', replacement).addClass('checkbox-checked');
            } else {
                $('span', replacement).addClass('checkbox-unchecked');
            }

            // Find label associated with checkbox (if present) and make that work with replacement
            var checkboxId = checkbox.attr('id');
            if (checkboxId.length) {
                var label = $('label[for='+checkboxId+']');
                label.click(function(){
                    toggle();
                    return false;
                });
            }

            return true;

        };

        initialise(inboundCheckbox, inboundCallbacks);
    };
    /* end replacementCheckbox class */
};
/* WorkRelatedEducation.js (369) */
/**
 * @package private_output_careers_wales_learningpathways
 * @version $Id: WorkExperience.js 8432 2008-05-23 14:09:25Z jamesrc $
 * @copyright Copyright (c) 2008 Box UK Ltd. All rights reserved.
 *
 * Adds tool tips and lightbox functionality to block.
 *
 * @audit
 * - 2009-08-11  JRC  Created file.
 */
var workRelatedEducation = function() {

    var self = this;

    self.initialise = function( block ) {
        Common_addCalendarControls( 'calendar', 'workEducationCal', block );
        $(block).tooglePathways({
            'content' : '.education',
            'module'  : 'WorkRelatedEducation'
         });
         $(".action .delete form").lightBoxDelete({
             'module': 'WorkRelatedEducation'
         });

         $('.education', block).editInPlace({
            'selectors': {
                'form' : '.edit form',
                'editForm' : 'form.new'
            },
            'instanceId' : self.getInstanceId(),
            'module': 'WorkRelatedEducation',
            'action': 'editEducation',
            'name'  : 'education',
            'aField': new Array('title', 'educationDate', 'description'),
            'postLoadAction': function( parameters ) {

                var form = parameters.form;
                var type = form.parent().parent().attr('id');
                var permCatId = type.split('-')[1];
                
                $('option[value="'+permCatId+'"]', form).attr('selected', 'selected');
            }
         });

         LearningPathways.initDefaultTextHandler(block);
    };

};
/* AboutMeMyDetails.js (370) */
/**
 * @package private_output_careers_wales_learningpathways
 * @version $Id: AboutMeMyDetails.js.370.allsites.js 42440 2011-11-09 17:34:53Z rod $
 * @copyright Copyright (c) 2008 Box UK Ltd. All rights reserved.
 *
 *
 * @audit
 * - 2009-09-21  JC  Created file.
 */

var aboutMeMyDetails = function() {

    var self = this;
    var addressLookup = null;
    var configuration = {
        ajaxErrorId:'AboutMeMyDetails_ajaxError',
        addressLookup:{}
    };

    self.componentId = function() {
        var componentId = self.getComponentId();
        return (componentId.substr(0, 1).toUpperCase())+(componentId.substr(1));
    };

    self.initialise = function(block) {

        var btnName = Amaxus.settings.siteCode == "cp" ? 'find_address' : 'findaddress';
        
        configuration.addressLookup = {
            instanceId:self.getInstanceId(),
            selectors: {
                lookupNumberOrNameField:'#numberOrName_lookup'+self.getInstanceId(),
                lookupPostcodeField:'#postcode_lookup'+self.getInstanceId(),
                manualNumberOrNameField:'#numberOrName'+self.getInstanceId(),
                manualLine1Field:'#line1'+self.getInstanceId(),
                manualLine2Field:'#line2'+self.getInstanceId(),
                manualLine3Field:'#line3'+self.getInstanceId(),
                manualPostcodeField:'#postcode'+self.getInstanceId()
                },
            button:{
                id:'AboutMeMyDetails_findAddressButton',
                src:  'custom/careers_wales/img/learningPathways/buttons/button_'+btnName+'_'+oLocale.getFieldValue( 'id' )+'.png',
                alt:'Find address'
            },
            ajax:{
                url:self.getApiUrl({'action':'lookupAddress'})
                },
            lightbox:{
                containerId:'addressLookup_lightbox',
                containerClasses:'AboutMeMyDetails_addressLookup',
                dataClasses:'AboutMeMyDetails_addressLookup_modalData'
            },
            events: {
                onFailure:function () {
                    self.ajaxError.display();
                },
                preLookup:function () {
                    self.ajaxError.clear();
                }                
                },
            content: {
                lightbox: {
                    PREPARING: {
                        title:self.getTranslation('lb_loading_title')
                },
                    RESULTS: {
                        title:self.getTranslation('lb_withresults_title'),
                        seeAllAddresses:self.getTranslation('lb_withresults_seeall'),
                        or:self.getTranslation('labelOr'),
                        enterYourAddressManually:self.getTranslation('labelEnterAddressManually')
                    },
                    NORESULTS: {
                        title:self.getTranslation('lb_noresults_title'),
                        'for':self.getTranslation('lb_noresults_for'),
                        tryAgain:self.getTranslation('lb_noresults_tryagain'),
                        or:self.getTranslation('labelOr'),
                        enterYourAddressManually:self.getTranslation('labelEnterAddressManually')
                }
            }
            }
    };

        self.drawAddressLookupFeatures();
        addressLookup = new CW.addressLookup(configuration.addressLookup);
    };

    self.drawAddressLookupFeatures = function() {
        var addressContainer = $('#address'+self.getInstanceId());
        var lookupContainer = $('<div />');

        var lookupTitle = $('<h4 />').addClass('lookup').html(self.getTranslation('addressLookupTitle'));

        var numberOrNameRow = self.createFormRow(self.getTranslation('addressLookupNumber'),
                                                 'numberOrName_lookup',
                                                 self.getInstanceId(),
                                                 global.formPrefillValues.lookup_numberOrName);

        var postcodeRow = self.createFormRow(self.getTranslation('addressLookupPostcode'),
                                                 'postcode_lookup',
                                                 self.getInstanceId(),
                                                 global.formPrefillValues.lookup_postcode);

        postcodeRow.append($().qToolTip.clone('#postcode'+self.getInstanceId()));

        lookupContainer.append(lookupTitle);
        lookupContainer.append(numberOrNameRow);
        lookupContainer.append(postcodeRow);
        lookupContainer.append($('<h4 />').addClass('manual').html(self.getTranslation('addressEntryTitle')));

        $('label', lookupContainer).css({
            'width':'180px'
        });

        addressContainer.prepend(lookupContainer);
    };

    self.createFormRow = function(labelText, inputName, moduleId, value) {
        var inputId = inputName+moduleId;

        var rowContainer = $('<div />');
        rowContainer.addClass('formRow');

        var label = $('<label for="'+inputId+'" />').html(labelText);
        var input = $('<input id="'+inputId+'" class="field-short" type="text" value="'+value+'" name="Module['+moduleId+']['+inputName+']" />');

        rowContainer.append(label);
        rowContainer.append(input);

        return rowContainer;
    };

    self.ajaxError = {
        display:function () {
            $.cwmodal.close();
            addressLookup.getButton().reference().parent().append(                
                $('<p />').attr({
                    id:configuration.ajaxErrorId
                }).text(
                    self.getTranslation('ajaxerror')
                )
            );
        },

        clear:function () {
            $('#'+configuration.ajaxErrorId).remove();
        }
    };
};
/* Interests.js (373) */
/**
 * @package private_output_careers_wales_learningpathways
 * @version $Id: Interests.js 8432 2008-05-23 14:09:25Z jamesrc $
 * @copyright Copyright (c) 2008 Box UK Ltd. All rights reserved.
 *
 * Adds tool tips and lightbox functionality to block.
 *
 * @audit
 * - 2009-08-11  JRC  Created file.
 */
var interests = function() {

    var self = this;

    self.initialise = function( block ) {
         $(block).tooglePathways({
            'content' : '.interest',
            'module'  : 'Interests'
         });
         $('.action .delete form').lightBoxDelete({
             'module': 'Interests'
         });
         $('.interest', block).editInPlace({
            'selectors': {
                'form' : '.edit form',
                'editForm' : 'form.new'
            },
            'instanceId' : self.getInstanceId(),
            'module': 'Interests',
            'action': 'editInterest',
            'name'  : 'interest',
            'aField': new Array('title', 'description')
         });
    };

};
/* TodoList.js (378) */
/**
 * @package private_output_careers_wales_learningpathways
 * @version $Id: SupportTeam.js 8432 2008-05-23 14:09:25Z jamesrc $
 * @copyright Copyright (c) 2008 Box UK Ltd. All rights reserved.
 */
var todoList = function() {

    var self = this;

    self.initialise = function( block ) {
        self.initCommenting(block);

        Common_addCalendarControls( 'calendar', 'todoListCal', block );

        $(block).tooglePathways({
            'module'  : 'TodoList',
            'form'    : 'form.new',
            'content' : '.todoListItem'
        });

        $(".delete form", block).lightBoxDelete({
            'module': 'TodoList'
        });

        $('.todoListItem', block).editInPlace({
            'selectors': {
                'form' : '.edit form',
                'editForm' : 'form.new'
            },
            'instanceId' : self.getInstanceId(),
            'module': 'TodoList',
            'action': 'updateItem',
            'name'  : 'item',
            'aField': ['title', 'dueDate', 'details']
        });

        $('.complete form', block).submit(function() {
            self.showCompletionLightbox(this, block);
            return false;
        });

        $('.toggleItemList'. block).each(function(){
            var heading = $('.toggleItemList .introduction', block);
            var header = $('h2', heading);
            var content = $('.toggleItemList .todoListItems', block);
            var contentContainsErrors = $('.errorMessage', content).size() > 0;

            content.css('float', 'right');

            $('span', header).removeClass('arrow');
            heading.css('cursor', 'pointer');
            header.append(
                $('<span class="arrow" />')
            );
            $('span', header).css('float', 'left');

            heading.click(function() {
                if (content.css('display') == 'block') {
                     //content.hide();
                    content.slideUp(function() {
                        heading.removeClass('whenSlidDown');
                        heading.addClass('whenSlidUp');

                    });
                } else {
                   //content.show();
                    content.slideDown(function() {
                        heading.removeClass('whenSlidUp');
                        heading.addClass('whenSlidDown');
                    });
                }

            });
            
            if (contentContainsErrors) { 
                heading.addClass('whenSlidDown');
            } else {
                heading.click();
            }

        });

        LearningPathways.initDefaultTextHandler(block);
    };

    self.initCommenting = function(block){
        self.oCommenting = new Commenting();
        self.oCommenting.init(block);
    };

    self.showCompletionLightbox = function(formElement, block) {
        var currentForm = $(formElement);
        var currentFormFields = currentForm.children('input[type=hidden]').clone();

        var form = $('<form method="post" />')
                 .attr('action', currentForm.attr('action'));

        // Build up set of input fields taken from existing completion form
        // -> also grab the name of the action field to get the module ID
        var inputSet = $('<fieldset />');
        var commentFieldName = '';
        for (var fieldIndex=0; fieldIndex < currentFormFields.length; fieldIndex++) {
            var currentFormField = $(currentFormFields[fieldIndex]);
            if (currentFormField.val() == 'markItemComplete') {
                commentFieldName = currentFormField.attr('name').replace('action', 'comment');
            }

            inputSet.append(currentFormField);
        }

        inputSet.append(
             $('<textarea />')
             .attr('style', 'height:80px;width:100%;margin-bottom:14px;')
             .attr('name', commentFieldName)
        );

        form.append(inputSet);

        var save =  $('<div class="formRow" />')
                    .append(
                        $('<input class="saveButton" type="image" />')
                        .attr('src', SITE_WEB_ROOT+ 'custom/careers_wales/img/learningPathways/buttons/button_save_'+oLocale.getFieldValue('id')+'.png')
                    );

        form.append(save);

        var cancelAnchor = $('<a href="#" style="font-weight:bold;" />').append(self.getTranslation('labelCancel'))
                                .click(function(){
                                    $.cwmodal.close();
                                    return false;
                                });

        var cancelText = $('<p class="cancel" style="clear:both;" />')
                            .append(self.getTranslation('labelOr')+' ')
                            .append(cancelAnchor)
                            .append(' '+self.getTranslation('labelToClose'));

        var completionContentId = 'TodoList_completionContent_'+block.attr('id').replace('block_', '');
        var lightboxContent = $('<div class="completeBox" />');
        if (document.getElementById(completionContentId).innerHTML.length > 0) {
            var header = $('.header', $('#'+completionContentId));
            var body = $('.body', $('#'+completionContentId));

            lightboxContent.append(
                $('<h3 />').text(header.text())
            ).append(
                body.html()
            );
        }

        lightboxContent.append(form)
                       .append(cancelText);

        $(lightboxContent).cwmodal({
            persist: false,
            containerId: 'learningPathwaysContainer',
            centre:{
                horizontal:{
                    events:{
                        open:{
                            hideBefore:true
                        },
                        resize:{
                            hideBefore:true
                        }
                    },
                    params:{
                        minimum:20,
                        maximum:null,
                        delta:20
                    }
                },
                vertical:{
                    events:{
                        open:{
                            hideBefore:true
                        },
                        resize:{
                            hideBefore:false
                        }
                    },
                    params:{
                        minimum:20,
                        maximum:160,
                        delta:20
                    }
                }
            }
        });
    };

    self.componentId = function() {
        var componentId = self.getComponentId();
        return (componentId.substr(0, 1).toUpperCase())+(componentId.substr(1));
    };

    self.getTranslation = function(key) {
        if (!(typeof(key) == 'string' || typeof(key) == 'number')) {
            return '';
        }

        return oLocale.getTranslation(self.componentId(), key);
    };
};
/* RateMySkills.js (380) */
/**
 * @package private_output_careers_wales_learningpathways
 * @version $Id: RateMySkills.js.380.allsites.js 42093 2011-10-25 08:22:04Z james $
 * @copyright Copyright (c) 2008 Box UK Ltd. All rights reserved.
 *
 * @audit
 * - 2009-10-30  JRC  Created file.
 */

var rateMySkills = function() {
    var self = this;

    var states = {
        PREPARING:0,
        INTRO:1,
        LOADINGQUESTIONS:2,
        QUESTIONS:3,
        SAVING:4,
        OUTRO:5
    };

    var currentState = null;                // Set using setState(), please don't fiddle with directly
    var defaultState = states.PREPARING;    // Starting state
    
    var currentActivityItem = null;

    var imageButtonPath = "custom/careers_wales/img/learningPathways/buttons/";
    var lightboxContainerId = 'rateMySkillsContainer';

    var documentContainer = function(jsonData) {
        var getDocument = function(documentObject){
            var documentObjectHasDocument = function (documentObject) {
                if (documentObject === undefined) {
                    return false;
                }

                return true;
            };

            var document = function(inTitle, inBody) {
                var title = inTitle;
                var body = inBody;

                this.title = function() {
                    return title;
                };

                this.body = function() {
                    return body;
                };
            };

            if (!documentObjectHasDocument(documentObject)) {
                return new document('','');
            }

            if (documentObject.length) {
                documentObject = documentObject[0];
            }

            var title = documentObject.oMetadataManager.oMetadata.aField.title;
            var body = documentObject.oContent.aField.bodyText;

            return new document(title, body);
        };

        var intro = getDocument(jsonData.Module.oIntroDocument);
        var outro = getDocument(jsonData.Module.oOutroDocument);

        this.intro = function() {
            return intro;
        };

        this.outro = function() {
            return outro;
        };
    };

    var questionSet = function() {
        var internalStates = {
            PREPARING:0,
            LOADING:1,
            READY:2
        };

        var internalState = internalStates.PREPARING;        

        var questions = [];             // Array of questions+answers, one set per activity ID
        var questionsOnScreen = [];     // Indexes of questions currently on screen, one set per activity ID
        var current = [];               // Index of current question, per activity ID
        var hasPreviousAnswers = [];    // Boolean flag, per activity ID - do we already have a question+answer set ready?

        var iterateForwards = true;

        this.state = function() {
            return internalState;
        };

        this.questionsOnScreen = function() {
            return questionsOnScreen[currentActivityItem.id()];
        };

        this.isReady = function() {
            return internalState == internalStates.READY;
        };

        this.hasPreviousAnswers = function() {
            return hasPreviousAnswers[currentActivityItem.id()] === true;
        };

        this.load = function() {
            hasPreviousAnswers[currentActivityItem.id()] = false;
            var url = self.getPageAjaxUrl() + '&Module[' + self.instanceId() + '][action]=getQuestionSet&Module[' + self.instanceId() + '][contentId]=' + currentActivityItem.id();
            internalState = internalStates.LOADING;

            $.get(url, function(data){
                var questionCounter = 0;

                if (typeof(questions[currentActivityItem.id()]) == 'undefined') {
                    questions[currentActivityItem.id()] = [];
                }

                $('ol li', data).each(function(){
                    questions[currentActivityItem.id()][questionCounter] = this;
                    questionCounter++;
                });

                var currentQuestion = null;
                var answerChoices = null;
                var answerValue = null;

                for (var questionIndex in questions[currentActivityItem.id()]) {
                    if (questions[currentActivityItem.id()].hasOwnProperty(questionIndex)) {
                        currentQuestion = questions[currentActivityItem.id()][questionIndex];

                        answerChoices = $('.answerChoices', currentQuestion);
                        answerValue = $('input[type=radio]', answerChoices).filter(':checked').val();

                        answerChoices.addClass('answerChoice slider slider-ans'+answerValue);
                    }
                }
                
                current[currentActivityItem.id()] = 0;
                questionsOnScreen[currentActivityItem.id()] = [];                
                hasPreviousAnswers[currentActivityItem.id()] = true;
                internalState = internalStates.READY;
            });
        };

        this.reset = function() {
            iterateForwards = true;
            current[currentActivityItem.id()] = 0;
            questionsOnScreen[currentActivityItem.id()] = [];
        };

        this.iterateForwards = function() {            
            if (this.iteratorDirection() == 'forwards') {
                this.resetScreenTotal();
                return true;
            }

            iterateForwards = true;
            if (this.current() == -1) {
                this.setCurrent(this.current() + this.screenTotal() + 1);
            } else {
                this.setCurrent(this.current() + this.screenTotal());
            }

            this.resetScreenTotal();
            return true;
        };

        this.iterateBackwards = function() {
            if (this.iteratorDirection() == 'backwards') {
                this.resetScreenTotal();
                return true;
            }

            iterateForwards = false;
            this.setCurrent(this.current() - this.screenTotal() - 1);
            this.resetScreenTotal();
            return true;
        };

        this.iteratorDirection = function() {
            return (iterateForwards) ? 'forwards' : 'backwards';
        };

        this.current = function() {
            return current[currentActivityItem.id()];
        };

        this.setCurrent = function(value) {
            current[currentActivityItem.id()] = value;
        };

        this.isAtEnd = function() {
            return this.current() >= this.size();
        };

        this.isAtStart = function() {
            if (this.iteratorDirection() == 'forwards') {
                return (this.current() - this.screenTotal() <= 0);
            }

            return this.current() < 0;
        };

        this.size = function() {
            if (typeof(questions[currentActivityItem.id()]) == 'undefined') {
                return 0;
            }

            return questions[currentActivityItem.id()].length;
        };

        this.screenTotal = function() {
            return questionsOnScreen[currentActivityItem.id()].length;
        };

        this.resetScreenTotal = function() {
            questionsOnScreen[currentActivityItem.id()] = [];
        };

        this.get = function(options) {
            var defaults = {
                index:this.current(),
                increment:true
            };

            var settings = $.extend(defaults,options);
            if (typeof(questions[currentActivityItem.id()][settings.index]) == 'undefined') {
                return false;
            }

            var question = questions[currentActivityItem.id()][settings.index];
            questionsOnScreen[currentActivityItem.id()][this.screenTotal()] = settings.index;
            
            if (settings.increment) {
                if (iterateForwards) {
                    current[currentActivityItem.id()]++;
                } else {
                    current[currentActivityItem.id()]--;
                }
            }

            return question;
        };
        
        this.toFormContent = function() {
             /*
                Hack alert:
                We used to use the above answer choice buttons to determine what form data to submit
                All until IE decided to lose ability to do this
                Now we (hackily) use the class that is set to determine which slider image to render
             */

            var hiddenFields = $('<div />');
            
            var questionSet = questions[currentActivityItem.id()];
            var currentQuestion = null;
            var currentQuestionName = null;
            var currentAnswer = null;
            var answerRegex = new RegExp('slider-ans[0-9]', 'g');
            var regexMatches = [];

            var classes = [];

            for (var index in questionSet) {
                if (questionSet.hasOwnProperty(index)) {
                    currentQuestion = $(questionSet[index]);
                    currentQuestionName = $($('input[type=radio]', currentQuestion).get(0)).attr('name');

                    classes = $('div.answerChoices', currentQuestion).attr('class').split(' ');
                    for (var classIndex in classes) {
                        if (classes.hasOwnProperty(classIndex)) {
                           regexMatches = answerRegex.exec(classes[classIndex]);

                           if (regexMatches !== null) {
                               currentAnswer = regexMatches[0].replace('slider-ans', '');
                           }

                        }
                    }

                    hiddenFields.append('<input type="hidden" name="'+currentQuestionName+'" value="'+currentAnswer+'" />');                    
                }                
            }

            return hiddenFields;            
        };
    };

    var questions = null;

    var isStateValid = function(newState) {
        for (var stateKey in states) {
            if (states[stateKey] == newState) {
                return true;
            }
        }

        return false;
    };

    var setState = function(newState) {
        // Set current state to requested state if the requested state is valid
        if (isStateValid(newState)) {
            currentState = newState;
            return true;
        }

        // Requested state not valid. Set to default
        return setState(defaultState);
    };

    var rmsActivityItem = function(rmsActivityBlock) {
        var self = this;

        var siteSections = {
            workExperience:{
                idPattern:/Module\[[0-9]+\]\[experience\]/
            },
            interests:{
                idPattern:/Module\[[0-9]+\]\[interest\]/
            },
            achievementsAndExperience:{
                idPattern:/Module\[[0-9]+\]\[achievement\]/
            },
            employment:{
                idPattern:/Module\[[0-9]+\]\[employment\]/
            },
            ideas:{
                idPattern:/Module\[[0-9]+\]\[experience\]/
            },
            certificatesAndCourses:{
                idPattern:/Module\[[0-9]+\]\[experience]/
            }
        };

        var title;
        var details;
        var id;
        var siteSection;    // Achievements & Experience : Cyraeddiadau a Phrofiad
                            // Employment : Cyflogaeth
                            // Interests : Diddordebau
                            // Work Experience : Profiad Gwaith
                            // Ideas

        this.isValid = function() {
            // Not valid if we have no id set
            if (!AMAXUS.validate.isPositiveInteger(id)) {
                return false;
            }

            return true;
        };

        var construct = function(rmsActivityBlock) {
            // Determine site section being dealt with
            var block = $(rmsActivityBlock).parents('.block');
            
            if(block.length === 0) {
                block = $(rmsActivityBlock).parents('.amax-block');
            }
            siteSection = block[0]._componentId;

            // Get ID of the activity item
            $('input[type=hidden]', rmsActivityBlock).each(function(){
                if (siteSections[siteSection].idPattern.test($(this).attr('name'))) {
                    id = $(this).val();
                }
            });

            // Get details and title
            // -> only if we have an ID!
            if (!self.isValid()) {
                return false;
            }

            title = $('span.title', rmsActivityBlock).text();
            details = $('span.description', rmsActivityBlock).text();

            return true;
        };

        this.title = function() {
            return title;
        };

        this.details = function() {
            if (!(details)) {
                return '';
            }

            return details;
        };

        this.id = function() {
            return id;
        };

        this.siteSection = function() {
            return siteSection;
        };

        construct(rmsActivityBlock);
    };

    var rmsLightbox = function(newContainerId) {
        var title = '';
        var body = {};
        for (var state in states) {
            if (states.hasOwnProperty(state)) {
                body[states[state]] = '';
            }
        }

        var containerId = newContainerId;

        var detectStartState = function() {
            if (configuration === null) {
                return states.PREPARING;
            }

            return states.INTRO;
        };

        var detectNextState = function() {
            switch (currentState) {
            case states.PREPARING:
                return states.INTRO;

            case states.INTRO:
            case states.LOADINGQUESTIONS:
                return (questions.hasPreviousAnswers()) ? states.QUESTIONS : states.LOADINGQUESTIONS;

            case states.QUESTIONS:
                return states.OUTRO;

            case states.OUTRO:
                return detectStartState();
            }

            return detectStartState();
        };

        var containerElement = function() {
            return $('#'+containerId);
        };

        var bodyElement = function() {
            return $('div.body', containerElement());
        };

        var contentElement = function() {
            return $('div.contentContainer', bodyElement());
        };

        var isPresent = function() {
            return containerElement().length > 0;
        };

        var renderTitle = function() {
            if (isPresent()) {
                $('h2', containerElement()).text(title);
            }

            return true;
        };

        var renderBody = function() {
            if (isPresent()) {
                $(bodyElement()).html(
                    $('<div class="contentContainer" />').html(body[currentState])
                );
            }

            return true;
        };

        var currentActivityContent = function() {
            return $('<div class="currentItem curvedBox" />')
                   .append(
                       $('<div class="bottom" />')
                       .append(
                           $('<div class="mid" />')
                           .append(
                               $('<h3 />').text(currentActivityItem.title())
                           ).append(
                               $('<p />').text(currentActivityItem.details())
                           )
                       )
                   );
        };

        var cancelContent = function() {
            var cancelAnchor = $('<a href="#" />')
                .append(self.getTranslation('labelCancel'))
                .click(function(){
                    setState(detectStartState());
                    $.cwmodal.close();
                    return false;
                 });

            var cancelText = $('<p />')
                .addClass('cancel')
                .append(self.getTranslation('labelOr')+' ')
                .append(cancelAnchor)
                .append(' '+self.getTranslation('labelToClose'));

            return cancelText;
        };

        var columnHeadings = function() {
            var answerChoicesContainer = $('<div class="columnHeadingContainer" />');
            var answerChoices = configuration.answerChoices();
            
            for (var answerIndex in answerChoices) {
                if (answerChoices.hasOwnProperty(answerIndex)) {
                    answerChoicesContainer.append(
                        $('<div class="columnHeading wording-ans'+answerIndex+'" />').append(answerChoices[answerIndex])
                    );
                }
            }

            return answerChoicesContainer;
        };

        var previousButton = function() {
            return $('<div class="rms-button rms-button-previous" />').append(
                       $('<img src="'+imageButtonPath+'button_previous_'+oLocale.getFieldValue('id')+'.png" alt="'+self.getTranslation('actionPrevious')+'"/>').click(function(){
                           questions.iterateBackwards();
                           setState(states.QUESTIONS);
                           lightbox.update();
                           return false;
                       }));
        };

        var nextButton = function() {
            return $('<div class="rms-button rms-button-next" />').append(
                       $('<img src="'+imageButtonPath+'button_next_'+oLocale.getFieldValue('id')+'.png" alt="'+self.getTranslation('actionNext')+'"/>').click(function(){
                           questions.iterateForwards();                           
                           setState(states.QUESTIONS);
                           lightbox.update();                            
                           return false;
                       }));
        };        

        var saveButton = function() {
            return $('<div class="rms-button rms-button-save" />').append(
                       $('<img src="'+imageButtonPath+'button_save_'+oLocale.getFieldValue('id')+'.png" alt="'+self.getTranslation('actionSave')+'"/>').click(function(){
                          setState(states.SAVING);
                          lightbox.update();

                          self.save(function(){
                              setState(states.OUTRO);

                              lightbox.setBody(
                                  $('<div />')
                                  .append(
                                      $('<div class="outroDocument" />').html(configuration.documents().outro().body())
                                  ).append(
                                      $('<div class="outroButtons" />')
                                      .append(
                                          $('<div class="rms-button rms-button-outro" />')
                                          .append(
                                              $('<img src="'+imageButtonPath+'button_viewYourSkillsCloud_'+oLocale.getFieldValue('id')+'.png" alt="'+self.getTranslation('actionViewCloud')+'"/>').click(function(){
                                                  window.location = configuration.skillsCloudUrl();
                                              })
                                          )
                                          .append(
                                              $('<img src="'+imageButtonPath+'button_backTo_'+currentActivityItem.siteSection()+'_'+oLocale.getFieldValue('id')+'.png" alt="'+self.getTranslation('actionBackTo')+' '+self.getTranslation('actionBackTo_'+currentActivityItem.siteSection())+'"/>').click(function(){
                                                  setState(states.INTRO);
                                                  $.cwmodal.close();
                                               })
                                          )
                                      )
                                  )
                              );
                              
                              
                              lightbox.update();
                          });
                          return false;
                       }));
        };

        var paginationContainer = function() {
            return $('<div class="paginationText" />');
        };

        var paginationContent = function() {
            var lowest = 0;
            var highest = 99;

            if (questions.iteratorDirection() == 'forwards') {
                lowest = questions.current() - questions.screenTotal() + 1;
                highest = questions.current();
            } else {
                if (questions.current() == -1) {
                    lowest = 1;
                    highest = questions.screenTotal();
                } else {
                    lowest = questions.current() + 2;
                    highest = lowest + questions.screenTotal() - 1;
                }
            }

            return lowest+'-'+highest+' '+self.getTranslation('labelOf')+' '+questions.size()+' '+self.getTranslation('labelQuestions');
        };

        this.setTitle = function(newTitle) {
            title = newTitle;
            return true;
        };

        this.setBody = function(newBody, state) {
            if (!isStateValid(state)) {
                state = currentState;
            }

            body[state] = newBody;
            return true;
        };

        this.update = function() {
            if (isPresent()) {
                renderTitle();
                renderBody();
            }

            switch (currentState) {
            case states.PREPARING:
                bodyElement().addClass('loading');
                break;

            case states.INTRO:
                bodyElement().removeClass('loading');
                if (currentActivityItem !== null) {
                    bodyElement().prepend(currentActivityContent());

                    bodyElement().append(
                        $('<div class="metaContainer" />').append(
                            $('<div class="rms-button rms-button-next" />').append(
                                $('<img src="'+imageButtonPath+'button_next_'+oLocale.getFieldValue('id')+'.png" alt="'+self.getTranslation('actionNext')+'"/>').click(function(){
                                    setState(detectNextState());
                                    lightbox.update();
                                })
                            )
                        )
                   );
 
                }
                break;

            case states.LOADINGQUESTIONS:
                bodyElement().addClass('loading');

                window.setTimeout(function(){
                    setState(detectNextState());
                    lightbox.update();
                }, 100);

                break;

            case states.QUESTIONS:
                // Odd condition relating to a bug
                // -> shouldn't get into this state if previous questions+answers haven't been loaded, but sometimes it happens
                if (!questions.hasPreviousAnswers()) {
                    setState(states.LOADINGQUESTIONS);
                        window.setTimeout(function(){
                            setState(detectNextState());
                            lightbox.update();
                        }, 100);

                    return true;
                }

                bodyElement().removeClass('loading');
                if (currentActivityItem !== null) {
                    bodyElement().prepend(currentActivityContent());
                    contentElement().prepend(columnHeadings());

                    var questionList = $('<ol />');
                    contentElement().append(questionList);

                    var previousButtonContent = previousButton();

                    var nextButtonContent = nextButton();
                    var pagintionContainerContent = paginationContainer();

                    var metaContainer = $('<div class="metaContainer" />');
                    bodyElement().append(metaContainer);

                    metaContainer.append(pagintionContainerContent);
                    metaContainer.append(previousButtonContent);
                    metaContainer.append(nextButtonContent);
                    metaContainer.append(saveButton());
                    metaContainer.append(cancelContent());

                    var lightboxIsBelowTheFold = false;
                    var currentQuestion = false;

                    if (questions.iteratorDirection() == 'forwards') {
                         while (!questions.isAtEnd() && !lightboxIsBelowTheFold) {
                             currentQuestion = $(questions.get());
                             if ($('span', currentQuestion).length === 0) {
                                 currentQuestion.prepend(
                                     $('<span />').text(questions.current()+'. ')
                                 );
                             }

                             questionList.append(
                                 currentQuestion
                             );

                             lightboxIsBelowTheFold = AMAXUS.dimensions.element.isBelowTheFold({
                                 selector:'#'+lightboxContainerId,
                                 topEdge:false,
                                 bottomEdge:true,
                                 offset:128
                             });
                        }

                    } else {
                        while (!questions.isAtStart() && !lightboxIsBelowTheFold) {
                            currentQuestion = $(questions.get());
                            if ($('span', currentQuestion).length === 0) {
                                currentQuestion.prepend(
                                    $('<span />').text(questions.current()+'. ')
                                );
                            }

                            questionList.prepend(
                                currentQuestion
                            );

                            lightboxIsBelowTheFold = AMAXUS.dimensions.element.isBelowTheFold({
                                selector:'#'+lightboxContainerId,
                                topEdge:false,
                                bottomEdge:true,
                                offset:10
                            });
                        }
                    }

                    if (questions.isAtEnd()) {
                        $(nextButtonContent).remove();
                    }

                    if (questions.isAtStart()) {
                        $(previousButtonContent).remove();
                    }

                    pagintionContainerContent.append(
                        paginationContent()
                    );
                        
                    var updateSliderImage = function(slider, value) {
                         var answerContainer = $(slider);
                         answerContainer.removeClass('slider-ans0');
                         answerContainer.removeClass('slider-ans1');
                         answerContainer.removeClass('slider-ans2');
                         answerContainer.removeClass('slider-ans3');

                         answerContainer.addClass('slider-ans'+value);
                    };

                    var updateSelectedAnswer = function(event) {
                         // Identify the clicken upon answer choice
                         var containerLeftPos = $(event.target).offset().left;
                         var eventLeftPos = event.pageX;
                         var containerClickOffset = eventLeftPos - containerLeftPos;
                         var answerIndex = null;

                         if (containerClickOffset <= 50) {
                             answerIndex = 0;
                         } else if (containerClickOffset > 50 && containerClickOffset <= 100) {
                             answerIndex = 1;
                         } else if (containerClickOffset > 100 && containerClickOffset <= 150) {
                             answerIndex = 2;
                         } else if (containerClickOffset > 150 && containerClickOffset <= 200) {
                             answerIndex = 3;
                         }
                         
                         if (answerIndex !== null) {
                             // Find the contained radio button and click it
                             var radioButton = $($('input[type=radio]', event.target).get(answerIndex));
                             radioButton.click();

                             // Then set the parent container class to get the imagery right
                             /*
                                Hack alert:
                                We used to use the above radio buttons to determine what form data to submit
                                All until IE decided to lose ability to do this
                                Now we (hackily) use the class as set by updateSliderImage below
                             */
                             updateSliderImage(event.target, radioButton.val());
                         }

                    };

                    // Apply 'slider' on top of radio button groups
                        // Hide all radio buttons, setting background imagery as appropriate for those that are checked
                        $('input', '.answerChoices').each(function(){
                            var currentInput = $(this);

                            currentInput.hide();
                            if (currentInput.is(':checked')) {
                                updateSliderImage(
                                    currentInput.parents('.answerChoices:last'),
                                    currentInput.val()
                                );
                            }
                        });

                        var currentAnswerChoiceSet = null;
                        var answerChoiceSetTimeout = null;

                        // Apply slider magic
                        $('.answerChoices')
                            .addClass('slider')
                            .click(function(event) {
                                updateSelectedAnswer(event);
                             })
                             .mouseover(function(){
                                 window.clearTimeout(answerChoiceSetTimeout);
                             })
                             .mouseout(function(){
                                 answerChoiceSetTimeout = window.setTimeout(function(){
                                     currentAnswerChoiceSet = null;
                                 }, 1000);
                             })
                             .mousedown(function(event){
                                 currentAnswerChoiceSet = this;
                                 updateSelectedAnswer(event);
                             })
                             .mouseup(function(){
                                 currentAnswerChoiceSet = null;
                             })
                             .mousemove(function(event){
                                 if (currentAnswerChoiceSet == this) {
                                     updateSelectedAnswer(event);
                                 }
                             });

                    $('input:checked', '.answerChoices').each(function() {
                        var checkedItem = $(this);
                        updateSliderImage(checkedItem.parent().parent(), checkedItem.val());
                    });
                }

                break;

            case states.SAVING:
                bodyElement().addClass('loading');
                break;


            case states.OUTRO:
                bodyElement().removeClass('loading');
                break;

            default:
                break;
            }            
            
            if ($(bodyElement()).length > 0) {
                if ($('.body .fullClear', '#'.lightboxContainerId).length === 0) {
                    bodyElement().append(
                        $('<div />').css({
                            'clear':'both',
                            'width':'100%',
                            'height':'1px'
                        }).addClass('fullClear')
                    );
                }
            }
        };

        this.render = function() {
            // Lightbox structure present?
            if (!isPresent()) {
                var lightboxContent = $('<div class="rateMySkills_modal" />')
                                      .append(
                                          $('<h2 />')
                                      ).append(
                                          $('<div class="body" />')
                                      ).append(
                                          $('<div />').css({
                                              'clear':'both',
                                              'width':'100%',
                                              'height':'1px'
                                          }).addClass('fullClear')
                                      );

                $(lightboxContent).cwmodal({
                    persist: false,
                    containerId: containerId,
                    onEsc:function(){
                        setState(states.INTRO);
                        return true;
                    }
                });
            }

            // Update lightbox content
            // -> lightbox draws whichever content is appropriate for the current state
            this.update();            
        };

        $().keydown(function(event) {
            if ($('#rateMySkillsContainer').length) {
                switch (event.keyCode) {
                    case 37:
                        // left arrow
                        if ($('.rms-button-previous').length) {
                            $('.rms-button-previous img').trigger('click');
                        }

                        break;
                        
                    case 39:                        
                        // right arrow
                        if ($('.rms-button-next').length) {
                            $('.rms-button-next img').trigger('click');
                        }
                        break;
                    
                    case 13:
                        // enter
                        break;
                        
                    default:
                        return true;
                }
            }

            return true;
        });
    };

    var lightbox = null;           // Instantiated to a new rmsLightbox in self.initialise()

    var rmsConfiguration = function(data) {
        var skillsCloudCategoryId = null;
        var answerChoices = [];

        var documents = null;

        var construct = function(data) {
            documents = new documentContainer(data);
            
            skillsCloudCategoryId = data.Module.oMetadata.aParsedParameter.skillsCloudId;
            if (typeof(skillsCloudCategoryId) == 'object') {
                skillsCloudCategoryId = skillsCloudCategoryId[0];
            }

            for (var answerIndex = 0; answerIndex <= 3; answerIndex++) {
                var answerKey = 'ans'+answerIndex;
                var parameterSetAnswerChoice = data.Module.oMetadata.aParsedParameter[answerKey][0];
                var localeSetAnswerChoice = data.Module.aXslText[answerKey];
                
                answerChoices[answerIndex] = (parameterSetAnswerChoice) ? parameterSetAnswerChoice : localeSetAnswerChoice;
            }

        };

        this.documents = function() {
            return documents;
        };

        this.answerChoices = function() {
            return answerChoices;
        };

        this.skillsCloudUrl = function() {
            return self.getPageUrl().replace(/show=nav\.[0-9]+/, 'show=nav.'+skillsCloudCategoryId);
        };

        construct(data);

    };

    var configuration = null;

    /*
     * Go!
     */
    self.initialise = function(block){        
        // Do we have any skill-ratable activities on this page?
        var rmsActivities = $('.userActivity');
        var rmsActivityTotal = rmsActivities.length;

        // No activities? Nothing more to do.
        if (rmsActivityTotal === 0) {
            return false;
        }

        // Prepare environment
        setState();
        lightbox = new rmsLightbox(lightboxContainerId);
        questions = new questionSet();

        // Preload configuration data for lightbox
        // -> get intro and outro documents
        // ->

        $.getJSON(self.getBlockJsonUrl(), function(data) {
            configuration = new rmsConfiguration(data);

            var introBody = $('<div />')
                            .append(
                                $('<div class="introDocument" />').html(configuration.documents().intro().body())
                            ).append(
                                $('<img src="custom/careers_wales/img/year10and11/learningPathways/sample-skill-cloud-'+oLocale.getFieldValue('id')+'.png" alt="" />')
                            );

            lightbox.setTitle(configuration.documents().intro().title());
            lightbox.setBody(introBody, states.INTRO);
            setState(states.INTRO);

            lightbox.update();
        });

        // Catch clicks on activities, collecting relevant data if the click
        // is on an RMS icon
        rmsActivities.click(function(event){
            var activityBlock = $(this);

            // Check click target
            // -> did the user click on the RMS icon?
            var isInputElement = $(event.target).is('input[type=image]');
            var targetParentIsRmsForm = $(event.target).parents().is('.rateMySkills');

            if (!isInputElement || !targetParentIsRmsForm) {
                // These are not the droids you are looking for
                return true;
            }
            
            // Prevent form from submiting
            $('.rateMySkills form', activityBlock).submit(function(){
                return false;
            });           

            // Use activity block to populate the current rms activity object
            currentActivityItem = new rmsActivityItem(this);

            lightbox.render();
            questions.iterateForwards();
            questions.setCurrent(0);
            questions.load();
            return false;
        });

        return true;
    };

    self.componentId = function() {
        var componentId = self.getComponentId();
        return (componentId.substr(0, 1).toUpperCase())+(componentId.substr(1));
    };

    self.getTranslation = function(key) {
        if (!(typeof(key) == 'string' || typeof(key) == 'number')) {
            return '';
        }

        return oLocale.getTranslation(self.componentId(), key);
    };

    self.instanceId = function(){
        var instanceId = self.getInstanceId();
        return (instanceId.substr(0, 1).toUpperCase()) + (instanceId.substr(1));
    };

    self.save = function(callback) {
        return $.post(
            self.getPageAjaxUrl(),
            $('<form />')
            .append(
                questions.toFormContent(true)
            ).append(
                '<input type="hidden" name="Module[' + self.instanceId() + '][action]" value="storeActivityScores" />')
            .append(
                '<input type="hidden" name="Module[' + self.instanceId() + '][contentId]" value="' + currentActivityItem.id() + '" />'
            ).serialize(),
            callback
        );
    };
};
/* TagCloud.js (384) */
/**
 * @package private_output_careers_wales_learningpathways
 * @version $Id: TagCloud.js.384.allsites.js 41853 2011-10-06 09:57:06Z james $
 * @copyright Copyright (c) 2008 Box UK Ltd. All rights reserved.
 *
 * Hijax hyperlinks to display content in lightbox
 *
 * @audit
 * - 2009-08-11  JRC  Created file.
 */

var tagCloud = function() {

    var self = this;
    var noAnswerDocument = null;
    var options = {
        'selectors' : {
            'container' : 'skillsViewContainer'
        },
        'actions'   : {
            'noAnswer' : 'viewDocument',
            'skill'    : 'viewSkill'
        },
        'lightboxFinalWidth' : 644
    };
    var aSkillInfo = [];

    self.initialise = function() {
        self.attachClickHandler();
    };

    var lightboxInitialLeftPosition = function() {
        var leftPosition = Math.round(($(window).width() - options.lightboxFinalWidth)/2);
        if (leftPosition < 0) {
            leftPosition = 0;
        }

        return leftPosition;
    };

    /**************************************************************************/
    /* User hasn't provided answers for skill methods                         */
    /**************************************************************************/

    self.attachClickHandler = function() {

        $('.cloud a').click(function() {          
            
            if( $(this).hasClass('noAnswers') ) {
                self.attachHandlerToEmptySkill($(this));
            }
            else {
                self.attachHandlerToAnsweredSkills($(this));
            }
            
            return false;
        });

        
    };

    self.attachHandlerToEmptySkill = function( element ) {

        self.showLoader();

        if( noAnswerDocument === null ) {
            self.getEmptyDocument( element );
            return false;
        }
        var currentSkill = element.text();
        var header       = self.getHeader( currentSkill );
        var subHeader    = self.getSubHeader( currentSkill );
        var bodyText     = self.getBodyText();
        var content      = self.getContent( subHeader, bodyText );

        self.showContent(
            {'top': '31%', 'left' : lightboxInitialLeftPosition()+'px', 'width': options.lightboxFinalWidth+'px'},
            [header, content, self.getContentCloser()]
        );
    };

    /**************************************************************************/
    /* User has provided answers for skill methods                            */
    /**************************************************************************/
    
    self.attachHandlerToAnsweredSkills = function( element ) {
        
        self.showLoader();
        
        var skillId = self.getSkillIdFromElement( element );

        if( aSkillInfo['skill-'+skillId] === undefined ) {
            self.getSkillInformation( element, skillId );
            return false;
        }

        self.showContent (
            {'top': '15%', 'left' : lightboxInitialLeftPosition()+'px', 'width': options.lightboxFinalWidth+'px'},
            [ aSkillInfo['skill-'+skillId], self.getSkillCloser()]
        );
    };

    self.getSkillIdFromElement = function( element ) {
        var skillId = null;

        var aHref = element.attr('href').split('&');
        var skillParam = aHref[2];
        skillId = skillParam.split('=')[1];

        return skillId;
    };


    self.getSkillInformation = function( element, skillId ) {

        var url = self.getAjaxSkillUrl( element );

        $.get(url, function(data){
            aSkillInfo['skill-'+skillId] = data;
            self.attachHandlerToAnsweredSkills(element);
        });
    };

    self.getAjaxSkillUrl = function( element ) {
        return element.attr('href') + '&outputFormat=ajax';
    };

    /**************************************************************************/
    /* Document methods                                                       */
    /**************************************************************************/
    /**
     * Returns the document to show the user when they haven't saved any skills
     * 
     */
    self.getEmptyDocument = function( element ) {
        var url = self.getEmptyDocumentUrl();
        
        $.getJSON(url, function(data) {
            var oDocument = data.Module.oDocument.oContent; 
            noAnswerDocument = oDocument.aField.bodyText;
            self.attachHandlerToEmptySkill( element );
        });
    };

    self.getEmptyDocumentUrl = function() {
        return self.getBlockJsonUrl() + '&' + self.getModuleFieldTitle('action') + '=' + options.actions.noAnswer;
    };

    /**************************************************************************/
    /* Content methods                                                        */
    /**************************************************************************/

    self.getHeader = function( currentSkill ) {
        return '<h1>'+self.getTranslation('labelHeader').replace('%s', currentSkill )+'</h1>';
    };

    self.getSubHeader = function( currentSkill ) {
        return '<h2>'+self.getTranslation('labelSubHeader').replace('%s', currentSkill )+'</h2>';
    };

    self.getBodyText = function() {
        return noAnswerDocument;
    };

    self.getContent = function( subHeader, bodyContent ) {
        if(bodyContent) {
            return '<div class="currentItem curvedBox"><div class="bottom"><div class="mid">'+subHeader+bodyContent+'</div></div></div>';
        }
        return '<div class="currentItem curvedBox"><div class="bottom"><div class="mid">'+subHeader+'</div></div></div>';
    };

    self.showContent = function( animationProps, aContent ) {
        var container  = $('#'+options.selectors.container);
        
        self.removeLoader();
        container.animate(animationProps, function() {
            $.each(aContent, function( i, item ) {
                $('#simplemodal-data', container).append( item );
            });
            
            $('div', container).fadeIn();
            $.cwmodal.triggerContentChange();
        });
    };


    /**************************************************************************/
    /* Loader methods                                                         */
    /**************************************************************************/
    
    self.getLoadingMessage = function() {
        var loading = self.getTranslation('labelLoading');
        return '<div class="message"><p>'+loading+'</p><img class="loadingImage" src="custom/careers_wales/img/ajax/spinner.gif" alt="'+loading+'" /></div>';
    };

    self.showLoader = function() {
        $.cwmodal(self.getLoadingMessage(),{
            containerId: options.selectors.container,
            keepAboveTheFold:{
                events:['open', 'resize', 'contentchange'],
                params:{restoreTopPosition:'15%'}
            },
            minHeight:false,
            minWidth:200,
            autoPosition: {
                horizontal:true,
                vertical:false
            },
            resize:{
                belowTheFold:{
                    events:{
                        open:{
                            hideBefore:true
                        },
                        resize:{
                            hideBefore:true
                        },
                        contentchange:true
                    },
                    params:{
                        minimum:20,
                        step:10,
                        padding:0,
                        margin:20,
                        scrollableContent:{
                            selector:'div.curvedBox',
                            widenForScrollbar:true
                        }
                    }
                }
            }
        });


    };
    
    self.removeLoader = function () {
        $('div.message', $('#'+options.selectors.container)).remove();
    };

    /**************************************************************************/
    /* Closer methods                                                         */
    /**************************************************************************/
    self.getContentCloser = function() {
        var cancelAnchor = $('<a href="#" />')
            .append(self.getTranslation('labelCancel'))
            .click(function(){
                $.cwmodal.close();
                return false;
             });

        var cancelText = $('<p />')
            .addClass('cancel')
            .append(cancelAnchor)
            .append(' '+self.getTranslation('labelToClose'));

        return cancelText;
    };

    self.getSkillCloser = function() {
        var cancelAnchor = $('<a href="#" />')
            .append(self.getTranslation('labelCancel'))
            .click(function(){
                $.cwmodal.close();
                return false;
             });

        var cancelText = $('<p />')
            .addClass('cancel')
            .append(self.getTranslation('labelOr')+' ')
            .append(cancelAnchor)
            .append(' '+self.getTranslation('labelToClose'))
//            .append(
//                $('<a href="">test</a>').click(function(){
//                    //console.log($.cwmodal.impl.dialog.offset());
//                    //console.log($.cwmodal.impl.dialog.position());
//
//                    return false;
//                })
//            )
                ;

        return cancelText;
    };
};
/* MySkillsOutput.js (386) */
/**
 * @package private_output_careers_wales_learningpathways
 * @version $Id: LearningPathways.js 8432 2008-05-23 14:09:25Z jamesrc $
 * @copyright Copyright (c) 2008 Box UK Ltd. All rights reserved.
 *
 *
 * @audit
 * - 2009-08-11  JRC  Created file.
 */
var mySkillsOutput = function() {

    var self = this;

    self.initialise = function( block ) {
        $('.download a').lightBoxDownload({
            'module'   : 'MySkillsOutput',
            'filename' : 'MySkills.pdf'
        });
    };
};
/* AMSInformation.js (423) */
function aMSInformation()
{
    this.URL = 'custom/careers_wales/js/scrollingblock/scrollingblock.js';
        
    this.CONTAINER_CLASS = '.scroller-container';
    this.CONTENTS_CLASS = '.scroller-contents';
    
    this.FADE_IN_CLASS = '.scroller-fade-in';
    this.FADE_OUT_CLASS = '.scroller-fade-out';
    
    /**
     * Initialises the block
     *
     * @param p_block The block
     */
    this.initialise = function (p_block)
    {
        var oThis = this;
        
        $.ajax({
            url: oThis.URL,
            dataType: 'script',
            success: function (data) {
                eval(data);

                oThis = new scrollingblock(
                    p_block,
                    oThis.CONTAINER_CLASS,
                    oThis.CONTENTS_CLASS,
                    oThis.FADE_IN_CLASS,
                    oThis.FADE_OUT_CLASS
                );
                oThis.initialise();
            }
        });
    };
}
/* AMSVacancies.js (425) */
function aMSVacancies()
{
    this.URL = 'custom/careers_wales/js/scrollingblock/scrollingblock.js';
    
    this.CONTAINER_CLASS = '.scroller-container';
    this.CONTENTS_CLASS = '.scroller-contents';
    
    this.FADE_IN_CLASS = '.scroller-fade-in';
    this.FADE_OUT_CLASS = '.scroller-fade-out';

    /**
     * Initialises the block
     *
     * @param p_block The block
     */
    this.initialise = function (p_block)
    {
        var oThis = this;
    
        $.ajax({
            async:false,
            url: oThis.URL,
            dataType: 'script',
            success: function (data) {
                eval(data);

                oThis = new scrollingblock(
                    p_block,
                    oThis.CONTAINER_CLASS,
                    oThis.CONTENTS_CLASS,
                    oThis.FADE_IN_CLASS,
                    oThis.FADE_OUT_CLASS
                );
                oThis.initialise();
            }
        });
    };
}
/* AMSProfile.js (429) */
function aMSProfile()
{
    var self = this;

    var addressLookup = null;
    
    var currentConfiguration = {};
    var addressLookupConfiguration = {};
        
    self.getLangCode = function() {
        var outputLang = /outputLang=Tr[0-9]+/.exec(window.location.href);
        
        if (outputLang) {
            return outputLang[0].replace('outputLang=Tr', '');
        } else {
            return 0;
        } 
    };

    self.componentId = function () {
        var componentId = self.getComponentId();
        return (componentId.substr(0, 1).toUpperCase()) + (componentId.substr(1));
    };

    self.getLocaleId = function () {
        return oLocale.getFieldValue('id');
    };

    self.getTranslation = function (key) {
        if (!(typeof(key) == 'string' || typeof(key) == 'number')) {
            return '';
        }

        return oLocale.getTranslation(self.componentId(), key);
    };
    
    var aMSProfileController = function (instanceId)
    {
        /**
         * Class representing the expandable / contractable definition lists
         */
        var DefinitionLists = function ()
        {
            this.initialise = function ()
            {
                $('dd.expanded').hide();
                $('dd.contracted').show();
                
                var errorState = $("dl:has(dd > fieldset input[id $= '_state'][value='error'])");
                
                $('dd.expanded', errorState).show();
                $('dd.contracted', errorState).hide();
                
                $('dt').click(
                    function () {
                        var dl = $(this).parent();
                        
                        var expandedDd = $('dd.expanded', dl);
                        var contractedDd = $('dd.contracted', dl);

                        var contractedDdToggled = false;

                        if (!contractedDd.is('.hidden')){
                            contractedDdToggled = true;
                            contractedDd.addClass('hidden');
                        }

                        // Show the expanded dd (or vice versa)
                        expandedDd.slideToggle(
                            'slow',
                            function () {
                                if (contractedDd.is('.hidden') && !contractedDdToggled){
                                    contractedDd.removeClass('hidden');
                                }
                            }
                        );
                    }
                );
            };
            
            this.initialise();
        };
        
        /**
         * Class representing the personal details fieldset
         */
        var PersonalDetails = function ()
        {
            this.siteCode = window.Amaxus.settings.siteCode;
            
            this.identifier = '.aMSProfile #personalDetails';
            
            /**
             * Initialises the class
             *
             * @return null
             */
            this.initialise = function ()
            {
                var buttonSrc = 'custom/careers_wales/img/';
                
                // Use the learningPathways button for year10and11...
                if (this.siteCode == 'year10and11' || this.siteCode == '16-19') {
                    buttonSrc += 'learningPathways/';
                }
                
                buttonSrc += 'buttons/button_findAddress_' + self.getLangCode() + '.png';
                
                addressLookupConfiguration = {
                    'default': {
                        selectors: {
                            lookupNumberOrNameField: '#' + self.getInstanceId() + '_personalDetails_houseNameNumber',
                            lookupPostcodeField: '#' + self.getInstanceId() + '_personalDetails_postCode',
                            manualLine1Field: '#' + self.getInstanceId() + '_personalDetails_address',
                            manualLine2Field: '#' + self.getInstanceId() + '_personalDetails_county'
                        },
                        button: {
                            id: 'lookupAddressButton',
                            src: buttonSrc,
                            alt: oLocale.getTranslation(self.componentId(), 'findAddress'),
                            title:  oLocale.getTranslation(self.componentId(), 'findAddress')
                        },
                        ajax: {
                            url: self.getApiUrl({'action': 'lookupAddress'})
                        },
                        lightbox: {
                            containerId: 'addressLookup_lightbox',
                            containerClasses: 'BuildYourCV_addressLookup',
                            dataClasses: 'BuildYourCV_addressLookup_modalData'
                        },
                        events: {
                            onFailure: function () {
                                console.log('AJAX fail');
                            },
                            preLookup: function () {
                                // Clear ajax fail message
                            }
                        },
                        content: {
                            lightbox: {
                                PREPARING: {
                                    'title': self.getTranslation('lb_loading_title')
                                },
                                RESULTS: {
                                    'title': self.getTranslation('lb_withresults_title'),
                                    'seeAllAddresses': self.getTranslation('lb_withresults_seeall') + ' ',
                                    'or': self.getTranslation('lb_withresults_or'),
                                    'enterYourAddressManually': self.getTranslation('lb_enterAddressMaually')
                                },
                                NORESULTS: {
                                    'title': self.getTranslation('lb_noresults_title'),
                                    'for': self.getTranslation('lb_noresults_for'),
                                    'tryAgain': self.getTranslation('lb_noresults_tryagain'),
                                    'or': self.getTranslation('lb_noresults_or'),
                                    'enterYourAddressManually': self.getTranslation('lb_enterAddressMaually')
                                }
                            }
                        }
                    }
                };
                
                currentConfiguration.instanceId = self.getInstanceId();
                currentConfiguration = addressLookupConfiguration['default'];    
                addressLookup = new CW.addressLookup(currentConfiguration);
                
                // Once the image is loaded, adjust the layout of the fieldset / inputs to accomodate it
                var postcodeInput = $(this.identifier + ' > .postCode > input');
        
                var postcodeButton = $(this.identifier + ' > .postCode > img#lookupAddressButton');
                
                postcodeButton.load(
                    function () {
                        postcodeInput.width(
                            (postcodeInput.width() - postcodeButton.width()) - postcodeInput.css('margin-right').replace('px', '')
                        );
                    }
                );
            };
        
            this.initialise();
        };

        /**
         * Class representing the type of apprenticeship fieldset
         */
        var TypeOfApprenticeship = function ()
        {
            var oThis = this;

            this.identifier = '.aMSProfile #typeOfApprenticeship';

            this.idPrefix = 'typeOfApprenticeship_';

            this.tempClassName = 'temp';

            /**
             * Initialises the class
             *
             * @return null
             */
            this.initialise = function ()
            {
                fieldset = $(this.identifier);

                input = $('> input', fieldset);

                showInput = false;

                $('ul li', fieldset).each(
                    function() {
                        if (this.id.replace(oThis.idPrefix, '') < 0) {
                            showInput = true;
                            $(this)
                                .addClass(oThis.tempClassName)
                                .hide();
                        }
                    }
                );
                               
                if (showInput) {
                    input.show();
                }

                input.click(
                    function() {
                        $('.' + oThis.tempClassName + ':first')
                            .removeClass(oThis.tempClassName)
                            .show('slow', function() {
                                if ($('ul li:visible', fieldset).length == 3) {
                                    input.hide();
                                }   
                            });

                        return false;
                    }
                );

                if ($('ul li:visible', fieldset).length == 0) {
                    input.trigger('click');
                }

                var occupation = $(this.identifier + ' .occupation');

                var occupationSelect = $(' > select', occupation);
                var occupationSubmit = $(" > #update-sector", occupation);

                occupationSubmit.remove();

                occupationSelect.change(
                    function () {
                        var sector = $(' .sector', $(this).parent().parent());

                        var label = $('label', sector);

                        var imgsAndAsSelector = '.ajax-spinner, .eclips-icon, a, span';

                        $(imgsAndAsSelector, sector).remove();

                        label.after(self.getAjaxSpinner());

                        occupationId = $('option:selected', this).val();

                        dataType = 'json';

                        $.ajax({
                            url: self.getApiUrl({
                                'action': 'lookupSector',
                                'occupationId': occupationId,
                                'dataType': dataType
                            }),
                            dataType: dataType,
                            success: function (data) {
                                $(imgsAndAsSelector, sector).remove();

                                img = $('<img />')
                                    .attr({
                                        'class': 'eclips-icon',
                                        'src': '../custom/careers_wales/img/eclips/groups/' + data.sector.imgFileName,
                                        'alt': oLocale.getTranslation(self.componentId(), 'eClipsGroupAltText'),
                                        'title': oLocale.getTranslation(self.componentId(), 'eClipsGroupTitle')
                                    });

                                a = $('<a />')
                                    .attr({'href': data.sector.linkHref, 'target': '_blank'})
                                    .html(data.sector.linkText);

                                label.after(img, a);
                            },
                            error: function () {
                                $(imgsAndAsSelector, sector).remove();

                                key = occupationId == '' ? 'noSectorSelected' : 'ajaxErrorSector';

                                span = $('<span />')
                                    .attr('class', 'ajax-error')
                                    .text(oLocale.getTranslation(self.componentId(), key));
                                
                                label.after(span);
                            }
                        });
                    }    
                );
            };

            this.initialise();
        };

        /**
         * Class representing the languages fieldset
         */
        var Languages = function ()
        {
            var oThis = this;
            
            this.identifier = '.aMSProfile #languages';
            
            /**
             * Initialises the class
             *
             * @return null
             */
            this.initialise = function ()
            {
                var welshWork = $(this.identifier + ' > .welshWork > input');
                var welshFirstLanguage = $(this.identifier + ' > .welshFirstLanguage > input');
                
                welshWork.click(
                    function () {
                        oThis.changeVal($(this), welshFirstLanguage, 'no');    
                    }
                );
                
                welshFirstLanguage.click(
                    function () {
                        oThis.changeVal($(this), welshWork, 'yes');    
                    }    
                );    
            };
            
            /**
             * Changes the value of a destination radio input,
             * based on the value of a source radio input.
             *
             * @param p_src The source radio input
             * @param p_dest The destination input
             * @param p_destVal The value of the destination input to check
             */
            this.changeVal = function (p_src, p_dest, p_destVal)
            {
                var val = p_src.val();
                if (val == p_destVal) {
                    $('input[value=' + val + ']', p_dest.parent()).attr('checked', 'checked');
                }
            };
            
            this.initialise();
        };
        
        /**
         * Class representing the LPP content containers (education and work experience)
         */
        var LPPContentContainers = function (instanceId)
        {
            var oThis = this;
            
            this.identifier = '.aMSProfile #education, .aMSProfile #workExperience';
        
            /**
             * Initialises the class
             *
             * @return null
             */
            this.initialise = function (instanceId)
            {
                $(this.identifier).each(
                    function () {
                        $('.update-grades').remove();
                        
                        var img = $('<img />').attr({
                            'src': '../custom/careers_wales/img/learningPathways/buttons/sortable.png',
                            'alt': oLocale.getTranslation(self.componentId(), 'changePriority'),
                            'title': oLocale.getTranslation(self.componentId(), 'changePriority')
                        });
                        
                        var span = $('<span />').addClass('handle');
                        
                        span.append(img);
                        
                        $('ul > li > .LPPContentContainer', this).prepend(span);
                        
                        /**
                         * Make education and work experience sortable
                         */
                        $('.sortable', this).sortable({
                            axis: 'vertical',
                            handle: '.handle',
                            opacity: 1,
                            update: function (event, ui) {
                                oThis.reprioritise(
                                    instanceId,
                                    $(this).sortable("serialize")
                                ); 
                            }
                        });
                        
                        /**
                         * Hide the form that allows the user
                         * to create new education / work experience
                         */
                        $('.LPPContentContainerAdd', this).hide();
                        
                        var errorState = $("dl:has(dd > fieldset input[id $= '_state'][value='error'])");
                        $('.LPPContentContainerAdd', errorState).show();
                
                        /**
                         * Show the form that allows the user
                         * to create new education / work experience
                         */
                        $('.add', this).click(
                            function () {
                                var fieldset = $(this).parent();
                                var lppContainerAdd = $('.LPPContentContainerAdd', fieldset);
                                if (!lppContainerAdd.is(':visible')) {
                                    lppContainerAdd.slideDown();
                                }
                                return false;
                            }
                        )
                        .show();
                        
                        /**
                         * The lightBoxDelete plugin only works
                         * when each element to be deleted
                         * is wrapped in it's own form.
                         *
                         * Since the apprenticeship profile is one big form,
                         * containing all the elements to be deleted,
                         * some additional jQuery is needed to replicate the behaviour 
                         */
                        
                        // Bind an handler to the click event
                        $('.remove').bind(
                            'click',
                            function () {
                                var targetElement = $(this);
                                // Show the lightbox
                                $(this).lightBoxDelete({
                                    'module': 'AMSProfile',
                                    // Confirm deletion
                                    'onConfirm': function () {
                                        targetElement
                                            // Unbind the handler from the click event
                                            .unbind('click')
                                            // Trigger a click event to submit the form, this time bypassing the lightBoxDelete
                                            .trigger('click');
                                    }
                                });
                                // Prevent default behaviour
                                return false;
                            }
                        );
                    }
                );

                var aQualificationSelect = $('.LPPContentContainer .qualification select', this.identifier);

                aQualificationSelect.change(
                    function () {
                        gradeSelect = $('.grade select', $(this).parent().parent());

                        gradeSelect.hide();

                        $('img, span.ajax-error', gradeSelect.parent()).remove();

                        gradeSelect.before(self.getAjaxSpinner());

                        qualification = $('option:selected', this).val();

                        dataType = 'json';

                        $.ajax({
                            url: self.getApiUrl({
                                'action': 'lookupGrades',
                                'qualification': qualification,
                                'dataType': dataType
                            }),
                            dataType: dataType,
                            success: function (data) {
                                $('img, span.ajax-error', gradeSelect.parent()).remove();

                                $('option', gradeSelect).remove();

                                for (var i = 0; i < data.length; i++) {
                                    gradeSelect.append(
                                        $('<option />')
                                            .val(data[i].name)
                                            .text(data[i].name)
                                    );
                                }

                                gradeSelect.show();
                            },
                            error: function () {
                                $('img, span.ajax-error', gradeSelect.parent()).remove();

                                key = qualification == '' ? 'noQualificationSelected' : 'ajaxErrorGrade';

                                span = $('<span />')
                                    .attr('class', 'ajax-error')
                                    .text(oLocale.getTranslation(self.componentId(), key));
                                
                                gradeSelect.before(span);
                            }
                        });
                    }
                );
            };
            
            this.reprioritise = function (instanceId, priorities) {
                var aPriority = priorities.split('&');
                for (var priority = 0; priority < aPriority.length; priority++) {
                    var aNameValue = aPriority[priority].split('=');
                    var name = aNameValue[0];
                    var value = aNameValue[1];             
                    
                    // Remove square brackets
                    name = name.substring(0, name.length - 2);

                    $('#' + instanceId + '_' + name + '_' + value + '_priority').val(priority);
                }
            };
            
            this.initialise(instanceId);
        };
        
        /**
         * Initialises the class
         *
         * @return null
         */
        this.initialise = function (instanceId)
        {
            var definitionLists = new DefinitionLists();
            
            var personalDetails = new PersonalDetails();
            
            var typeOfApprenticeship = new TypeOfApprenticeship();

            var languages = new Languages();
            
            var lppContentContainers = new LPPContentContainers(instanceId);
        };
        
        this.initialise(instanceId);
    };

    this.refreshDateWidget = function(p_oDayEl, p_oMonthEl, p_oYearEl) {
        var year = p_oYearEl.val(),
            month = p_oMonthEl.val(),
            days = p_oDayEl.children('option'),
            lastDay = 31,
            aMonthName = {'September': 1, 'April': 1, 'June': 1, 'November': 1},
            i;

        days.show();

        if (aMonthName[month]) {
            lastDay = 30;
        }
        else if (month == 'February') {
            lastDay = new Date(year, 1, 29).getDate() == 29 ? 29 : 28;
        }
        
        $(days).each(function () {
            if ($(this).val() > lastDay) {
                $(this).hide();

                if ($(this).attr('selected')) {
                    $(days[lastDay]).attr('selected', true);    
                }
            }
        });  
    };

    this.getAjaxSpinner = function () {
        return $('<img />').attr({
            'src': '../custom/careers_wales/img/ajax/spinner.gif',
            'class': 'ajax-spinner'
        });
    };
  
    this.initialise = function (block)
    {
        var self = this,
            instanceId = block.context._instanceId;

        aMSProfileController = new aMSProfileController(instanceId);

        jQuery(".aMSProfile select[name$='[personalDetails][dateOfBirth][month]']").change(function () {
            var oCurrEl = jQuery(this);

            self.refreshDateWidget(oCurrEl.prev('select'), oCurrEl, oCurrEl.next('select'));
        });

        jQuery(".aMSProfile select[name$='[personalDetails][dateOfBirth][year]']").change(function () {
            var oCurrEl = jQuery(this),
                oPrevEl = oCurrEl.prev('select');

            self.refreshDateWidget(oPrevEl.prev('select'), oPrevEl, oCurrEl);
        });
    };
}
/* AboutMeMyPersonalProfile.js (437) */
/**
 * @package private_output_careers_wales_learningpathways
 * @version $Id: AboutMeMyDetails.js.370.allsites.js 31408 2010-04-08 14:45:46Z jonc $
 * @copyright Copyright (c) 2008 Box UK Ltd. All rights reserved.
 *
 *
 * @audit
 * - 2009-09-21  JC  Created file.
 */

var aboutMeMyPersonalProfile = function() {

    var self = this;

    self.initialise = function(block) {
        $('textarea.defaultGreyText', $(block)).bind('click', function(){
               $(this).val('');
               $(this).attr('class', '');
               $(this).unbind('click');
           });
    };
    
};
/* GoalsAndAspirations.js (443) */
/**
 * @package private_output_careers_wales_learningpathways
 * @version $Id: GoalsAndAspirations.js 8432 2008-05-23 14:09:25Z jamesrc $
 * @copyright Copyright (c) 2010 Box UK Ltd. All rights reserved.
 *
 * Adds tool tips and lightbox functionality to block.
 *
 * @audit
 * - 2010-05-13  AR  Created file.
 */
var goalsAndAspirations = function() {

    var self = this;

    self.initialise = function( block ) {
         $(block).tooglePathways({
            'content' : '.goalAndAspiration',
            'module'  : 'GoalsAndAspirations'
         });
         $('.action .delete form').lightBoxDelete({
             'module': 'GoalsAndAspirations'
         });
         $('.goalAndAspiration', block).editInPlace({
            'selectors': {
                'form' : '.edit form',
                'editForm' : 'form.new'
            },
            'instanceId' : self.getInstanceId(),
            'module': 'GoalsAndAspirations',
            'action': 'editGoalAndAspiration',
            'name'  : 'goalsAndAspirations',
            'aField': new Array('title', 'whenBy', 'details')
         });

         Common_addCalendarControls( 'calendar', 'todoListCal', block );

         LearningPathways.initDefaultTextHandler(block);
    };
};
/* UserProvider.js (447) */
/**
 * @package private_output_careers_wales_learningpathways
 * @version $Id: UserProvider.js 8432 2008-05-23 14:09:25Z jamesrc $
 * @copyright Copyright (c) 2008 Box UK Ltd. All rights reserved.
 *
 * Adds confirm dialog when user attempt to remove their current provider
 *
 * @audit
 * - 2009-08-11  JRC  Created file.
 */
var userProvider = function() {

    var self = this;

    self.initialise = function( block ) {
        self.hideRadioButtons(block);
        self.hijaxDeleteAction();
    };

    self.hideRadioButtons = function( block ) {
        $('.provider-results .provider', block).click(function() {
            $(this).addClass('selected').siblings().removeClass('selected');
            $(this).find('input[type="radio"]').attr('checked', 'checked');
            $(this).siblings().find('input[type="radio"]').attr('checked', '');
        }).find('input').hide();
    };

    self.hijaxDeleteAction = function() {
        $(".current-provider form").lightBoxDelete({
             'module': 'UserProvider'
        });
    };
};
/* ManageMyDocuments.js (450) */
function manageMyDocuments ()
{
    var self   = this;
    var player = null;
    
    var customDir         = 'custom/careers_wales/';
    var buttonDir         = 'img/manageMyDocuments/buttons/';
    var iconDir           = 'img/manageMyDocuments/icons/';
    var thumbnailFileName = 'thumbnail_icon_img.png'; 
    
    /**
     * Initialises the block
     *
     * @param block The block
     *
     * @return null
     */
    this.initialise = function (block)
    {
        self.siteCode = window.Amaxus.settings.siteCode;
        
        self.setDeleteAction();
        
        self.setUpdateAction();

        self.setUpMediaPlayer(block);
        
        self.replaceFileInput();

        self.setUpUploadValidation(block);

        self.displayAudioButton();

        self.handlePostUploadRedirect();
    };
    
    /**
     * Sets the action that will be performed when a delete button is clicked
     *
     * @return null
     */
    this.setDeleteAction = function()
    {   
        var removeButton = 'button_remove_' + oLocale.getFieldValue('id') + '.png';
        
        if (self.siteCode == 'prof') {
            removeButton =  'button_remove_prof_' + oLocale.getFieldValue('id') + '.gif';
        }
        
        $('.delete').lightBoxDelete({
            'module'        : 'ManageMyDocuments',
            'containerId'   : 'ManageMyDocumentsEdit',
            'contentClass'  : 'file-wrapper',
            'showPreLoadIndicator': true,
            'preloadAction' : function(parameters) {
                self.loadContent(parameters.id, function(data, textStatus) {
                    var oContent  = data.Module[0].oContent;
                    var oMetadata = data.Module[0].oMetadataManager.oMetadata;
                    var form      = parameters.form;
                    var message   = form.find('h3').text();

                    form.find('h3').text(oMetadata.aField.title);
                    form.find('.file-wrapper-inner').prepend($('<h3 />').text(message));
                    form.find('.file-wrapper-inner').prepend(self.getThumbnail(oContent, form));
                    
                    parameters.callback(form);
                });
                return false;
            },
            'removeButton': SITE_WEB_ROOT + customDir + buttonDir + removeButton
        });
    };

    /**
     * Returns the thumbnail for the current item being deleted.
     *
     * @return jQuery
     */
    this.getThumbnail = function (oContent, form)
    {
        var script   = 'showMyDocument.php';
        var fileName = oContent.aField.fileName;
        var params   = '?fileName=' + fileName + '&thumbnail=1';
                    
        return  $('<div />').append(
            $('<img />')
                .attr('src', customDir + script + params)
                .error(
                    function() {
                        $(this).attr('src', customDir + iconDir + thumbnailFileName);
                    }
                ).load(
                    function() {
                    $(this).parent().css({
                        'width': $(this).width() + 'px',
                        'margin': '0px auto'
                    });

                    //need to do this for IE6 to force the
                    // browser to reposition the elements
                    if (/msie|MSIE 6/.test(navigator.userAgent)){
                        form.append('<div/>');
                    }
                }
            )
        );
    };
    
    /**
     * Sets the action that will be performed when an edit button is clicked
     *
     * @return null
     */
    this.setUpdateAction = function()
    {
        $('.file').lightBoxEdit({
            'instanceId'  : self.getInstanceId(),
            'module'      : 'ManageMyDocuments',
            'containerId' : 'ManageMyDocumentsEdit',
            'formClass'   : 'file-wrapper',
            'action'      : 'update',
            'selectors'   : {
                'form'      : 'span.update form',
                'editForm'  : 'form.update',
                'editField' : 'update'
            },
            'name'         : 'contentId',
            'aField'       : ['title', 'description'],
            'showPreLoadIndicator': true,
            'preLoadAction': function(parameters) {
                return self.loadContent(parameters.id, function(data, textStatus) {
                    var oContent  = data.Module[0].oContent;
                    var oMetadata = data.Module[0].oMetadataManager.oMetadata;

                    var form = parameters.form;

                    var script   = 'showMyDocument.php';
                    var fileName = oContent.aField.fileName;
                    var params   = '?fileName=' + fileName + '&thumbnail=1';
                    var download = '?fileName=' + fileName + '&download=1';

                    $('.thumbnailContainer', form).each(
                        function() {
                            $('> span', this).html(oContent.aField.fileSize + 'Kb');
                            $('> img', this)
                                .attr('src', customDir + script + params)
                                .error(
                                    function() {
                                        $(this).attr('src', customDir + iconDir + thumbnailFileName);
                                    }
                                )
                                .load(
                                    function() {
                                        var parent = $(this).parent();
                                        var width = ($(this).width() + $(this).siblings().width() + 4) + 'px';
                                        var marginLeft = ((parent.parent().width() - $(this).width()) / 2) + 'px';
                                        $(this).parent().css({
                                            'width': width,
                                            'margin-left': marginLeft
                                        });
                                            
                                        // need to do this for IE6 to force the
                                        // browser to reposition the elements
                                        if (/msie|MSIE 6/.test(navigator.userAgent)){
                                            $(form).append('<div/>');
                                        }
                                    }
                                );
                        }
                    );

                    $('input[name="'+self.getModuleFieldTitle('title')+'"]', form).attr('value', oMetadata.aField.title);
                    $('input[name="'+self.getModuleFieldTitle('description')+'"]', form).attr('value', oMetadata.aField.description);
                    form.find('h3').text(oMetadata.aField.title);
                    if (/msie|MSIE 6/.test(navigator.userAgent)){
                        form.find('h3').css({zoom:'1'}); // IE6 Bug
                    }

                    $('.download input, .download a', form).remove();
                    $('.download', form).append(
                        $('<a />').attr({
                            'href'  : customDir + script + download,
                            'class' : 'file-download',
                            'title' : oLocale.getTranslation('ManageMyDocuments', 'labelDownload')
                        }).text(oLocale.getTranslation('ManageMyDocuments', 'labelDownload'))
                    );

                    parameters.callBack();    
                });
            }
        });
    };

    /**
     * Loads content for a particular item
     */
    this.loadContent = function(id, callback) {
        var aParameters = {
            'action'   : 'getJSON',
            'contentId': id,
            'format'   : 'json'
        };

        $.ajax({
            'url'     : self.getApiUrl(aParameters),
            'dataType': 'json',
            'success' : function(data,textStatus) {
                return callback(data, textStatus);
            }
        });
    };
    
    /**
     * Replaces the unstylable file input with an text and image input
     *
     * @return null
     */
    this.replaceFileInput = function()
    {
        var removeButton = 'button_browse_';
        if (self.siteCode == 'prof') {
            removeButton += 'prof_';
        }
        removeButton += oLocale.getFieldValue('id') + '.png';
           
        $('#uploadedFile').replaceFileInput({
            'textInputId': '',
            'textInputClass': 'textInput',
            'browseImgId': '',
            'browseImgClass': 'browseImg',
            'src': customDir + buttonDir + removeButton,
            'alt': 'Browse',
            'title': 'Browse',
            'imgWidth': '91px',
            'imgHeight': '26px'            
        });        
        
        var curvedBox = $('.uploadAFileCurvedBox');
        
        var content = $('.introduction *:not(h2, h2 > span), form, .actionDispatcherMessages', curvedBox);
        
        if ($('.actionDispatcherMessages:visible', curvedBox).length > 0) {
            curvedBox.addClass('curvedBox725');    
        } else {
            curvedBox.addClass('curvedBox200');
            content.hide();
        }
        
        $('.curvedBox200').live(
            'click',
            function() {
                var oThis = this;
                $(oThis).slideUp(
                    'slow',
                    function() {
                        content.show();
                        $(oThis)
                            .removeClass('curvedBox200')
                            .addClass('curvedBox725')
                            .slideDown('slow');
                    }
                );    
            }
        );
        
        $('#cancel').click(
            function() {
                var parent = $(this);
                while (!parent.is('.uploadAFileCurvedBox')) {
                    parent = parent.parent();
                }
                parent.slideUp(
                    'slow',
                    function() {
                        content.hide();
                        parent
                            .removeClass('curvedBox725')
                            .addClass('curvedBox200')
                            .slideDown('slow');    
                    }
                );    
            }
        );   
    };

    /**
     * Hijax the form to ensure that the user has entered a title
     * or description before they submit it
     *
     */
    this.setUpUploadValidation = function(block)
    {
        var form       = $('.uploadAFileCurvedBox form', block);
        var oValidator = new ManageMyDocumentsFormValidator(self.getInstanceId(), form);
        
        form.live('submit', function() {
            return oValidator.isValid();
        });
    };

    /**
     * Display the audio button to enhance user experience
     */
    this.displayAudioButton = function()
    {
        $('.play').fadeIn();
    };

    /**
     * Setup media inter
     */
    this.setUpMediaPlayer = function(block)
    {
        var player = new ManageMyDocumentsMediaPlayer(self.getInstanceId());
        player.init();
    };

    /**
     * Perform a JavaScript redirect after the user has uploaded a file.
     */
    this.handlePostUploadRedirect = function(block)
    {
        $('.post-upload a', block).each(function() {
            var uri  = $(this).attr('href');
            
            $(this).slideUp( function() {
                $('<p />')
                    .text(oLocale.getTranslation('ManageMyDocuments', 'labelPostUploadRedirect'))
                    .hide()
                    .appendTo($(this).parent())
                    .fadeIn(function() {
                        window.location = uri;
                    });
            });
        });
    };
};

/**
 * Responsible for handing all interactions with the media player for
 * ManageMyDocuments block
 *
 */
var ManageMyDocumentsMediaPlayer = function(playerId)
{

    var self   = this;
    var id     = 'media-player-'+playerId;
    var player = null;

    /**
     * Set up the media handler
     */
    self.init = function()
    {
        player = getPlayer();
        self.attachHandlers();
    };

    /**
     * Handles the switching of media
     * 
     */
    self.attachHandlers = function(){
        $('.video a').click(self.handleMediaClick);
        $('.audio a').click(self.handleMediaClick);
    };

    self.handleMediaClick = function(){
        var media   = {
            file : $(this).attr('href'),
            type : self.getFileType($(this)),
            title: self.getFileTitle($(this))
        };
        player.sendEvent('LOAD', media);

        if($(this).attr('class') == 'play') {
            player.sendEvent('PLAY');
        }
        return false;
    };

    /**
     * Returns the provider type for JW Player, JW Player will need this
     * as our files are not static files that it can determine the file
     * extension from
     *
     * @return string
     */
    self.getFileType = function(element)
    {
        var type = element.parent().parent().attr('class');
        var mediaType = type.split(' ')[1];

        if( mediaType == 'audio' ) {
            mediaType = 'sound';
        }
        return mediaType;
    };

    /**
     * Returns the title of the media file
     *
     * @return string
     */
    self.getFileTitle = function(element)
    {
        return element.parent().parent().find('.titleContainer a').text();
    };

    /**
     * Returns the media player
     *
     * @return HTMLObject
     */
    var getPlayer = function()
    {
        var mediaPlayerId = id;

        if( $.browser.msie ) {
            mediaPlayerId = 'player-'+playerId;
        }
        return document.getElementById(mediaPlayerId);
    };
};

/**
 * Valids whether the form is valid
 */
var ManageMyDocumentsFormValidator = function(blockId, form)
{
    
    var self   = this;
    var aField = ['title', 'description', 'terms'];
    var aError = [];

    /**
     * Returns whether the form is valid for submission
     * @return bool
     */
    self.isValid = function()
    {
        var isValid = true;
        resetErrors();
        
        $(aField).each(function(i, fieldName) {
            var elem  = form.find('input[name="Module['+blockId+']['+fieldName+']"]');

            if( elem.length == 0 ) {
                return true;
            }
            var value = elem.val();

            if( (elem.is(':text') && !(value.length > 0)) ||
                (elem.is(':checkbox') && !elem.is(':checked'))) {
                isValid = false;
                aError.push({message: oLocale.getTranslation('ManageMyDocuments', getLocaleKey(fieldName))});
            }
        });
        
        if(aError.length > 0) {
            addErrorMessage();
        }
        return isValid;
    };

    /**
     * Resets the messages
     */
    var resetErrors = function()
    {
        aError = [];
    };

    /**
     * Adds error message to the form, removing any if they are already present
     */
    var addErrorMessage = function()
    {
        form.siblings(".actionDispatcherMessages").fadeOut(function() {
            $(this).removeClass('hidden').html('').fadeIn().html(CW.errorList.makeHTML(aError));
        });
    };

    /**
     * Returns the locale key for a particular field
     * @return string
     */
    var getLocaleKey = function(fieldName)
    {
        var firstLetter = fieldName.charAt(0).toUpperCase();
        var key = firstLetter + fieldName.substring(1);
        
        return 'noFile' + key;
    };
};
/* VenueDetails.js (456) */
/**
 * @package private_output_careers_wales
 * @version $Id: AchievementsAndExperience.js 8432 2008-05-23 14:09:25Z jamesrc $
 * @copyright Copyright (c) 2008 Box UK Ltd. All rights reserved.
 *
 */

var venueDetails = function() {
    var self = this;

    self.initialise = function(block) {
        AMAXUS.google.maps.insertApiScript('VenueDetails_initialse');
    };
};

var VenueDetails_initialse = function () {   

    $('div.venueDetails .map').each(function() {

        /**
         * Get postcode value from map element
         * Postcode should be the last class attribute as "postcode: <postcode value>"
         * e.g. <div class="map postcode:CF10 1DD" />
         */
        var getPostcodeFromMap = function (map) {
            
            /**
             * From an array of classnames on the map element, get the index where the postcode
             * declaration starts
             */
            var postcodeClassnameIndex = function (classNames) {
                for (var classNameIndex = 0; classNameIndex < classNames.length; classNameIndex++) {
                    if (classNames[classNameIndex].indexOf('postcode:') != -1) {
                        return classNameIndex;
                    }
                }

                return -1;
            };            

            /* IE uses getAttribute('className'), others use just getAttribute('class'), consolidate with obj.className*/
            var classString = (map.getAttribute('className') === null) ? map.getAttribute('class') : map.getAttribute('className');
            var classNames = classString.split(' ');
                                    
            var postcode = '';
            var startIndex = postcodeClassnameIndex(classNames);
            
            for (var classNameIndex = startIndex; classNameIndex < classNames.length; classNameIndex++) {
                postcode += classNames[classNameIndex] + ' ';
            }

            return postcode.replace('postcode:', '').substr(0, postcode.length - 1);
        };

        var postcode = getPostcodeFromMap(this);
        var mapElement = this;

        AMAXUS.google.maps.geocoder.get({
            address:postcode + ', UK'
        }, function (result, status) {
            if (status !== 'OK') {
                return;
            }

            var mapOptions = {
                zoom:13,
                center: result[0].geometry.location,
                mapTypeId: google.maps.MapTypeId.ROADMAP,
                mapTypeControl:false,
                scaleControl:false,
                zoomControl:false,
                navigationControl:false
            };

            var map = new google.maps.Map(mapElement, mapOptions);

            var marker = new google.maps.Marker({
               position: result[0].geometry.location,
               map: map
            });
        });

    });
};
/* SavedContent.js (396) */
/**
 * @package private_output_careers_wales_learningpathways
 * @version $Id: Research.js 8432 2008-05-23 14:09:25Z jamesrc $
 * @copyright Copyright (c) 2008 Box UK Ltd. All rights reserved.
 *
 * Adds tool tips and lightbox functionality to block.
 *
 * @audit
 * - 2009-11-19     JJ  Created
 */
var savedContent = function() {

    var self = this;

    self.initialise = function( block ) {
        $(".action .delete form").lightBoxDelete({
             'module': 'SavedContent'
        });
    };
};
/* Ideas.js (398) */
/**
 * @package private_output_careers_wales_learningpathways
 * @version $Id: WorkExperience.js 8432 2008-05-23 14:09:25Z jamesrc $
 * @copyright Copyright (c) 2009 Box UK Ltd. All rights reserved.
 *
 * Adds tool tips and lightbox functionality to block.
 *
 * @audit
 * - 2009-11-20  AR  Created file.
 */

var ideas = function() {
    var self = this;

    var actionItem = function(options) {
        var defaults = {
            id:null,
            title:'',
            who:'',
            when:''
        };

        var settings = $.extend(defaults, options);

        this.id = function(){
            return settings.id;
        };

        this.title = function(){
            return settings.title;
        };

        this.who = function(){
            return settings.who;
        };

        this.when = function(){
            return settings.when;
        };

        this.validate = function(){
            if (settings.title.length === 0) {
                return false;
            }

            if (settings.who.length === 0) {
                return false;
            }

            if (settings.when.length === 0) {
                return false;
            }

            return true;
        };

        this.populate = function(populateOptions) {
            var populateDefaults = {
                id:null,
                selectors:{
                    title:'',
                    who:'',
                    when:''
                },
                scope:window.document
            };

            var populateSettings = $.extend(populateDefaults, populateOptions);
            settings.id = populateSettings.id;
            settings.title = $(populateSettings.selectors.title, populateSettings.scope).val();
            settings.who = $(populateSettings.selectors.who, populateSettings.scope).val();
            settings.when = $(populateSettings.selectors.when, populateSettings.scope).val();

            return true;
        };

        this.save = function(callback) {
            var actionData = '';
            for (var settingsIndex in settings) {
                if (settings.hasOwnProperty(settingsIndex)) {
                    actionData += '<input name="Module[' + self.getInstanceId() + '][actionPlan]['+settingsIndex+']" value="'+settings[settingsIndex]+'" />';
                }
            }

            var serverAction = (this.id() === null) ? 'addAction' : 'saveAction';

            $.post(
                self.getPageAjaxUrl(),
                $('<form />').append(
                    '<input name="Module[' + self.getInstanceId() + '][action]" value="'+serverAction+'" />').append(
                    actionData+
                    '<input name="Module[' + self.getInstanceId() + '][ideaId]" value="' + self.oIdea.contentId + '" />'
                ).serialize(),
                callback
            );
        };

        this.remove = function(callback) {
            $.post(
                self.getPageAjaxUrl(),
                $('<form />').append(
                    '<input name="Module[' + self.getInstanceId() + '][action]" value="removeAction" />').append(
                    '<input name="Module[' + self.getInstanceId() + '][ideaId]" value="' + self.oIdea.contentId + '" />').append(
                    '<input name="Module[' + self.getInstanceId() + '][actionId]" value="' + this.id() + '" />'
                ).serialize(),
                callback
            );
        };
    };

    self.oIdea = null;
    self.lightbox = null;
    self.controlNamePrefix = null;
    self.imageButtonPath = "custom/careers_wales/img/learningPathways/buttons/";

    self.initialise = function( block ) {
        self.controlNamePrefix = "Module[" + self.getInstanceId() + "]";
        self.initTogglePathways(block);
        self.initDeleteLightbox();
        self.initEditInPlace(block);

        self.initViewActionPlan(block);

        LearningPathways.initDefaultTextHandler(block);
    };

    self.initTogglePathways = function(block){
        $(block).tooglePathways({
            'content' : '.conIdea',
            'module'  : 'Ideas'
         });
    };

    self.initDeleteLightbox = function(){
         $(".action .delete form").lightBoxDelete({
             'module': 'Ideas'
         });
    };

    self.initEditInPlace = function(block){
         $('.conIdea', block).editInPlace({
            'selectors': {
                'form' : '.edit form',
                'editForm' : 'form.new'
            },
            'instanceId' : self.getInstanceId(),
            'module': 'Ideas',
            'action': 'saveItem',
            'name'  : 'contentId',
            'aField': ['title', 'summary']
         });
    };

    self.initViewActionPlan = function(block) {
        $('.viewActionPlan', block).click(function(){
            self.oIdea = self.getIdea(this);
            self.lightbox = $('<div><h2>' + self.getTranslation('makeANewActionPlan') + '</h2></div>');
            self.lightbox.append(self.createCurvedBox('<h3>' + self.oIdea.title + '</h3><p>' + self.oIdea.summary + '</p>'));
            self.lightbox.append('<div id="actionContainer" />');
            self.lightbox.append('<div id="addActionContainer" />');
            self.lightbox.append($(self.cancelButton()));

            $(self.lightbox).cwmodal({
                persist: false,
                containerId: 'ideasContainer',
                autoPosition:{
                    horizontal:true,
                    vertical:false
                }
            });
            self.getActions(self.displayActions);            
        });
    };
    
    self.createCurvedBox = function(content){
        return $('<div class="curvedBox" />').append(
                   $('<div class="bottom" />').append(
                       $('<div class="mid" />').append(
                           content
                       )
                   )
               );
    };

    self.getIdea = function(scope){
        var ideaContainer = $(scope).parent().parent().parent();
        var oIdea = {};

        // Get the idea's content id - is appended to the end of the container's 'conIdea' class
        oIdea.contentId = null;
        var ideaContainerClasses = ideaContainer.attr('class').split(' ');
        for (var classIndex in ideaContainerClasses) {
            if (oIdea.contentId === null) {
                if (ideaContainerClasses.hasOwnProperty(classIndex)) {
                    var currentClass = ideaContainerClasses[classIndex];
                    if (/conIdea-[0-9]*/.test(currentClass)) {
                        oIdea.contentId = currentClass.replace('conIdea-', '');
                    }
                }
            }
        }
        
        oIdea.title     = $('.title', ideaContainer).html();
        oIdea.summary   = $('.summary', ideaContainer).html();

        return oIdea;
    };

    self.addActionForm = function(oIdea){
        var container = $('<div />');

        container.append(self.createTextInput(1, 'addForm_action', 'action', self.getTranslation('action') + ':', ''));
        container.append(self.createTextInput(2, 'addForm_who', 'who', self.getTranslation('byWhom') + ':', ''));
        container.append(self.createTextInput(3, 'addForm_when', 'when', self.getTranslation('byWhen') + ':', ''));

        container.append(
            $('<div class="addButton" />').click(
                self.doAddAction
            ).addClass('addButton-tr'+oLocale.getFieldValue('id'))
        );

        var formContainer = $('<div />');
        formContainer.append($('<h3>' + self.getTranslation('addAnAction') + '</h3>'));
        formContainer.append(self.createCurvedBox(container));

        return $(formContainer);
    };

    self.createTextInput = function(containerNum, id, name, labelText, inputValue){
        var container = $('<div class="formRow formRow' + containerNum + '" />');

        container.append($('<label for="' + id + '">' + labelText + '</label>'));
        container.append($('<input type="text" id="' + id + '" name="' + self.controlNamePrefix + '[' + name + ']" value="' + inputValue + '" />'));

        return container;
    };

    self.doAddAction = function(){
        var clearAddActionForm = function() {
            $('#addForm_action', self.oLightbox).val('');
            $('#addForm_who', self.oLightbox).val('');
            $('#addForm_when', self.oLightbox).val('');            
        };
        
        var oAction = new actionItem();
        oAction.populate({
            selectors:{
                title:'#addForm_action',
                who:'#addForm_who',
                when:'#addForm_when'
            },
            scope:self.lightbox
        });

        if (!oAction.validate()) {
            return false;
        }

        self.showIndicator();
        oAction.save(function(html){
            clearAddActionForm();
            self.displayActions(html);
        });

        return true;
    };

    self.getActions = function(callback) {
        self.showIndicator();
        return $.get(
            self.getPageAjaxUrl(),
            $('<form />')
            .append(
                '<input type="hidden" name="Module[' + self.getInstanceId() + '][action]" value="getActions" />'
            )
            .append(
                '<input type="hidden" name="Module[' + self.getInstanceId() + '][ideaId]" value="' + self.oIdea.contentId + '" />'
            ).serialize(),
            callback
        );
    };

    self.displayActions = function(html) {
        $('div#actionContainer').html('');


        $('div#actionContainer').append($('#actionPlanContent',html));

        $('div#addActionContainer').html('');
        $('div#addActionContainer').append(self.addActionForm(self.oIdea));

        //set-up some event handlers
        $('img.remove', '#actionContainer').click(self.removeAction);
        $('img.edit',   '#actionContainer').click(self.editAction);

        $('img', '#actionContainer').css('cursor', 'pointer');
    };

    self.removeAction = function(){        
        self.showIndicator();
        var oAction = new actionItem({
            id:($(this).parent().parent().parent().attr('id')+'').replace(/idea-action-/, '')
        });
        
        oAction.remove(function(html){
            self.displayActions(html);
        });
        
        return true;

    };

    self.editAction = function(){
        //we need to replace the spans with fields and add a submit button
        var actionContainer = $(this).parent().parent().parent();

        var actionValue = $('span.action',actionContainer).html();
        $('span.action', actionContainer).html('<input type="text" id="actionEdit_action" value="' + actionValue + '" />');

        var whoValue = $('span.who',actionContainer).html();
        $('span.who', actionContainer).html('<input type="text" id="actionEdit_who" value="' + whoValue + '" />');

        var whenValue = $('span.when',actionContainer).html();
        $('span.when', actionContainer).html('<input type="text" id="actionEdit_when" value="' + whenValue + '" />');

        // Add save and cancel actions
        actionContainer.append(
            $('<div class="saveContainer" />').append(
                $('<img />')
                .attr('src', self.imageButtonPath + 'button_save_' + oLocale.getFieldValue('id') + '.png')
                .attr('alt', self.getTranslation('actionSave'))
                .click(self.saveAction)
            ).append(
                $('<a href="#" class="cancel">' + self.getTranslation('labelCancelCapital') + '</a>')
                .click(function(){
                    self.cancelEdit(actionContainer);
                    return false;
                })
            )
        );

        //hide all the actions
        $('ul.actions', actionContainer).hide();
    };

    self.saveAction = function(){
        var actionContainer = $(this).parent().parent();
        
        var oAction = new actionItem();
        oAction.populate({
            id:$(actionContainer).attr('id').replace(/idea-action-/, ''),
            selectors:{
                title:'#actionEdit_action',
                who:'#actionEdit_who',
                when:'#actionEdit_when'
            },
            scope:actionContainer
        });
        
        if (!oAction.validate()) {
            return false;            
        }

        self.showIndicator();
        oAction.save(function(html){
            self.displayActions(html);
        });

        return true;
    };

    self.cancelEdit = function(actionContainer){
        var actionValue = $('input#actionEdit_action',actionContainer).attr('value');

        $('.action', actionContainer).html(actionValue);

        var whoValue = $('input#actionEdit_who',actionContainer).attr('value');
        $('.who', actionContainer).html(whoValue);

        var whenValue = $('input#actionEdit_when',actionContainer).attr('value');
        $('.when', actionContainer).html(whenValue);

        $('.saveContainer', actionContainer).remove();

        $('ul.actions', $('#actionContainer')).show();
    };

    self.showIndicator = function(){
        $('#actionContainer').html('<div class="loading" />');
        $('#addActionContainer').html('');
    };

    self.cancelButton = function(){
        var cancelAnchor = $('<a href="#" />')
            .append(self.getTranslation('labelCancel'))
            .click(function(){
                $.modal.close();
                return false;
             });

        var cancelText = $('<p />')
            .addClass('cancel')
            .append(self.getTranslation('labelOr')+' ')
            .append(cancelAnchor)
            .append(' '+self.getTranslation('labelToClose'));

        return cancelText;
    };

};
/* CreateYourCV.js (408) */
/**
 * @package private_output_careers_wales_learningpathways
 * @version $Id: CreateYourCV.js.408.allsites.js 34441 2010-08-31 11:33:55Z jonc $
 * @copyright Copyright (c) 2008 Box UK Ltd. All rights reserved.
 */
var createYourCV = function(block) {
    var self = this;

    var constants = {
        totalCheckNotReadyRetry:100,    // Number of MILLISECONDS to wait if WCV limit check is currently in progress
        ajaxRequestTimeout:5000,        // Number of MILLISECONDS to wait before timing out
        ajaxRequestRetryLimit:3         // Number of times to retry a failed Ajax request
    };

    /*
     * Block class variables
     */
    var cvTotalChecker = null;

    self.initialise = function (block) {
        cvTotalChecker = new CW.userCvTotalChecker({
            url:self.getApiUrl({'action':'checkCvLimitExceeded'}),
            ajaxRequestTimeout:constants.ajaxRequestTimeout,
            ajaxRequestRetryLimit:constants.ajaxRequestRetryLimit
        });

        var retryCvTotalChecker = function (link) {
            window.setTimeout(function(){
                $(link).trigger('click');
            }, constants.totalCheckNotReadyRetry);
        };

        var showError = function () {
            var errorContainer = $('.actionDispatcherMessages', block);
            var errorListHTML = CW.errorList.makeHTML([{message:CVBuilder_create_tooManyCvsError}]);

            errorContainer.hide();
            errorContainer.append(errorListHTML);
            errorContainer.slideDown(function () {
                window.setTimeout(function () {
                    errorContainer.slideUp();
                }, 2000);
            });
        };

        var clearError = function() {
            var errorContainer = $('.actionDispatcherMessages', block);

            errorContainer.hide();
            $('ul', errorContainer).remove();
        };

        $('h2', block).css('cursor', 'pointer');

        // Ensure rounded intro box is of suitable height to accommodate the icon
        var introbox = $('.curvedBox-createYourCV .introduction');
        if (introbox.height() < 50) {
            introbox.height(50);
        }

        if (CVBuilder_create_isLoggedIn === 0) {
            return true;
        }

        $('h2', block).click(function () {
            $(this).addClass('spinner');
            clearError();
            cvTotalChecker.isExceeded();

            switch (cvTotalChecker.getState()) {
            case cvTotalChecker.states().WAITING:
            case cvTotalChecker.states().CHECKING:
                retryCvTotalChecker(this);
                break;

            case cvTotalChecker.states().EXCEEDED:
                // User has exceeded their CV total
                $(this).removeClass('spinner');
                showError();
                cvTotalChecker.reset();
                return false;

            case cvTotalChecker.states().NOTEXCEEDED:
                // User hasn't exceeded their CV total, OK to allow link click to continue
                window.location.href = $('a', this).attr('href');
                return true;

            case cvTotalChecker.states().FAILURE:
                // Lookup failed despite a few retries
                // Let's go to where the link points anyway
                //  -> repeated AJAX request failures probably means the link won't work anyway
                window.location.href = $('a', this).attr('href');
                return true;
            }

            return false;
        });
    };
};
/* ExistingCVs.js (410) */
/**
 * @package private_output_careers_wales_learningpathways
 * @version $Id: CreateYourCV.js.408.allsites.js 29077 2010-01-05 14:48:52Z jonc $
 * @copyright Copyright (c) 2008 Box UK Ltd. All rights reserved.
 */
var existingCVs = function(block) {
    var self = this;
    
    var constants = {
        totalCheckNotReadyRetry:100,    // Number of MILLISECONDS to wait if WCV limit check is current in progress
        ajaxRequestTimeout:5000,        // Number of MILLISECONDS to wait before timing out
        ajaxRequestRetryLimit:3         // Number of times to retry a failed Ajax request
    };

    /*
     * Block class variables
     */
    //var cvTotalChecker = null;

    self.initialise = function (block) {
        self.block = block;
        
        // Ensure rounded intro box is of suitable height to accommodate the icon
        var introbox = $('.CVBuilder .curvedBox-register .introduction');
        if (introbox.height() < 50) {
            introbox.height(50);
        }

        $(".actions .remove form").lightBoxDelete({
            'module': 'WorkExperience',
            forceInputDisplayInline: true
        });
        
        cvTotalChecker = new CW.userCvTotalChecker({
            url:self.getApiUrl({'action':'checkCvLimitExceeded'}),
            ajaxRequestTimeout:constants.ajaxRequestTimeout,
            ajaxRequestRetryLimit:constants.ajaxRequestRetryLimit
        });
        
        var retryCvTotalChecker = function (link) {
            window.setTimeout(function(){
                $(link).trigger('click');
            }, constants.totalCheckNotReadyRetry);
        };

        var showError = function () {
            var errorContainer = $('.createYourCV .actionDispatcherMessages');
            var errorListHTML = CW.errorList.makeHTML([{message:CVBuilder_create_tooManyCvsError}]);

            errorContainer.hide();
            errorContainer.append(errorListHTML);
            errorContainer.fadeIn();
        };
        
        var clearError = function() {
            var errorContainer = $('.createYourCV .actionDispatcherMessages', block);
            
            errorContainer.hide();
            $('ul', errorContainer).remove();
        };
        
        $('li.createFromExisting', $(self.block)).click(function(){
            clearError();
            cvTotalChecker.isExceeded();

            switch (cvTotalChecker.getState()) {
            case cvTotalChecker.states().WAITING:
            case cvTotalChecker.states().CHECKING:            
                retryCvTotalChecker(this);
                break;

            case cvTotalChecker.states().EXCEEDED:
                // User has exceeded their CV total
                $(this).removeClass('spinner');
                showError();
                cvTotalChecker.reset();
                return false;

            case cvTotalChecker.states().NOTEXCEEDED:
                // User hasn't exceeded their CV total, OK to allow link click to continue
                window.location.href = $('a', this).attr('href');
                return true;

            case cvTotalChecker.states().FAILURE:
                // Lookup failed despite a few retries
                // Let's go to where the link points anyway
                //  -> repeated AJAX request failures probably means the link won't work anyway
                window.location.href = $('a', this).attr('href');
                return true;
            }

            return false;
        });
        
    };
};
/* BuildYourCV.js (412) */
/**
 * @package private_output_careers_wales_learningpathways
 * @version $Id: CreateYourCV.js.408.allsites.js 29212 2010-01-08 13:45:12Z jonc $
 * @copyright Copyright (c) 2008 Box UK Ltd. All rights reserved.
 */
var buildYourCV = function () {
    var self = this;
    var cvContentController = null;        // cvBuilderContentController object, instantiated during initialise() if needed
    var cvTemplateController = null;       // cvBuilderTemplateController object, instantiated during initialise() if needed
    var addressLookup = null;              // CW.addressLookup object, instantiated during initialise()
    
    var addressLookupConfiguration = {};
    var currentConfiguration = {};

    self.initPreviewButton = function(){
        $('.cvBuilder_buildYourCv_preview', self.oBlock).bind('click', function(){
            $('.cvBuilder_buildYourCv_form', self.oBlock).attr('target', '_blank');
            return true;
        });

        $('.cvBuilder_buildYourCv_save', self.oBlock).bind('click', function(){
            $('.cvBuilder_buildYourCv_form', self.oBlock).attr('target', '');
            return true;
        });
    };

    self.initPreviewButton();

    self.componentId = function () {
        var componentId = self.getComponentId();
        return (componentId.substr(0, 1).toUpperCase())+(componentId.substr(1));
    };

    self.getTranslation = function (key) {
        if (!(typeof(key) == 'string' || typeof(key) == 'number')) {
            return '';
        }

        return oLocale.getTranslation(self.componentId(), key);
    };
    
    self.getLocaleId = function () {
        return oLocale.getFieldValue('id');
    };

    /**
     * Class modelling the main CV content entry process
     *
     */
    var cvBuilderContentController = function (options) {
        
        var settings = {};

        /**
         * Class representing a set of content sections
         *
         * @constructor
         *
         * @param inboundSelectors {} jQuery selectors for various DOM objects (see cvBuilderContentController.initialise for values)
         */
        var contentSectionSet = function (inboundSelectors) {
            /**
             * Properties
             *
             */
            var selectors;
            var sections = {};

            this.applyNumbering = function () {
                var index = [];
                var indexPositions = {};
                
                var buildIndex = function () {
                    $(selectors.contentSections.contentSection.root, selectors.contentSections.root).each(function() {
                        var sectionName = getSectionName(this);
                        if ($(this).is('.ui-sortable-helper') === false) {
                            index[index.length] = sectionName;
                        }
                    });

                    for (var indexPosition in index) {
                        if (index.hasOwnProperty(indexPosition)) {
                            indexPositions[index[indexPosition]] = indexPosition;
                        }
                    }
                };

                buildIndex();

                for (var sectionName in sections) {
                    if (sections.hasOwnProperty(sectionName)) {
                        sections[sectionName].setNumber(parseInt(indexPositions[sectionName], 10) + 1);
                    }
                }
            };

            var getSectionName = function (rawContentSection) {
                var classes = $(rawContentSection).attr('class').split(' ');
                var currentClass = '';
                var currentBaseName = '';

                for (var classIndex in classes) {
                    if (classes.hasOwnProperty(classIndex)) {
                        currentClass = classes[classIndex];
                        currentBaseName = currentClass.substr(0, selectors.base.length);

                        if (currentBaseName == selectors.base) {
                            return currentClass.replace(selectors.base, '');
                        }
                    }
                }

                return false;
            };

            this.getSectionName = function (rawContentSection) {
                return getSectionName(rawContentSection);
            };

            this.get = function (sectionName) {
                return sections[sectionName];
            };

            this.each = function (callback) {
                for (var sectionName in sections) {
                    if (sections.hasOwnProperty(sectionName)) {
                        callback.apply(sections[sectionName]);
                    }
                }
            };

            this.displaySection = function(sectionName){
                //Go through each section and ensure that only the
                // one section is displayed

                this.each(function(){
                    var currentSectionName = this.getSectionName();
                    if (currentSectionName == sectionName){
                        this.toggleDisplayState();
                    } else if (currentSectionName != sectionName && this.isExpanded()){
                        this.toggleDisplayState();
                    }
                });
            };

            this.initialise = function (inboundSelectors) {
                selectors = inboundSelectors;
                var self = this;

                $(selectors.contentSections.contentSection.root, selectors.contentSections.root).each(function(){
                      sections[getSectionName(this)] = new contentSection(this, selectors.contentSections.contentSection);
                      
                      //Add an event handler
                      sections[getSectionName(this)].addHeadingClickHandler(function(rawContentSection){
                         this.displaySection(getSectionName(rawContentSection));
                      }, self);
                });
            };

            this.initialise(inboundSelectors);
        };
        /* end contentSectionSet class  */


        /**
         * Class representing a single content section
         * -> is only used within contentSectionSet
         * 
         * @constructor
         *
         * @param rawContentSection DOMElement raw DOM element for this content section
         * @param inboundSelectors  {}  jQuery selectors for identifying aspects of a content section (a copy of cvBuilderContentController.initialise.defaults.contentSections.contentSection)
         */
        var contentSection = function(rawContentSection, inboundSelectors) {
            var _rawContentSection = null;
            var section = null;     // reference to jQuery object for whole content section
            var heading = null;     // reference to jquery object for content section heading (for convenience)
            var body = null;        // reference to jquery object for content section content (for convenience)
            var content = null;
            var inclusionCheckbox = null;
            var listedContent =  null;
            var hasRecentlyMoved = false;

            var selectors = {base: 'BuildYourCV_'};

            var setRecentlyMoved = function(recentlyMoved) {
                if (typeof recentlyMoved != 'boolean') {
                    recentlyMoved = false;
                }

                hasRecentlyMoved = recentlyMoved;
            };

            this.setRecentlyMoved = function (recentlyMoved) {
                setRecentlyMoved(recentlyMoved);
            };

            this.heading = function () {
                return heading;
            };

            this.section = function () {
                return section;
            };

            var stateComponents = ['display', 'inclusion'];

            var states = {
                display: {
                    expanded:0,
                    collapsed:1
                },

                inclusion: {
                    included:2,
                    excluded:3
                }
            };

            var defaultState = {
                display: states.display.collapsed,
                inclusion: states.display.included
            };

            var currentState = {
                display: null,
                inclusion:null
            };
            
            var isStateComponentValid = function (component) {                
                return ($.inArray(component, stateComponents) != -1);
            };

            var isStateValid = function (newState, component) {
                // Component valid?
                if (!isStateComponentValid(component)) {
                    return false;
                }

                // State ID valid?
                for (var stateName in states[component]) {
                    if (states[component].hasOwnProperty(stateName)) {
                        if (states[component][stateName] == newState) {
                            return true;
                        }
                    }
                }

                return false;
            };

            var setState = function (newState, component) {
                if (!isStateValid(newState, component)) {
                    component = stateComponents[0];
                    newState = defaultState[component];
                }

                currentState[component] = newState;
            };

            var getState = function (component) {
                return currentState[component];
            };

            var getStateName = function (component) {
                var stateSet = states[component];

                for (var stateKey in stateSet) {
                    if (stateSet.hasOwnProperty(stateKey)) {
                        if (stateSet[stateKey] == getState(component)) {
                            return component+'.'+stateKey;
                        }
                    }
                }

                return false;
            };

            var updateState = function (newState, stateComponent) {
                setState(newState, stateComponent);
                updateInterface(stateComponent);
            };
            
            var include = function () {
                updateState(states.inclusion.included, 'inclusion');
            };

            this.include = function () {               
                include();
            };

            this.isIncluded = function () {
                return getState('inclusion') == states.inclusion.included;
            };
            
            var exclude = function () {
                updateState(states.inclusion.excluded, 'inclusion');
            };

            this.exclude = function () {
                exclude();                
            };

            this.isExpanded = function (){
                return getState('display') == states.display.expanded;
            };

            var toggleDisplayState = function () {
                if (hasRecentlyMoved) {
                    return true;
                }

                switch (getStateName('display')) {
                    case 'display.collapsed':
                        setState(states.display.expanded, 'display');
                        break;

                    case 'display.expanded':
                        setState(states.display.collapsed, 'display');
                        break;
                }

                return updateInterface('display');
            };

            this.toggleDisplayState = function(){
                toggleDisplayState();
            };

            var updateInterface = function(stateComponent, atInitialisationTime) {
                var currentStateComponent = '';

                var setHeadingImage = function (heading, isDisabled) {

                    var newImagePathContainerClass = (isDisabled) ? 'disabledImage' : 'enabledImage';
                    var newImageContainer = $('.'+newImagePathContainerClass, heading);
                    if (!newImageContainer.length) {
                        return true;
                    }

                    heading.css('background-image', 'url("'+newImageContainer.attr('title')+'")');
                    return true;
                };
                
                var updateInterfaceForStateComponent = function (atInitialisationTime) {
                    switch (getStateName(currentStateComponent)) {
                        case 'display.collapsed':
                            if (typeof atInitialisationTime == 'boolean' && atInitialisationTime === true) {
                                body.removeClass('expanded');
                                body.addClass('collapsed');
                            } else {
                                content.slideUp(500, function(){
                                    body.removeClass('expanded');
                                    body.addClass('collapsed');
                                });
                            }
  
                            break;

                        case 'display.expanded':
                            content.slideDown(500, function(){
                                body.removeClass('collapsed');
                                body.addClass('expanded');
                            });
                            break;

                        case 'inclusion.included':
                            $('.contentSectionStatusText', body).html(self.getTranslation('contentSectionStatusShown'));
                            
                            if (inclusionCheckbox !== null) {
                                inclusionCheckbox.check();
                            }                            

                            body.removeClass('disabled');
                            setHeadingImage($('h3.sectionTitle', body), false);
                            break;

                        case 'inclusion.excluded':
                            $('.contentSectionStatusText', body).html(self.getTranslation('contentSectionStatusHidden'));
                            inclusionCheckbox.uncheck();
                            body.addClass('disabled');
                            setHeadingImage($('h3.sectionTitle', body), true);
                            break;
                    }
                };
                
                if (isStateComponentValid(stateComponent)) {
                    currentStateComponent = stateComponent;
                    updateInterfaceForStateComponent(atInitialisationTime);
                    return true;
                }                

                for (var stateComponentIndex in stateComponents) {
                    if (stateComponents.hasOwnProperty(stateComponentIndex)) {
                        currentStateComponent = stateComponents[stateComponentIndex];
                        updateInterfaceForStateComponent(atInitialisationTime);
                    }
                }

                return true;
            };

            var addDragHandle = function () {
                var dragHandleContainer = $('<span class="draghandleContainer" />').click(function(){
                    return false;
                });
                
                if (section.is('.sortable')) {
                    dragHandleContainer.append(
                        '<span class="handle" />'
                    );

                    dragHandleContainer.css('cursor', 'n-resize');
                }
                
                heading.prepend (
                    dragHandleContainer
                );
                 
            };

            var setNumber = function (number) {
                var headingText = $('h3', heading).text().replace(/[0-9]\./, number+'.');
                $('h3', heading).text(headingText);
            };

            this.setNumber = function (number) {
                setNumber(number);
            };

            this.addHeadingClickHandler = function(callback, scope){
                heading.click(function(){
                    callback.call(scope, _rawContentSection);
                });
            };

            this.getSectionName = function () {
                var classes = section.attr('class').split(' ');
                var currentClass = '';
                var currentBaseName = '';

                for (var classIndex in classes) {
                    if (classes.hasOwnProperty(classIndex)) {
                        currentClass = classes[classIndex];
                        currentBaseName = currentClass.substr(0, selectors.base.length);

                        if (currentBaseName == selectors.base) {
                            return currentClass.replace(selectors.base, '');
                        }
                    }
                }

                return false;
            };

            var initialise = function (rawContentSection, selectors) {

                _rawContentSection = rawContentSection;
                section = $(rawContentSection);
                heading = $(selectors.heading, section);
                body = $(selectors.body, section);
                content = $(selectors.content, body);
                inclusionCheckbox = null;

                listedContent = new listableContentItems(content, selectors.listedContent);
                
                var checkboxSearch = $('input[type=checkbox]', heading);
                if (checkboxSearch.length > 0) {
                    inclusionCheckbox = new replacementCheckbox(
                        checkboxSearch[0],
                        {
                            on: function () {
                                include();

                            },
                            off: function () {
                                exclude();
                            }
                        }
                    );
                }

                var setInitialDisplayState = function () {
                    // For now, default to collapsing all sections
                    // ?Will later either collapse or expand based on error-display logic?
                    setState(states.display.collapsed, 'display');
                };

                var setInitialInclusionState = function () {
                    if (inclusionCheckbox === null) {
                        include();
                        return true;
                    }

                    var initialInclusionState = (inclusionCheckbox.isChecked()) ? states.inclusion.included : states.inclusion.excluded;
                    setState(initialInclusionState, 'inclusion');
                    return true;
                };

                // Set initial display and inclusion states
                setInitialDisplayState();
                setInitialInclusionState();

                // Clear up CSS styling that makes slideup/slidedown a bit jarring
                // -> temporary, will adjust in CSS before too long ...
                var headingElement = $('h3', heading);               
                headingElement.css({
                    'text-indent':headingElement.css('text-indent').replace('px', '') - 15
                });

                // Make whole heading look like a clickable action
                //heading.hover(function(){
                //    $(this).addClass('over');
                //},function(){
                //    $(this).removeClass('over');
                //});

                // Add visual affordance for dragging
                addDragHandle();

                // Swap out standard checkboxes for fancified ones
                $('input[type=checkbox][class!=replaced]', content).each(function(){
                    new replacementCheckbox(this);
                });

                updateInterface(null, true);
            };

            initialise(rawContentSection, inboundSelectors);
        };
        /* end contentSection class */

        /**
         * A template from a listable content item
         *
         */
        var listableContentItemTemplate = function (baseItem) {
            this.templateElement = null;

            var cloneItemAndChangeIndex = function (item, idPattern, newIndex) {
                // Grab inital jQuery representation of template
                var newItem = $($(item).get(0).cloneNode(true));
                
                // Modify to make a generic template
                //
                // -> replace specific item indexes in name attributes
                var nameIndexRegex = new RegExp('\\]\\['+idPattern+'\\]\\[');

                var currentElement = '';
                var currentName = '';
                var newName = '';
                $('[name]', newItem).each(function () {
                    currentElement = $(this);
                    
                    if (currentElement.attr('type') != 'radio'){

                        currentName = currentElement.attr('name');
                        newName = currentName.replace(nameIndexRegex, ']['+newIndex+'][');

                        currentElement.get(0).setAttribute('name', newName);
                    }
                });

                // -> replace specific item indexes in id attributes and associated for elements
                var idIndexRegex = new RegExp('_'+idPattern);

                currentElement = '';
                var currentId = '';
                var newId = '';
                
                $.each($('[id]', newItem), function(){
                    currentElement = $(this);
                    currentId = currentElement.attr('id');

                    if (idIndexRegex.test(currentId) && currentElement.attr('type' != 'radio')) {
                        newId = currentId.replace(idIndexRegex, '_'+newIndex);
                        //currentElement.attr('id', newId);
                        currentElement.get(0).setAttribute('id', newId);

                        $('label[for='+currentId+']', newItem).attr('for', newId);
                    }
                });
                
                // IE has a bug with option elements, so if we are using IE6,
                // we need to remove them and rebuild them, before we start
                // changing the names - otherwise the old ones will get changed as well
                newItem = cloneOptionElements(newItem, nameIndexRegex, idIndexRegex, newIndex);

                return newItem;
            };

            var cloneOptionElements = function(newItem, nameIndexRegex, idIndexRegex, newIndex){
                $.each($('input[type=radio]', newItem), function(){
                    var currentId    = $(this).attr('id');
                    var currentName  = $(this).attr('name');
                    
                    var value   = $(this).attr('value');
                    var checked = $(this).attr('checked');
                    var elClass = $(this).attr('class');
                    
                    var newId   = currentId.replace(idIndexRegex, '_'+newIndex);
                    var newName = currentName.replace(nameIndexRegex, ']['+newIndex+'][');

                    var el = null;

                    if (checked == 'checked'){
                        el = $('<input type="radio" id="' + newId + '" name="' + newName + '" value="' + value + '" checked="checked" class="' + elClass + '">');
                    } else {
                        el = $('<input type="radio" id="' + newId + '" name="' + newName + '" value="' + value + '" class="' + elClass + '">');
                    }

                    el.insertAfter($(this));
                    $(this).remove();
                });
                
                return newItem;
            };

            this.getIndexedItem = function (index) {
                return cloneItemAndChangeIndex(this.templateElement, 'INDEX', index).get(0);
            };

            this.getTemplate = function () {
                return this.templateElement;
            };

            this.initialise = function (baseItem) {
                this.templateElement = cloneItemAndChangeIndex(baseItem, '[0-9]+', 'INDEX');

                //Now we need to remove the base item
                $(baseItem).remove();
            };

            this.initialise(baseItem);
        };

        /**
         * Class representing a set of listable content items found within a content section
         * -> e.g. a set of qualifications, a set of references, a set of langauges
         *
         * @constructor
         * 
         * @param content {} jQuery refernce to a contentSection instance's <div class="contentSection"> area
         * @param listedItemSelector string jQuery reference to ...
         */
        var listableContentItems = function (inboundContent, inboundSelectors) {
            var content = null;     // All listable content items and their container (jQuery)
            var selectors = null;
            var template = null;    // Blank template for a new content item (jQuery)
            var items = [];

            /**
             * Does this content section contain any listed items?
             *
             */
            var containsListedContent = function (inboundContent, inboundSelectors) {
                var itemsContainer = $(inboundSelectors.root, inboundContent);
                if (itemsContainer.length === 0) {
                    return false;
                }

                var items = $(inboundSelectors.item, itemsContainer);
                return items.length > 0;
            };

            /**
             * Get the number of listed items in this content section
             *
             */
            var length = function () {
                return $(selectors.item, content).length;
            };

            /**
             *
             */
            var nextIndex = function () {
                var highestIndex = 0;

                for (var itemArrayIndex in items) {
                    if (items.hasOwnProperty(itemArrayIndex)) {
                        if (items[itemArrayIndex].getIndex() > highestIndex ) {
                            highestIndex = items[itemArrayIndex].getIndex();
                        }
                    }
                }

                return highestIndex + 1;
            };

            /**
             * Get position of item in list based on the item's removal icon
             *
             * @return int
             *
             */
            var getRemovalItemIndex = function (removalIcon) {
                var currentItem;

                for (var itemIndex in items) {
                    if (items.hasOwnProperty(itemIndex)) {//
                        currentItem = items[itemIndex];
                        if (currentItem.removalIcon().attr('name') == removalIcon.attr('name')) {
                            return itemIndex;
                        }
                    }
                }

                return -1;
            };

            /**
             * Handle the removal of an item
             *
             */
            var remove = function (itemIndex) {
                items[itemIndex].remove();
                buildItemsList();
                
                return true;
            };

            /**
             *
             */
            var addItem = function () {
                var newItem =  template.getIndexedItem(nextIndex());

                $('input[type=checkbox][class=replaced]', newItem).each(function() {
                    new replacementCheckbox(this);
                });

                $('.toolTip', newItem).qToolTip();

                //Add a drag handle for the new item
                var dragHandle = $('<span class="ui-sortable-draghandle"></span>');

                //Determine how to place the handle
                if ($('.cv-content-left', newItem).length > 0){
                    //Section has multiple parts
                    $('.cv-content-left', newItem).prepend(dragHandle);
                } else {
                    //Section has only one part
                    $('.container', newItem).prepend(dragHandle);
                }

                $(selectors.root + ' .addButton', content).after(newItem);
                buildItemsList();
                reinitialiseWysiwygEditors();   
            };
            
            var reinitialiseWysiwygEditors = function () {
                
                var initialise = function () {
                    tinyMCE.init({
                        spellchecker_rpc_url : 'custom/careers_wales/js/tinymce/plugins/spellchecker/rpc.php',
                        mode : "specific_textareas",
                        plugins: "table,spellchecker",
                        editor_selector : "wysiwyg",
                        editor_deselector: "noWysiwyg",
                        theme : "advanced",
                        theme_advanced_toolbar_align : "left",
                        convert_urls : true,
                        theme_advanced_toolbar_location : "top",
                        theme_advanced_buttons1 : "bold,italic,underline,separator,spellchecker,bullist",
                        theme_advanced_buttons2 : "",
                        theme_advanced_buttons3 : "",
                        width:"100%",
                        height:"75px",
                        spellchecker_languages : "+English=en"
                    });                    
                };
                
                var removeSurplusEditors = function () {
                    
                    var editorIdToTextareaId = function (editorId) {
                        return editorId.replace('_parent', '');
                    };
                    
                    var editors = $('.mceEditor');
                    editors.each(function () {
                        var currentEditor = $(this);
                        var parentId = editorIdToTextareaId(currentEditor.attr('id'));                        
                        var parentExists = $('#' + parentId).length > 0;
                        
                        if (parentExists) {
                            currentEditor.css('display', 'block');
                        } else {
                            currentEditor.remove();
                        }                        
                    });
                };
                
                initialise();
                removeSurplusEditors();               
            };
            
            var buildItemsList = function () {
                items = [];

                $(selectors.item, content).each(function () {
                    items[items.length] = new listableContentItem(this);
                });                
            };

            var addSortableBehaviour = function(content) {

                var editors = [];

                //Add a drag handle for each item
                var dragHandle = $('<span class="ui-sortable-draghandle"></span>');

                //Determine how to place the handle
                if ($('.listed-content-items .listed-content:first .cv-content-left', content).length > 0){
                    //Section has multiple parts
                    $('.listed-content-items .listed-content .container .cv-content-left', content).prepend(dragHandle);
                } else {
                    //Section has only one part
                    $('.listed-content-items .listed-content .container', content).prepend(dragHandle);
                }

                //Now apply the sortable behaviour
                $('.listed-content-items', content).sortable({
                    items: 'div.listed-content',
                    handle: '.ui-sortable-draghandle',
                    placeholder: 'ui-sortable-placeholder',
                    start: function(event, ui){
                        tinyMCE.triggerSave(false, true);
                        var i, t = tinyMCE.editors;
                        for (i in t){
                            if (t.hasOwnProperty(i)){
                                t[i].remove();
                            }
                        }
                        $('textarea.wysiwyg').show();
                    },
                    stop: function(event, ui){
                        tinyMCE.init({
                            spellchecker_rpc_url : 'custom/careers_wales/js/tinymce/plugins/spellchecker/rpc.php',
                            mode : "specific_textareas",
                            plugins: "table,spellchecker",
                            editor_selector : "wysiwyg",
                            editor_deselector: "noWysiwyg",
                            theme : "advanced",
                            theme_advanced_toolbar_align : "left",
                            convert_urls : true,
                            theme_advanced_toolbar_location : "top",
                            theme_advanced_buttons1 : "bold,italic,underline,separator,spellchecker,bullist",
                            theme_advanced_buttons2 : "",
                            theme_advanced_buttons3 : "",
                            width:"100%",
                            height:"75px",
                            spellchecker_languages : "+English=en"
                        });
                    }
                });
            };


            /**
             * Can a new listable item be added to an existing set of listable items?
             *
             * This is /not/ allowed if the first listed item is a blank template
             */
            var canAddNewItem = function() {
                // If there are no listable items, go and add one
                if (!$('.listed-content-items .listed-content', content).length){
                    return true;
                }

                // Check if what the new item will be is identical to the first listable item
                // -> can add if these are not the same
                var newItemInputs = $(':input', template.getIndexedItem(nextIndex()));
                var firstItemInputs = $(':input', $('.listed-content-items .listed-content:first', content));
                
                var formElementsAreEqual = function (form1, form2) {

                    var formValues = function (form) {
                        var values = [];

                        form.each(function () {
                            
                            var key = function () {
                                var key = this.nodeName;
                                var type = this.getAttribute('type');

                                if (type) {
                                    key += '.' + type;
                                }

                                return key;
                            };
                            
                            values.push(key.call(this) + '.' + $(this).val());

                        });

                        return values;
                    };

                    var form1Values = formValues(form1);
                    var form2Values = formValues(form2);

                    if (form1Values.length != form2Values.length) {
                        return true;
                    }

                    for (var formValueIndex = 0; formValueIndex < form1Values.length; formValueIndex++) {
                        if (form1Values[formValueIndex] != form2Values[formValueIndex]) {
                            return true;
                        }
                    }

                    return false;
                };

                return formElementsAreEqual(newItemInputs, firstItemInputs);
            };

            var initialise = function (inboundContent, inboundSelectors) {
                if (!containsListedContent(inboundContent, inboundSelectors)) {
                    return false;
                }
                
                content = inboundContent;
                selectors = inboundSelectors;

                buildItemsList();
                
                template = new listableContentItemTemplate(items[0].contentItem());

                // Handle the 'remove' action from the perspective of the whole list of content items
                // -> the action to perform depends on the list length which an individual item won't know
                //content.live('click', function (event) {
                content.click(function(event) {

                    if ($(event.target).parent().is('.remove')) {
                        
                        $(event.target).lightBoxDelete({
                            onConfirm:function(){
                                remove(getRemovalItemIndex($(event.target)));
                            }
                        });
                        return false;
                    }

                    return true;
                });

                $('.addButton', content).click(function () {
                    //need to if we can add another item
                    if (canAddNewItem()){
                    addItem();
                    }
                    return false;
                });

                addSortableBehaviour(content);

                return true;
            };
            
            initialise(inboundContent, inboundSelectors);
        };

        /**
         * Class representing an individual listable content item
         * -> e.g. a qualification, a reference, a language
         *
         * @constructor
         */
        var listableContentItem = function (inboundContentItem) {
            var contentItem = null;
            var index = null;

            var findIndex = function () {
                var itemIndexRegex = /\]\[[0-9]+\]\[/;
                var sampleElement = '';
                var indexMatches = [];
                var replacement = new RegExp('(\\[|\\])', 'g');

                $('input:first', contentItem).each(function () {
                    sampleElement = $(this);
                    indexMatches = itemIndexRegex.exec(sampleElement.attr('name'));

                    if (indexMatches.length) {
                        index = parseInt(indexMatches[0].replace(replacement, ''), 10);
                    }
                });
            };

            var initialise = function (inboundContentItem) {
                contentItem = inboundContentItem;
                findIndex();

                $('input[type=checkbox][class!=replaced]', contentItem).each(function(){
                    new replacementCheckbox(this);
                });

                $('.workDetails select', contentItem).each(function(){
                    new employmentDropdown(contentItem);
                });

                $('.radioGroupColumn', contentItem).each(function() {
                   new radioSelector(contentItem);
                });
            };

            this.contentItem = function () {
                return contentItem;
            };

            this.removalIcon = function () {
                var removalContainer = $('.remove', contentItem);
                var removalIcon = $('input[type=image]', removalContainer);

                return removalIcon;
            };

            this.getIndex = function () {
                return index;
            };

            this.remove = function () {
                $(contentItem).remove();
            };

            this.reset = function (template) {
                // Grab all form field values from the template and apply to this item

                var templateContent = template.getTemplate();

                // Text inputs, select menus
                var currentTemplateInput = '';
                var attributeNames = ['id', 'name'];
                var attributeMatches = [];
                var currentAttributeName = '';
                var currentItemInput = '';
                var haveMatch = false;
                
                $('input[type=text], texarea, select', templateContent).each(function () {
                    currentTemplateInput = $(this);
                    haveMatch = false;
                    
                    for (var attributeMatchIndex in attributeNames) {
                        if (!haveMatch) {
                            if (attributeNames.hasOwnProperty(attributeMatchIndex)) {
                                currentAttributeName = attributeNames[attributeMatchIndex];

                                attributeMatches = $('#'+currentTemplateInput.attr(currentAttributeName).replace('INDEX', index), contentItem);
                                if (attributeMatches.length) {
                                    currentItemInput = $(attributeMatches[0]);
                                    currentItemInput.val(currentTemplateInput.val());
                                    haveMatch = true;
                                }
                            }
                        }
                    }
                });


            };

            initialise(inboundContentItem);
        };

        /**
         * Radio selector class, used to select a correct radio button depending on
         * date formats selected
         */
        var radioSelector = function (inboundContent) {

            var fields = ['dateFrom', 'dateAwarded'];

            $.each(fields, function(key, value) {
                $('.' + value + ' select', inboundContent).change(function() {
                    $('.' + value + ' .radio:eq(0)', inboundContent).attr('checked', 'checked');
                });
            });

        };

        /**
         * Class representing an employment dropdown, used to switch some content
         * around on selection of 'other'
         *
         */
        var employmentDropdown = function (inboundContent) {

            var otherValue = 4;
            var whenFields = null;
            var fieldsToSwitch = ['position','orgName','orgLocation'];

            var otherView = function(inboundItem) {

                $('.otherTitle', inboundItem).show();

                $.each(fieldsToSwitch, function(n,val) {
                   $('.' + val, inboundItem).hide();
                });

                // Detach right hand fields
                whenFields = $('.cv-content-right .when-fields', inboundItem).clone(true).end();
                whenFields.appendTo($('.cv-content-left', inboundItem));

                // Update the h3
                $('.cv-content-left .when-fields h3', inboundItem).text(self.getTranslation('enterTheDates'));

                // Remove the now un-needed right hand side fields
                $('.cv-content-right .when-fields', inboundItem).remove();

                $('.hideDates', inboundItem).attr('style', 'position: relative; left: 423px; top:-43px;');
                $('.radioGroupColumn.buttons .formRow:nth-child(3)', inboundItem).attr('style', 'position: relative; left: 417px; top:-41px;');

                //Add the 'or..' header                
                if ($('.cv-content-left .orOtherHeading', inboundItem).text()) {
                    $('.cv-content-left .orOtherHeading', inboundItem).text($(self.getTranslation('label-or-capital')));
                } else {
                    $('.cv-content-left', inboundItem).append($('<h3 class="orOtherHeading">' + self.getTranslation('label-or-capital') + '</h3>').attr('style', 'position: relative; left: 30px; margin-left: 320px;'));
                }
            };

            var standardView = function(inboundItem) {
                $('.otherTitle', inboundItem).hide();

                $.each(fieldsToSwitch, function(n,val) {
                   $('.' + val, inboundItem).show();
                });

                // Add back right hand fields
                if (whenFields) {
                    whenFields.appendTo($('.cv-content-right', inboundItem));
                    $('.cv-content-right h3', inboundItem).text(self.getTranslation('whenDidYouWork'));
                    //whenField = null;
                }

                $('.hideDates', inboundItem).attr('style', '');
                $('.radioGroupColumn.buttons .formRow:nth-child(3)', inboundItem).attr('style', '');

                $('.cv-content-left h3.orOtherHeading').remove();
            };

            var switchView = function(element, inboundContent) {                
                // If they have chosen other show the extra fields
                if ($(element, inboundContent).val() == otherValue) {
                    otherView(inboundContent);
                } else {
                    standardView(inboundContent);
                }
            };

            var initialise = function(inboundContent) {
                $(function() {
                    switchView($('.details select',inboundContent),inboundContent);
                });

                $('.details select', inboundContent).change(function() {
                    switchView(this, inboundContent);
                });

            };

            initialise(inboundContent);
            
        };

        /**
         * Class representing a fancified checkbox that is used to replace the browser default
         *
         * @constructor
         */
        var replacementCheckbox = function (inboundCheckbox, inboundCallbacks) {
            var checkbox = null;        // The checkbox we're replacing (jQuery object)
            var replacement = null;
            var callbacks = {};

            var isChecked = function () {
                if (checkbox === null) {
                    return true;
                }

                return checkbox.is(':checked');
            };

            this.isChecked = function () {
                return isChecked();
            };

            var check = function () {
                if (checkbox === null) {
                    return true;
                }

                // Update actual checkbox
                checkbox.attr('checked', 'checked');

                // Update replacement checkbox imagery
                $('span', replacement).addClass('checkbox-checked');
                $('span', replacement).removeClass('checkbox-unchecked');

                return true;
            };

            this.check = function () {
                return check();
            };

            var uncheck = function () {
                if (checkbox === null) {
                    return true;
                }

                // Update actual checkbox
                checkbox.attr('checked', '');

                // Update replacement checkbox imagery
                $('span', replacement).addClass('checkbox-unchecked');
                $('span', replacement).removeClass('checkbox-checked');
                return true;
            };

            this.uncheck = function () {
                return uncheck();
            };

            var toggle = function () {
                if (isChecked()) {
                    uncheck();

                    if (typeof callbacks.off == 'function') {
                        callbacks.off();
                    }

                } else {
                    check();

                   if (typeof callbacks.on == 'function') {
                        callbacks.on();
                   }
                }

                return true;
            };

            var initialise = function (inboundCheckbox, inboundCallbacks) {
                // Keep original checkbox
                checkbox = $(inboundCheckbox);

                // Check and store callback options
                if (typeof inboundCallbacks == 'object') {
                    callbacks = inboundCallbacks;
                }

                // Swap out checkbox with replacement imagery
                if (!checkbox.is('replaced')) {
                    checkbox.addClass('replaced');
                }
                
                replacement = $('<span />').addClass('checkarea').append('<span class="checkbox" />').click(function () {
                    toggle();
                    return false;
                });

                replacement.attr('title', checkbox.attr('title'));

                var existingReplacement = checkbox.next('span.checkarea');
                if (existingReplacement.length) {
                    existingReplacement.remove();
                }

                checkbox.after(replacement);

                // Set initial checked/unchecked state of replacement
                if (isChecked()) {
                    $('span', replacement).addClass('checkbox-checked');
                } else {
                    $('span', replacement).addClass('checkbox-unchecked');
                }

                // Find label associated with checkbox (if present) and make that work with replacement
                var checkboxId = checkbox.attr('id');
                if (checkboxId.length) {
                    var label = $('label[for='+checkboxId+']');
                    label.click(function(){
                        toggle();
                        return false;
                    });
                }

                return true;

            };

            initialise(inboundCheckbox, inboundCallbacks);
        };
        /* end replacementCheckbox class */

        /**
         *
         */
        var getSectionOrderAndInclusionString = function (settings, sections) {
            var currentSectionName = null;
            var orderAndInclusionString = '';

            $(settings.selectors.contentSections.contentSection.root, $(settings.selectors.contentSections.root)).each(function () {
                currentSectionName = sections.getSectionName(this);

                orderAndInclusionString += currentSectionName + '=';
                orderAndInclusionString += sections.get(currentSectionName).isIncluded() ? '1' : '0';
                orderAndInclusionString += ',';
            });

            orderAndInclusionString = orderAndInclusionString.substr(0, orderAndInclusionString.length - 1);

            return orderAndInclusionString;
        };

        /**
         *
         */
        var buildSectionOrderValues = function (settings, sections) {
            // Find the form to which this all applies
            var form = $(settings.selectors.contentSections.root).closest('form');

            // Add in containing fieldset if not present
            var dataContainer = $('#'+settings.data.fieldSetId, form);

            // Add the content order field if not present
            if (dataContainer.length === 0) {
                form.append(
                    $('<fieldset id="'+settings.data.fieldSetId+'" />')
                );

                dataContainer = $('#'+settings.data.fieldSetId, form);
            }
            
            // Add the contentorder+include field if not present
            var contentOrderAndIncludeField = $('input[name='+settings.data.sectionOrder+']', dataContainer);
            if (contentOrderAndIncludeField.length === 0) {
                dataContainer.append(
                    $('<input type="hidden" name="'+settings.data.sectionOrder+'" />')
                );
                    
                contentOrderAndIncludeField = $('input[name='+settings.data.sectionOrder+']', dataContainer);    
            }

            // Generate and store the content order
            contentOrderAndIncludeField.val(getSectionOrderAndInclusionString(settings, sections));
        };

        /**
         * Initialiser for cvBuilderContentController
         * -> is called automatically be constructor, no need to call directly
         * 
         */
        var initialise = function (options) {
            var defaults = {
                selectors: {
                    base:'BuildYourCV_',    // Common stem of a content section selector
                    contentSections: {
                        root:'#BuildYourCV_contentSections',    // Container for all content sections
                        contentSection: {
                            root: 'li[class^=BuildYourCV_]',    // Container for single content section
                            heading: '.sectionHead',            // Content section heading
                            body: 'div:first',                  // Content section body
                            content: '.contentSection',         // Content section content area
                            listedContent: {
                                root: '.listed-content-items',
                                item: '.listed-content'
                            }
                        }
                    }
                },
                data: {
                    fieldSetId:'BuildYourCV_data',
                    sectionOrder:'sections'
                }
            };
            
            var settings = $.extend({}, defaults, options);
            var sections = new contentSectionSet(settings.selectors);

            $(settings.selectors.contentSections.root).closest('form').submit(function () {
                buildSectionOrderValues(settings, sections);
            });

            var titleField = $('h2' , $('.CVBuilder')).next('input');
            if (titleField.val() === '') {
                titleField.focus();
            }

        };

        initialise(options);
    };
    /* end cvBuilderContentController class */

    /**
     * Class modelling the CV template selection process
     *
     */
    var cvBuilderTemplateController = function (options) {
        var settings = {};
        var templates = null;   // templateSet object, instantiated during initialise()

        
        /**
         * Class modelling a set of templates
         *
         */
        var templateSet = function (inboundSettings, inboundDescriptions) {
            var settings = null;
            var descriptions = null;

            var content = null;

            var templates = [];

            var getTemplateName = function (templateContent) {
                var classes = $(templateContent).attr('class').split(' ');
                var templateNameRegex = /template-/;

                for (var classIndex in classes) {
                    if (classes.hasOwnProperty(classIndex)) {
                        if (templateNameRegex.test(classes[classIndex])) {
                            return classes[classIndex].replace('template-', '');
                        }
                    }
                }

                return '';
            };

            var setSelectedTemplate = function (templateAnchor) {
                var selectedTemplateName = getTemplateName($(templateAnchor).closest('.template'));
                var templateNames = [];
                
                // Tick the selected icon
                for (var templateName in templates) {
                    if (templates.hasOwnProperty(templateName)) {
                        templates[templateName].setSelected(templateName == selectedTemplateName);
                    }

                    templateNames.push(templateName);
                }

                // Update the preview image
                var previewImageContainer = $(settings.preview , content);
                var previewImage = $('img', previewImageContainer);                

                var currentTemplateName = '';
                var currentImageSrc = '';
                var newImageSrc = '';

                for (var templateNameIndex in templateNames) {
                    if (templateNames.hasOwnProperty((templateNameIndex))) {
                        currentTemplateName = templateNames[templateNameIndex];

                        if (currentTemplateName != selectedTemplateName) {
                            var searchRegex = new RegExp(currentTemplateName, 'i');

                            currentImageSrc = previewImage.attr('src');                            
                            newImageSrc = currentImageSrc.replace(searchRegex, selectedTemplateName);
                            previewImage.attr('src', newImageSrc);
                        }
                    }
                }
                
                // Update the template description
                var previewDescription = $('p:first', previewImageContainer);
                previewDescription.replaceWith(
                    $('<p />').append(
                        $('<strong />').text(descriptions[selectedTemplateName].name+': ')
                    ).append(descriptions[selectedTemplateName].desc)
                );
                
            };

            var initialise = function (inboundSettings, inboundDescriptions) {
                settings = inboundSettings;
                descriptions = inboundDescriptions;
                content = $(settings.root);

                $(settings.template.root, content).each(function () {
                    templates[getTemplateName(this)] = new template(this, settings, getTemplateName(this));
                });

                $('a', content).click(function () {
                    setSelectedTemplate(this);
                    return false;
                });
            };

            initialise(inboundSettings, inboundDescriptions);

        };
        /* end templateSet class */


        /**
         * Class modelling a single template
         *
         */
        var template = function (rawContent, inboundSelectors, inboundName) {
            var content;
            var selectors;
            var name;

            var select = function () {
                if (isSelected()) {
                    return true;
                }

                $('.templateIcon', content).append(
                    $('<span class="templateSelected" />')
                );

                content.css({
                    cursor:'default'
                });

                var form = $(selectors.template.form.root);
                var templateField = $(selectors.template.form.templateId, form);

                templateField.val(name);
                return true;
            };
            
            var deselect = function () {
                $('.templateSelected', content).remove();

                content.css({
                    cursor:'pointer'
                });
            };

            var isSelected = function () {
                return $('.templateSelected', content).length > 0;
            };

            this.isSelected = function () {
                return isSelected();
            };

            this.setSelected = function (selectedState) {
                if (typeof selectedState != 'boolean') {
                    selectedState = false;
                }

                if (selectedState) {
                    select();
                } else {
                    deselect();
                }
            };

            var initialise = function (rawContent, inboundSelectors, inboundName) {
                content = $(rawContent);
                selectors = inboundSelectors;
                name = inboundName;

                $('a', content).mouseover(function () {                    
                    if (isSelected()) {
                        $(this).css({
                            cursor:'default'
                        });
                    } else {
                        $(this).css({
                            cursor:'pointer'
                        });
                    }
                });
            };

            initialise(rawContent, inboundSelectors, inboundName);
        };
        /* end template class */

        var initialise = function () {
            var defaults = {
                selectors: {
                    block:'.buildYourCV',
                    templates: {
                        root:'.templates',
                        preview: ' + .previewPanel',
                        template: {
                            root:'.template',
                            form: {
                                root:'.buildYourCV form',   // Form holding template reference. relative to document
                                templateId:'.templateId'    // Field for template reference, relative to form
                            }
                        }
                    }                    
                },
                descriptions:{
                }

            };

            var settings = $.extend({}, defaults, options);

            templates = new templateSet(settings.selectors.templates, settings.descriptions);
        };

        initialise();
    };
    /* end cvBuilderTemplateController class */

    self.initialise = function (block) {
        addressLookupConfiguration = {
            'default': {
                selectors: {
                    lookupNumberOrNameField:'#'+self.getInstanceId()+'_personalDetails_houseNameNumber_0',
                    lookupPostcodeField:'#'+self.getInstanceId()+'_personalDetails_postCode_0',
                    manualLine1Field:'#'+self.getInstanceId()+'_personalDetails_address_0',
                    manualLine2Field:'#'+self.getInstanceId()+'_personalDetails_city_0',
                    manualLine3Field:'#'+self.getInstanceId()+'_personalDetails_county_0'
                },
                button: {
                    id:'BuildYourCV_findAddressButton',
                    src:'custom/careers_wales/img/buttons/button_findAddress_'+self.getLocaleId()+'.png',
                    alt:self.getTranslation('findAddress')
                },
                ajax: {
                    url:self.getApiUrl({'action':'lookupAddress'})
                },
                lightbox:{
                    containerId:'addressLookup_lightbox',
                    containerClasses:'BuildYourCV_addressLookup',
                    dataClasses:'BuildYourCV_addressLookup_modalData'
                },
                events: {
                    onFailure:function () {
                        //console.log('AJAX fail');
                    },
                    preLookup:function() {
                        // Clear ajax fail message
                    }
                },
                content: {
                    lightbox: {
                        PREPARING: {
                            title:self.getTranslation('lb_loading_title')
                        },
                        RESULTS: {
                            title:self.getTranslation('lb_withresults_title'),
                            seeAllAddresses:self.getTranslation('lb_withresults_seeall'),
                            or:self.getTranslation('lb_withresults_or'),
                            enterYourAddressManually:self.getTranslation('lb_enterAddressMaually')
                        },
                        NORESULTS: {
                            title:self.getTranslation('lb_noresults_title'),
                            'for':self.getTranslation('lb_noresults_for'),
                            tryAgain:self.getTranslation('lb_noresults_tryagain'),
                            or:self.getTranslation('lb_noresults_or'),
                            enterYourAddressManually:self.getTranslation('lb_enterAddressMaually')
                        }
                    }
                }
            }
        };

        var getOutputLangFromUrl = function(url) {
            var outputLangQueryValue = /outputLang=Tr[0-9]+/.exec(url);
            if (outputLangQueryValue === null) {
                return null;
            }

            return outputLangQueryValue[0].replace('outputLang=', '');
        };

        var setFormOutputLang = function(form, outputLang) {
            var outputLangField = $('input[name=outputLang]', form);
            if (outputLangField.length === 0) {
                outputLangField = $('<input type="hidden" name="outputLang" />');
                form.append(outputLangField);
            }
            
            outputLangField.val(outputLang);
        };

        // Take relevant actions dependent on the stage of the CV building process we're at
        var stageTag = $('#BuildYourCV_stageTag');
        var stageName = (stageTag.length) ? stageTag.attr('class') : 'contentBuilder';

        switch (stageName) {
            case 'selectTemplate':
                cvTemplateController = new cvBuilderTemplateController({
                    descriptions:{
                       traditional:{
                           name:self.getTranslation('name_traditional'),
                           desc:self.getTranslation('description_traditional')
                       },
                       skills:{
                           name:self.getTranslation('name_skills'),
                           desc:self.getTranslation('description_skills')
                       }
                    }
                });

                // Catch clicks on language switching link and save form instead (after adding language choice to form)
                // -> otherwise CV building process breaks
                $('#langOptions a').click(function(){
                    setFormOutputLang(
                        $('.buildYourCV form'),
                        getOutputLangFromUrl($(this).attr('href'))
                    );

                    $('.buildYourCV form input[type=hidden][value="saveTemplate"]').val('previewTemplate');
                    $('.buildYourCV form').submit();
                    return false;
                });

                break;

            case 'viewSaveOrPrint':
                $('.CVBuilder .curvedBox .introduction').each(function () {
                    var currentBox = $(this)                    ;
                    if (currentBox.height() < 50) {
                        currentBox.height(50);
                    }
                });

                // Catch clicks on language switching link and save form instead (after adding language choice to form)
                // -> otherwise CV building process breaks
                $('#langOptions a').click(function() {
                    var outputLangChoice = getOutputLangFromUrl($(this).attr('href'));
                    var newUrl = $('.buildYourCV .previousLink').attr('href');
                    newUrl = newUrl.replace('previewTemplate', 'saveTemplate');
                    newUrl = newUrl.replace(/(\?|&)outputLang=(Tr[0-9]+)?/, '');
                    newUrl += '&outputLang='+outputLangChoice;

                    $(this).attr('href', newUrl);
                });

                break;
            
            default:
                cvContentController = new cvBuilderContentController();

                //todo: Need to get the correct configuration for the current site.
                //      Initially the CV builder will be in the adults site only, but will later spread.
                currentConfiguration = addressLookupConfiguration['default'];
                currentConfiguration.instanceId = self.getInstanceId();
                addressLookup = new CW.addressLookup(currentConfiguration);
                
                // Modify address lookup positioning:
                // Default positioning causes tooltip icon to drop down to next row
                $('#'+currentConfiguration.button.id).wrap(
                    $('<div />').css({
                        'float':'left'
                    })
                ).css({
                    'margin-left':'7px'
                });
 

                // Catch clicks on language switching link and save form instead (after adding language choice to form)
                // -> otherwise CV building process breaks
                $('#langOptions a').click(function(){
                    setFormOutputLang(
                        $('.buildYourCV form'),
                        getOutputLangFromUrl($(this).attr('href'))
                    );

                    $('.buildYourCV form').submit();
                    return false;
                });

                /**
                 * Make additional text field show if they have selected other for driving licence type
                 */
                $('.licenceType select').change(function() {

                    // If they have chosen other show the extra field
                    if ($(this).val() == 'other') {
                        $('.additionalInfo .licenceTypeOther').show();
                    } else {
                        $('.additionalInfo .licenceTypeOther').hide();
                    }
                });                

                break;
        }
    };

};
/* Commenting.js (416) */
var Commenting = function(){
    var self = this;
    var editForm = null;
    self.block = null;
    
    self.init = function(block){
        self.block = block;
        
        self.cloneForm();
        
        //add event handlers to the comment buttons
        self.initCommentShowClick();
        self.initCommentHideClick();
        
        //edit button
        self.initCommentEditShowClick();
    };
    
    self.cloneForm = function(){
        var editForm = $('.commentForm-addItemComment form');
        
        //We may not always have a form here
        if (editForm.length > 0){
            self.editForm = $(editForm[0]).clone();
            $('input.action', self.editForm).val('editCommentItem');
            $('label', self.editForm).remove();
            $('div.accompanyingText', self.editForm).remove();
            $('textarea', self.editForm).attr('id', '');
        }
    };
    
    self.initCommentShowClick = function(){
        $('ul.action li.comment form', $(self.block)).bind('submit', function(){
            $('.comments', $(this).parent().parent().parent().parent()).toggle('0.5');
            return false;
        });
    };
    
    self.initCommentHideClick = function(){
        $('.commentForm .closeFormLink a', $(self.block)).bind('click', function(){
            $(this).parent().parent().parent().parent().parent().parent().slideUp('0.5');
            return false;
        });
        
        $('.closeLink a', $(self.block)).bind('click', function(){
            $(this).parent().parent().parent().slideUp('0.5');
            return false;
        });
        
    };
    
    self.initCommentEditShowClick = function(){
        $('ul.action li.editComment form', $(self.block)).bind('submit', function(){
            var parentEl = $(this).parent().parent().parent();
            
            $('.commentForm',$(parentEl).parent()).hide();
            $('.body', $(parentEl)).hide();
            $('ul.action', $(parentEl).parent()).hide();
            
            var form = self.editForm.clone();
            
            //add in the input for specifying which comment this is
            var commentId  = self.getCommentIdFromElementId($(parentEl).attr('id'));
            var instanceId = self.block[0]._instanceId;
            
            $('div.hidden', $(form)).append('<input type="hidden" name="Module[' + instanceId + '][comment][commentId]" value="' + commentId + '" />');
            
            //Change the input for specifying which todoListItem this is
            var todoListItemId = self.getTodoListItemIdFromElementId($(parentEl).parent().attr('id'));
            
            $('input.todoListItemId', $(form)).val(todoListItemId);
            
            //change the action
            $('div.hidden input.action', $(form)).val('editItemComment');
            
            //add the bodyText
            $('textarea', $(form)).val($('.body', $(parentEl)).html());
            
            //change the button
            $('div.submitRow input', $(form)).attr('src', new String($('div.submitRow input', $(form)).attr('src')).replace(/add/, 'save'));
            
            //add handler for close button
            $('.closeFormLink a',$(form)).bind('click', self.commentEditHideClick);
            
            //now add the extra containing div
            var containingEl = $('<div class="commentForm" />');
            containingEl.append(form);
            $(parentEl).append(containingEl);
            
            return false;
        });
    };
    
    self.commentEditHideClick = function(){
        var parentEl = $(this).parent().parent().parent().parent().parent();
        //Remove the form
        $('div.commentForm', $(parentEl)).remove();
        
        //show all the elements previously hidden
        $('div.commentForm', $(parentEl).parent()).show();
        $('.body', $(parentEl)).show();
        $('ul.action', $(parentEl).parent()).show();
        
        return false;
    };
    
    self.getCommentIdFromElementId = function(elId){
        return new String(elId).replace(/todoList-comment-/, '');
    };
    
    self.getTodoListItemIdFromElementId = function(elId){
        return new String(elId).replace(/todoList-/,'');
    };
};
/* SSRS.js (253) */
var sSRS = function() {
	
	var self = this;
	
	self.initialise = function( block ) {
		
       var oForm = $('form', block);
       $('input[type=submit]', oForm).attr ('style', 'display: none');
       oForm.submit();
    };
};
/* CollaborativeProgrammeOptions.js (287) */
var Common_collaborativeProgrammeOptions = function(){

    var self = this;
    self.oCollaborativeProgramme = null; //The object we will get our data from.
    //This has already been instantiated
    //in the XSL
    self.selectedOptions      = new Array(); //Will hold all the courses selected
    self.optionTypes          = new Array();
    self.aIgnoreRuleId        = new Array(); // An array with IDs for rules to be ignored
    self.aIgnoreDisableRuleId = new Array(); // will be used to prevent recursion
    self.aMarkers             = new Array(); // An array of markers
    self.aProviderDetails     = new Array();
    self.aProviderPoints      = new Array();
    self.oMap                 = null;
    
    self.queue = new Array();
    self.runQueue = true;
	
    self.initialise = function( block ){
        try{
            //all of this relies on there being a
            //oCollaborativeProgramme object
            //and we don't want it to show an error
            //if there isn't one
            self.optionTypes['r1'] = 'a';
            self.optionTypes['r2'] = 'b';
            self.optionTypes['r3'] = 'c';
            self.optionTypes['r4'] = 'd';
            self.optionTypes['r5'] = 'e';
            self.optionTypes['r6'] = 'f';
			
            //firstly, bring in the object
            //which was created in the XSL
            self.oCollaborativeProgramme = oCollaborativeProgramme;
            //oCollaborativeProgramme = null;
			
            //remove the labels
            self.replaceLabels();
			
            self.initOptionSelectionFeedback();
            self.initOptionSelection();
            self.initialGreyOutCanOnlyBeSelectedWithRules();
			
            //Select any options that have been ticked
            self.selectSelectedOptions();
        } catch(e){
        //don't do anything, the object isn't there
        //if we are actually on the page with the options
        //table then the user will be given the
        //non-javascript version instead
        }
        self.initViewSavedOptionCourses();
        self.initMaps( block );
    };
	
    /**
	 * Replace all the labels in the table to normal text
	 * because the event handlers will run twice and
	 * make it impossible to select any options with
	 * rules assigned
	 */
    self.replaceLabels = function(){
        $('.collaborativeProgrammeOptions table label').each(function(el){
            $(this).parent().attr('id', 'td-' + $(this).attr('for'));
            $(this).replaceWith($(this).html());
        });
    };
	
    /**
	 * Creates a DIV element ready to output
	 * the currently selected options
	 */
    self.initOptionSelectionFeedback = function(){
        var feedbackEl = $('<div class="feedback" />')
        .append($('<h2 />').html( oLocale.getTranslation('CollaborativeProgrammeOptions', 'yourCurrentChoices')))
        .append('<ul />');
        $(feedbackEl).insertAfter('.collaborativeProgrammeOptions table');
    };
	
    /**
	 * hides the checkboxes and adds an event handler
	 * on the td elements to tick the hidden checkboxes
	 */
    self.initOptionSelection = function(){
        //Move the elements off the screen
        $('.collaborativeProgrammeOptions input[type=checkbox]').css('position', 'absolute');
        $('.collaborativeProgrammeOptions input[type=checkbox]').css('top', '-200px');
		
        //Add event handler for when an option is clicked
        $('.collaborativeProgrammeOptions td.option').bind('click', self.optionClicked);
    };
	
    /**
	 * Runs through each rule and grey's out all courses
	 * that can only be selected if another course is
	 * selected first
	 */
    self.initialGreyOutCanOnlyBeSelectedWithRules = function(){
        //Go through all options
        for (var optionId in self.oCollaborativeProgramme.aoCollaborativeProgrammeOption) {
            var oCollaborativeProgrammeOption = self.oCollaborativeProgramme.aoCollaborativeProgrammeOption[optionId];
            $(self.oCollaborativeProgramme.aoCollaborativeProgrammeOption[optionId].aoCollaborativeProgrammeRule).each(function(){
                //forward rules only
                if (this.ruleType == 'canOnlyBeSelectedWith' && oCollaborativeProgrammeOption.optionType == 'r'+this.fromOptionType &&
                    oCollaborativeProgrammeOption.providerCourseId==this.fromProviderCourseId){
					
                    //grey out this option
                    $('td#td-' + optionId).attr('class', 'disabled');
					
                    //check for dependants
                    self.greyOutDependants(optionId);
                }
            });
        }
    };
	
    self.greyOutDependants = function(optionId){
        //get the rules
        var oCollaborativeProgrammeOption = self.oCollaborativeProgramme.aoCollaborativeProgrammeOption[optionId];
        $(oCollaborativeProgrammeOption.aoCollaborativeProgrammeRule).each(function(){
            if ( this.ruleType == 'mustBeSelectedWith') {
                //grey out this option
                var id = 'r' + this.toOptionType + '-' + this.toProviderCourseId;
                $('td#td-' + id).attr('class', 'disabled');
            }
        });
		
    };
	
    /**
	 * Event handler for when an option course
	 * has been clicked
	 */
    self.optionClicked = function(){
		
        self.runQueue = true;
		
        var optionId = $(this).attr('id');
        optionId = optionId.replace(/td-/, '');
        var elCheckbox = $('input#' + optionId);
		
        if (elCheckbox.attr('checked')) {
            self.removeSelectedCourse(optionId);
        }
        else {
            self.checkRules(optionId);
            self.queue.push({
                type:'add',
                id:optionId
            });
        }

        //clear the ignore array
        self.aIgnoreRuleId = new Array();
		
        if (self.runQueue) {
            //run through the queue
            $(self.queue).each(function(){
                self.addSelectedCourse(this.id, false);
            });
			
            //check here for courses that may have now
            //become available
            self.processRulesForEnableDisable(optionId, 'enable');
            //clear the ignore list again
            self.aIgnoreRuleId = new Array();
            self.count = 0;
        }
        self.queue = new Array();
    };
	
    self.count = 0;

    self.processRulesForEnableDisable = function(id, type){
        //self.count = self.count+1;
        var oCollaborativeProgrammeOption = self.oCollaborativeProgramme.aoCollaborativeProgrammeOption[id];
		
        var className;
        if (type == 'disable'){
            className = 'disabled';
        } else {
            className = 'option';
        }
		
        $(oCollaborativeProgrammeOption.aoCollaborativeProgrammeRule).each(function(){
            if (!self.isRuleIgnored(this)) {
                var fromId        = 'r' + this.fromOptionType + '-' + this.fromProviderCourseId;
                var toId          = 'r' + this.toOptionType + '-' + this.toProviderCourseId;
				
                var ruleProcessed = false;
				
                if (className == 'disabled' && !self.in_array(toId, self.aIgnoreRuleId)) {
                //ruleProcessed = true;
                //console.log('Disabling ' + id);
                }
				
                if (this.ruleType == 'canOnlyBeSelectedWith' && toId == id && $('td#td-' + fromId).attr('class') == 'disabled' && $('td#td-' + id).attr('class')=='optionSelected') {
                    $('td#td-' + fromId).attr('class', className);
                    ruleProcessed = true;
                }
				
                if (this.ruleType == 'mustBeSelectedWith' && fromId == id && $('td#td-' + toId).attr('class') == 'disabled') {
                    $('td#td-' + toId).attr('class', className);
                    ruleProcessed = true;
                }
				
                //alert( $('td#td-' + toId).attr('class') );
				
                if (this.ruleType == 'cannotBeSelectedWith' && toId==id && $('td#td-' + toId).attr('class')=='optionSelected'){
                    $('td#td-' + fromId).attr('class', 'disabled');
                    ruleProcessed = true;
                }
				
                self.setRuleIsIgnored(this, 'from');
                //we need to run this rule on this function
                if (ruleProcessed && self.count < 100) {
                    self.processRulesForEnableDisable(fromId, type);
                }
            }
        });
    };
	
    self.disableOptions = function(id){
        self.count++;
		
        //console.log('Course de-selected. Running through rules');
        var oCollaborativeProgrammeOption = self.oCollaborativeProgramme.aoCollaborativeProgrammeOption[id];
		
        $(oCollaborativeProgrammeOption.aoCollaborativeProgrammeRule).each(function(){
            //console.log('Checking if rule is set as ignored');
			
            //console.log(this.fromOptionType + '-' + this.fromProviderCourseId + '-' + this.ruleType);
            //console.log(this.toOptionType + '-' + this.toProviderCourseId + '-' + this.ruleType);
			
            if (!self.isRuleIgnored(this, self.aIgnoreDisableRuleId, 'to')){
                //console.log(self.count + ' ..Rule not ignored.');
                var fromId = 'r' + this.fromOptionType + '-' + this.fromProviderCourseId;
                var toId   = 'r' + this.toOptionType   + '-' + this.toProviderCourseId;
				
                var ruleProcessed = false;
				
                self.setRuleIsIgnored(this, 'to', self.aIgnoreDisableRuleId);
                //self.setRuleIsIgnored(this, 'both', self.aIgnoreDisableRuleId);
                //console.log('Rule set as ignored.');
				
                if (this.ruleType == 'canOnlyBeSelectedWith' && toId == id){
                    //console.log('canOnlyBeSelectedWith rule found');
                    ruleProcessed = true;
                    $('td#td-' + fromId).attr('class', 'disabled');
                }
				
                if (this.ruleType == 'mustBeSelectedWith' && toId == id && $('td#td-' + toId).attr('class')=='disabled'){
                    ;
                    //console.log('mustBeSelectedWith rule found ' + id);
                    ruleProcessed = true;
                    $('td#td-' + fromId).attr('class', 'disabled');
                } else if(this.ruleType == 'canOnlyBeSelectedWith' && fromId == id) {
                    //this is here because sometimes
                    //when there is a chaining rule,
                    //it makes some options appear
                    //disabled
					
                    $('td#td-' + fromId).attr('class', 'option');
                //$('td#td-' + toId).attr('class', 'option');
                }
				
                if (this.ruleType == 'cannotBeSelectedWith'){
                    //console.log('cannotBeSelectedWith rule found');
                    $('td#td-' + fromId).attr('class', 'option');
                    $('td#td-' + toId).attr('class', 'option');
                }
				
                if (self.count < 100) {
                    //console.log(self.count + ' Running again...');
                    self.disableOptions(fromId);
                }
				
            } else {
        //console.log(self.count + ' ..Rule is ignored.');
        }
			
        });
    };
	
    /**
	 * Adds an option course as selected.
	 * Checks if another course in the option
	 * is selected and deselects it, and
	 * also ensures the rules are adhered to
	 *
	 * @param int id
	 */
    self.addSelectedCourse = function(id, checkRules){
        //alert(id);
        if (checkRules == null) {
            checkRules = true;
        }
		
        //before we add this course, we must ensure
        //that there isn't another course already
        //selected in this column
        var aIdParts = id.split('-');
        var optionType = aIdParts[0];
        var providerCourseId = aIdParts[1];
		
        if (self.selectedOptions[optionType]) {
            //there is already an item here
            //alert('There is already a course selected in this column');
            self.removeSelectedCourse(optionType + '-' + self.selectedOptions[optionType]);
        }
		
        //..and also check the user isn't breaking any rules
		
        var ruleStatus = null;
		
        if (checkRules && self.checkRules(id)){
            ruleStatus = true;
        } else if (checkRules){
            ruleStatus = false;
        } else {
            ruleStatus = true;
        }
		
        //
		
        if (ruleStatus && self.runQueue) {
            $('input#' + id).attr('checked', 'checked');
            $('input#' + id).parent().attr('class', 'optionSelected');
			
            self.selectedOptions[optionType] = providerCourseId;
            self.addFeedbackItem(id);
			
            return true;
        }
        return false;
    };
	
    /**
	 * Removes an already selected course
	 * It deselects it visually, remove feedback
	 * and remove from array
	 *
	 * @param {Object} id
	 */
    self.removeSelectedCourse = function(id) {
        var aIdParts = id.split('-');
        var optionType = aIdParts[0];
		
        //ensure that rules are adhered to
        self.checkRulesOnRemove(id);

        self.selectedOptions[optionType] = null;
        $('input#' + id).attr('checked', '');
        $('input#' + id).parent().attr('class', 'option');
		
        self.disableOptions(id);
        self.count = 0;
		
        self.aIgnoreDisableRuleId = new Array();
		
        self.removeFeedbackItem(id);
    };
	
    /**
	 * Adds an item to the feedback list
	 * @param {Object} id
	 */
    self.addFeedbackItem = function(id){
        //need to some course information
        var optionType = self.oCollaborativeProgramme.aoCollaborativeProgrammeOption[id].optionType;
        var courseName = self.oCollaborativeProgramme.aoCollaborativeProgrammeOption[id].title;
		
        $('.feedback ul').append('<li class="feedback-' + id + '">' + courseName + '</li>');
    };
	
    /**
	 * Removes an item from the feedback list
	 * @param {Object} id
	 */
    self.removeFeedbackItem = function(id){
        $('.feedback ul li.feedback-' + id).remove();
    };
	
    /**
	 * Ensures that adding the option (in ID) will
	 * breach any rules associated with this option
	 *
	 * Returns true if everything is fine, false otherwise
	 *
	 * @param {Object} id
	 *
	 * @return bool
	 */
    self.checkRules = function(id){
        var aoRule = self.oCollaborativeProgramme.aoCollaborativeProgrammeOption[id].aoCollaborativeProgrammeRule;
		
        var aIdParts                 = id.split('-');
        var selectedOptionType       = aIdParts[0];
        var selectedProviderCourseId = aIdParts[1];
		
        var status = true;
		
        $.each(aoRule, function(ruleIndex){
            var oRule = aoRule[ruleIndex];
			
            //this rule should only be run if
            //it is the forward rule...backwards rules
            //are run when a course is deselected
            if ((oRule.fromProviderCourseId == selectedProviderCourseId && 'r' + oRule.fromOptionType == selectedOptionType) && !self.isRuleIgnored(oRule)) {
                if (oRule.ruleType == 'mustBeSelectedWith') {
                    if (!self.checkRule_mustBeSelectedWith(oRule)) {
                        status = false;
                    }
                }
                else if (oRule.ruleType == 'cannotBeSelectedWith') {
                    if (!self.checkRule_cannotBeSelectedWith(oRule)) {
                        status = false;
                    }
                }else if (oRule.ruleType == 'canOnlyBeSelectedWith') {
                    if (!self.checkRule_canOnlyBeSelectedWith(oRule)){
                        status = false;
                    }
                }
            }
        });
		
        return status;
    };
	
    /**
	 * Ensures that a must be selected rule
	 * is adhered to
	 * 
	 * @param {Object} oRule
	 * 
	 * @return bool
	 */
    self.checkRule_mustBeSelectedWith = function(oRule){
        //firstly, we must check if the other
        //option in this rule has been selected
        //if it has, we can pass the rule
        if (self.selectedOptions['r' + oRule.toOptionType] == oRule.toProviderCourseId) {
            return true;
        }
		
        //now check if the option has been filled, if so fail
        if (self.selectedOptions['r' + oRule.toOptionType]){
			
            //get the course name and option type
            var oCollaborativeProgrammeOption = self.oCollaborativeProgramme.aoCollaborativeProgrammeOption['r' + oRule.toOptionType + '-' + oRule.toProviderCourseId];
            var courseName = oCollaborativeProgrammeOption.title;
            var optionTypeLabel = oLocale.getTranslation('CollaborativeProgrammeOptions', self.optionTypes['r' + oRule.toOptionType]);
            var optionLabel = oLocale.getTranslation('CollaborativeProgrammeOptions', 'option');
			
            alert('This course must be selected with ' + optionLabel + ' ' + optionTypeLabel + ' ' + courseName + ', but ' + optionLabel + ' ' + optionTypeLabel + ' has already been set');
            self.runQueue = false;
            return false;
        }
		
        //Select the other course in this rule, and run all rules associated with this
        //but ignore all rules regarding the course being selected
        self.setRuleIsIgnored(oRule, 'both');

        if (self.checkRules('r' + oRule.toOptionType + '-' + oRule.toProviderCourseId)){
            //we need to add this to a queue to wait for the outcome of other rules
            self.queue.push({
                type:'add',
                id: 'r' + oRule.toOptionType + '-' + oRule.toProviderCourseId
            });
        }
    };
	
    /**
	 * Checks that the course on the other part
	 * part of the rule is selected. If it is,
	 * returns false, returns true if it isn't
	 * 
	 * @param {Object} oRule
	 * 
	 * @return bool
	 */
    self.checkRule_cannotBeSelectedWith = function(oRule){
        //Just check the to option column doesn't contain
        //this course
		
        if (self.selectedOptions['r' + oRule.toOptionType] == oRule.toProviderCourseId) {
            var oCollaborativeProgrammeOption = self.oCollaborativeProgramme.aoCollaborativeProgrammeOption['r' + oRule.toOptionType + '-' + oRule.toProviderCourseId];
            var courseName = oCollaborativeProgrammeOption.title;
            var optionTypeLabel = oLocale.getTranslation('CollaborativeProgrammeOptions', self.optionTypes['r' + oRule.toOptionType]);
            var optionLabel = oLocale.getTranslation('CollaborativeProgrammeOptions', 'option');
			
            //empty the queue
            self.runQueue = false;
            return false;
        }
        return true;
    };
	
    /**
	 * Ensures that the other part of the rule is selected
	 * If it is, returns true. False otherwise
	 * 
	 * @param {Object} oRule
	 */
    self.checkRule_canOnlyBeSelectedWith = function(oRule){
        //all we need to do is ensure
        //the 'to' course and option has
        //been selected to allow the selection
        //to go ahead
		
        if (self.selectedOptions['r' + oRule.toOptionType] == oRule.toProviderCourseId) {
            return true;
        }
		
        //empty the queue
        self.runQueue = false;
        return false;
    };
	
    self.in_array = function(val, arr){
        if (!arr.length){
            return false;
        }
        var retVal = false;
		
        $(arr).each(function(index) {
            if (arr[index]==val){
                retVal = true;
            }
        });
        return retVal;
    };
	
    self.setRuleIsIgnored = function(oRule, type, arr){
		
        if (arr == null) {
            arr = self.aIgnoreRuleId;
        }
		
        if (type=='to' || type=='both'){
            arr.push({
                optionType: oRule.toOptionType,
                providerCourseId: oRule.toProviderCourseId,
                ruleType: oRule.ruleType
            });
        }
		
        if (type=='from' || type=='both'){
            arr.push({
                optionType: oRule.fromOptionType,
                providerCourseId: oRule.fromProviderCourseId,
                ruleType: oRule.ruleType
            });
        }
		
        if (type=='mixed'){
            arr.push({
                optionType: oRule.toOptionType,
                providerCourseId: oRule.fromProviderCourseId,
                ruleType: oRule.ruleType
            });
			
        }
    };
	
    self.isRuleIgnored = function(oRule, arr, type){
		
        if (arr == null) {
            arr = self.aIgnoreRuleId;
        }
                
        if (type == null) {
            type = 'from';
        }
		
        var retVal = false;
		
        if (type == 'from'){
            $(arr).each(function(){
                if (this.optionType == oRule.fromOptionType && this.providerCourseId==oRule.fromProviderCourseId && this.ruleType == oRule.ruleType){
                    retVal = true;
                }
            });
        }
		
        if (type == 'to'){
            $(arr).each(function(){
                if (this.optionType == oRule.toOptionType && this.providerCourseId==oRule.toProviderCourseId && this.ruleType == oRule.ruleType){
                    retVal = true;
                }
            });
        }
		
        return retVal;
    };
	
    self.checkRulesOnRemove = function(id){
        var aoRule = self.oCollaborativeProgramme.aoCollaborativeProgrammeOption[id].aoCollaborativeProgrammeRule;
		
        var aIdParts  				 = id.split('-');
        var selectedOptionType		 = aIdParts[0];
        var selectedProviderCourseId = aIdParts[1];
		
        $.each(aoRule, function(ruleIndex){
            var oRule = aoRule[ruleIndex];
			
            if (('r' + oRule.toOptionType == selectedOptionType && oRule.toProviderCourseId == selectedProviderCourseId) && !self.isRuleIgnored(oRule) ){
                //run the rule
                if (oRule.ruleType == 'mustBeSelectedWith') {
                    self.checkRuleOnRemove_mustBeSelectedWith(oRule);
                }
                else if (oRule.ruleType == 'cannotBeSelectedWith') {
                //alert('Cannot Be Selected With rule not implemented');
                }else if (oRule.ruleType == 'canOnlyBeSelectedWith') {
                    self.checkRuleOnRemove_canOnlyBeSelectedWith(oRule);
                }
				
            }
			
        });
		
    };
	
    self.checkRuleOnRemove_mustBeSelectedWith = function(oRule){
        //the course is being deselected, we need to remove
        //the opposite course
		
        //if the opposite course is selected, remove it
        //and ignore this rule
        self.setRuleIsIgnored(oRule, 'to');
		
		
        if (self.selectedOptions['r' + oRule.fromOptionType] == oRule.fromProviderCourseId) {
            self.removeSelectedCourse('r' + oRule.fromOptionType + '-' + oRule.fromProviderCourseId);
        }
    };
	
    self.checkRuleOnRemove_canOnlyBeSelectedWith = function(oRule){
        self.setRuleIsIgnored(oRule, 'to');
        if (self.selectedOptions['r' + oRule.fromOptionType] == oRule.fromProviderCourseId) {
            self.removeSelectedCourse('r' + oRule.fromOptionType + '-' + oRule.fromProviderCourseId);
        }
    };
	
	
    self.selectSelectedOptions = function(){
        $('.collaborativeProgrammeOptions input[type=checkbox][checked]').each(function(){
            self.addSelectedCourse($(this).attr('id'), false);
        });
		
    };
	
    self.initViewSavedOptionCourses = function(){
        $('.collaborativeProgrammeOptions table.savedOptions td.actionView a').bind('click', self.viewSavedOptionCoursesClicked);
    };
	
    self.viewSavedOptionCoursesClicked = function(){
        //get the URL from the link
        var url = $(this).attr('href');
        //add an output format so Amaxus
        //will only give out the content we need
        url = url + "&outputFormat=ajax";
		
        var tdEl = $(this).parent();
        var trEl = $(this).parent().parent();
		
        //need to put an image in here
        tdEl.html('<img src="custom/careers_wales/img/ajax/largeSpinner.gif" alt="Please Wait..." />');
		
        $.ajax({
            type: 'GET',
            url: url,
            dataType: 'html',
            success: function(data){
                //Change the class of all <td> elements
                //that will act as a heading for the course list
                //existing classes must stay
                $('td', trEl).each(function(){
                    $(this).attr('class', $(this).attr('class') + ' heading');
                });
				
                trEl.after('<tr><td colspan="8" class="savedOptionCourseList">' + data + '</td></tr>');
				
                //Clear the cell where the view button was
                tdEl.html('');
            }
        });
		
        //we don't want the click event to be processed any further
        //so the browser won't navigate away
        return false;
    };

    /**
     * Adds map icons to the Collaborative Programme display
     *
     */
    self.initMaps = function ( block ) {

        var cluster = $('input[name="Module[iOptions][clusterId]"]').attr('value');

        $('.collaborativeProgrammeOptions table span.provider').each(
            function() {
                var provider = $(this).attr('id');

                $(this).append(
                    $('<img src="custom/careers_wales/img/year11/map.gif" alt="view map" />').click(
                        function() {
                            self.launchMap( cluster, provider );
                        }
                        )
                    );
            }
            );
    };

    /**
     * Launchs the map.
     */
    self.launchMap = function( cluster, provider ) {

        // Check whether we have already loaded the map
        if( $('#clusterMap').attr('class') !== 'init' ) {
            $('body').append('<div id="mapWrapper"><div id="clusterMap" class="init" style="width: 560px; height: 400px;" /></div>');
            
            var map = new GMap2(document.getElementById("clusterMap"));
            map.setCenter(new GLatLng(52.469978, -3.830377), 7);
            map.addControl(new GSmallMapControl());
            map.addControl(new GMapTypeControl());
            self.loadMarkers( map, cluster, provider );
            self.oMap = map;

            if( $.browser.msie ) {
                self.initCloseButtonandOverlay();
            }
        }else {
            // The user has previously loaded the map, now re cetner the map to the
            // selected provider
            if( $('#mapWrapper').css('display') == 'none' && $.browser.msie ) {
                $('#mapWrapper').fadeIn();
                $('#mapOverlay').fadeIn();
            }
            if( self.aProviderPoints['provider'+provider] ) {
                self.oMap.setCenter(self.aProviderPoints['provider'+provider], 12);
            }
        }

        if( ! $.browser.msie ) {
            self.initModal();
        }
    };

    /**
     * Add overlay and close button
     * 
     */
    self.initCloseButtonandOverlay = function() {

        $('<div id="mapOverlay" class="modalOverlay" />')
        .insertBefore('#mapWrapper')
        .attr('style', 'filter:alpha(opacity=50); zoom: 1; height: 100%; width: 100%; position: fixed; left: 0pt; top: 0pt;');
            
        $('<a title="Close" class="modalCloseImg modalClose"/>')
        .insertBefore('#clusterMap')
        .click( function() {
            $('#mapWrapper').fadeOut();
            $('#mapOverlay').fadeOut();
        });
    };

    /**
     * Extract the markers, this is only needed once.  After the first
     * time we can just use the already extracted markers.
     * 
     */
    self.loadMarkers = function( map, cluster, selectedProvider ) {

        // Request all postcodes for providers in the request cluster
        if( !(self.aMarkers.length > 0) ) {
            var submitUrl = SITE_WEB_ROOT + 'server.php?change=CollaborativeProgrammeDisplay&Module[iOptions][action]=getProviderPostCodes&Module[iOptions][cluster]='+cluster+'&jsonOutput=iOptions';
            $.getJSON(submitUrl, 
                function(json) {
                    var module = json.Module;
                    
                    if( module.aProviderPostCodes && module.aProviderPostCodes.length > 0 ) {
                        for( var i = 0; i < module.aProviderPostCodes.length; i++ ) {
                            var providerPostCode = module.aProviderPostCodes[i];
                            // Store the postcodes and provider id's for later use
                            self.aMarkers.push(
                                new Array( providerPostCode.providerId, providerPostCode.postCode )
                                );
                        }
                    }
                    self.addMarkers( map, selectedProvider );
                }
                );
        }
    };

    /**
     * Loop over all the providers and create a marker for each
     */
    self.addMarkers = function ( map, selectedProvider ) {

        for(var i = 0; i < self.aMarkers.length; i++ ) {
            self.createMarker( map, self.aMarkers[i], selectedProvider);
        }
    };

    /**
     * Create a marker, get the lat and long coord for each provider.
     * Add the marker, and attach event lister.
     *
     */
    self.createMarker = function ( map, provider, selectedProvider ) {

        var id        = provider[0];
        var postCode  = provider[1];
        var geocoder = new GClientGeocoder();
        
        geocoder.getLatLng (
            postCode + ", UK",
            function( point ) {
                var marker = new GMarker(point);
                map.addOverlay(marker);
                var submitUrl = SITE_WEB_ROOT + 'server.php?change=CollaborativeProgrammeDisplay&Module[iOptions][action]=getProviderDetails&Module[iOptions][provider]='+id+'&jsonOutput=iOptions';
                
                if( id == selectedProvider) {
                    map.setCenter(point, 12);
                }

                // When clicked for the first time, load the provider details and
                // display, otherwise display the already extracted details.
                GEvent.addListener(marker, "click", function() {
                    if( !self.aProviderDetails['provider'+id] ) {

                        $.getJSON(submitUrl,
                            function(json) {
                                var module = json.Module;

                                if( module.aProvider ) {
                                    var lineBreak = '<br />';
                                    var oProvider  = module.aProvider[0];

                                    var addressHTML = '<strong>'+oProvider.title+'</strong>'+lineBreak;
                                    addressHTML    += oProvider.address1+lineBreak;
                                    addressHTML    += oProvider.address2+lineBreak;
                                    addressHTML    += oProvider.town+lineBreak;
                                    addressHTML    += oProvider.postCode;
                                    self.aProviderDetails['provider'+id] = addressHTML;
                                    marker.openInfoWindowHtml( addressHTML );
                                }
                            }
                            );
                    }
                    else {
                        marker.openInfoWindowHtml ( self.aProviderDetails['provider'+id] );
                    }
                });
                // Store this point for repeat requests
                self.aProviderPoints['provider'+id] = point;
            }
            );
    };

    /**
     * Init the the lightbox that will store the map.
     *
     */
    self.initModal = function() {
        $('#mapWrapper').modal( {
            overlayId: 'mapOverlay',
            containerId: 'mapContainer',
            persist: true,
            onOpen: function (dialog) {
                dialog.overlay.fadeIn('fast', function () {
                    dialog.container.slideDown('normal', function () {
                        dialog.data.fadeIn('fast');
                    });
                });
            },
            onClose: function (dialog) {
                dialog.data.fadeOut('fast', function () {
                    dialog.container.slideUp('normal', function () {
                        dialog.overlay.fadeOut('fast', function () {
                            $('.modalClose').hide();
                            $.modal.close();
                        });
                    });
                });
            }
        });
    };
};

$(document).ready(function(){
    var oColProgOptions = new Common_collaborativeProgrammeOptions();
    oColProgOptions.initialise();
});
/* NetworkCourseSearch.js (470) */
/**
 * @package private_output_careers_wales
 * @version $Id: CertificateAndCourses.js 8432 2008-05-23 14:09:25Z jamesrc $
 * @copyright Copyright (c) 2008 Box UK Ltd. All rights reserved.
 *
 * 
 *
 */
var networkCourseSearch = function() {

    var self = this;

    self.initialise = function( block ) {

        var heading = $('.refineByProvider h2', block);
        var content = $('.refineByProvider .content');

        heading.click(function () {
            if (content.css('display') === 'none') {
                content.slideDown();
            } else {
                content.slideUp();
            }
        });

        heading.click();

        /**
         * We only really want to clone an existing:
         *
         * Choice X: [select]
         *
         * and add to the set of choices, however IE6 and the version of
         * jQuery we're using doesn't work well with $(<selector>).clone(),
         * so we have to build the new choice by hand
         *
         */
        var addAnotherChoice = function () {
            var newChoiceNumber = $('.choiceSets .choices', block).length + 1;
            var firstChoice = $('.choiceSets .choices:first', block);

            var newLabel = $('label', firstChoice).clone();
            var newChoiceId = newLabel.attr('for').replace('NetworkCourseSearch_choice_1', 'NetworkCourseSearch_choice_' + newChoiceNumber);
            newLabel.attr('for', newChoiceId);
            newLabel.text(newLabel.text().replace('1:', newChoiceNumber+':'));

            var newChoiceName = $('select', firstChoice).attr('name');
            var newSelect = $('<select id="'+newChoiceId+'" name="'+newChoiceName+'" />');

            var firstChoiceOptions = $('option', firstChoice);
            var currentOptionIndex = 0;
            firstChoiceOptions.each(function () {
                var newOption = $('<option />').text($(this).text());
                if (currentOptionIndex == 0) {
                    newOption.val('0');
                }
                
                newSelect.append(
                    newOption
                );
                    
                currentOptionIndex++;
            });

            var addChoiceAction = $('.choiceSets .choices:last .addAnotherChoice', block);

            var newChoiceAction = addChoiceAction.clone();
            addChoiceAction.remove();

            var newChoice = $('<div class="choices" />').append(
                newLabel
            ).append(
                $('<div class="subjectChoiceWrapper" />').append(
                    newSelect
                ).append(
                    newChoiceAction.click(function () {
                        return addAnotherChoice();
                    })
                )
            );

            $('.choiceSets .choices:last', block).after(newChoice);
            $('select', newChoice).focus();

            return false;
        };

        $('.addAnotherChoice', block).click(function () {
            return addAnotherChoice();
        });

    };

};
/* OptionTextSearchFields.js (472) */
var optionTextSearchFields = function() {

    var self = this;

    /**
     *  initialise this block
     *
     *  @param HTMLDivElement block
     *
     */
    self.initialise = function( block ) {
        self.initProvider();
        self.initHideExtraSearchOptions();
        self.initPartnerships();
    };    
    
     /**
     *  initialise this provider ajax
     *
     *  @param HTMLDivElement block
     *
     */
    self.initProvider = function() {

        $( '#providerSearch' ).associateProvider( {
            'instanceId' : self.getInstanceId(),
            'template'   : '',
            'module'     : 'ProviderCourseAdmin',
            'selector'  : {
                'form'     : '#providerForm',
                'field'    : '#providerQuery',
                'feedback' : '#providerFeedback',
                'searchButton'   : '#searchProvider',
                'deliveredByMyProviderButton' : '#deliveredByMyProviderButton',
                'addButton' : '#addProviderButton',
                'letters' : '.enhanced-atoz-selector'                
            }
        });
    };    
    
    /**
     * Hide the 2 extra course options
     */
    self.initHideExtraSearchOptions = function() {
        $('.extraOption').hide();
        $('.extraOption').prev().append('<a href="#" class="moreLink">' + oLocale.getTranslation('OptionTextSearchFields','searchMoreCourses') + '</a>').click(function() {
            $('.extraOption').fadeIn().show();
            $('.moreLink').hide();
        });
        
    };


    /**
     * Partnerships dropdown based on selected area
     */
    self.initPartnerships = function() {
        $('#area').change(function() {
            self.updatePartnerships();
        });

        self.updatePartnerships();
    };

    /**
     * Updates the partnership dropdown
     */
    self.updatePartnerships = function() {
        
        var url = self.getApiUrl({
            'action' : 'getPartners',
            'networkId' : $('#area').val()
        });
        
        $.ajax({
            url: url,
            dataType: 'json',
            success: function(data) {
                $('#partnerId option').remove();
                $('#partnerId').append(
                    $("<option></option>").attr("value", 0)
                );

                // Add new entries
                $(data.partners).each(function() {
                    $('#partnerId').append(
                        $("<option></option>").attr("value", this.id).text(this.title)
                    );
                });
            }
        });
    };
};
/* OptionSearchContent.js (474) */
var optionSearchContent = function() {
	
    var self = this;

    /**
     *  initialise this block
     *
     *  @param {Element} block
     *
     */
    self.initialise = function( block ) {
        self.initViewCourses();
    };      
    
    /**
     * JS funk to show all courses for the provider
     */
    self.initViewCourses = function() {
        $('ul.courseResults').each(function(){
            $(this).children('li:gt(9)').hide();
            if ($(this).children('li').length > 10){
                $(this).after('<a href="#" class="update showHideCourses">'+oLocale.getTranslation('OptionSearchContent','viewAllCourses')+'</a>');
            }

        });

        $('.showHideCourses').each(function(){
            var link = this;
            $(this).click(function(e) {
                e.preventDefault();
                $(this).prev('ul').children('li:gt(0)').slideDown();
                $(this).fadeOut('slow');
                //$('ul.courseResults').not($(this).prev('ul')).each(function(){
                      //$(this).children('li:gt(0)').hide();
                //});
            });
        });

    };

};
/* WblCourseSearch.js (476) */
var wBLCourseSearch = function() {
	
    var self = this;        

    /**
     *  initialise this block
     *
     *  @param HTMLDivElement block
     *
     */
    self.initialise = function( block ) {};
  
    
};
/* ProviderPartnershipAdmin.js (480) */
var providerPartnershipAdmin = function() {

    var self = this;

    self.initialise = function( block ) {
        self.addConfirmDelete();
        self.addConfirmDeleteProvider();
        self.initProviderSearchSelection();
    };
    
    self.addConfirmDelete = function() {
        $('.deleteLink').click(function() {

            var url     = $(this).attr('href');
            var confirm = $('<div />')
            .append($('<div />').addClass('outter')
                .append($('<div />').addClass('mid')
                    .append($('<div />').addClass('inner')
                        .append($('<h3 />').html(oLocale.getTranslation('ProviderPartnershipAdmin','msgDeleteCourse')))
                        .append($('<p />')
                            .append($('<h4 />').html(oLocale.getTranslation('ProviderPartnershipAdmin','msgDeleteConfirm')))
                            .append($('<a />')
                                .attr('href', url)
                                .html(oLocale.getTranslation('ProviderPartnershipAdmin','labelYes'))
                                )
                            .append($('<a href="#" />')
                                .html(oLocale.getTranslation('ProviderPartnershipAdmin','labelNo'))
                                .click(function() {
                                    $.modal.close();
                                    return false;
                                })
                                )
                            )
                        )
                    )
                );

            $(confirm).modal( {
                overlayId: 'courseDeleteOverlay',
                containerId: 'courseDeleteContainer',
                persist: true
            });
            //var answer = confirm(oLocale.getTranslation('ProviderPartnershipAdmin','msgDeleteConfirm'));
            return false;
        });
    };

    self.addConfirmDeleteProvider = function() {
        $('.deleteProviderLink').click(function() {

            var url     = $(this).attr('href');
            var confirm = $('<div />')
            .append($('<div />').addClass('outter')
                .append($('<div />').addClass('mid')
                    .append($('<div />').addClass('inner')
                        .append($('<h3 />').html(oLocale.getTranslation('ProviderPartnershipAdmin','msgDeleteProvider')))
                        .append($('<p />')
                            .append($('<h4 />').html(oLocale.getTranslation('ProviderPartnershipAdmin','msgDeleteProviderConfirm')))
                            .append($('<a />')
                                .attr('href', url)
                                .html(oLocale.getTranslation('ProviderPartnershipAdmin','labelYes'))
                                )
                            .append($('<a href="#" />')
                                .html(oLocale.getTranslation('ProviderPartnershipAdmin','labelNo'))
                                .click(function() {
                                    $.modal.close();
                                    return false;
                                })
                                )
                            )
                        )
                    )
                );

            $(confirm).modal( {
                overlayId: 'courseDeleteOverlay',
                containerId: 'courseDeleteContainer',
                persist: true
            });
            //var answer = confirm(oLocale.getTranslation('ProviderPartnershipAdmin','msgDeleteConfirm'));
            return false;
        });
    };

    self.initProviderSearchSelection = function(){
        $('.provider-results .provider input').bind('click', function(){
            $('.provider-results .provider').removeClass('selected');
            $(this).parent().addClass('selected');
        });
    };
};
/* CollaborativeOfferAdmin.js (482) */
var collaborativeOfferAdmin = function() {

    var self = this;

    self.initialise = function( block ) {
        self.toggleTimetable();
    };

    self.toggleTimetable = function(){        
        
        var timetables = $('div.timetableSet div.timetable');
        
        timetables.each(function() {
            var showHideLink = null;
            var tblDiv = $('.tableDiv', this);
            var timetable = $(this);
            
            if (timetable.is('.currentProvider')){
                showHideLink = $('<div class="showHide">' + oLocale.getTranslation('CollaborativeOfferAdmin', 'hideTimetable') +'</div>');
            } else {
                showHideLink = $('<div class="showHide">' + oLocale.getTranslation('CollaborativeOfferAdmin', 'showTimetable') +'</div>');
                tblDiv.hide();
            }
            
            $('h3', timetable).after(showHideLink);
            
            showHideLink.toggle(function () {
                if (timetable.is('.currentProvider')){
                    tblDiv.slideUp();
                    showHideLink.text(oLocale.getTranslation('CollaborativeOfferAdmin', 'showTimetable'));
                } else {
                    tblDiv.slideDown(function () {
                        showHideLink.text(oLocale.getTranslation('CollaborativeOfferAdmin', 'hideTimetable'));
                    });
                }
            }, function () {                
                if (timetable.is('.currentProvider')){
                    tblDiv.slideDown(function () {
                        showHideLink.text(oLocale.getTranslation('CollaborativeOfferAdmin', 'hideTimetable'));
                    });
                } else {
                    tblDiv.slideUp();
                    showHideLink.text(oLocale.getTranslation('CollaborativeOfferAdmin', 'showTimetable'));
                }
            });            

        });                                                     

    };
};
/* SwanseaGuaranteeChoices.js (491) */

/* SwanseaGuarantee.js (492) */

/* WBLCourseSearchCourse.js (494) */

/* CourseSearchCourse.js (495) */

/* PersonalLearningRecord.js (497) */

/* PersonalLearningRecordAdmin.js (499) */


