/* Merged Plone Javascript file
 * This file is dynamically assembled from separate parts.
 * Some of these parts have 3rd party licenses or copyright information attached
 * Such information is valid for that section,
 * not for the entire composite file
 * originating files are separated by - filename.js -
 */

/* - ++resource++scrollto.js - */
// http://www.signhealthintranet.org.uk/portal_javascripts/++resource++scrollto.js?original=1
;(function(h){var m=h.scrollTo=function(b,c,g){h(window).scrollTo(b,c,g)};m.defaults={axis:'y',duration:1};m.window=function(b){return h(window).scrollable()};h.fn.scrollable=function(){return this.map(function(){var b=this.parentWindow||this.defaultView,c=this.nodeName=='#document'?b.frameElement||b:this,g=c.contentDocument||(c.contentWindow||c).document,i=c.setInterval;return c.nodeName=='IFRAME'||i&&h.browser.safari?g.body:i?g.documentElement:this})};h.fn.scrollTo=function(r,j,a){if(typeof j=='object'){a=j;j=0}if(typeof a=='function')a={onAfter:a};a=h.extend({},m.defaults,a);j=j||a.speed||a.duration;a.queue=a.queue&&a.axis.length>1;if(a.queue)j/=2;a.offset=n(a.offset);a.over=n(a.over);return this.scrollable().each(function(){var k=this,o=h(k),d=r,l,e={},p=o.is('html,body');switch(typeof d){case'number':case'string':if(/^([+-]=)?\d+(px)?$/.test(d)){d=n(d);break}d=h(d,this);case'object':if(d.is||d.style)l=(d=h(d)).offset()}h.each(a.axis.split(''),function(b,c){var g=c=='x'?'Left':'Top',i=g.toLowerCase(),f='scroll'+g,s=k[f],t=c=='x'?'Width':'Height',v=t.toLowerCase();if(l){e[f]=l[i]+(p?0:s-o.offset()[i]);if(a.margin){e[f]-=parseInt(d.css('margin'+g))||0;e[f]-=parseInt(d.css('border'+g+'Width'))||0}e[f]+=a.offset[i]||0;if(a.over[i])e[f]+=d[v]()*a.over[i]}else e[f]=d[i];if(/^\d+$/.test(e[f]))e[f]=e[f]<=0?0:Math.min(e[f],u(t));if(!b&&a.queue){if(s!=e[f])q(a.onAfterFirst);delete e[f]}});q(a.onAfter);function q(b){o.animate(e,j,a.easing,b&&function(){b.call(this,r,a)})};function u(b){var c='scroll'+b,g=k.ownerDocument;return p?Math.max(g.documentElement[c],g.body[c]):k[c]}}).end()};function n(b){return typeof b=='object'?b:{top:b,left:b}}})(jQuery);

/* - ++resource++localscroll.js - */
// http://www.signhealthintranet.org.uk/portal_javascripts/++resource++localscroll.js?original=1
;(function($){var g=location.href.replace(/#.*/,''),h=$.localScroll=function(a){$('body').localScroll(a)};h.defaults={duration:1e3,axis:'y',event:'click',stop:1};h.hash=function(a){a=$.extend({},h.defaults,a);a.hash=0;if(location.hash)setTimeout(function(){i(0,location,a)},0)};$.fn.localScroll=function(b){b=$.extend({},h.defaults,b);return(b.persistent||b.lazy)?this.bind(b.event,function(e){var a=$([e.target,e.target.parentNode]).filter(c)[0];a&&i(e,a,b)}):this.find('a,area').filter(c).bind(b.event,function(e){i(e,this,b)}).end().end();function c(){var a=this;return!!a.href&&!!a.hash&&a.href.replace(a.hash,'')==g&&(!b.filter||$(a).is(b.filter))}};function i(e,a,b){var c=a.hash.slice(1),d=document.getElementById(c)||document.getElementsByName(c)[0],f;if(d){e&&e.preventDefault();f=$(b.target||$.scrollTo.window());if(b.lock&&f.is(':animated')||b.onBefore&&b.onBefore.call(a,e,d,f)===!1)return;if(b.stop)f.queue('fx',[]).stop();f.scrollTo(d,b).trigger('notify.serialScroll',[d]);if(b.hash)f.queue(function(){location=a.hash;$(this).dequeue()})}}})(jQuery);

/* - ++resource++biggerlink.js - */
// http://www.signhealthintranet.org.uk/portal_javascripts/++resource++biggerlink.js?original=1
(function($){$.fn.biggerlink=function(options){var settings={hoverclass:'hover',clickableclass:'hot',follow:true};if(options){$.extend(settings,options)}
$(this).filter(function(){return $('a',this).length>0}).addClass(settings.clickableclass).each(function(i){$(this).attr('title',$('a[title]:first',this).attr('title'));$(this).mouseover(function(){window.status=$('a:first',this).attr('href');$(this).addClass(settings.hoverclass)}).mouseout(function(){window.status='';$(this).removeClass(settings.hoverclass)}).bind('click',function(){$(this).find('a:first').trigger('click')}).find('a').bind('focus',function(){$(this).parents('.'+settings.clickableclass).addClass(settings.hoverclass)}).bind('blur',function(){$(this).parents('.'+settings.clickableclass).removeClass(settings.hoverclass)}).end().find('a:first').bind('click',function(e){if(settings.follow==true){window.location=this.href}
e.stopPropagation()}).end().find('a',this).not(':first').bind('click',function(){$(this).parents('.'+settings.clickableclass).find('a:first').trigger('click');return false})});return this}})(jQuery);

/* - ++resource++tag.js - */
// http://www.signhealthintranet.org.uk/portal_javascripts/++resource++tag.js?original=1
(function($){var globalTags=[];window.setGlobalTags=function(tags){globalTags=getTags(tags)};
function getTags(tags){var tag,i,goodTags=[];for(i=0;i<tags.length;i++){tag=tags[i];if(typeof tags[i]=='object'){tag=tags[i].tag}
goodTags.push(tag.toLowerCase())}
return goodTags}
$.fn.tagSuggest=function(options){var defaults={'matchClass':'tagMatches','tagContainer':'div','tagWrap':'div','sort':true,'tags':null,'url':null,'delay':0,'separator':' '};var i,tag,userTags=[],settings=$.extend({},defaults,options);if(settings.tags){userTags=getTags(settings.tags)} else{userTags=globalTags}
return this.each(function(){var tagsElm=$(this);var elm=this;var matches,fromTab=false;var suggestionsShow=false;var workingTags=[];var currentTag={"position":0,tag:""};var tagMatches=document.createElement(settings.tagContainer);
function showSuggestionsDelayed(el,key){if(settings.delay){if(elm.timer) clearTimeout(elm.timer);elm.timer=setTimeout(function(){showSuggestions(el,key)},settings.delay)} else{showSuggestions(el,key)}}
function showSuggestions(el,key){strreplace=el.value.replace(/, +/g,',');strreplace=strreplace.replace(/ +,/g,',');workingTags=strreplace.split(settings.separator);matches=[];var i,html='',chosenTags={},tagSelected=false;currentTag={position:currentTags.length-1,tag:''};for(i=0;i<currentTags.length&&i<workingTags.length;i++){if(!tagSelected&&currentTags[i].toLowerCase()!=workingTags[i].toLowerCase()){currentTag={position:i,tag:workingTags[i].toLowerCase()};tagSelected=true}
chosenTags[currentTags[i].toLowerCase()]=true}
if(currentTag.tag){if(settings.url){$.ajax({'url':settings.url,'dataType':'json','data':{'tag':currentTag.tag},'async':false,'success': function(m){matches=m}})} else{for(i=0;i<userTags.length;i++){if(userTags[i].indexOf(currentTag.tag)===0){matches.push(userTags[i])}}}
matches=$.grep(matches, function(v,i){return!chosenTags[v.toLowerCase()]});if(settings.sort){matches=matches.sort()}
for(i=0;i<matches.length;i++){html+='<'+settings.tagWrap+' class="_tag_suggestion">'+matches[i]+'</'+settings.tagWrap+'>'}
tagMatches.html(html);if(html.length>0)
tagMatches.slideDown("fast");suggestionsShow=!!(matches.length)} else{hideSuggestions()}}
function hideSuggestions(){var html='';tagMatches.slideUp("fast");tagMatches.html(html);matches=[];suggestionsShow=false}
function setSelection(){var v=tagsElm.val();if(v==tagsElm.attr('title')&&tagsElm.is('.hint')) v='';strreplace=v.replace(/, +/g,',');strreplace=strreplace.replace(/ +,/g,',');currentTags=strreplace.split(settings.separator);hideSuggestions()}
function chooseTag(tag){var i,index;for(i=0;i<currentTags.length;i++){if(currentTags[i].toLowerCase()!=workingTags[i].toLowerCase()){index=i;break}}
if(index==workingTags.length-1) tag=tag+settings.separator;workingTags[i]=tag;tagsElm.val(workingTags.join(settings.separator));tagsElm.blur().focus();setSelection()}
function handleKeys(ev){fromTab=false;var type=ev.type;var resetSelection=false;switch(ev.keyCode){case 37:case 38:case 39:case 40:{hideSuggestions();return true}
case 224:case 17:case 16:case 18:{return true}
case 46:case 8:{if(this.value==''){hideSuggestions();setSelection();return true} else{type='keyup';resetSelection=true;showSuggestionsDelayed(this,ev.charCode);return true}
break}
case 9:case 13:{if(suggestionsShow){chooseTag(matches[0]);fromTab=true;return false} else{return true}}
case 27:{hideSuggestions();setSelection();return true}
case 32:{setSelection();return true}}
if(type=='keyup'){switch(ev.charCode){case 9:case 13:{return true}}
if(resetSelection){setSelection()}
showSuggestionsDelayed(this,ev.charCode)}}
tagsElm.after(tagMatches).keypress(handleKeys).keyup(handleKeys).blur(function(){if(fromTab==true||suggestionsShow){fromTab=false;tagsElm.focus()}});tagMatches=$(tagMatches).click(function(ev){if(ev.target.nodeName==settings.tagWrap.toUpperCase()&&$(ev.target).is('._tag_suggestion')){chooseTag(ev.target.innerHTML)}}).addClass(settings.matchClass);setSelection()})}})(jQuery);

/* - ++resource++jqui.js - */
/*
 * jQuery UI 1.5.3
 *
 * Copyright (c) 2008 Paul Bakaus (ui.jquery.com)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * http://docs.jquery.com/UI
 */
;(function($) {

$.ui = {
	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) { return; }
			
			for (var i = 0; i < set.length; i++) {
				if (instance.options[set[i][0]]) {
					set[i][1].apply(instance.element, args);
				}
			}
		}	
	},
	cssCache: {},
	css: function(name) {
		if ($.ui.cssCache[name]) { return $.ui.cssCache[name]; }
		var tmp = $('<div class="ui-gen">').addClass(name).css({position:'absolute', top:'-5000px', left:'-5000px', display:'block'}).appendTo('body');
		
		//if (!$.browser.safari)
			//tmp.appendTo('body'); 
		
		//Opera and Safari set width and height to 0px instead of auto
		//Safari returns rgba(0,0,0,0) when bgcolor is not set
		$.ui.cssCache[name] = !!(
			(!(/auto|default/).test(tmp.css('cursor')) || (/^[1-9]/).test(tmp.css('height')) || (/^[1-9]/).test(tmp.css('width')) || 
			!(/none/).test(tmp.css('backgroundImage')) || !(/transparent|rgba\(0, 0, 0, 0\)/).test(tmp.css('backgroundColor')))
		);
		try { $('body').get(0).removeChild(tmp.get(0));	} catch(e){}
		return $.ui.cssCache[name];
	},
	disableSelection: function(el) {
		$(el).attr('unselectable', 'on').css('MozUserSelect', 'none');
	},
	enableSelection: function(el) {
		$(el).attr('unselectable', 'off').css('MozUserSelect', '');
	},
	hasScroll: function(e, a) {
		var scroll = /top/.test(a||"top") ? 'scrollTop' : 'scrollLeft', has = false;
		if (e[scroll] > 0) return true; e[scroll] = 1;
		has = e[scroll] > 0 ? true : false; e[scroll] = 0;
		return has;
	}
};


/** jQuery core modifications and additions **/

var _remove = $.fn.remove;
$.fn.remove = function() {
	$("*", this).add(this).triggerHandler("remove");
	return _remove.apply(this, arguments );
};

// $.widget is a factory to create jQuery plugins
// taking some boilerplate code out of the plugin code
// created by Scott González and Jörn Zaefferer
function getter(namespace, plugin, method) {
	var methods = $[namespace][plugin].getter || [];
	methods = (typeof methods == "string" ? methods.split(/,?\s+/) : methods);
	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);
		
		if (isMethodCall && getter(namespace, name, options)) {
			var instance = $.data(this[0], name);
			return (instance ? instance[options].apply(instance, args)
				: undefined);
		}
		
		return this.each(function() {
			var instance = $.data(this, name);
			if (isMethodCall && instance && $.isFunction(instance[options])) {
				instance[options].apply(instance, args);
			} else if (!isMethodCall) {
				$.data(this, name, new $[namespace][name](this, options));
			}
		});
	};
	
	// create widget constructor
	$[namespace][name] = function(element, options) {
		var self = this;
		
		this.widgetName = name;
		this.widgetBaseClass = namespace + '-' + name;
		
		this.options = $.extend({}, $.widget.defaults, $[namespace][name].defaults, options);
		this.element = $(element)
			.bind('setData.' + name, function(e, key, value) {
				return self.setData(key, value);
			})
			.bind('getData.' + name, function(e, key) {
				return self.getData(key);
			})
			.bind('remove', function() {
				return self.destroy();
			});
		this.init();
	};
	
	// add widget prototype
	$[namespace][name].prototype = $.extend({}, $.widget.prototype, prototype);
};

$.widget.prototype = {
	init: function() {},
	destroy: function() {
		this.element.removeData(this.widgetName);
	},
	
	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');
		}
	},
	
	enable: function() {
		this.setData('disabled', false);
	},
	disable: function() {
		this.setData('disabled', true);
	}
};

$.widget.defaults = {
	disabled: false
};


/** Mouse Interaction Plugin **/

$.ui.mouse = {
	mouseInit: function() {
		var self = this;
	
		this.element.bind('mousedown.'+this.widgetName, function(e) {
			return self.mouseDown(e);
		});
		
		// 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(e) {
		// we may have missed mouseup (out of window)
		(this._mouseStarted && this.mouseUp(e));
		
		this._mouseDownEvent = e;
		
		var self = this,
			btnIsLeft = (e.which == 1),
			elIsCancel = (typeof this.options.cancel == "string" ? $(e.target).parents().add(e.target).filter(this.options.cancel).length : false);
		if (!btnIsLeft || elIsCancel || !this.mouseCapture(e)) {
			return true;
		}
		
		this._mouseDelayMet = !this.options.delay;
		if (!this._mouseDelayMet) {
			this._mouseDelayTimer = setTimeout(function() {
				self._mouseDelayMet = true;
			}, this.options.delay);
		}
		
		if (this.mouseDistanceMet(e) && this.mouseDelayMet(e)) {
			this._mouseStarted = (this.mouseStart(e) !== false);
			if (!this._mouseStarted) {
				e.preventDefault();
				return true;
			}
		}
		
		// these delegates are required to keep context
		this._mouseMoveDelegate = function(e) {
			return self.mouseMove(e);
		};
		this._mouseUpDelegate = function(e) {
			return self.mouseUp(e);
		};
		$(document)
			.bind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
			.bind('mouseup.'+this.widgetName, this._mouseUpDelegate);
		
		return false;
	},
	
	mouseMove: function(e) {
		// IE mouseup check - mouseup happened when mouse was out of window
		if ($.browser.msie && !e.button) {
			return this.mouseUp(e);
		}
		
		if (this._mouseStarted) {
			this.mouseDrag(e);
			return false;
		}
		
		if (this.mouseDistanceMet(e) && this.mouseDelayMet(e)) {
			this._mouseStarted =
				(this.mouseStart(this._mouseDownEvent, e) !== false);
			(this._mouseStarted ? this.mouseDrag(e) : this.mouseUp(e));
		}
		
		return !this._mouseStarted;
	},
	
	mouseUp: function(e) {
		$(document)
			.unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
			.unbind('mouseup.'+this.widgetName, this._mouseUpDelegate);
		
		if (this._mouseStarted) {
			this._mouseStarted = false;
			this.mouseStop(e);
		}
		
		return false;
	},
	
	mouseDistanceMet: function(e) {
		return (Math.max(
				Math.abs(this._mouseDownEvent.pageX - e.pageX),
				Math.abs(this._mouseDownEvent.pageY - e.pageY)
			) >= this.options.distance
		);
	},
	
	mouseDelayMet: function(e) {
		return this._mouseDelayMet;
	},
	
	// These are placeholder methods, to be overriden by extending plugin
	mouseStart: function(e) {},
	mouseDrag: function(e) {},
	mouseStop: function(e) {},
	mouseCapture: function(e) { return true; }
};

$.ui.mouse.defaults = {
	cancel: null,
	distance: 1,
	delay: 0
};

})(jQuery);
/*
 * jQuery UI Tabs
 *
 * Copyright (c) 2007, 2008 Klaus Hartl (stilbuero.de)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * http://docs.jquery.com/UI/Tabs
 *
 * Depends:
 *	ui.core.js
 */
(function($) {

$.widget("ui.tabs", {
	init: function() {
		this.options.event += '.tabs'; // namespace event
		
		// create tabs
		this.tabify(true);
	},
	setData: function(key, value) {
		if ((/^selected/).test(key))
			this.select(value);
		else {
			this.options[key] = value;
			this.tabify();
		}
	},
	length: function() {
		return this.$tabs.length;
	},
	tabId: function(a) {
		return a.title && a.title.replace(/\s/g, '_').replace(/[^A-Za-z0-9\-_:\.]/g, '')
			|| this.options.idPrefix + $.data(a);
	},
	ui: function(tab, panel) {
		return {
			options: this.options,
			tab: tab,
			panel: panel,
			index: this.$tabs.index(tab)
		};
	},
	tabify: function(init) {

		this.$lis = $('li:has(a[href])', this.element);
		this.$tabs = this.$lis.map(function() { return $('a', this)[0]; });
		this.$panels = $([]);

		var self = this, o = this.options;

		this.$tabs.each(function(i, a) {
			// inline tab
			if (a.hash && a.hash.replace('#', '')) // Safari 2 reports '#' for an empty hash
				self.$panels = self.$panels.add(a.hash);
			// remote tab
			else if ($(a).attr('href') != '#') { // prevent loading the page itself if href is just "#"
				$.data(a, 'href.tabs', a.href); // required for restore on destroy
				$.data(a, 'load.tabs', a.href); // mutable
				var id = self.tabId(a);
				a.href = '#' + id;
				var $panel = $('#' + id);
				if (!$panel.length) {
					$panel = $(o.panelTemplate).attr('id', id).addClass(o.panelClass)
						.insertAfter( self.$panels[i - 1] || self.element );
					$panel.data('destroy.tabs', true);
				}
				self.$panels = self.$panels.add( $panel );
			}
			// invalid tab href
			else
				o.disabled.push(i + 1);
		});

		if (init) {

			// attach necessary classes for styling if not present
			this.element.addClass(o.navClass);
			this.$panels.each(function() {
				var $this = $(this);
				$this.addClass(o.panelClass);
			});

			// Selected tab
			// use "selected" option or try to retrieve:
			// 1. from fragment identifier in url
			// 2. from cookie
			// 3. from selected class attribute on <li>
			if (o.selected === undefined) {
				if (location.hash) {
					this.$tabs.each(function(i, a) {
						if (a.hash == location.hash) {
							o.selected = i;
							// prevent page scroll to fragment
							if ($.browser.msie || $.browser.opera) { // && !o.remote
								var $toShow = $(location.hash), toShowId = $toShow.attr('id');
								$toShow.attr('id', '');
								setTimeout(function() {
									$toShow.attr('id', toShowId); // restore id
								}, 500);
							}
							scrollTo(0, 0);
							return false; // break
						}
					});
				}
				else if (o.cookie) {
					var index = parseInt($.cookie('ui-tabs' + $.data(self.element)),10);
					if (index && self.$tabs[index])
						o.selected = index;
				}
				else if (self.$lis.filter('.' + o.selectedClass).length)
					o.selected = self.$lis.index( self.$lis.filter('.' + o.selectedClass)[0] );
			}
			o.selected = o.selected === null || o.selected !== undefined ? o.selected : 0; // first tab selected by default

			// Take disabling tabs via class attribute from HTML
			// into account and update option properly.
			// A selected tab cannot become disabled.
			o.disabled = $.unique(o.disabled.concat(
				$.map(this.$lis.filter('.' + o.disabledClass),
					function(n, i) { return self.$lis.index(n); } )
			)).sort();
			if ($.inArray(o.selected, o.disabled) != -1)
				o.disabled.splice($.inArray(o.selected, o.disabled), 1);
			
			// highlight selected tab
			this.$panels.addClass(o.hideClass);
			this.$lis.removeClass(o.selectedClass);
			if (o.selected !== null) {
				this.$panels.eq(o.selected).show().removeClass(o.hideClass); // use show and remove class to show in any case no matter how it has been hidden before
				this.$lis.eq(o.selected).addClass(o.selectedClass);
				
				// seems to be expected behavior that the show callback is fired
				var onShow = function() {
					$(self.element).triggerHandler('tabsshow',
						[self.fakeEvent('tabsshow'), self.ui(self.$tabs[o.selected], self.$panels[o.selected])], o.show);
				}; 

				// load if remote tab
				if ($.data(this.$tabs[o.selected], 'load.tabs'))
					this.load(o.selected, onShow);
				// just trigger show event
				else
					onShow();
				
			}
			
			// clean up to avoid memory leaks in certain versions of IE 6
			$(window).bind('unload', function() {
				self.$tabs.unbind('.tabs');
				self.$lis = self.$tabs = self.$panels = null;
			});

		}

		// disable tabs
		for (var i = 0, li; li = this.$lis[i]; i++)
			$(li)[$.inArray(i, o.disabled) != -1 && !$(li).hasClass(o.selectedClass) ? 'addClass' : 'removeClass'](o.disabledClass);

		// reset cache if switching from cached to not cached
		if (o.cache === false)
			this.$tabs.removeData('cache.tabs');
		
		// set up animations
		var hideFx, showFx, baseFx = { 'min-width': 0, duration: 1 }, baseDuration = 'normal';
		if (o.fx && o.fx.constructor == Array)
			hideFx = o.fx[0] || baseFx, showFx = o.fx[1] || baseFx;
		else
			hideFx = showFx = o.fx || baseFx;

		// reset some styles to maintain print style sheets etc.
		var resetCSS = { display: '', overflow: '', height: '' };
		if (!$.browser.msie) // not in IE to prevent ClearType font issue
			resetCSS.opacity = '';

		// Hide a tab, animation prevents browser scrolling to fragment,
		// $show is optional.
		function hideTab(clicked, $hide, $show) {
			$hide.animate(hideFx, hideFx.duration || baseDuration, function() { //
				$hide.addClass(o.hideClass).css(resetCSS); // maintain flexible height and accessibility in print etc.
				if ($.browser.msie && hideFx.opacity)
					$hide[0].style.filter = '';
				if ($show)
					showTab(clicked, $show, $hide);
			});
		}

		// Show a tab, animation prevents browser scrolling to fragment,
		// $hide is optional.
		function showTab(clicked, $show, $hide) {
			if (showFx === baseFx)
				$show.css('display', 'block'); // prevent occasionally occuring flicker in Firefox cause by gap between showing and hiding the tab panels
			$show.animate(showFx, showFx.duration || baseDuration, function() {
				$show.removeClass(o.hideClass).css(resetCSS); // maintain flexible height and accessibility in print etc.
				if ($.browser.msie && showFx.opacity)
					$show[0].style.filter = '';

				// callback
				$(self.element).triggerHandler('tabsshow',
					[self.fakeEvent('tabsshow'), self.ui(clicked, $show[0])], o.show);

			});
		}

		// switch a tab
		function switchTab(clicked, $li, $hide, $show) {
			/*if (o.bookmarkable && trueClick) { // add to history only if true click occured, not a triggered click
				$.ajaxHistory.update(clicked.hash);
			}*/
			$li.addClass(o.selectedClass)
				.siblings().removeClass(o.selectedClass);
			hideTab(clicked, $hide, $show);
		}

		// attach tab event handler, unbind to avoid duplicates from former tabifying...
		this.$tabs.unbind('.tabs').bind(o.event, function() {

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

			// If tab is already selected and not unselectable or tab disabled or 
			// or is already loading or click callback returns false stop here.
			// Check if click handler returns false last so that it is not executed
			// for a disabled or loading tab!
			if (($li.hasClass(o.selectedClass) && !o.unselect)
				|| $li.hasClass(o.disabledClass) 
				|| $(this).hasClass(o.loadingClass)
				|| $(self.element).triggerHandler('tabsselect', [self.fakeEvent('tabsselect'), self.ui(this, $show[0])], o.select) === false
				) {
				this.blur();
				return false;
			}

			self.options.selected = self.$tabs.index(this);

			// if tab may be closed
			if (o.unselect) {
				if ($li.hasClass(o.selectedClass)) {
					self.options.selected = null;
					$li.removeClass(o.selectedClass);
					self.$panels.stop();
					hideTab(this, $hide);
					this.blur();
					return false;
				} else if (!$hide.length) {
					self.$panels.stop();
					var a = this;
					self.load(self.$tabs.index(this), function() {
						$li.addClass(o.selectedClass).addClass(o.unselectClass);
						showTab(a, $show);
					});
					this.blur();
					return false;
				}
			}

			if (o.cookie)
				$.cookie('ui-tabs' + $.data(self.element), self.options.selected, o.cookie);

			// stop possibly running animations
			self.$panels.stop();

			// show new tab
			if ($show.length) {

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

				var a = this;
				self.load(self.$tabs.index(this), $hide.length ? 
					function() {
						switchTab(a, $li, $hide, $show);
					} :
					function() {
						$li.addClass(o.selectedClass);
						showTab(a, $show);
					}
				);

				// 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() {
					scrollTo(scrollX, scrollY);
				}, 0);*/

			} else
				throw 'jQuery UI Tabs: Mismatching fragment identifier.';

			// Prevent IE from keeping other link focussed when using the back button
			// and remove dotted border from clicked link. This is controlled in modern
			// browsers via CSS, also blur removes focus from address bar in Firefox
			// which can become a usability and annoying problem with tabsRotate.
			if ($.browser.msie)
				this.blur();

			//return o.bookmarkable && !!trueClick; // convert trueClick == undefined to Boolean required in IE
			return false;

		});

		// disable click if event is configured to something else
		if (!(/^click/).test(o.event))
			this.$tabs.bind('click.tabs', function() { return false; });

	},
	add: function(url, label, index) {
		if (index == undefined) 
			index = this.$tabs.length; // append by default

		var o = this.options;
		var $li = $(o.tabTemplate.replace(/#\{href\}/g, url).replace(/#\{label\}/g, label));
		$li.data('destroy.tabs', true);

		var id = url.indexOf('#') == 0 ? url.replace('#', '') : this.tabId( $('a:first-child', $li)[0] );

		// try to find an existing element before creating a new one
		var $panel = $('#' + id);
		if (!$panel.length) {
			$panel = $(o.panelTemplate).attr('id', id)
				.addClass(o.hideClass)
				.data('destroy.tabs', true);
		}
		$panel.addClass(o.panelClass);
		if (index >= this.$lis.length) {
			$li.appendTo(this.element);
			$panel.appendTo(this.element[0].parentNode);
		} else {
			$li.insertBefore(this.$lis[index]);
			$panel.insertBefore(this.$panels[index]);
		}
		
		o.disabled = $.map(o.disabled,
			function(n, i) { return n >= index ? ++n : n });
			
		this.tabify();

		if (this.$tabs.length == 1) {
			$li.addClass(o.selectedClass);
			$panel.removeClass(o.hideClass);
			var href = $.data(this.$tabs[0], 'load.tabs');
			if (href)
				this.load(index, href);
		}

		// callback
		this.element.triggerHandler('tabsadd',
			[this.fakeEvent('tabsadd'), this.ui(this.$tabs[index], this.$panels[index])], o.add
		);
	},
	remove: function(index) {
		var o = this.options, $li = this.$lis.eq(index).remove(),
			$panel = this.$panels.eq(index).remove();

		// If selected tab was removed focus tab to the right or
		// in case the last tab was removed the tab to the left.
		if ($li.hasClass(o.selectedClass) && this.$tabs.length > 1)
			this.select(index + (index + 1 < this.$tabs.length ? 1 : -1));

		o.disabled = $.map($.grep(o.disabled, function(n, i) { return n != index; }),
			function(n, i) { return n >= index ? --n : n });

		this.tabify();

		// callback
		this.element.triggerHandler('tabsremove',
			[this.fakeEvent('tabsremove'), this.ui($li.find('a')[0], $panel[0])], o.remove
		);
	},
	enable: function(index) {
		var o = this.options;
		if ($.inArray(index, o.disabled) == -1)
			return;
			
		var $li = this.$lis.eq(index).removeClass(o.disabledClass);
		if ($.browser.safari) { // fix disappearing tab (that used opacity indicating disabling) after enabling in Safari 2...
			$li.css('display', 'inline-block');
			setTimeout(function() {
				$li.css('display', 'block');
			}, 0);
		}

		o.disabled = $.grep(o.disabled, function(n, i) { return n != index; });

		// callback
		this.element.triggerHandler('tabsenable',
			[this.fakeEvent('tabsenable'), this.ui(this.$tabs[index], this.$panels[index])], o.enable
		);

	},
	disable: function(index) {
		var self = this, o = this.options;
		if (index != o.selected) { // cannot disable already selected tab
			this.$lis.eq(index).addClass(o.disabledClass);

			o.disabled.push(index);
			o.disabled.sort();

			// callback
			this.element.triggerHandler('tabsdisable',
				[this.fakeEvent('tabsdisable'), this.ui(this.$tabs[index], this.$panels[index])], o.disable
			);
		}
	},
	select: function(index) {
		if (typeof index == 'string')
			index = this.$tabs.index( this.$tabs.filter('[href$=' + index + ']')[0] );
		this.$tabs.eq(index).trigger(this.options.event);
	},
	load: function(index, callback) { // callback is for internal usage only
		
		var self = this, o = this.options, $a = this.$tabs.eq(index), a = $a[0],
				bypassCache = callback == undefined || callback === false, url = $a.data('load.tabs');

		callback = callback || function() {};
		
		// no remote or from cache - just finish with callback
		if (!url || !bypassCache && $.data(a, 'cache.tabs')) {
			callback();
			return;
		}

		// load remote from here on
		
		var inner = function(parent) {
			var $parent = $(parent), $inner = $parent.find('*:last');
			return $inner.length && $inner.is(':not(img)') && $inner || $parent;
		};
		var cleanup = function() {
			self.$tabs.filter('.' + o.loadingClass).removeClass(o.loadingClass)
						.each(function() {
							if (o.spinner)
								inner(this).parent().html(inner(this).data('label.tabs'));
						});
			self.xhr = null;
		};
		
		if (o.spinner) {
			var label = inner(a).html();
			inner(a).wrapInner('<em></em>')
				.find('em').data('label.tabs', label).html(o.spinner);
		}

		var ajaxOptions = $.extend({}, o.ajaxOptions, {
			url: url,
			success: function(r, s) {
				$(a.hash).html(r);
				cleanup();
				
				if (o.cache)
					$.data(a, 'cache.tabs', true); // if loaded once do not load them again

				// callbacks
				$(self.element).triggerHandler('tabsload',
					[self.fakeEvent('tabsload'), self.ui(self.$tabs[index], self.$panels[index])], o.load
				);
				o.ajaxOptions.success && o.ajaxOptions.success(r, s);
				
				// This callback is required because the switch has to take
				// place after loading has completed. Call last in order to 
				// fire load before show callback...
				callback();
			}
		});
		if (this.xhr) {
			// terminate pending requests from other tabs and restore tab label
			this.xhr.abort();
			cleanup();
		}
		$a.addClass(o.loadingClass);
		setTimeout(function() { // timeout is again required in IE, "wait" for id being restored
			self.xhr = $.ajax(ajaxOptions);
		}, 0);

	},
	url: function(index, url) {
		this.$tabs.eq(index).removeData('cache.tabs').data('load.tabs', url);
	},
	destroy: function() {
		var o = this.options;
		this.element.unbind('.tabs')
			.removeClass(o.navClass).removeData('tabs');
		this.$tabs.each(function() {
			var href = $.data(this, 'href.tabs');
			if (href)
				this.href = href;
			var $this = $(this).unbind('.tabs');
			$.each(['href', 'load', 'cache'], function(i, prefix) {
				$this.removeData(prefix + '.tabs');
			});
		});
		this.$lis.add(this.$panels).each(function() {
			if ($.data(this, 'destroy.tabs'))
				$(this).remove();
			else
				$(this).removeClass([o.selectedClass, o.unselectClass,
					o.disabledClass, o.panelClass, o.hideClass].join(' '));
		});
	},
	fakeEvent: function(type) {
		return $.event.fix({
			type: type,
			target: this.element[0]
		});
	}
});

$.ui.tabs.defaults = {
	// basic setup
	unselect: false,
	event: 'click',
	disabled: [],
	cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true }
	// TODO history: false,

	// Ajax
	spinner: 'Loading&#8230;',
	cache: false,
	idPrefix: 'ui-tabs-',
	ajaxOptions: {},

	// animations
	fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 }

	// templates
	tabTemplate: '<li><a href="#{href}"><span>#{label}</span></a></li>',
	panelTemplate: '<div></div>',

	// CSS classes
	navClass: 'ui-tabs-nav',
	selectedClass: 'ui-tabs-selected',
	unselectClass: 'ui-tabs-unselect',
	disabledClass: 'ui-tabs-disabled',
	panelClass: 'ui-tabs-panel',
	hideClass: 'ui-tabs-hide',
	loadingClass: 'ui-tabs-loading'
};

$.ui.tabs.getter = "length";

/*
 * Tabs Extensions
 */

/*
 * Rotate
 */
$.extend($.ui.tabs.prototype, {
	rotation: null,
	rotate: function(ms, continuing) {
		
		continuing = continuing || false;
		
		var self = this, t = this.options.selected;
		
		function start() {
			self.rotation = setInterval(function() {
				t = ++t < self.$tabs.length ? t : 0;
				self.select(t);
			}, ms); 
		}
		
		function stop(e) {
			if (!e || e.clientX) { // only in case of a true click
				clearInterval(self.rotation);
			}
		}
		
		// start interval
		if (ms) {
			start();
			if (!continuing)
				this.$tabs.bind(this.options.event, stop);
			else
				this.$tabs.bind(this.options.event, function() {
					stop();
					t = self.options.selected;
					start();
				});
		}
		// stop interval
		else {
			stop();
			this.$tabs.unbind(this.options.event, stop);
		}
	}
});

})(jQuery);
/*
 * jQuery UI Datepicker
 *
 * Copyright (c) 2006, 2007, 2008 Marc Grabanski
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 * 
 * http://docs.jquery.com/UI/Datepicker
 *
 * Depends:
 *	ui.core.js
 *
 * Marc Grabanski (m@marcgrabanski.com) and Keith Wood (kbwood@virginbroadband.com.au).
 */
   
(function($) { // hide the namespace

var PROP_NAME = 'datepicker';

/* Date picker manager.
   Use the singleton instance of this class, $.datepicker, to interact with the date picker.
   Settings for (groups of) date pickers are maintained in an instance object,
   allowing multiple different settings on the same page. */

function Datepicker() {
	this.debug = false; // Change this to true to start debugging
	this._curInst = null; // The current instance in use
	this._disabledInputs = []; // List of date picker inputs that have been disabled
	this._datepickerShowing = false; // True if the popup picker is showing , false if not
	this._inDialog = false; // True if showing within a "dialog", false if not
	this._mainDivId = 'ui-datepicker-div'; // The ID of the main datepicker division
	this._appendClass = 'ui-datepicker-append'; // The name of the append marker class
	this._triggerClass = 'ui-datepicker-trigger'; // The name of the trigger marker class
	this._dialogClass = 'ui-datepicker-dialog'; // The name of the dialog marker class
	this._promptClass = 'ui-datepicker-prompt'; // The name of the dialog prompt marker class
	this._unselectableClass = 'ui-datepicker-unselectable'; // The name of the unselectable cell marker class
	this._currentClass = 'ui-datepicker-current-day'; // The name of the current day marker class
	this.regional = []; // Available regional settings, indexed by language code
	this.regional[''] = { // Default regional settings
		clearText: 'Clear', // Display text for clear link
		clearStatus: 'Erase the current date', // Status text for clear link
		closeText: 'Close', // Display text for close link
		closeStatus: 'Close without change', // Status text for close link
		prevText: '&#x3c;Prev', // Display text for previous month link
		prevStatus: 'Show the previous month', // Status text for previous month link
		nextText: 'Next&#x3e;', // Display text for next month link
		nextStatus: 'Show the next month', // Status text for next month link
		currentText: 'Today', // Display text for current month link
		currentStatus: 'Show the current month', // Status text for current month link
		monthNames: ['January','February','March','April','May','June',
			'July','August','September','October','November','December'], // Names of months for drop-down and formatting
		monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], // For formatting
		monthStatus: 'Show a different month', // Status text for selecting a month
		yearStatus: 'Show a different year', // Status text for selecting a year
		weekHeader: 'Wk', // Header for the week of the year column
		weekStatus: 'Week of the year', // Status text for the week of the year column
		dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], // For formatting
		dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], // For formatting
		dayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'], // Column headings for days starting at Sunday
		dayStatus: 'Set DD as first week day', // Status text for the day of the week selection
		dateStatus: 'Select DD, M d', // Status text for the date selection
		dateFormat: 'mm/dd/yy', // See format options on parseDate
		firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
		initStatus: 'Select a date', // Initial Status text on opening
		isRTL: false // True if right-to-left language, false if left-to-right
	};
	this._defaults = { // Global defaults for all the date picker instances
		showOn: 'focus', // 'focus' for popup on focus,
			// 'button' for trigger button, or 'both' for either
		showAnim: 'show', // Name of jQuery animation for popup
		showOptions: {}, // Options for enhanced animations
		defaultDate: null, // Used when field is blank: actual date,
			// +/-number for offset from today, null for today
		appendText: '', // Display text following the input box, e.g. showing the format
		buttonText: '...', // Text for trigger button
		buttonImage: '', // URL for trigger button image
		buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
		closeAtTop: true, // True to have the clear/close at the top,
			// false to have them at the bottom
		mandatory: false, // True to hide the Clear link, false to include it
		hideIfNoPrevNext: false, // True to hide next/previous month links
			// if not applicable, false to just disable them
		navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
		gotoCurrent: false, // True if today link goes back to current selection instead
		changeMonth: true, // True if month can be selected directly, false if only prev/next
		changeYear: true, // True if year can be selected directly, false if only prev/next
		yearRange: '-10:+10', // Range of years to display in drop-down,
			// either relative to current year (-nn:+nn) or absolute (nnnn:nnnn)
		changeFirstDay: true, // True to click on day name to change, false to remain as set
		highlightWeek: false, // True to highlight the selected week
		showOtherMonths: false, // True to show dates in other months, false to leave blank
		showWeeks: false, // True to show week of the year, false to omit
		calculateWeek: this.iso8601Week, // How to calculate the week of the year,
			// takes a Date and returns the number of the week for it
		shortYearCutoff: '+10', // Short year values < this are in the current century,
			// > this are in the previous century, 
			// string value starting with '+' for current year + value
		showStatus: false, // True to show status bar at bottom, false to not show it
		statusForDate: this.dateStatus, // Function to provide status text for a date -
			// takes date and instance as parameters, returns display text
		minDate: null, // The earliest selectable date, or null for no limit
		maxDate: null, // The latest selectable date, or null for no limit
		duration: 'normal', // Duration of display/closure
		beforeShowDay: null, // Function that takes a date and returns an array with
			// [0] = true if selectable, false if not, [1] = custom CSS class name(s) or '', 
			// [2] = cell title (optional), e.g. $.datepicker.noWeekends
		beforeShow: null, // Function that takes an input field and
			// returns a set of custom settings for the date picker
		onSelect: null, // Define a callback function when a date is selected
		onChangeMonthYear: null, // Define a callback function when the month or year is changed
		onClose: null, // Define a callback function when the datepicker is closed
		numberOfMonths: 1, // Number of months to show at a time
		stepMonths: 1, // Number of months to step back/forward
		rangeSelect: false, // Allows for selecting a date range on one date picker
		rangeSeparator: ' - ', // Text between two dates in a range
		altField: '', // Selector for an alternate field to store selected dates into
		altFormat: '' // The date format to use for the alternate field
	};
	$.extend(this._defaults, this.regional['']);
	this.dpDiv = $('<div id="' + this._mainDivId + '" style="display: none;"></div>');
}

$.extend(Datepicker.prototype, {
	/* Class name added to elements to indicate already configured with a date picker. */
	markerClassName: 'hasDatepicker',

	/* Debug logging (if enabled). */
	log: function () {
		if (this.debug)
			console.log.apply('', arguments);
	},
	
	/* Override the default settings for all instances of the date picker. 
	   @param  settings  object - the new settings to use as defaults (anonymous object)
	   @return the manager object */
	setDefaults: function(settings) {
		extendRemove(this._defaults, settings || {});
		return this;
	},

	/* Attach the date picker to a jQuery selection.
	   @param  target    element - the target input field or division or span
	   @param  settings  object - the new settings to use for this date picker instance (anonymous) */
	_attachDatepicker: function(target, settings) {
		// check for settings on the control itself - in namespace 'date:'
		var inlineSettings = null;
		for (attrName in this._defaults) {
			var attrValue = target.getAttribute('date:' + attrName);
			if (attrValue) {
				inlineSettings = inlineSettings || {};
				try {
					inlineSettings[attrName] = eval(attrValue);
				} catch (err) {
					inlineSettings[attrName] = attrValue;
				}
			}
		}
		var nodeName = target.nodeName.toLowerCase();
		var inline = (nodeName == 'div' || nodeName == 'span');
		if (!target.id)
			target.id = 'dp' + new Date().getTime();
		var inst = this._newInst($(target), inline);
		inst.settings = $.extend({}, settings || {}, inlineSettings || {}); 
		if (nodeName == 'input') {
			this._connectDatepicker(target, inst);
		} else if (inline) {
			this._inlineDatepicker(target, inst);
		}
	},

	/* Create a new instance object. */
	_newInst: function(target, inline) {
		return {id: target[0].id, input: target, // associated target
			selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
			drawMonth: 0, drawYear: 0, // month being drawn
			inline: inline, // is datepicker inline or not
			dpDiv: (!inline ? this.dpDiv : // presentation div
			$('<div class="ui-datepicker-inline"></div>'))};
	},

	/* Attach the date picker to an input field. */
	_connectDatepicker: function(target, inst) {
		var input = $(target);
		if (input.hasClass(this.markerClassName))
			return;
		var appendText = this._get(inst, 'appendText');
		var isRTL = this._get(inst, 'isRTL');
		if (appendText)
			input[isRTL ? 'before' : 'after']('<span class="' + this._appendClass + '">' + appendText + '</span>');
		var showOn = this._get(inst, 'showOn');
		if (showOn == 'focus' || showOn == 'both') // pop-up date picker when in the marked field
			input.focus(this._showDatepicker);
		if (showOn == 'button' || showOn == 'both') { // pop-up date picker when button clicked
			var buttonText = this._get(inst, 'buttonText');
			var buttonImage = this._get(inst, 'buttonImage');
			var trigger = $(this._get(inst, 'buttonImageOnly') ? 
				$('<img/>').addClass(this._triggerClass).
					attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
				$('<button type="button"></button>').addClass(this._triggerClass).
					html(buttonImage == '' ? buttonText : $('<img/>').attr(
					{ src:buttonImage, alt:buttonText, title:buttonText })));
			input[isRTL ? 'before' : 'after'](trigger);
			trigger.click(function() {
				if ($.datepicker._datepickerShowing && $.datepicker._lastInput == target)
					$.datepicker._hideDatepicker();
				else
					$.datepicker._showDatepicker(target);
				return false;
			});
		}
		input.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).
			bind("setData.datepicker", function(event, key, value) {
				inst.settings[key] = value;
			}).bind("getData.datepicker", function(event, key) {
				return this._get(inst, key);
			});
		$.data(target, PROP_NAME, inst);
	},

	/* Attach an inline date picker to a div. */
	_inlineDatepicker: function(target, inst) {
		var input = $(target);
		if (input.hasClass(this.markerClassName))
			return;
		input.addClass(this.markerClassName).append(inst.dpDiv).
			bind("setData.datepicker", function(event, key, value){
				inst.settings[key] = value;
			}).bind("getData.datepicker", function(event, key){
				return this._get(inst, key);
			});
		$.data(target, PROP_NAME, inst);
		this._setDate(inst, this._getDefaultDate(inst));
		this._updateDatepicker(inst);
	},

	/* Pop-up the date picker in a "dialog" box.
	   @param  input     element - ignored
	   @param  dateText  string - the initial date to display (in the current format)
	   @param  onSelect  function - the function(dateText) to call when a date is selected
	   @param  settings  object - update the dialog date picker instance's settings (anonymous object)
	   @param  pos       int[2] - coordinates for the dialog's position within the screen or
	                     event - with x/y coordinates or
	                     leave empty for default (screen centre)
	   @return the manager object */
	_dialogDatepicker: function(input, dateText, onSelect, settings, pos) {
		var inst = this._dialogInst; // internal instance
		if (!inst) {
			var id = 'dp' + new Date().getTime();
			this._dialogInput = $('<input type="text" id="' + id +
				'" size="1" style="position: absolute; top: -100px;"/>');
			this._dialogInput.keydown(this._doKeyDown);
			$('body').append(this._dialogInput);
			inst = this._dialogInst = this._newInst(this._dialogInput, false);
			inst.settings = {};
			$.data(this._dialogInput[0], PROP_NAME, inst);
		}
		extendRemove(inst.settings, settings || {});
		this._dialogInput.val(dateText);

		this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
		if (!this._pos) {
			var browserWidth = window.innerWidth || document.documentElement.clientWidth ||	document.body.clientWidth;
			var browserHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
			var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
			var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
			this._pos = // should use actual width/height below
				[(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
		}

		// move input on screen for focus, but hidden behind dialog
		this._dialogInput.css('left', this._pos[0] + 'px').css('top', this._pos[1] + 'px');
		inst.settings.onSelect = onSelect;
		this._inDialog = true;
		this.dpDiv.addClass(this._dialogClass);
		this._showDatepicker(this._dialogInput[0]);
		if ($.blockUI)
			$.blockUI(this.dpDiv);
		$.data(this._dialogInput[0], PROP_NAME, inst);
		return this;
	},

	/* Detach a datepicker from its control.
	   @param  target    element - the target input field or division or span */
	_destroyDatepicker: function(target) {
		var nodeName = target.nodeName.toLowerCase();
		var $target = $(target);
		$.removeData(target, PROP_NAME);
		if (nodeName == 'input') {
			$target.siblings('.' + this._appendClass).remove().end().
				siblings('.' + this._triggerClass).remove().end().
				removeClass(this.markerClassName).
				unbind('focus', this._showDatepicker).
				unbind('keydown', this._doKeyDown).
				unbind('keypress', this._doKeyPress);
		} else if (nodeName == 'div' || nodeName == 'span')
			$target.removeClass(this.markerClassName).empty();
	},

	/* Enable the date picker to a jQuery selection.
	   @param  target    element - the target input field or division or span */
	_enableDatepicker: function(target) {
		target.disabled = false;
		$(target).siblings('button.' + this._triggerClass).each(function() { this.disabled = false; }).end().
			siblings('img.' + this._triggerClass).css({opacity: '1.0', cursor: ''});
		this._disabledInputs = $.map(this._disabledInputs,
			function(value) { return (value == target ? null : value); }); // delete entry
	},

	/* Disable the date picker to a jQuery selection.
	   @param  target    element - the target input field or division or span */
	_disableDatepicker: function(target) {
		target.disabled = true;
		$(target).siblings('button.' + this._triggerClass).each(function() { this.disabled = true; }).end().
			siblings('img.' + this._triggerClass).css({opacity: '0.5', cursor: 'default'});
		this._disabledInputs = $.map(this._disabledInputs,
			function(value) { return (value == target ? null : value); }); // delete entry
		this._disabledInputs[this._disabledInputs.length] = target;
	},

	/* Is the first field in a jQuery collection disabled as a datepicker?
	   @param  target    element - the target input field or division or span
	   @return boolean - true if disabled, false if enabled */
	_isDisabledDatepicker: function(target) {
		if (!target)
			return false;
		for (var i = 0; i < this._disabledInputs.length; i++) {
			if (this._disabledInputs[i] == target)
				return true;
		}
		return false;
	},

	/* Update the settings for a date picker attached to an input field or division.
	   @param  target  element - the target input field or division or span
	   @param  name    object - the new settings to update or
	                   string - the name of the setting to change or
	   @param  value   any - the new value for the setting (omit if above is an object) */
	_changeDatepicker: function(target, name, value) {
		var settings = name || {};
		if (typeof name == 'string') {
			settings = {};
			settings[name] = value;
		}
		if (inst = $.data(target, PROP_NAME)) {
			extendRemove(inst.settings, settings);
			this._updateDatepicker(inst);
		}
	},

	/* Set the dates for a jQuery selection.
	   @param  target   element - the target input field or division or span
	   @param  date     Date - the new date
	   @param  endDate  Date - the new end date for a range (optional) */
	_setDateDatepicker: function(target, date, endDate) {
		var inst = $.data(target, PROP_NAME);
		if (inst) {
			this._setDate(inst, date, endDate);
			this._updateDatepicker(inst);
		}
	},

	/* Get the date(s) for the first entry in a jQuery selection.
	   @param  target  element - the target input field or division or span
	   @return Date - the current date or
	           Date[2] - the current dates for a range */
	_getDateDatepicker: function(target) {
		var inst = $.data(target, PROP_NAME);
		if (inst)
			this._setDateFromField(inst); 
		return (inst ? this._getDate(inst) : null);
	},

	/* Handle keystrokes. */
	_doKeyDown: function(e) {
		var inst = $.data(e.target, PROP_NAME);
		var handled = true;
		if ($.datepicker._datepickerShowing)
			switch (e.keyCode) {
				case 9:  $.datepicker._hideDatepicker(null, '');
						break; // hide on tab out
				case 13: $.datepicker._selectDay(e.target, inst.selectedMonth, inst.selectedYear,
							$('td.ui-datepicker-days-cell-over', inst.dpDiv)[0]);
						return false; // don't submit the form
						break; // select the value on enter
				case 27: $.datepicker._hideDatepicker(null, $.datepicker._get(inst, 'duration'));
						break; // hide on escape
				case 33: $.datepicker._adjustDate(e.target, (e.ctrlKey ? -1 :
							-$.datepicker._get(inst, 'stepMonths')), (e.ctrlKey ? 'Y' : 'M'));
						break; // previous month/year on page up/+ ctrl
				case 34: $.datepicker._adjustDate(e.target, (e.ctrlKey ? +1 :
							+$.datepicker._get(inst, 'stepMonths')), (e.ctrlKey ? 'Y' : 'M'));
						break; // next month/year on page down/+ ctrl
				case 35: if (e.ctrlKey) $.datepicker._clearDate(e.target);
						break; // clear on ctrl+end
				case 36: if (e.ctrlKey) $.datepicker._gotoToday(e.target);
						break; // current on ctrl+home
				case 37: if (e.ctrlKey) $.datepicker._adjustDate(e.target, -1, 'D');
						break; // -1 day on ctrl+left
				case 38: if (e.ctrlKey) $.datepicker._adjustDate(e.target, -7, 'D');
						break; // -1 week on ctrl+up
				case 39: if (e.ctrlKey) $.datepicker._adjustDate(e.target, +1, 'D');
						break; // +1 day on ctrl+right
				case 40: if (e.ctrlKey) $.datepicker._adjustDate(e.target, +7, 'D');
						break; // +1 week on ctrl+down
				default: handled = false;
			}
		else if (e.keyCode == 36 && e.ctrlKey) // display the date picker on ctrl+home
			$.datepicker._showDatepicker(this);
		else
			handled = false;
		if (handled) {
			e.preventDefault();
			e.stopPropagation();
		}
	},

	/* Filter entered characters - based on date format. */
	_doKeyPress: function(e) {
		var inst = $.data(e.target, PROP_NAME);
		var chars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat'));
		var chr = String.fromCharCode(e.charCode == undefined ? e.keyCode : e.charCode);
		return e.ctrlKey || (chr < ' ' || !chars || chars.indexOf(chr) > -1);
	},

	/* Pop-up the date picker for a given input field.
	   @param  input  element - the input field attached to the date picker or
	                  event - if triggered by focus */
	_showDatepicker: function(input) {
		input = input.target || input;
		if (input.nodeName.toLowerCase() != 'input') // find from button/image trigger
			input = $('input', input.parentNode)[0];
		if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput == input) // already here
			return;
		var inst = $.data(input, PROP_NAME);
		var beforeShow = $.datepicker._get(inst, 'beforeShow');
		extendRemove(inst.settings, (beforeShow ? beforeShow.apply(input, [input, inst]) : {}));
		$.datepicker._hideDatepicker(null, '');
		$.datepicker._lastInput = input;
		$.datepicker._setDateFromField(inst);
		if ($.datepicker._inDialog) // hide cursor
			input.value = '';
		if (!$.datepicker._pos) { // position below input
			$.datepicker._pos = $.datepicker._findPos(input);
			$.datepicker._pos[1] += input.offsetHeight; // add the height
		}
		var isFixed = false;
		$(input).parents().each(function() {
			isFixed |= $(this).css('position') == 'fixed';
			return !isFixed;
		});
		if (isFixed && $.browser.opera) { // correction for Opera when fixed and scrolled
			$.datepicker._pos[0] -= document.documentElement.scrollLeft;
			$.datepicker._pos[1] -= document.documentElement.scrollTop;
		}
		var offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
		$.datepicker._pos = null;
		inst.rangeStart = null;
		// determine sizing offscreen
		inst.dpDiv.css({position: 'absolute', display: 'block', top: '-1000px'});
		$.datepicker._updateDatepicker(inst);
		// fix width for dynamic number of date pickers
		inst.dpDiv.width($.datepicker._getNumberOfMonths(inst)[1] *
			$('.ui-datepicker', inst.dpDiv[0])[0].offsetWidth);
		// and adjust position before showing
		offset = $.datepicker._checkOffset(inst, offset, isFixed);
		inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
			'static' : (isFixed ? 'fixed' : 'absolute')), display: 'none',
			left: offset.left + 'px', top: offset.top + 'px'});
		if (!inst.inline) {
			var showAnim = $.datepicker._get(inst, 'showAnim') || 'show';
			var duration = $.datepicker._get(inst, 'duration');
			var postProcess = function() {
				$.datepicker._datepickerShowing = true;
				if ($.browser.msie && parseInt($.browser.version) < 7) // fix IE < 7 select problems
					$('iframe.ui-datepicker-cover').css({width: inst.dpDiv.width() + 4,
						height: inst.dpDiv.height() + 4});
			};
			if ($.effects && $.effects[showAnim])
				inst.dpDiv.show(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess);
			else
				inst.dpDiv[showAnim](duration, postProcess);
			if (duration == '')
				postProcess();
			if (inst.input[0].type != 'hidden')
				inst.input[0].focus();
			$.datepicker._curInst = inst;
		}
	},

	/* Generate the date picker content. */
	_updateDatepicker: function(inst) {
		var dims = {width: inst.dpDiv.width() + 4,
			height: inst.dpDiv.height() + 4};
		inst.dpDiv.empty().append(this._generateDatepicker(inst)).
			find('iframe.ui-datepicker-cover').
			css({width: dims.width, height: dims.height});
		var numMonths = this._getNumberOfMonths(inst);
		inst.dpDiv[(numMonths[0] != 1 || numMonths[1] != 1 ? 'add' : 'remove') +
			'Class']('ui-datepicker-multi');
		inst.dpDiv[(this._get(inst, 'isRTL') ? 'add' : 'remove') +
			'Class']('ui-datepicker-rtl');
		if (inst.input && inst.input[0].type != 'hidden')
			$(inst.input[0]).focus();
	},

	/* Check positioning to remain on screen. */
	_checkOffset: function(inst, offset, isFixed) {
		var pos = inst.input ? this._findPos(inst.input[0]) : null;
		var browserWidth = window.innerWidth || document.documentElement.clientWidth;
		var browserHeight = window.innerHeight || document.documentElement.clientHeight;
		var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
		var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
		// reposition date picker horizontally if outside the browser window
		if (this._get(inst, 'isRTL') || (offset.left + inst.dpDiv.width() - scrollX) > browserWidth)
			offset.left = Math.max((isFixed ? 0 : scrollX),
				pos[0] + (inst.input ? inst.input.width() : 0) - (isFixed ? scrollX : 0) - inst.dpDiv.width() -
				(isFixed && $.browser.opera ? document.documentElement.scrollLeft : 0));
		else
			offset.left -= (isFixed ? scrollX : 0);
		// reposition date picker vertically if outside the browser window
		if ((offset.top + inst.dpDiv.height() - scrollY) > browserHeight)
			offset.top = Math.max((isFixed ? 0 : scrollY),
				pos[1] - (isFixed ? scrollY : 0) - (this._inDialog ? 0 : inst.dpDiv.height()) -
				(isFixed && $.browser.opera ? document.documentElement.scrollTop : 0));
		else
			offset.top -= (isFixed ? scrollY : 0);
		return offset;
	},
	
	/* Find an object's position on the screen. */
	_findPos: function(obj) {
        while (obj && (obj.type == 'hidden' || obj.nodeType != 1)) {
            obj = obj.nextSibling;
        }
        var position = $(obj).offset();
	    return [position.left, position.top];
	},

	/* Hide the date picker from view.
	   @param  input  element - the input field attached to the date picker
	   @param  duration  string - the duration over which to close the date picker */
	_hideDatepicker: function(input, duration) {
		var inst = this._curInst;
		if (!inst)
			return;
		var rangeSelect = this._get(inst, 'rangeSelect');
		if (rangeSelect && this._stayOpen)
			this._selectDate('#' + inst.id, this._formatDate(inst,
				inst.currentDay, inst.currentMonth, inst.currentYear));
		this._stayOpen = false;
		if (this._datepickerShowing) {
			duration = (duration != null ? duration : this._get(inst, 'duration'));
			var showAnim = this._get(inst, 'showAnim');
			var postProcess = function() {
				$.datepicker._tidyDialog(inst);
			};
			if (duration != '' && $.effects && $.effects[showAnim])
				inst.dpDiv.hide(showAnim, $.datepicker._get(inst, 'showOptions'),
					duration, postProcess);
			else
				inst.dpDiv[(duration == '' ? 'hide' : (showAnim == 'slideDown' ? 'slideUp' :
					(showAnim == 'fadeIn' ? 'fadeOut' : 'hide')))](duration, postProcess);
			if (duration == '')
				this._tidyDialog(inst);
			var onClose = this._get(inst, 'onClose');
			if (onClose)
				onClose.apply((inst.input ? inst.input[0] : null),
					[this._getDate(inst), inst]);  // trigger custom callback
			this._datepickerShowing = false;
			this._lastInput = null;
			inst.settings.prompt = null;
			if (this._inDialog) {
				this._dialogInput.css({ position: 'absolute', left: '0', top: '-100px' });
				if ($.blockUI) {
					$.unblockUI();
					$('body').append(this.dpDiv);
				}
			}
			this._inDialog = false;
		}
		this._curInst = null;
	},

	/* Tidy up after a dialog display. */
	_tidyDialog: function(inst) {
		inst.dpDiv.removeClass(this._dialogClass).unbind('.ui-datepicker');
		$('.' + this._promptClass, inst.dpDiv).remove();
	},

	/* Close date picker if clicked elsewhere. */
	_checkExternalClick: function(event) {
		if (!$.datepicker._curInst)
			return;
		var $target = $(event.target);
		if (($target.parents('#' + $.datepicker._mainDivId).length == 0) &&
				!$target.hasClass($.datepicker.markerClassName) &&
				!$target.hasClass($.datepicker._triggerClass) &&
				$.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI))
			$.datepicker._hideDatepicker(null, '');
	},

	/* Adjust one of the date sub-fields. */
	_adjustDate: function(id, offset, period) {
		var target = $(id);
		var inst = $.data(target[0], PROP_NAME);
		this._adjustInstDate(inst, offset, period);
		this._updateDatepicker(inst);
	},

	/* Action for current link. */
	_gotoToday: function(id) {
		var target = $(id);
		var inst = $.data(target[0], PROP_NAME);
		if (this._get(inst, 'gotoCurrent') && inst.currentDay) {
			inst.selectedDay = inst.currentDay;
			inst.drawMonth = inst.selectedMonth = inst.currentMonth;
			inst.drawYear = inst.selectedYear = inst.currentYear;
		}
		else {
		var date = new Date();
		inst.selectedDay = date.getDate();
		inst.drawMonth = inst.selectedMonth = date.getMonth();
		inst.drawYear = inst.selectedYear = date.getFullYear();
		}
		this._adjustDate(target);
		this._notifyChange(inst);
	},

	/* Action for selecting a new month/year. */
	_selectMonthYear: function(id, select, period) {
		var target = $(id);
		var inst = $.data(target[0], PROP_NAME);
		inst._selectingMonthYear = false;
		inst[period == 'M' ? 'drawMonth' : 'drawYear'] =
			select.options[select.selectedIndex].value - 0;
		this._adjustDate(target);
		this._notifyChange(inst);
	},

	/* Restore input focus after not changing month/year. */
	_clickMonthYear: function(id) {
		var target = $(id);
		var inst = $.data(target[0], PROP_NAME);
		if (inst.input && inst._selectingMonthYear && !$.browser.msie)
			inst.input[0].focus();
		inst._selectingMonthYear = !inst._selectingMonthYear;
	},

	/* Action for changing the first week day. */
	_changeFirstDay: function(id, day) {
		var target = $(id);
		var inst = $.data(target[0], PROP_NAME);
		inst.settings.firstDay = day;
		this._updateDatepicker(inst);
	},

	/* Action for selecting a day. */
	_selectDay: function(id, month, year, td) {
		if ($(td).hasClass(this._unselectableClass))
			return;
		var target = $(id);
		var inst = $.data(target[0], PROP_NAME);
		var rangeSelect = this._get(inst, 'rangeSelect');
		if (rangeSelect) {
			this._stayOpen = !this._stayOpen;
			if (this._stayOpen) {
				$('.ui-datepicker td').removeClass(this._currentClass);
				$(td).addClass(this._currentClass);
			} 
		}
		inst.selectedDay = inst.currentDay = $('a', td).html();
		inst.selectedMonth = inst.currentMonth = month;
		inst.selectedYear = inst.currentYear = year;
		if (this._stayOpen) {
			inst.endDay = inst.endMonth = inst.endYear = null;
		}
		else if (rangeSelect) {
			inst.endDay = inst.currentDay;
			inst.endMonth = inst.currentMonth;
			inst.endYear = inst.currentYear;
		}
		this._selectDate(id, this._formatDate(inst,
			inst.currentDay, inst.currentMonth, inst.currentYear));
		if (this._stayOpen) {
			inst.rangeStart = this._daylightSavingAdjust(
				new Date(inst.currentYear, inst.currentMonth, inst.currentDay));
			this._updateDatepicker(inst);
		}
		else if (rangeSelect) {
			inst.selectedDay = inst.currentDay = inst.rangeStart.getDate();
			inst.selectedMonth = inst.currentMonth = inst.rangeStart.getMonth();
			inst.selectedYear = inst.currentYear = inst.rangeStart.getFullYear();
			inst.rangeStart = null;
			if (inst.inline)
				this._updateDatepicker(inst);
		}
	},

	/* Erase the input field and hide the date picker. */
	_clearDate: function(id) {
		var target = $(id);
		var inst = $.data(target[0], PROP_NAME);
		if (this._get(inst, 'mandatory'))
			return;
		this._stayOpen = false;
		inst.endDay = inst.endMonth = inst.endYear = inst.rangeStart = null;
		this._selectDate(target, '');
	},

	/* Update the input field with the selected date. */
	_selectDate: function(id, dateStr) {
		var target = $(id);
		var inst = $.data(target[0], PROP_NAME);
		dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
		if (this._get(inst, 'rangeSelect') && dateStr)
			dateStr = (inst.rangeStart ? this._formatDate(inst, inst.rangeStart) :
				dateStr) + this._get(inst, 'rangeSeparator') + dateStr;
		if (inst.input)
			inst.input.val(dateStr);
		this._updateAlternate(inst);
		var onSelect = this._get(inst, 'onSelect');
		if (onSelect)
			onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);  // trigger custom callback
		else if (inst.input)
			inst.input.trigger('change'); // fire the change event
		if (inst.inline)
			this._updateDatepicker(inst);
		else if (!this._stayOpen) {
			this._hideDatepicker(null, this._get(inst, 'duration'));
			this._lastInput = inst.input[0];
			if (typeof(inst.input[0]) != 'object')
				inst.input[0].focus(); // restore focus
			this._lastInput = null;
		}
	},
	
	/* Update any alternate field to synchronise with the main field. */
	_updateAlternate: function(inst) {
		var altField = this._get(inst, 'altField');
		if (altField) { // update alternate field too
			var altFormat = this._get(inst, 'altFormat');
			var date = this._getDate(inst);
			dateStr = (isArray(date) ? (!date[0] && !date[1] ? '' :
				this.formatDate(altFormat, date[0], this._getFormatConfig(inst)) +
				this._get(inst, 'rangeSeparator') + this.formatDate(
				altFormat, date[1] || date[0], this._getFormatConfig(inst))) :
				this.formatDate(altFormat, date, this._getFormatConfig(inst)));
			$(altField).each(function() { $(this).val(dateStr); });
		}
	},

	/* Set as beforeShowDay function to prevent selection of weekends.
	   @param  date  Date - the date to customise
	   @return [boolean, string] - is this date selectable?, what is its CSS class? */
	noWeekends: function(date) {
		var day = date.getDay();
		return [(day > 0 && day < 6), ''];
	},
	
	/* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
	   @param  date  Date - the date to get the week for
	   @return  number - the number of the week within the year that contains this date */
	iso8601Week: function(date) {
		var checkDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
		var firstMon = new Date(checkDate.getFullYear(), 1 - 1, 4); // First week always contains 4 Jan
		var firstDay = firstMon.getDay() || 7; // Day of week: Mon = 1, ..., Sun = 7
		firstMon.setDate(firstMon.getDate() + 1 - firstDay); // Preceding Monday
		if (firstDay < 4 && checkDate < firstMon) { // Adjust first three days in year if necessary
			checkDate.setDate(checkDate.getDate() - 3); // Generate for previous year
			return $.datepicker.iso8601Week(checkDate);
		} else if (checkDate > new Date(checkDate.getFullYear(), 12 - 1, 28)) { // Check last three days in year
			firstDay = new Date(checkDate.getFullYear() + 1, 1 - 1, 4).getDay() || 7;
			if (firstDay > 4 && (checkDate.getDay() || 7) < firstDay - 3) { // Adjust if necessary
				checkDate.setDate(checkDate.getDate() + 3); // Generate for next year
				return $.datepicker.iso8601Week(checkDate);
			}
		}
		return Math.floor(((checkDate - firstMon) / 86400000) / 7) + 1; // Weeks to given date
	},
	
	/* Provide status text for a particular date.
	   @param  date  the date to get the status for
	   @param  inst  the current datepicker instance
	   @return  the status display text for this date */
	dateStatus: function(date, inst) {
		return $.datepicker.formatDate($.datepicker._get(inst, 'dateStatus'),
			date, $.datepicker._getFormatConfig(inst));
	},

	/* Parse a string value into a date object.
	   See formatDate below for the possible formats.

	   @param  format    string - the expected format of the date
	   @param  value     string - the date in the above format
	   @param  settings  Object - attributes include:
	                     shortYearCutoff  number - the cutoff year for determining the century (optional)
	                     dayNamesShort    string[7] - abbreviated names of the days from Sunday (optional)
	                     dayNames         string[7] - names of the days from Sunday (optional)
	                     monthNamesShort  string[12] - abbreviated names of the months (optional)
	                     monthNames       string[12] - names of the months (optional)
	   @return  Date - the extracted date value or null if value is blank */
	parseDate: function (format, value, settings) {
		if (format == null || value == null)
			throw 'Invalid arguments';
		value = (typeof value == 'object' ? value.toString() : value + '');
		if (value == '')
			return null;
		var shortYearCutoff = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff;
		var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort;
		var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames;
		var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort;
		var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames;
		var year = -1;
		var month = -1;
		var day = -1;
		var literal = false;
		// Check whether a format character is doubled
		var lookAhead = function(match) {
			var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
			if (matches)
				iFormat++;
			return matches;	
		};
		// Extract a number from the string value
		var getNumber = function(match) {
			lookAhead(match);
			var origSize = (match == '@' ? 14 : (match == 'y' ? 4 : 2));
			var size = origSize;
			var num = 0;
			while (size > 0 && iValue < value.length &&
					value.charAt(iValue) >= '0' && value.charAt(iValue) <= '9') {
				num = num * 10 + (value.charAt(iValue++) - 0);
				size--;
			}
			if (size == origSize)
				throw 'Missing number at position ' + iValue;
			return num;
		};
		// Extract a name from the string value and convert to an index
		var getName = function(match, shortNames, longNames) {
			var names = (lookAhead(match) ? longNames : shortNames);
			var size = 0;
			for (var j = 0; j < names.length; j++)
				size = Math.max(size, names[j].length);
			var name = '';
			var iInit = iValue;
			while (size > 0 && iValue < value.length) {
				name += value.charAt(iValue++);
				for (var i = 0; i < names.length; i++)
					if (name == names[i])
						return i + 1;
				size--;
			}
			throw 'Unknown name at position ' + iInit;
		};
		// Confirm that a literal character matches the string value
		var checkLiteral = function() {
			if (value.charAt(iValue) != format.charAt(iFormat))
				throw 'Unexpected literal at position ' + iValue;
			iValue++;
		};
		var iValue = 0;
		for (var iFormat = 0; iFormat < format.length; iFormat++) {
			if (literal)
				if (format.charAt(iFormat) == "'" && !lookAhead("'"))
					literal = false;
				else
					checkLiteral();
			else
				switch (format.charAt(iFormat)) {
					case 'd':
						day = getNumber('d');
						break;
					case 'D': 
						getName('D', dayNamesShort, dayNames);
						break;
					case 'm': 
						month = getNumber('m');
						break;
					case 'M':
						month = getName('M', monthNamesShort, monthNames); 
						break;
					case 'y':
						year = getNumber('y');
						break;
					case '@':
						var date = new Date(getNumber('@'));
						year = date.getFullYear();
						month = date.getMonth() + 1;
						day = date.getDate();
						break;
					case "'":
						if (lookAhead("'"))
							checkLiteral();
						else
							literal = true;
						break;
					default:
						checkLiteral();
				}
		}
		if (year < 100)
			year += new Date().getFullYear() - new Date().getFullYear() % 100 +
				(year <= shortYearCutoff ? 0 : -100);
		var date = this._daylightSavingAdjust(new Date(year, month - 1, day));
		if (date.getFullYear() != year || date.getMonth() + 1 != month || date.getDate() != day)
			throw 'Invalid date'; // E.g. 31/02/*
		return date;
	},

	/* Standard date formats. */
	ATOM: 'yy-mm-dd', // RFC 3339 (ISO 8601)
	COOKIE: 'D, dd M yy',
	ISO_8601: 'yy-mm-dd',
	RFC_822: 'D, d M y',
	RFC_850: 'DD, dd-M-y',
	RFC_1036: 'D, d M y',
	RFC_1123: 'D, d M yy',
	RFC_2822: 'D, d M yy',
	RSS: 'D, d M y', // RFC 822
	TIMESTAMP: '@',
	W3C: 'yy-mm-dd', // ISO 8601

	/* Format a date object into a string value.
	   The format can be combinations of the following:
	   d  - day of month (no leading zero)
	   dd - day of month (two digit)
	   D  - day name short
	   DD - day name long
	   m  - month of year (no leading zero)
	   mm - month of year (two digit)
	   M  - month name short
	   MM - month name long
	   y  - year (two digit)
	   yy - year (four digit)
	   @ - Unix timestamp (ms since 01/01/1970)
	   '...' - literal text
	   '' - single quote

	   @param  format    string - the desired format of the date
	   @param  date      Date - the date value to format
	   @param  settings  Object - attributes include:
	                     dayNamesShort    string[7] - abbreviated names of the days from Sunday (optional)
	                     dayNames         string[7] - names of the days from Sunday (optional)
	                     monthNamesShort  string[12] - abbreviated names of the months (optional)
	                     monthNames       string[12] - names of the months (optional)
	   @return  string - the date in the above format */
	formatDate: function (format, date, settings) {
		if (!date)
			return '';
		var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort;
		var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames;
		var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort;
		var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames;
		// Check whether a format character is doubled
		var lookAhead = function(match) {
			var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
			if (matches)
				iFormat++;
			return matches;	
		};
		// Format a number, with leading zero if necessary
		var formatNumber = function(match, value) {
			return (lookAhead(match) && value < 10 ? '0' : '') + value;
		};
		// Format a name, short or long as requested
		var formatName = function(match, value, shortNames, longNames) {
			return (lookAhead(match) ? longNames[value] : shortNames[value]);
		};
		var output = '';
		var literal = false;
		if (date)
			for (var iFormat = 0; iFormat < format.length; iFormat++) {
				if (literal)
					if (format.charAt(iFormat) == "'" && !lookAhead("'"))
						literal = false;
					else
						output += format.charAt(iFormat);
				else
					switch (format.charAt(iFormat)) {
						case 'd':
							output += formatNumber('d', date.getDate()); 
							break;
						case 'D': 
							output += formatName('D', date.getDay(), dayNamesShort, dayNames);
							break;
						case 'm': 
							output += formatNumber('m', date.getMonth() + 1); 
							break;
						case 'M':
							output += formatName('M', date.getMonth(), monthNamesShort, monthNames); 
							break;
						case 'y':
							output += (lookAhead('y') ? date.getFullYear() : 
								(date.getYear() % 100 < 10 ? '0' : '') + date.getYear() % 100);
							break;
						case '@':
							output += date.getTime(); 
							break;
						case "'":
							if (lookAhead("'"))
								output += "'";
							else
								literal = true;
							break;
						default:
							output += format.charAt(iFormat);
					}
			}
		return output;
	},

	/* Extract all possible characters from the date format. */
	_possibleChars: function (format) {
		var chars = '';
		var literal = false;
		for (var iFormat = 0; iFormat < format.length; iFormat++)
			if (literal)
				if (format.charAt(iFormat) == "'" && !lookAhead("'"))
					literal = false;
				else
					chars += format.charAt(iFormat);
			else
				switch (format.charAt(iFormat)) {
					case 'd': case 'm': case 'y': case '@':
						chars += '0123456789'; 
						break;
					case 'D': case 'M':
						return null; // Accept anything
					case "'":
						if (lookAhead("'"))
							chars += "'";
						else
							literal = true;
						break;
					default:
						chars += format.charAt(iFormat);
				}
		return chars;
	},

	/* Get a setting value, defaulting if necessary. */
	_get: function(inst, name) {
		return inst.settings[name] !== undefined ?
			inst.settings[name] : this._defaults[name];
	},

	/* Parse existing date and initialise date picker. */
	_setDateFromField: function(inst) {
		var dateFormat = this._get(inst, 'dateFormat');
		var dates = inst.input ? inst.input.val().split(this._get(inst, 'rangeSeparator')) : null; 
		inst.endDay = inst.endMonth = inst.endYear = null;
		var date = defaultDate = this._getDefaultDate(inst);
		if (dates.length > 0) {
			var settings = this._getFormatConfig(inst);
			if (dates.length > 1) {
				date = this.parseDate(dateFormat, dates[1], settings) || defaultDate;
				inst.endDay = date.getDate();
				inst.endMonth = date.getMonth();
				inst.endYear = date.getFullYear();
			}
			try {
				date = this.parseDate(dateFormat, dates[0], settings) || defaultDate;
			} catch (e) {
				this.log(e);
				date = defaultDate;
			}
		}
		inst.selectedDay = date.getDate();
		inst.drawMonth = inst.selectedMonth = date.getMonth();
		inst.drawYear = inst.selectedYear = date.getFullYear();
		inst.currentDay = (dates[0] ? date.getDate() : 0);
		inst.currentMonth = (dates[0] ? date.getMonth() : 0);
		inst.currentYear = (dates[0] ? date.getFullYear() : 0);
		this._adjustInstDate(inst);
	},
	
	/* Retrieve the default date shown on opening. */
	_getDefaultDate: function(inst) {
		var date = this._determineDate(this._get(inst, 'defaultDate'), new Date());
		var minDate = this._getMinMaxDate(inst, 'min', true);
		var maxDate = this._getMinMaxDate(inst, 'max');
		date = (minDate && date < minDate ? minDate : date);
		date = (maxDate && date > maxDate ? maxDate : date);
		return date;
	},

	/* A date may be specified as an exact value or a relative one. */
	_determineDate: function(date, defaultDate) {
		var offsetNumeric = function(offset) {
			var date = new Date();
			date.setDate(date.getDate() + offset);
			return date;
		};
		var offsetString = function(offset, getDaysInMonth) {
			var date = new Date();
			var year = date.getFullYear();
			var month = date.getMonth();
			var day = date.getDate();
			var pattern = /([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g;
			var matches = pattern.exec(offset);
			while (matches) {
				switch (matches[2] || 'd') {
					case 'd' : case 'D' :
						day += (matches[1] - 0); break;
					case 'w' : case 'W' :
						day += (matches[1] * 7); break;
					case 'm' : case 'M' :
						month += (matches[1] - 0); 
						day = Math.min(day, getDaysInMonth(year, month));
						break;
					case 'y': case 'Y' :
						year += (matches[1] - 0);
						day = Math.min(day, getDaysInMonth(year, month));
						break;
				}
				matches = pattern.exec(offset);
			}
			return new Date(year, month, day);
		};
		date = (date == null ? defaultDate :
			(typeof date == 'string' ? offsetString(date, this._getDaysInMonth) :
			(typeof date == 'number' ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : date)));
		date = (date && date.toString() == 'Invalid Date' ? defaultDate : date);
		if (date) {
			date.setHours(0);
			date.setMinutes(0);
			date.setSeconds(0);
			date.setMilliseconds(0);
		}
		return this._daylightSavingAdjust(date);
	},

	/* Handle switch to/from daylight saving.
	   Hours may be non-zero on daylight saving cut-over:
	   > 12 when midnight changeover, but then cannot generate 
	   midnight datetime, so jump to 1AM, otherwise reset.
	   @param  date  (Date) the date to check
	   @return  (Date) the corrected date */
	_daylightSavingAdjust: function(date) {
		if (!date) return null;
		date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
		return date;
	},

	/* Set the date(s) directly. */
	_setDate: function(inst, date, endDate) {
		var clear = !(date);
		date = this._determineDate(date, new Date());
		inst.selectedDay = inst.currentDay = date.getDate();
		inst.drawMonth = inst.selectedMonth = inst.currentMonth = date.getMonth();
		inst.drawYear = inst.selectedYear = inst.currentYear = date.getFullYear();
		if (this._get(inst, 'rangeSelect')) {
			if (endDate) {
				endDate = this._determineDate(endDate, null);
				inst.endDay = endDate.getDate();
				inst.endMonth = endDate.getMonth();
				inst.endYear = endDate.getFullYear();
			} else {
				inst.endDay = inst.currentDay;
				inst.endMonth = inst.currentMonth;
				inst.endYear = inst.currentYear;
			}
		}
		this._adjustInstDate(inst);
		if (inst.input)
			inst.input.val(clear ? '' : this._formatDate(inst) +
				(!this._get(inst, 'rangeSelect') ? '' : this._get(inst, 'rangeSeparator') +
				this._formatDate(inst, inst.endDay, inst.endMonth, inst.endYear)));
	},

	/* Retrieve the date(s) directly. */
	_getDate: function(inst) {
		var startDate = (!inst.currentYear || (inst.input && inst.input.val() == '') ? null :
			this._daylightSavingAdjust(new Date(
			inst.currentYear, inst.currentMonth, inst.currentDay)));
		if (this._get(inst, 'rangeSelect')) {
			return [inst.rangeStart || startDate,
				(!inst.endYear ? inst.rangeStart || startDate :
				this._daylightSavingAdjust(new Date(inst.endYear, inst.endMonth, inst.endDay)))];
		} else
			return startDate;
	},

	/* Generate the HTML for the current state of the date picker. */
	_generateDatepicker: function(inst) {
		var today = new Date();
		today = this._daylightSavingAdjust(
			new Date(today.getFullYear(), today.getMonth(), today.getDate())); // clear time
		var showStatus = this._get(inst, 'showStatus');
		var isRTL = this._get(inst, 'isRTL');
		// build the date picker HTML
		var clear = (this._get(inst, 'mandatory') ? '' :
			'<div class="ui-datepicker-clear"><a onclick="jQuery.datepicker._clearDate(\'#' + inst.id + '\');"' +
			(showStatus ? this._addStatus(inst, this._get(inst, 'clearStatus') || '&#xa0;') : '') + '>' +
			this._get(inst, 'clearText') + '</a></div>');
		var controls = '<div class="ui-datepicker-control">' + (isRTL ? '' : clear) +
			'<div class="ui-datepicker-close"><a onclick="jQuery.datepicker._hideDatepicker();"' +
			(showStatus ? this._addStatus(inst, this._get(inst, 'closeStatus') || '&#xa0;') : '') + '>' +
			this._get(inst, 'closeText') + '</a></div>' + (isRTL ? clear : '')  + '</div>';
		var prompt = this._get(inst, 'prompt');
		var closeAtTop = this._get(inst, 'closeAtTop');
		var hideIfNoPrevNext = this._get(inst, 'hideIfNoPrevNext');
		var navigationAsDateFormat = this._get(inst, 'navigationAsDateFormat');
		var numMonths = this._getNumberOfMonths(inst);
		var stepMonths = this._get(inst, 'stepMonths');
		var isMultiMonth = (numMonths[0] != 1 || numMonths[1] != 1);
		var currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
			new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
		var minDate = this._getMinMaxDate(inst, 'min', true);
		var maxDate = this._getMinMaxDate(inst, 'max');
		var drawMonth = inst.drawMonth;
		var drawYear = inst.drawYear;
		if (maxDate) {
			var maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
				maxDate.getMonth() - numMonths[1] + 1, maxDate.getDate()));
			maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
			while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
				drawMonth--;
				if (drawMonth < 0) {
					drawMonth = 11;
					drawYear--;
				}
			}
		}
		// controls and links
		var prevText = this._get(inst, 'prevText');
		prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
			this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
			this._getFormatConfig(inst)));
		var prev = '<div class="ui-datepicker-prev">' + (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ? 
			'<a onclick="jQuery.datepicker._adjustDate(\'#' + inst.id + '\', -' + stepMonths + ', \'M\');"' +
			(showStatus ? this._addStatus(inst, this._get(inst, 'prevStatus') || '&#xa0;') : '') + '>' + prevText + '</a>' :
			(hideIfNoPrevNext ? '' : '<label>' + prevText + '</label>')) + '</div>';
		var nextText = this._get(inst, 'nextText');
		nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
			this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
			this._getFormatConfig(inst)));
		var next = '<div class="ui-datepicker-next">' + (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
			'<a onclick="jQuery.datepicker._adjustDate(\'#' + inst.id + '\', +' + stepMonths + ', \'M\');"' +
			(showStatus ? this._addStatus(inst, this._get(inst, 'nextStatus') || '&#xa0;') : '') + '>' + nextText + '</a>' :
			(hideIfNoPrevNext ? '' : '<label>' + nextText + '</label>')) + '</div>';
		var currentText = this._get(inst, 'currentText');
		currentText = (!navigationAsDateFormat ? currentText: this.formatDate(
			currentText, today, this._getFormatConfig(inst)));
		var html = (prompt ? '<div class="' + this._promptClass + '">' + prompt + '</div>' : '') +
			(closeAtTop && !inst.inline ? controls : '') +
			'<div class="ui-datepicker-links">' + (isRTL ? next : prev) +
			(this._isInRange(inst, (this._get(inst, 'gotoCurrent') && inst.currentDay ?
			currentDate : today)) ? '<div class="ui-datepicker-current">' +
			'<a onclick="jQuery.datepicker._gotoToday(\'#' + inst.id + '\');"' +
			(showStatus ? this._addStatus(inst, this._get(inst, 'currentStatus') || '&#xa0;') : '') + '>' +
			currentText + '</a></div>' : '') + (isRTL ? prev : next) + '</div>';
		var firstDay = this._get(inst, 'firstDay');
		var changeFirstDay = this._get(inst, 'changeFirstDay');
		var dayNames = this._get(inst, 'dayNames');
		var dayNamesShort = this._get(inst, 'dayNamesShort');
		var dayNamesMin = this._get(inst, 'dayNamesMin');
		var monthNames = this._get(inst, 'monthNames');
		var beforeShowDay = this._get(inst, 'beforeShowDay');
		var highlightWeek = this._get(inst, 'highlightWeek');
		var showOtherMonths = this._get(inst, 'showOtherMonths');
		var showWeeks = this._get(inst, 'showWeeks');
		var calculateWeek = this._get(inst, 'calculateWeek') || this.iso8601Week;
		var status = (showStatus ? this._get(inst, 'dayStatus') || '&#xa0;' : '');
		var dateStatus = this._get(inst, 'statusForDate') || this.dateStatus;
		var endDate = inst.endDay ? this._daylightSavingAdjust(
			new Date(inst.endYear, inst.endMonth, inst.endDay)) : currentDate;
		for (var row = 0; row < numMonths[0]; row++)
			for (var col = 0; col < numMonths[1]; col++) {
				var selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
				html += '<div class="ui-datepicker-one-month' + (col == 0 ? ' ui-datepicker-new-row' : '') + '">' +
					this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
					selectedDate, row > 0 || col > 0, showStatus, monthNames) + // draw month headers
					'<table class="ui-datepicker" cellpadding="0" cellspacing="0"><thead>' + 
					'<tr class="ui-datepicker-title-row">' +
					(showWeeks ? '<td>' + this._get(inst, 'weekHeader') + '</td>' : '');
				for (var dow = 0; dow < 7; dow++) { // days of the week
					var day = (dow + firstDay) % 7;
					var dayStatus = (status.indexOf('DD') > -1 ? status.replace(/DD/, dayNames[day]) :
						status.replace(/D/, dayNamesShort[day]));
					html += '<td' + ((dow + firstDay + 6) % 7 >= 5 ? ' class="ui-datepicker-week-end-cell"' : '') + '>' +
						(!changeFirstDay ? '<span' :
						'<a onclick="jQuery.datepicker._changeFirstDay(\'#' + inst.id + '\', ' + day + ');"') + 
						(showStatus ? this._addStatus(inst, dayStatus) : '') + ' title="' + dayNames[day] + '">' +
						dayNamesMin[day] + (changeFirstDay ? '</a>' : '</span>') + '</td>';
				}
				html += '</tr></thead><tbody>';
				var daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
				if (drawYear == inst.selectedYear && drawMonth == inst.selectedMonth)
					inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
				var leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
				var numRows = (isMultiMonth ? 6 : Math.ceil((leadDays + daysInMonth) / 7)); // calculate the number of rows to generate
				var printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
				for (var dRow = 0; dRow < numRows; dRow++) { // create date picker rows
					html += '<tr class="ui-datepicker-days-row">' +
						(showWeeks ? '<td class="ui-datepicker-week-col">' + calculateWeek(printDate) + '</td>' : '');
					for (var dow = 0; dow < 7; dow++) { // create date picker days
						var daySettings = (beforeShowDay ?
							beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, '']);
						var otherMonth = (printDate.getMonth() != drawMonth);
						var unselectable = otherMonth || !daySettings[0] ||
							(minDate && printDate < minDate) || (maxDate && printDate > maxDate);
						html += '<td class="ui-datepicker-days-cell' +
							((dow + firstDay + 6) % 7 >= 5 ? ' ui-datepicker-week-end-cell' : '') + // highlight weekends
							(otherMonth ? ' ui-datepicker-otherMonth' : '') + // highlight days from other months
							(printDate.getTime() == selectedDate.getTime() && drawMonth == inst.selectedMonth ?
							' ui-datepicker-days-cell-over' : '') + // highlight selected day
							(unselectable ? ' ' + this._unselectableClass : '') +  // highlight unselectable days
							(otherMonth && !showOtherMonths ? '' : ' ' + daySettings[1] + // highlight custom dates
							(printDate.getTime() >= currentDate.getTime() && printDate.getTime() <= endDate.getTime() ?  // in current range
							' ' + this._currentClass : '') + // highlight selected day
							(printDate.getTime() == today.getTime() ? ' ui-datepicker-today' : '')) + '"' + // highlight today (if different)
							((!otherMonth || showOtherMonths) && daySettings[2] ? ' title="' + daySettings[2] + '"' : '') + // cell title
							(unselectable ? (highlightWeek ? ' onmouseover="jQuery(this).parent().addClass(\'ui-datepicker-week-over\');"' + // highlight selection week
							' onmouseout="jQuery(this).parent().removeClass(\'ui-datepicker-week-over\');"' : '') : // unhighlight selection week
							' onmouseover="jQuery(this).addClass(\'ui-datepicker-days-cell-over\')' + // highlight selection
							(highlightWeek ? '.parent().addClass(\'ui-datepicker-week-over\')' : '') + ';' + // highlight selection week
							(!showStatus || (otherMonth && !showOtherMonths) ? '' : 'jQuery(\'#ui-datepicker-status-' +
							inst.id + '\').html(\'' + (dateStatus.apply((inst.input ? inst.input[0] : null),
							[printDate, inst]) || '&#xa0;') +'\');') + '"' +
							' onmouseout="jQuery(this).removeClass(\'ui-datepicker-days-cell-over\')' + // unhighlight selection
							(highlightWeek ? '.parent().removeClass(\'ui-datepicker-week-over\')' : '') + ';' + // unhighlight selection week
							(!showStatus || (otherMonth && !showOtherMonths) ? '' : 'jQuery(\'#ui-datepicker-status-' +
							inst.id + '\').html(\'&#xa0;\');') + '" onclick="jQuery.datepicker._selectDay(\'#' +
							inst.id + '\',' + drawMonth + ',' + drawYear + ', this);"') + '>' + // actions
							(otherMonth ? (showOtherMonths ? printDate.getDate() : '&#xa0;') : // display for other months
							(unselectable ? printDate.getDate() : '<a>' + printDate.getDate() + '</a>')) + '</td>'; // display for this month
						printDate.setDate(printDate.getDate() + 1);
						printDate = this._daylightSavingAdjust(printDate);
					}
					html += '</tr>';
				}
				drawMonth++;
				if (drawMonth > 11) {
					drawMonth = 0;
					drawYear++;
				}
				html += '</tbody></table></div>';
			}
		html += (showStatus ? '<div style="clear: both;"></div><div id="ui-datepicker-status-' + inst.id + 
			'" class="ui-datepicker-status">' + (this._get(inst, 'initStatus') || '&#xa0;') + '</div>' : '') +
			(!closeAtTop && !inst.inline ? controls : '') +
			'<div style="clear: both;"></div>' + 
			($.browser.msie && parseInt($.browser.version) < 7 && !inst.inline ? 
			'<iframe src="javascript:false;" class="ui-datepicker-cover"></iframe>' : '');
		return html;
	},
	
	/* Generate the month and year header. */
	_generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
			selectedDate, secondary, showStatus, monthNames) {
		minDate = (inst.rangeStart && minDate && selectedDate < minDate ? selectedDate : minDate);
		var html = '<div class="ui-datepicker-header">';
		// month selection
		if (secondary || !this._get(inst, 'changeMonth'))
			html += monthNames[drawMonth] + '&#xa0;';
		else {
			var inMinYear = (minDate && minDate.getFullYear() == drawYear);
			var inMaxYear = (maxDate && maxDate.getFullYear() == drawYear);
			html += '<select class="ui-datepicker-new-month" ' +
				'onchange="jQuery.datepicker._selectMonthYear(\'#' + inst.id + '\', this, \'M\');" ' +
				'onclick="jQuery.datepicker._clickMonthYear(\'#' + inst.id + '\');"' +
				(showStatus ? this._addStatus(inst, this._get(inst, 'monthStatus') || '&#xa0;') : '') + '>';
			for (var month = 0; month < 12; month++) {
				if ((!inMinYear || month >= minDate.getMonth()) &&
						(!inMaxYear || month <= maxDate.getMonth()))
					html += '<option value="' + month + '"' +
						(month == drawMonth ? ' selected="selected"' : '') +
						'>' + monthNames[month] + '</option>';
			}
			html += '</select>';
		}
		// year selection
		if (secondary || !this._get(inst, 'changeYear'))
			html += drawYear;
		else {
			// determine range of years to display
			var years = this._get(inst, 'yearRange').split(':');
			var year = 0;
			var endYear = 0;
			if (years.length != 2) {
				year = drawYear - 10;
				endYear = drawYear + 10;
			} else if (years[0].charAt(0) == '+' || years[0].charAt(0) == '-') {
				year = endYear = new Date().getFullYear();
				year += parseInt(years[0], 10);
				endYear += parseInt(years[1], 10);
			} else {
				year = parseInt(years[0], 10);
				endYear = parseInt(years[1], 10);
			}
			year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
			endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
			html += '<select class="ui-datepicker-new-year" ' +
				'onchange="jQuery.datepicker._selectMonthYear(\'#' + inst.id + '\', this, \'Y\');" ' +
				'onclick="jQuery.datepicker._clickMonthYear(\'#' + inst.id + '\');"' +
				(showStatus ? this._addStatus(inst, this._get(inst, 'yearStatus') || '&#xa0;') : '') + '>';
			for (; year <= endYear; year++) {
				html += '<option value="' + year + '"' +
					(year == drawYear ? ' selected="selected"' : '') +
					'>' + year + '</option>';
			}
			html += '</select>';
		}
		html += '</div>'; // Close datepicker_header
		return html;
	},

	/* Provide code to set and clear the status panel. */
	_addStatus: function(inst, text) {
		return ' onmouseover="jQuery(\'#ui-datepicker-status-' + inst.id + '\').html(\'' + text + '\');" ' +
			'onmouseout="jQuery(\'#ui-datepicker-status-' + inst.id + '\').html(\'&#xa0;\');"';
	},

	/* Adjust one of the date sub-fields. */
	_adjustInstDate: function(inst, offset, period) {
		var year = inst.drawYear + (period == 'Y' ? offset : 0);
		var month = inst.drawMonth + (period == 'M' ? offset : 0);
		var day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) +
			(period == 'D' ? offset : 0);
		var date = this._daylightSavingAdjust(new Date(year, month, day));
		// ensure it is within the bounds set
		var minDate = this._getMinMaxDate(inst, 'min', true);
		var maxDate = this._getMinMaxDate(inst, 'max');
		date = (minDate && date < minDate ? minDate : date);
		date = (maxDate && date > maxDate ? maxDate : date);
		inst.selectedDay = date.getDate();
		inst.drawMonth = inst.selectedMonth = date.getMonth();
		inst.drawYear = inst.selectedYear = date.getFullYear();
		if (period == 'M' || period == 'Y')
			this._notifyChange(inst);
	},

	/* Notify change of month/year. */
	_notifyChange: function(inst) {
		var onChange = this._get(inst, 'onChangeMonthYear');
		if (onChange)
			onChange.apply((inst.input ? inst.input[0] : null),
				[new Date(inst.selectedYear, inst.selectedMonth, 1), inst]);
	},
	
	/* Determine the number of months to show. */
	_getNumberOfMonths: function(inst) {
		var numMonths = this._get(inst, 'numberOfMonths');
		return (numMonths == null ? [1, 1] : (typeof numMonths == 'number' ? [1, numMonths] : numMonths));
	},

	/* Determine the current maximum date - ensure no time components are set - may be overridden for a range. */
	_getMinMaxDate: function(inst, minMax, checkRange) {
		var date = this._determineDate(this._get(inst, minMax + 'Date'), null);
		return (!checkRange || !inst.rangeStart ? date :
			(!date || inst.rangeStart > date ? inst.rangeStart : date));
	},

	/* Find the number of days in a given month. */
	_getDaysInMonth: function(year, month) {
		return 32 - new Date(year, month, 32).getDate();
	},

	/* Find the day of the week of the first of a month. */
	_getFirstDayOfMonth: function(year, month) {
		return new Date(year, month, 1).getDay();
	},

	/* Determines if we should allow a "next/prev" month display change. */
	_canAdjustMonth: function(inst, offset, curYear, curMonth) {
		var numMonths = this._getNumberOfMonths(inst);
		var date = this._daylightSavingAdjust(new Date(
			curYear, curMonth + (offset < 0 ? offset : numMonths[1]), 1));
		if (offset < 0)
			date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
		return this._isInRange(inst, date);
	},

	/* Is the given date in the accepted range? */
	_isInRange: function(inst, date) {
		// during range selection, use minimum of selected date and range start
		var newMinDate = (!inst.rangeStart ? null : this._daylightSavingAdjust(
			new Date(inst.selectedYear, inst.selectedMonth, inst.selectedDay)));
		newMinDate = (newMinDate && inst.rangeStart < newMinDate ? inst.rangeStart : newMinDate);
		var minDate = newMinDate || this._getMinMaxDate(inst, 'min');
		var maxDate = this._getMinMaxDate(inst, 'max');
		return ((!minDate || date >= minDate) && (!maxDate || date <= maxDate));
	},
	
	/* Provide the configuration settings for formatting/parsing. */
	_getFormatConfig: function(inst) {
		var shortYearCutoff = this._get(inst, 'shortYearCutoff');
		shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff :
			new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
		return {shortYearCutoff: shortYearCutoff,
			dayNamesShort: this._get(inst, 'dayNamesShort'), dayNames: this._get(inst, 'dayNames'),
			monthNamesShort: this._get(inst, 'monthNamesShort'), monthNames: this._get(inst, 'monthNames')};
	},

	/* Format the given date for display. */
	_formatDate: function(inst, day, month, year) {
		if (!day) {
			inst.currentDay = inst.selectedDay;
			inst.currentMonth = inst.selectedMonth;
			inst.currentYear = inst.selectedYear;
		}
		var date = (day ? (typeof day == 'object' ? day :
			this._daylightSavingAdjust(new Date(year, month, day))) :
			this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
		return this.formatDate(this._get(inst, 'dateFormat'), date, this._getFormatConfig(inst));
	}
});

/* jQuery extend now ignores nulls! */
function extendRemove(target, props) {
	$.extend(target, props);
	for (var name in props)
		if (props[name] == null || props[name] == undefined)
			target[name] = props[name];
	return target;
};

/* Determine whether an object is an array. */
function isArray(a) {
	return (a && (($.browser.safari && typeof a == 'object' && a.length) ||
		(a.constructor && a.constructor.toString().match(/\Array\(\)/))));
};

/* Invoke the datepicker functionality.
   @param  options  string - a command, optionally followed by additional parameters or
                    Object - settings for attaching new datepicker functionality
   @return  jQuery object */
$.fn.datepicker = function(options){
	var otherArgs = Array.prototype.slice.call(arguments, 1);
	if (typeof options == 'string' && (options == 'isDisabled' || options == 'getDate'))
		return $.datepicker['_' + options + 'Datepicker'].
			apply($.datepicker, [this[0]].concat(otherArgs));
	return this.each(function() {
		typeof options == 'string' ?
			$.datepicker['_' + options + 'Datepicker'].
				apply($.datepicker, [this].concat(otherArgs)) :
			$.datepicker._attachDatepicker(this, options);
	});
};

$.datepicker = new Datepicker(); // singleton instance
	
/* Initialise the date picker. */
$(document).ready(function() {
	$(document.body).append($.datepicker.dpDiv).
		mousedown($.datepicker._checkExternalClick);
});

})(jQuery);


/* - ++resource++jqnyromodal.js - */
/*
 * nyroModal - jQuery Plugin
 * http://nyromodal.nyrodev.com
 *
 * Copyright (c) 2008 Cedric Nirousset (nyrodev.com)
 * Licensed under the MIT license
 *
 * $Date: 2009-02-19 (Thu, 19 Feb 2009) $
 * $version: 1.4.2
 */
eval(function(p,a,c,k,e,r){e=function(c){return(c<62?'':e(parseInt(c/62)))+((c=c%62)>35?String.fromCharCode(c+29):c.toString(36))};if('0'.replace(0,e)==0){while(c--)r[e(c)]=k[c];k=[function(e){return r[e]||e}];e=function(){return'([3-68]|[1-5]\\w)'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('jQuery(8(e){6 u=navigator.userAgent.2A();6 N=(u.46(/.+(?:rv|it|ra|ie)[\\/: ]([\\d.]+)/)||[0,\'0\'])[1];6 x=(/3n/.1V(u)&&!/opera/.1V(u)&&47(N)<7);6 v=e(\'23\');6 a;6 E=13;6 C=13;6 y;6 F;6 b={2O:13,1P:13,1D:13,1q:13,2j:13,1Q:13,1E:13,2P:13,1R:13,1A:19,24:19,1J:19,bg:19,1g:19,1a:19,11:19,1e:19,16:19,2Q:1W 2B(),2R:1W 2B()};6 p={4:13,5:13};e.fn.1B=8(d){3(!1f)15 13;15 1f.2S(8(){3(1f.2C.2A()==\'1X\'){e(1f).48(8(c){3(e(1f).26(\'3o\'))15 12;3(1f.49==\'4a/1X-26\'){z(e.1j(d,{1m:1f}));15 12}c.1Y();z(e.1j(d,{1m:1f}));15 13})}14{e(1f).28(8(c){c.1Y();z(e.1j(d,{1m:1f}));15 13})}})};e.fn.2k=8(c){3(!1f.1L)z(c);15 1f.2S(8(){z(e.1j(c,{1m:1f}))})};e.2k=8(c){z(c)};e.2l=8(c,d,f){l(c,d,f);3(!d&&b.2O){3(b.bg&&c.2D)a.4b(b,a,8(){});3(b.16&&c.1y)O();3(((c.4&&c.4==a.4)||(c.5&&c.5==a.5))){3(b.16)P(12);3(b.16&&b.16.is(\':visible\')&&!b.2j){3(C)b.11.10({1o:\'\'});a.4c(b,a,8(){3(C)b.11.10({1o:\'3p\'});3(e.1Z(a.3q))a.3q(b,a)})}}}};e.nyroModalRemove=8(){A()};e.2E=8(){6 c=G(1);3(c)15 c.2k(H());15 13};e.2F=8(){6 c=G(-1);3(c)15 c.2k(H());15 13};e.fn.1B.29={2T:13,1A:13,2m:13,1b:\'\',1m:\'\',hash:\'\',3r:19,2G:\'nyroModalSel\',2U:\'1B\',11:19,2D:\'#000000\',20:{},21:{wmode:\'transparent\'},4:19,5:19,3s:2n,3t:4d,2V:12,3u:12,1C:25,4e:\'[^\\.]\\.(jpg|jpeg|png|tiff|gif|bmp)\\s*$\',3v:\'3w\',4f:12,4g:12,2o:19,4h:\'<a 1z="#" 1u="2F">Prev</a><a 1z="#"  1u="2E">Next</a>\',10:{bg:{1o:\'2H\',1F:\'1S\',1v:0,1w:0,5:\'1G%\',4:\'1G%\'},1e:{1o:\'2H\',1v:\'50%\',1w:\'50%\'},2I:{},11:{1F:\'1M\'},1g:{1o:\'2H\',1v:\'50%\',1w:\'50%\',1k:\'-2W\',1l:\'-2W\'}},4i:{17:\'<17 1u="1e"></17>\',20:\'<17 1u="1e"></17>\',1X:\'<17 1u="1e"></17>\',3x:\'<17 1u="1e"></17>\',2p:\'<17 1u="wrapperImg"></17>\',21:\'<17 1u="wrapperSwf"></17>\',1c:\'<17 1u="4j"></17>\',2X:\'<17 1u="4j"></17>\',4k:\'<17 1u="1e"></17>\'},4l:\'<a 1z="#" 1u="2Y" id="closeBut" 1y="close">4m</a>\',1y:19,3y:12,3z:\'.1B\',2Z:\'.2Y\',4n:\'<a 1z="#" 1u="2Y">Cancel</a>\',4o:\'1R\',4p:\'The requested 11 cannot be loaded.<br />Please try again later.<br /><a 1z="#" 1u="2Y">4m</a>\',3C:19,4q:bb,30:bc,3D:19,4t:bd,31:19,3E:19,3F:be,4v:bf,4x:bg,4y:bh,3G:bi,4c:bj,3q:19,4b:bk,32:19};8 z(f){3(b.1Q||b.1E||b.1q)15;j(\'processModal\');b.2O=12;bl(f);3(!b.1J)b.24=b.1A=19;b.1R=13;b.2P=13;b.1D=13;b.2Q=1W 2B();b.2R=1W 2B();a.1b=bm();3(e.1Z(a.3r))a.3r(a);1m=a.1m;1h=a.1h;3(a.1b==\'21\'){a.2V=13;l({1F:\'1S\'},\'10\',\'11\');a.11=\'<4F classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" 4="\'+a.4+\'" 5="\'+a.5+\'"><33 1N="movie" 2q="\'+1h+\'"></33>\';6 h=\'\';e.2S(a.21,8(c,d){a.11+=\'<33 1N="\'+c+\'" 2q="\'+d+\'"></33>\';h+=\' \'+c+\'="\'+d+\'"\'});a.11+=\'<4G 1T="\'+1h+\'" 1b="application/x-shockwave-flash" 4="\'+a.4+\'" 5="\'+a.5+\'"\'+h+\'></4G></4F>\'}3(1m){6 g=e(1m);3(a.1b==\'1X\'){6 i=e(1m).serializeArray();i.2J({1N:a.2U,2q:1});3(a.1p)i.2J({1N:a.2G,2q:a.1p.2a(1)});e.20(e.1j({},a.20,{1h:1h,26:i,1b:1m.method,4H:Q,1R:r}));j(\'3H 4I 2r: \'+g.1d(\'2s\'));s()}14 3(a.1b==\'3x\'){w();g.1d(\'2t\',\'2b\');g.1d(\'2s\',1h);g.2K(\'<3I 1b="1S" 1N="\'+a.2U+\'" 2q="1" />\');3(a.1p)g.2K(\'<3I 1b="1S" 1N="\'+a.2G+\'" 2q="\'+a.1p.2a(1)+\'" />\');b.1a.1i(\'<1c 3J="0" 3K="0" 1N="2b"></1c>\');e(\'1c\',b.1a).10({4:a.4,5:a.5}).1R(r).2c(bn);j(\'3H Data 2r: \'+g.1d(\'2s\'));s();t()}14 3(a.1b==\'2p\'){6 k=g.1d(\'1y\')||a.3v;w();b.1a.1i(\'<2u id="4K" />\').22(\'2u\').1d(\'3L\',k);j(\'3w 2r: \'+1h);b.1a.10({4L:0});e(\'2u\',b.1a).1R(r).2c(8(){j(\'3w Loaded: \'+1f.1T);e(1f).3M(\'2c\');6 c=b.1a.4();6 d=b.1a.5();b.1a.10({4L:\'\'});p.4=c;p.5=d;l({4:c,5:d,34:c,35:d});l({1F:\'1S\'},\'10\',\'11\');b.1D=12;3(b.1Q||b.1E)t()}).1d(\'1T\',1h);s()}14 3(a.1b==\'2X\'){w();b.1a.1i(\'<1c 3J="0" 3K="0" 1T="" 1N="2b" id="2b"></1c>\');j(\'4M 3H 2r: \'+1h);e(\'1c\',b.1a).eq(0).10({4:\'1G%\',5:e.4N.4O?\'99%\':\'1G%\'}).2c(8(c){3(a.3y&&1h.36(1U.2d.2v)>-1)e.2l({1y:e(\'1c\',b.1J).1H().22(\'1y\').3O()})});b.1D=12;s()}14 3(a.1b==\'1c\'){w();b.1a.1i(\'<1c 3J="0" 3K="0" 1T="\'+1h+\'" 1N="2b" id="2b"></1c>\');j(\'4M 2r: \'+1h);e(\'1c\',b.1a).eq(0).10({4:\'1G%\',5:e.4N.4O?\'99%\':\'1G%\'}).2c(8(c){3(a.3y&&1h.36(1U.2d.2v)>-1)e.2l({1y:e(\'1c\',b.1J).1H().22(\'1y\').3O()})});b.1D=12;s()}14 3(a.1b){j(\'4Q: \'+a.1b);w();b.1a.1i(a.11);6 n=b.1a.4();6 q=b.1a.5();6 o=e(a.1b);3(o.1L){l({1b:\'17\'});n=o.4();q=o.5();3(y)F=y;y=o;b.1a.1O(o.1H())}l({4:n,5:q});3(b.1a.1i())b.1D=12;14 r();3(!b.1P)s();14 I()}14{j(\'4I 2r: \'+1h);l({1b:\'20\'});6 i=a.20.26||{};3(a.1p){3(3P i=="3Q"){i+=\'&\'+a.2G+\'=\'+a.1p.2a(1)}14{i[a.2G]=a.1p.2a(1)}}e.20(e.1j(12,a.20,{1h:1h,4H:Q,1R:r,26:i}));s()}}14 3(a.11){j(\'4Q: \'+a.1b);l({1b:\'4k\'});w();b.1a.1i(e(\'<17/>\').1i(a.11).1H());3(b.1a.1i())b.1D=12;14 r();s()}14{}}8 bl(c){j(\'setDefaultCurrentSettings\');a=e.1j(12,{},e.fn.1B.29,c);a.1p=\'\';a.3a=0;a.3b=0;a.2V=12;J()}8 l(c,d,f){3(b.2O){3(d&&f){e.1j(12,a[d][f],c)}14 3(d){e.1j(12,a[d],c)}14{3(b.2j){3(c.4){c.3R=c.4;3c c[\'4\'];E=12}3(c.5){c.3S=c.5;3c c[\'5\'];E=12}}e.1j(12,a,c)}}14{3(d&&f){e.1j(12,e.fn.1B.29[d][f],c)}14 3(d){e.1j(12,e.fn.1B.29[d],c)}14{e.1j(12,e.fn.1B.29,c)}}}8 R(){3(x&&!b.1A){3(2e.3T){a.2f=2e.3T.4R;a.2g=2e.3T.3d}14{a.2f=2e.23.4R;a.2g=2e.23.3d}}14{a.2f=0;a.2g=0}}8 J(){R();a.1l=-(a.4+a.3a)/2;a.1k=-(a.5+a.3b)/2;3(!b.1A){a.1l+=a.2f;a.1k+=a.2g}}8 K(){R();6 c=D(b.1g);a.2L=-(b.1g.5()+c.h.1r+c.h.1C)/2;a.3e=-(b.1g.4()+c.w.1r+c.w.1C)/2;3(!b.1A){a.marginLefttLoading+=a.2f;a.2L+=a.2g}}8 O(){6 c=e(\'h1#4S\',b.16);3(c.1L)c.3O(a.1y);14 b.16.2K(\'<h1 id="4S">\'+a.1y+\'</h1>\')}8 w(){j(\'initModal\');3(!b.1J){3(a.2T)l({color:\'white\'},\'10\',\'bg\');6 h={2M:1G,1o:\'3p\',1v:0,1w:0,4:\'1G%\',5:\'1G%\'};6 g=v;6 i=\'\';3(a.1A){b.1A=g=e(a.1A);6 k=b.1A.offset();6 n=b.1A.3f();6 q=b.1A.3g();3(x){l({5:\'1G%\',4:\'1G%\',1v:0,1w:0},\'10\',\'bg\')}b.24={1v:k.1v,1w:k.1w,4:n,5:q};6 o=(/3n/.1V(u)?0:m(v.3h(0),\'4T\'));6 B=(/3n/.1V(u)?0:m(v.3h(0),\'4U\'));h={1o:\'2H\',1v:k.1v+o,1w:k.1w+B,4:n,5:q}}14 3(x){v.10({5:v.5()+\'px\',4:v.4()+\'px\',1o:\'static\',1F:\'1S\'});e(\'1i\').10({1F:\'1S\'});l({10:{bg:{1o:\'2H\',2M:101,5:\'4V%\',4:\'4V%\',1v:a.2g+\'px\',1w:a.2f+\'px\'},1e:{2M:102},1g:{2M:103}}});i=e(\'<1c id="nyroModalIframeHideIe"></1c>\').10(e.1j({},a.10.bg,{1I:0,2M:50,1r:\'3V\'}))}g.1O(e(\'<17 id="4W"><17 id="4X"></17><17 id="4Y"><17 id="4Z"></17></17><17 id="51"></17><17 id="52"></17></17>\').1s());b.1J=e(\'#4W\').10(h).2h();b.bg=e(\'#4X\').10(e.1j({3i:a.2D},a.10.bg)).3W(i);3(!a.2m)b.bg.28(A);b.1g=e(\'#52\').10(a.10.1g).1s();b.16=e(\'#4Y\').10(a.10.1e).1s();b.11=e(\'#4Z\');b.1a=e(\'#51\').1s();3(e.1Z(e.fn.53)){b.11.53(8(c,d){6 f=b.11.3h(0);3((d>0&&f.3d==0)||(d<0&&f.scrollHeight-f.3d==f.clientHeight)){c.1Y();c.stopPropagation()}})}e(2e).54(S);b.11.10({4:\'1M\',5:\'1M\'});b.16.10({4:\'1M\',5:\'1M\'})}}8 s(){j(\'showModal\');3(!b.1P){w();b.1q=12;a.4q(b,a,bo)}14{b.1q=12;b.1E=12;a.4v(b,a,8(){I();b.1q=13;t()})}}8 S(c){3(c.2N==27){3(!a.2m)A()}14 3(a.2o&&b.1P&&b.1D&&!b.1q&&!b.1E){3(c.2N==39||c.2N==40){c.1Y();e.2E();15 13}14 3(c.2N==37||c.2N==38){c.1Y();e.2F();15 13}}}8 bm(){3(a.3X){6 c=a.3X;3(!a.11)a.1m=12;a.3X=19;15 c}6 d=a.1m;6 f;3(d&&d.2C){6 h=e(d);a.1h=f=d.2C.2A()==\'1X\'?h.1d(\'2s\'):d.1z;3(h.1d(\'56\')==\'2m\')a.2m=12;a.1y=h.1d(\'1y\');3(d&&d.3j)a.2o=d.3j;6 g=T(f,d);3(g)15 g;6 i=13;3(d.2t&&d.2t.2A()==\'57\'||(d.2v&&d.2v.3Y(/:\\d*$/,\'\')!=1U.2d.2v.3Y(/:\\d*$/,\'\'))){i=12}3(d.2C.2A()==\'1X\'){3(i)15\'2X\';l(U(f));3(h.1d(\'49\')==\'4a/1X-26\')15\'3x\';15\'1X\'}3(i)15\'1c\'}14{f=a.1h;3(!a.11)a.1m=12;3(!f)15 19;6 k=1W 3Z("^http://","g");3(f.46(k))15\'1c\'}6 g=T(f,d);3(g)15 g;6 n=1W 3Z(\'[^\\.]\\.(21)\\s*$\',\'i\');3(n.1V(f))15\'21\';6 c=U(f);l(c);3(!c.1h)15 c.1p}8 T(c,d){6 f=1W 3Z(a.4e,\'i\');3(f.1V(c)){15\'2p\'}}8 U(c){6 d={1h:19,1p:19};3(c){6 f=V(c);6 h=V(1U.2d.1z);6 g=1U.2d.1z.2a(0,1U.2d.1z.1L-h.1L);6 i=c.2a(0,c.1L-f.1L);3(i==g){d.1p=f}14{d.1h=i;d.1p=f}}15 d}8 r(){j(\'loadingError\');b.1R=12;3(!b.1P)15;3(e.1Z(a.3C))a.3C(b,a);b.1g.addClass(a.4o).1i(a.4p);e(a.2Z,b.1g).28(A);K();b.1g.10({1k:a.2L+\'px\',1l:a.3e+\'px\'})}8 W(){j(\'fillContent\');3(!b.1a.1i())15;b.11.1i(b.1a.1H());b.1a.41();bp();3(a.1b==\'2X\'){e(a.1m).1d(\'2t\',\'2b\').26(\'3o\',1).48().1d(\'2t\',\'57\').removeData(\'3o\')}3(e.1Z(a.3D))a.3D(b,a);b.11.1O(b.2Q);e(a.2Z,b.16).28(A);e(a.3z,b.16).1B(H())}8 H(){6 c=e.1j(12,{},a);3(p.4)c.4=19;3(p.5)c.5=19;c.10.11.1F=\'1M\';15 c}8 bp(){j(\'wrapContent\');6 d=e(a.4i[a.1b]);b.11.1O(d.3k().2w());b.16.wrapInner(d);3(a.2o){b.11.1O(a.4h);6 f=H();6 h=G(-1);3(h){6 g=e(\'.2F\',b.16).1d(\'1z\',h.1d(\'1z\')).28(8(c){c.1Y();h.2k(f);15 13});3(x&&a.1b==\'21\'){g.3W(e(\'<1c id="nyroModalIframeHideIeGalleryPrev"></1c>\').10({1o:g.10(\'1o\'),1v:g.10(\'1v\'),1w:g.10(\'1w\'),4:g.4(),5:g.5(),1I:0,1r:\'3V\'}))}}14{e(\'.2F\',b.16).2w()}6 i=G(1);3(i){6 k=e(\'.2E\',b.16).1d(\'1z\',i.1d(\'1z\')).28(8(c){c.1Y();i.2k(f);15 13});3(x&&a.1b==\'21\'){k.3W(e(\'<1c id="nyroModalIframeHideIeGalleryNext"></1c>\').10(e.1j({},{1o:k.10(\'1o\'),1v:k.10(\'1v\'),1w:k.10(\'1w\'),4:k.4(),5:k.5(),1I:0,1r:\'3V\'})))}}14{e(\'.2E\',b.16).2w()}}P()}8 G(c){3(a.2o){3(!a.4g)c*=-1;6 d=e(\'[3j="\'+a.2o+\'"]\');6 f=d.index(a.1m);6 h=f+c;3(h>=0&&h<d.1L)15 d.eq(h)}15 13}8 P(c){j(\'calculateSize\');3(!b.1e)b.1e=b.16.3k(\':first\');p.4=13;p.5=13;3(a.3u&&(!a.4||!a.5)){b.16.10({1I:0,4:\'1M\',5:\'1M\'}).2h();6 d={4:\'1M\',5:\'1M\'};3(a.4){d.4=a.4}14 3(a.1b==\'1c\'){d.4=a.3s}3(a.5){d.5=a.5}14 3(a.1b==\'1c\'){d.5=a.3t}b.11.10(d);3(!a.4){a.4=b.11.3f(12);p.4=12}3(!a.5){a.5=b.11.3g(12);p.5=12}b.16.1s().10({1I:1})}a.4=2i.59(a.4,a.3s);a.5=2i.59(a.5,a.3t);6 f=D(b.16);6 h=D(b.1e);6 g=D(b.11);6 d={11:{4:a.4,5:a.5},2I:{4:a.4+g.w.1t,5:a.5+g.h.1t},1e:{4:a.4+g.w.1t+h.w.1t,5:a.5+g.h.1t+h.h.1t}};3(a.2V){6 i=b.24?b.24.5:e(1U).5()-f.h.1r-(d.1e.5-a.5);6 k=b.24?b.24.4:e(1U).4()-f.w.1r-(d.1e.4-a.4);i-=a.1C*2;k-=a.1C*2;3(d.11.5>i||d.11.4>k){3(a.1b==\'2p\'){6 n=d.11.4-a.34;6 q=d.11.5-a.35;3(q<0)q=0;3(n<0)n=0;6 o=i-q;6 B=k-n;6 X=2i.42(o/a.35,B/a.34);o=2i.5a(a.35*X);B=2i.5a(a.34*X);e(\'2u#4K\',b.11).10({5:o+\'px\',4:B+\'px\'});d.11.5=o+q;d.11.4=B+n}14{d.11.5=2i.42(d.11.5,i);d.11.4=2i.42(d.11.4,k)}d.2I={4:d.11.4+g.w.1t,5:d.11.5+g.h.1t};d.1e={4:d.11.4+g.w.1t+h.w.1t,5:d.11.5+g.h.1t+h.h.1t}}}b.11.10(e.1j({},d.11,a.10.11));b.1e.10(e.1j({},d.2I,a.10.2I));3(!c){b.16.10(e.1j({},d.1e,a.10.1e));3(a.1b==\'2p\'){6 Y=e(\'2u\',b.11).1d(\'3L\');e(\'2u\',b.11).removeAttr(\'3L\');3(Y!=a.3v){6 L=e(\'<17>\'+Y+\'</17>\');b.11.1O(L);3(a.4f){6 bq=D(L);L.10({4:(d.11.4+g.w.1C-bq.w.1t)+\'px\'})}}}3(!a.2m)b.16.2K(a.4l)}3(a.1y)O();d.1e.3a=f.w.1r;d.1e.3b=f.h.1r;l(d.1e);J()}8 A(c){j(\'removeModal\');3(c)c.1Y();3(b.1J&&b.1P){b.1P=13;b.1q=12;b.2P=12;3(b.1Q||b.1E){a.3G(b,a,8(){b.1g.1s();b.1Q=13;b.1E=13;a.30(b,a,M)})}14{3(C)b.11.10({1o:\'\'});b.1e.10({1F:\'1S\'});b.11.10({1F:\'1S\'});3(e.1Z(a.3E)){a.3E(b,a,8(){a.3F(b,a,8(){I();a.30(b,a,M)})})}14{a.3F(b,a,8(){I();a.30(b,a,M)})}}}3(c)15 13}8 t(){j(\'showContentOrLoading\');3(b.1P&&!b.1q){3(b.1D){3(b.1a.1i()){b.1q=12;3(b.1E){W();b.2j=12;a.4x(b,a,8(){b.1g.1s();b.1E=13;b.1Q=13;Z()})}14{a.3G(b,a,8(){b.1g.1s();b.1Q=13;W();K();J();b.2j=12;a.4t(b,a,Z)})}}}14 3(!b.1Q&&!b.1E){b.1q=12;b.1Q=12;3(b.1R)r();14 b.1g.1i(a.4n);e(a.2Z,b.1g).28(A);K();a.4y(b,a,8(){b.1q=13;t()})}}}8 Q(c){j(\'AjaxLoaded: \'+1f.1h);b.1a.1i(a.1p?ba(e(\'<17>\'+c+\'</17>\').22(a.1p).1H()):ba(c));3(b.1a.1i()){b.1D=12;t()}14 r()}8 bn(){j(\'formDataLoaded\');6 c=e(a.1m);c.1d(\'2s\',c.1d(\'2s\')+a.1p);c.1d(\'2t\',\'\');e(\'3I[1N=\'+a.2U+\']\',a.1m).2w();6 d=b.1a.3k(\'1c\');6 f=d.3M(\'2c\').1H().22(a.1p||\'23\').not(\'5c[1T]\');d.1d(\'1T\',\'about:blank\');b.1a.1i(f.1i());3(b.1a.1i()){b.1D=12;t()}14 r()}8 I(){j(\'endHideContent\');b.1q=13;3(F){F.1O(b.11.1H());F=19}14 3(y){y.1O(b.11.1H());y=19}b.11.41();b.16.1s().3k().2w().41().1d(\'style\',\'\').1s();3(b.2P||b.1E)b.16.1s();b.16.10(a.10.1e).1O(b.11);t()}8 M(){j(\'32\');e(2e).3M(\'54\',S);b.1q=13;b.1J.2w();b.1J=19;3(x){v.10({5:\'\',4:\'\',1o:\'\',1F:\'\'});e(\'1i\').10({1F:\'\'})}3(e.1Z(a.32))a.32(b,a)}8 bo(){j(\'endBackground\');b.1P=12;b.1q=13;t()}8 Z(){j(\'31\');b.1q=13;b.2j=13;b.16.10({1I:\'\'});C=/mozilla/.1V(u)&&!/(compatible|webkit)/.1V(u)&&parseFloat(N)<1.9&&a.1b!=\'2p\';3(C)b.11.10({1o:\'3p\'});b.11.1O(b.2R);3(a.3u&&a.1b==\'1c\'){6 h=b.11.22(\'1c\');3(h.1L&&h.1d(\'1T\').36(1U.2d.2v)!==-1){6 g=h.1H().22(\'23\');3(g.5()>0){6 i=g.3g(12)+1;6 k=g.3f(12)+1;e.2l({5:i,4:k})}14{h.bind(\'2c\',8(){6 c=h.1H().22(\'23\');3(c.1L&&c.5()>0){6 d=c.3g(12)+1;6 f=c.3f(12)+1;e.2l({5:d,4:f})}})}}}3(e.1Z(a.31))a.31(b,a);3(E){E=13;e.2l({4:a.3R,5:a.3S});3c a[\'3R\'];3c a[\'3S\']}3(p.4)l({4:19});3(p.5)l({5:19})}8 V(c){3(3P c==\'3Q\'){6 d=c.36(\'#\');3(d>-1)15 c.2a(d)}15\'\'}8 ba(c){3(3P c==\'3Q\')c=c.3Y(/<\\/?(1i|head|23)([^>]*)>/gi,\'\');6 d=1W 2B();e.2S(e.clean({0:c},1f.ownerDocument),8(){3(e.2C(1f,"5c")){3(!1f.1T||e(1f).1d(\'3j\')==\'forceLoad\'){3(e(1f).1d(\'56\')==\'shown\')b.2R.2J(1f);14 b.2Q.2J(1f)}}14 d.2J(1f)});15 d}8 D(c){c=c.3h(0);6 d={h:{3l:m(c,\'1k\')+m(c,\'marginBottom\'),1r:m(c,\'4T\')+m(c,\'borderBottomWidth\'),1C:m(c,\'paddingTop\')+m(c,\'paddingBottom\')},w:{3l:m(c,\'1l\')+m(c,\'marginRight\'),1r:m(c,\'4U\')+m(c,\'borderRightWidth\'),1C:m(c,\'paddingLeft\')+m(c,\'paddingRight\')}};d.h.3m=d.h.3l+d.h.1r;d.w.3m=d.w.3l+d.w.1r;d.h.5d=d.h.1C+d.h.1r;d.w.5d=d.w.1C+d.w.1r;d.h.1t=d.h.3m+d.h.1C;d.w.1t=d.w.3m+d.w.1C;15 d}8 m(c,d){6 f=47(e.curCSS(c,d,12));3(isNaN(f))f=0;15 f}8 j(c){3(e.fn.1B.29.2T||a&&a.2T)5e(c,b,a||{})}8 bb(c,d,f){c.bg.10({1I:0}).5f(500,0.75,f)}8 bc(c,d,f){c.bg.44(4d,f)}8 bh(c,d,f){c.1g.10({1k:d.2L+\'px\',1l:d.3e+\'px\',1I:0}).2h().2x({1I:1},{2y:f,2z:2n})}8 bi(c,d,f){f()}8 bd(c,d,f){c.1g.10({1k:d.2L+\'px\',1l:d.3e+\'px\'}).2h().2x({4:d.4+\'px\',5:d.5+\'px\',1k:d.1k+\'px\',1l:d.1l+\'px\'},{2z:45,2y:8(){c.16.10({4:d.4+\'px\',5:d.5+\'px\',1k:d.1k+\'px\',1l:d.1l+\'px\'}).2h();c.1g.44(200,f)}})}8 be(c,d,f){c.16.2x({5:\'2W\',4:\'2W\',1k:(-(25+d.3b)/2+d.2g)+\'px\',1l:(-(25+d.3a)/2+d.2f)+\'px\'},{2z:45,2y:8(){c.16.1s();f()}})}8 bf(c,d,f){c.1g.10({1k:c.16.10(\'1k\'),1l:c.16.10(\'1l\'),5:c.16.10(\'5\'),4:c.16.10(\'4\'),1I:0}).2h().5f(2n,1,8(){c.16.1s();f()})}8 bg(c,d,f){c.16.1s().10({4:d.4+\'px\',5:d.5+\'px\',1l:d.1l+\'px\',1k:d.1k+\'px\',1I:1});c.1g.2x({4:d.4+\'px\',5:d.5+\'px\',1l:d.1l+\'px\',1k:d.1k+\'px\'},{2y:8(){c.16.2h();c.1g.44(2n,8(){c.1g.1s();f()})},2z:45})}8 bj(c,d,f){c.16.2x({4:d.4+\'px\',5:d.5+\'px\',1l:d.1l+\'px\',1k:d.1k+\'px\'},{2y:f,2z:2n})}8 bk(c,d,f){3(!e.fx.step.3i){c.bg.10({3i:d.2D});f()}14 c.bg.2x({3i:d.2D},{2y:f,2z:2n})}e(e.fn.1B.29.3z).1B()});8 5e(c,d,f){3(d.1J)d.bg.2K(c+\'<br />\')}',[],326,'|||if|width|height|var||function||||||||||||||||||||||||||||||||||||||||||||||||||||||css|content|true|false|else|return|contentWrapper|div||null|tmp|type|iframe|attr|wrapper|this|loading|url|html|extend|marginTop|marginLeft|from||position|selector|anim|border|hide|total|class|top|left||title|href|blocker|nyroModal|padding|dataReady|transition|overflow|100|contents|opacity|full||length|auto|name|append|ready|loadingShown|error|hidden|src|window|test|new|form|preventDefault|isFunction|ajax|swf|find|body|blockerVars||data||click|settings|substring|nyroModalIframe|load|location|document|marginScrollLeft|marginScrollTop|show|Math|animContent|nyroModalManual|nyroModalSettings|modal|400|gallery|image|value|Load|action|target|img|hostname|remove|animate|complete|duration|toLowerCase|Array|nodeName|bgColor|nyroModalNext|nyroModalPrev|selIndicator|absolute|wrapper2|push|prepend|marginTopLoading|zIndex|keyCode|started|closing|scripts|scriptsShown|each|debug|formIndicator|resizable|50px|iframeForm|nyroModalClose|closeSelector|hideBackground|endShowContent|endRemove|param|imgWidth|imgHeight|indexOf||||borderW|borderH|delete|scrollTop|marginLeftLoading|outerWidth|outerHeight|get|backgroundColor|rel|children|margin|outer|msie|processing|fixed|endResize|processHandler|minWidth|minHeight|autoSizable|defaultImgAlt|Image|formData|titleFromIframe|openSelector|||handleError|endFillContent|beforeHideContent|hideContent|hideLoading|Form|input|frameborder|hspace|alt|unbind||text|typeof|string|setWidth|setHeight|documentElement||none|before|forceType|replace|RegExp||empty|min||fadeOut|350|match|parseInt|submit|enctype|multipart|updateBgColor|resize|300|regexImg|setWidthImgTitle|ltr|galleryLinks|wrap|wrapperIframe|manual|closeButton|Close|contentLoading|errorClass|contentError|showBackground|||showContent||showTransition||hideTransition|showLoading|||||||object|embed|success|Ajax||nyroModalImg|lineHeight|Iframe|support|boxModel||Content|scrollLeft|nyroModalTitle|borderTopWidth|borderLeftWidth|110|nyroModalFull|nyroModalBg|nyroModalWrapper|nyroModalContent||nyrModalTmp|nyroModalLoading|mousewheel|keydown||rev|_blank||max|floor||script|inner|nyroModalDebug|fadeTo'.split('|'),0,{}))

/* - ++resource++jqbtips.js - */
/*
 * @name BeautyTips
 * @desc a tooltips/baloon-help plugin for jQuery
 *
 * @author Jeff Robbins - Lullabot - http://www.lullabot.com
 * @version 0.9.1  (2/15/2009)
 *  
 * @type jQuery
 * @cat Plugins/bt
 * @requires jQuery v1.2+ (not tested on versions prior to 1.2.6)
 *
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 *
 * Encourage development. If you use BeautyTips for anything cool 
 * or on a site that people have heard of, please drop me a note.
 * - jeff ^at lullabot > com
 *
 * No guarantees, warranties, or promises of any kind
 *
 */

/**
 * @credit Inspired by Karl Swedberg's ClueTip
 *    (http://plugins.learningjquery.com/cluetip/), which in turn was inspired
 *    by Cody Lindley's jTip (http://www.codylindley.com)
 *
 * @fileoverview
 * Beauty Tips is a jQuery tooltips plugin which uses the canvas drawing element
 * in the HTML5 spec in order to dynamically draw tooltip "talk bubbles" around
 * the descriptive help text associated with an item. This is in many ways
 * similar to Google Maps which both provides similar talk-bubbles and uses the
 * canvas element to draw them.
 *
 * The canvas element is supported in modern versions of FireFox, Safari, and
 * Opera. However, Internet Explorer needs a separate library called ExplorerCanvas
 * included on the page in order to support canvas drawing functions. ExplorerCanvas
 * was created by Google for use with their web apps and you can find it here:
 * http://excanvas.sourceforge.net/
 *
 * Beauty Tips was written to be simple to use and pretty. All of its options
 * are documented at the bottom of this file and defaults can be overwritten
 * globally for the entire page, or individually on each call.
 *
 * By default each tooltip will be positioned on the side of the target element
 * which has the most free space. This is affected by the scroll position and
 * size of the current window, so each Beauty Tip is redrawn each time it is
 * displayed. It may appear above an element at the bottom of the page, but when
 * the page is scrolled down (and the element is at the top of the page) it will
 * then appear below it. Additionally, positions can be forced or a preferred
 * order can be defined. See examples below.
 *
 * To fix z-index problems in IE6, include the bgiframe plugin on your page
 * http://plugins.jquery.com/project/bgiframe - BeautyTips will automatically
 * recognize it and use it.
 *
 * BeautyTips also works with the hoverIntent plugin
 * http://cherne.net/brian/resources/jquery.hoverIntent.html
 * see hoverIntent example below for usage
 *
 * Usage
 * The function can be called in a number of ways.
 * $(selector).bt();
 * $(selector).bt('Content text');
 * $(selector).bt('Content text', {option1: value, option2: value});
 * $(selector).bt({option1: value, option2: value});
 *
 * For more/better documentation and lots of examples, visit the demo page included with the distribution
 *
 */
$=jq;
jQuery.fn.bt = function(content, options) {

  if (typeof content != 'string') {
    var contentSelect = true;
    options = content;
    content = false;
  }
  else {
    var contentSelect = false;
  }
  
  // if hoverIntent is installed, use that as default instead of hover
  if (jQuery.fn.hoverIntent && jQuery.bt.defaults.trigger == 'hover') {
    jQuery.bt.defaults.trigger = 'hoverIntent';
  }

  return this.each(function(index) {

    var opts = jQuery.extend(false, jQuery.bt.defaults, options);

    // clean up the options
    opts.spikeLength = numb(opts.spikeLength);
    opts.spikeGirth = numb(opts.spikeGirth);
    opts.overlap = numb(opts.overlap);
    
    var ajaxTimeout = false;
    
    /**
     * This is sort of the "starting spot" for the this.each()
     * These are sort of the init functions to handle the call
     */

    if (opts.killTitle) {
      $(this).find('[title]').andSelf().each(function() {
        if (!$(this).attr('bt-xTitle')) {
          $(this).attr('bt-xTitle', $(this).attr('title')).attr('title', '');
        }
      });
    }    
    
    if (typeof opts.trigger == 'string') {
      opts.trigger = [opts.trigger];
    }
    if (opts.trigger[0] == 'hoverIntent') {
      var hoverOpts = $.extend(opts.hoverIntentOpts, {
        over: function() {
          this.btOn();
        },
        out: function() {
          this.btOff();
        }});
      $(this).hoverIntent(hoverOpts);
    
    }
    else if (opts.trigger[0] == 'hover') {
      $(this).hover(
        function() {
          this.btOn();
        },
        function() {
          this.btOff();
        }
      );
    }
    else if (opts.trigger[0] == 'now') {
      // toggle the on/off right now
      // note that 'none' gives more control (see below)
      if ($(this).hasClass('bt-active')) {
        this.btOff();
      }
      else {
        this.btOn();
      }
    }
    else if (opts.trigger[0] == 'none') {
      // initialize the tip with no event trigger
      // use javascript to turn on/off tip as follows:
      // $('#selector').btOn();
      // $('#selector').btOff();
    }
    else if (opts.trigger.length > 1 && opts.trigger[0] != opts.trigger[1]) {
      $(this)
        .bind(opts.trigger[0], function() {
          this.btOn();
        })
        .bind(opts.trigger[1], function() {
          this.btOff();
        });
    }
    else {
      // toggle using the same event
      $(this).bind(opts.trigger[0], function() {
        if ($(this).hasClass('bt-active')) {
          this.btOff();
        }
        else {
          this.btOn();
        }
      });
    }
    
    
    /**
     *  The BIG TURN ON
     *  Any element that has been initiated
     */
    this.btOn = function () {
      if (typeof $(this).data('bt-box') == 'object') {
        // if there's already a popup, remove it before creating a new one.
        this.btOff();
      }

      // trigger preShow function
      opts.preShow.apply(this);
      
      // turn off other tips
      $(jQuery.bt.vars.closeWhenOpenStack).btOff();
      
      // add the class to the target element (for hilighting, for example)
      // bt-active is always applied to all, but activeClass can apply another
      $(this).addClass('bt-active ' + opts.activeClass);

      if (contentSelect && opts.ajaxPath == null) {
        // bizarre, I know
        if (opts.killTitle) {
          // if we've killed the title attribute, it's been stored in 'bt-xTitle' so get it..
          $(this).attr('title', $(this).attr('bt-xTitle'));
        }
        // then evaluate the selector... title is now in place
        content = eval(opts.contentSelector);
        if (opts.killTitle) {
          // now remove the title again, so we don't get double tips
          $(this).attr('title', '');
        }
      }
      
      // ----------------------------------------------
      // All the Ajax(ish) stuff is in this next bit...
      // ----------------------------------------------
      if (opts.ajaxPath != null && content == false) {
        if (typeof opts.ajaxPath == 'object') {
          var url = eval(opts.ajaxPath[0]);
          url += opts.ajaxPath[1] ? ' ' + opts.ajaxPath[1] : '';
        }
        else {
          var url = opts.ajaxPath;
        }
        var off = url.indexOf(" ");
    		if ( off >= 0 ) {
    			var selector = url.slice(off, url.length);
    			url = url.slice(0, off);
    		}
      
        // load any data cached for the given ajax path
        var cacheData = opts.ajaxCache ? $(document.body).data('btCache-' + url.replace(/\./g, '')) : null;
        if (typeof cacheData == 'string') {
          content = selector ? jQuery("<div/>").append(cacheData.replace(/<script(.|\s)*?\/script>/g, "")).find(selector) : cacheData;
        }
        else {
          var target = this;
                    
          // set up the options
          var ajaxOpts = jQuery.extend(false,
          {
            type: opts.ajaxType,
            data: opts.ajaxData,
            cache: opts.ajaxCache,
            url: url,
            complete: function(XMLHttpRequest, textStatus) {
              if (textStatus == 'success' || textStatus == 'notmodified') {
                if (opts.ajaxCache) {
                  $(document.body).data('btCache-' + url.replace(/\./g, ''), XMLHttpRequest.responseText);
                }
                ajaxTimeout = false;
                content = 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(XMLHttpRequest.responseText.replace(/<script(.|\s)*?\/script>/g, ""))
      
      							// Locate the specified elements
      							.find(selector) :
      
      						// If not, just inject the full result
      						XMLHttpRequest.responseText;
      				   
              }
              else {
                if (textStatus == 'timeout') {
                  // if there was a timeout, we don't cache the result
                  ajaxTimeout = true;
                }
                content = opts.ajaxError.replace(/%error/g, XMLHttpRequest.statusText);
              }
              // if the user rolls out of the target element before the ajax request comes back, don't show it
              if ($(target).hasClass('bt-active')) {
                target.btOn();
              }
            }
          }, opts.ajaxData);
          // do the ajax request
          $.ajax(ajaxOpts);
          // load the throbber while the magic happens
          content = opts.ajaxLoading;
        }
      }
      // </ ajax stuff >
      

      // now we start actually figuring out where to place the tip
      
      var offsetParent = $(this).offsetParent();
      var pos = $(this).btPosition();
      // top, left, width, and height values of the target element
      var top = numb(pos.top) + numb($(this).css('margin-top')); // IE can return 'auto' for margins
      var left = numb(pos.left) + numb($(this).css('margin-left'));
      var width = $(this).outerWidth();
      var height = $(this).outerHeight();
      
      if (typeof content == 'object') {
        // if content is a DOM object (as opposed to text)
        // use a clone, rather than removing the original element
        // and ensure that it's visible
        content = $(content).clone(true).show();
        
      }
      
      // create the tip content div, populate it, and style it
      var $text = $('<div class="bt-content"></div>').append(content).css({padding: opts.padding, position: 'absolute', width: opts.width, zIndex: opts.textzIndex}).css(opts.cssStyles);
      // create the wrapping box which contains text and canvas
      // put the content in it, style it, and append it to the same offset parent as the target
      var $box = $('<div class="bt-wrapper"></div>').append($text).addClass(opts.cssClass).css({position: 'absolute', width: opts.width, zIndex: opts.wrapperzIndex}).appendTo(offsetParent);
      
      // use bgiframe to get around z-index problems in IE6
      // http://plugins.jquery.com/project/bgiframe
      if ($.fn.bgiframe) {
        $text.bgiframe();
        $box.bgiframe();  
      }

      $(this).data('bt-box', $box);

      // see if the text box will fit in the various positions
      var scrollTop = numb($(document).scrollTop());
      var scrollLeft = numb($(document).scrollLeft());
      var docWidth = numb($(window).width());
      var docHeight = numb($(window).height());
      var winRight = scrollLeft + docWidth;
      var winBottom = scrollTop + docHeight;
      var space = new Object();
      space.top = $(this).offset().top - scrollTop;
      space.bottom = docHeight - (($(this).offset().top + height) - scrollTop);
      space.left = $(this).offset().left - scrollLeft;
      space.right = docWidth - (($(this).offset().left + width) - scrollLeft);
      var textOutHeight = numb($text.outerHeight());
      var textOutWidth = numb($text.outerWidth());
      if (opts.positions.constructor == String) {
        opts.positions = opts.positions.replace(/ /, '').split(',');
      }
      if (opts.positions[0] == 'most') {
        // figure out which is the largest
        var position = 'top'; // prime the pump
        for (var pig in space) { // pigs in space!
          position = space[pig] > space[position] ? pig : position;
        }
      }
      else {
        for (var x in opts.positions) {
          var position = opts.positions[x];
          if ((position == 'left' || position == 'right') && space[position] > textOutWidth + opts.spikeLength) {
            break;
          }
          else if ((position == 'top' || position == 'bottom') && space[position] > textOutHeight + opts.spikeLength) {
            break;
          }
        }
      }

      // horizontal (left) offset for the box
      var horiz = left + ((width - textOutWidth) * .5);
      // vertical (top) offset for the box
      var vert = top + ((height - textOutHeight) * .5);
      var animDist = opts.animate ? numb(opts.distance) : 0;
      var points = new Array();
      var textTop, textLeft, textRight, textBottom, textTopSpace, textBottomSpace, textLeftSpace, textRightSpace, crossPoint, textCenter, spikePoint;

      // Yes, yes, this next bit really could use to be condensed
      // each switch case is basically doing the same thing in slightly different ways
      switch(position) {
        case 'top':
          // spike on bottom
          $text.css('margin-bottom', opts.spikeLength + 'px');
          $box.css({top: (top - $text.outerHeight(true) - animDist) + opts.overlap, left: horiz});
          // move text left/right if extends out of window
          textRightSpace = (winRight - opts.windowMargin) - ($text.offset().left + $text.outerWidth(true));
          var xShift = 0;
          if (textRightSpace < 0) {
            // shift it left
            $box.css('left', (numb($box.css('left')) + textRightSpace) + 'px');
            xShift -= textRightSpace;
          }
          // we test left space second to ensure that left of box is visible
          textLeftSpace = ($text.offset().left + numb($text.css('margin-left'))) - (scrollLeft + opts.windowMargin);
          if (textLeftSpace < 0) {
            // shift it right
            $box.css('left', (numb($box.css('left')) - textLeftSpace) + 'px');
            xShift += textLeftSpace;
          }
          textTop = $text.btPosition().top + numb($text.css('margin-top'));
          textLeft = $text.btPosition().left + numb($text.css('margin-left'));
          textRight = textLeft + $text.outerWidth();
          textBottom = textTop + $text.outerHeight();
          textCenter = {x: textLeft + ($text.outerWidth()*opts.centerPointX), y: textTop + ($text.outerHeight()*opts.centerPointY)};
          // points[points.length] = {x: x, y: y};
          points[points.length] = spikePoint = {y: textBottom + opts.spikeLength, x: ((textRight-textLeft) * .5) + xShift, type: 'spike'};
          crossPoint = findIntersectX(spikePoint.x, spikePoint.y, textCenter.x, textCenter.y, textBottom);
          // make sure that the crossPoint is not outside of text box boundaries
          crossPoint.x = crossPoint.x < textLeft + opts.spikeGirth/2 + opts.cornerRadius ? textLeft + opts.spikeGirth/2 + opts.cornerRadius : crossPoint.x;
          crossPoint.x =  crossPoint.x > (textRight - opts.spikeGirth/2) - opts.cornerRadius ? (textRight - opts.spikeGirth/2) - opts.CornerRadius : crossPoint.x;
          points[points.length] = {x: crossPoint.x - (opts.spikeGirth/2), y: textBottom, type: 'join'};
          points[points.length] = {x: textLeft, y: textBottom, type: 'corner'};  // left bottom corner
          points[points.length] = {x: textLeft, y: textTop, type: 'corner'};     // left top corner
          points[points.length] = {x: textRight, y: textTop, type: 'corner'};    // right top corner
          points[points.length] = {x: textRight, y: textBottom, type: 'corner'}; // right bottom corner
          points[points.length] = {x: crossPoint.x + (opts.spikeGirth/2), y: textBottom, type: 'join'};
          points[points.length] = spikePoint;
          break;
        case 'left':
          // spike on right
          $text.css('margin-right', opts.spikeLength + 'px');
          $box.css({top: vert + 'px', left: ((left - $text.outerWidth(true) - animDist) + opts.overlap) + 'px'});
          // move text up/down if extends out of window
          textBottomSpace = (winBottom - opts.windowMargin) - ($text.offset().top + $text.outerHeight(true));
          var yShift = 0;
          if (textBottomSpace < 0) {
            // shift it up
            $box.css('top', (numb($box.css('top')) + textBottomSpace) + 'px');
            yShift -= textBottomSpace;
          }
          // we ensure top space second to ensure that top of box is visible
          textTopSpace = ($text.offset().top + numb($text.css('margin-top'))) - (scrollTop + opts.windowMargin);
          if (textTopSpace < 0) {
            // shift it down
            $box.css('top', (numb($box.css('top')) - textTopSpace) + 'px');
            yShift += textTopSpace;
          }
          textTop = $text.btPosition().top + numb($text.css('margin-top'));
          textLeft = $text.btPosition().left + numb($text.css('margin-left'));
          textRight = textLeft + $text.outerWidth();
          textBottom = textTop + $text.outerHeight();
          textCenter = {x: textLeft + ($text.outerWidth()*opts.centerPointX), y: textTop + ($text.outerHeight()*opts.centerPointY)};
          points[points.length] = spikePoint = {x: textRight + opts.spikeLength, y: ((textBottom-textTop) * .5) + yShift, type: 'spike'};
          crossPoint = findIntersectY(spikePoint.x, spikePoint.y, textCenter.x, textCenter.y, textRight);
          // make sure that the crossPoint is not outside of text box boundaries
          crossPoint.y = crossPoint.y < textTop + opts.spikeGirth/2 + opts.cornerRadius ? textTop + opts.spikeGirth/2 + opts.cornerRadius : crossPoint.y;
          crossPoint.y =  crossPoint.y > (textBottom - opts.spikeGirth/2) - opts.cornerRadius ? (textBottom - opts.spikeGirth/2) - opts.cornerRadius : crossPoint.y;
          points[points.length] = {x: textRight, y: crossPoint.y + opts.spikeGirth/2, type: 'join'};
          points[points.length] = {x: textRight, y: textBottom, type: 'corner'}; // right bottom corner
          points[points.length] = {x: textLeft, y: textBottom, type: 'corner'};  // left bottom corner
          points[points.length] = {x: textLeft, y: textTop, type: 'corner'};     // left top corner
          points[points.length] = {x: textRight, y: textTop, type: 'corner'};    // right top corner
          points[points.length] = {x: textRight, y: crossPoint.y - opts.spikeGirth/2, type: 'join'};
          points[points.length] = spikePoint;
          break;
        case 'bottom':
          // spike on top
          $text.css('margin-top', opts.spikeLength + 'px');
          $box.css({top: (top + height + animDist) - opts.overlap, left: horiz});
          // move text up/down if extends out of window
          textRightSpace = (winRight - opts.windowMargin) - ($text.offset().left + $text.outerWidth(true));
          var xShift = 0;
          if (textRightSpace < 0) {
            // shift it left
            $box.css('left', (numb($box.css('left')) + textRightSpace) + 'px');
            xShift -= textRightSpace;
          }
          // we ensure left space second to ensure that left of box is visible
          textLeftSpace = ($text.offset().left + numb($text.css('margin-left')))  - (scrollLeft + opts.windowMargin);
          if (textLeftSpace < 0) {
            // shift it right
            $box.css('left', (numb($box.css('left')) - textLeftSpace) + 'px');
            xShift += textLeftSpace;
          }
          textTop = $text.btPosition().top + numb($text.css('margin-top'));
          textLeft = $text.btPosition().left + numb($text.css('margin-left'));
          textRight = textLeft + $text.outerWidth();
          textBottom = textTop + $text.outerHeight();
          textCenter = {x: textLeft + ($text.outerWidth()*opts.centerPointX), y: textTop + ($text.outerHeight()*opts.centerPointY)};
          points[points.length] = spikePoint = {x: ((textRight-textLeft) * .5) + xShift, y: 0, type: 'spike'};
          crossPoint = findIntersectX(spikePoint.x, spikePoint.y, textCenter.x, textCenter.y, textTop);
          // make sure that the crossPoint is not outside of text box boundaries
          crossPoint.x = crossPoint.x < textLeft + opts.spikeGirth/2 + opts.cornerRadius ? textLeft + opts.spikeGirth/2 + opts.cornerRadius : crossPoint.x;
          crossPoint.x =  crossPoint.x > (textRight - opts.spikeGirth/2) - opts.cornerRadius ? (textRight - opts.spikeGirth/2) - opts.cornerRadius : crossPoint.x;
          points[points.length] = {x: crossPoint.x + opts.spikeGirth/2, y: textTop, type: 'join'};
          points[points.length] = {x: textRight, y: textTop, type: 'corner'};    // right top corner
          points[points.length] = {x: textRight, y: textBottom, type: 'corner'}; // right bottom corner
          points[points.length] = {x: textLeft, y: textBottom, type: 'corner'};  // left bottom corner
          points[points.length] = {x: textLeft, y: textTop, type: 'corner'};     // left top corner
          points[points.length] = {x: crossPoint.x - (opts.spikeGirth/2), y: textTop, type: 'join'};
          points[points.length] = spikePoint;
          break;
        case 'right':
          // spike on left
          $text.css('margin-left', (opts.spikeLength + 'px'));
          $box.css({top: vert + 'px', left: ((left + width + animDist) - opts.overlap) + 'px'});
          // move text up/down if extends out of window
          textBottomSpace = (winBottom - opts.windowMargin) - ($text.offset().top + $text.outerHeight(true));
          var yShift = 0;
          if (textBottomSpace < 0) {
            // shift it up
            $box.css('top', (numb($box.css('top')) + textBottomSpace) + 'px');
            yShift -= textBottomSpace;
          }
          // we ensure top space second to ensure that top of box is visible
          textTopSpace = ($text.offset().top + numb($text.css('margin-top'))) - (scrollTop + opts.windowMargin);
          if (textTopSpace < 0) {
            // shift it down
            $box.css('top', (numb($box.css('top')) - textTopSpace) + 'px');
            yShift += textTopSpace;
          }
          textTop = $text.btPosition().top + numb($text.css('margin-top'));
          textLeft = $text.btPosition().left + numb($text.css('margin-left'));
          textRight = textLeft + $text.outerWidth();
          textBottom = textTop + $text.outerHeight();
          textCenter = {x: textLeft + ($text.outerWidth()*opts.centerPointX), y: textTop + ($text.outerHeight()*opts.centerPointY)};
          points[points.length] = spikePoint = {x: 0, y: ((textBottom-textTop) * .5) + yShift, type: 'spike'};
          crossPoint = findIntersectY(spikePoint.x, spikePoint.y, textCenter.x, textCenter.y, textLeft);
          // make sure that the crossPoint is not outside of text box boundaries
          crossPoint.y = crossPoint.y < textTop + opts.spikeGirth/2 + opts.cornerRadius ? textTop + opts.spikeGirth/2 + opts.cornerRadius : crossPoint.y;
          crossPoint.y =  crossPoint.y > (textBottom - opts.spikeGirth/2) - opts.cornerRadius ? (textBottom - opts.spikeGirth/2) - opts.cornerRadius : crossPoint.y;
          points[points.length] = {x: textLeft, y: crossPoint.y - opts.spikeGirth/2, type: 'join'};
          points[points.length] = {x: textLeft, y: textTop, type: 'corner'};     // left top corner
          points[points.length] = {x: textRight, y: textTop, type: 'corner'};    // right top corner
          points[points.length] = {x: textRight, y: textBottom, type: 'corner'}; // right bottom corner
          points[points.length] = {x: textLeft, y: textBottom, type: 'corner'};  // left bottom corner
          points[points.length] = {x: textLeft, y: crossPoint.y + opts.spikeGirth/2, type: 'join'};
          points[points.length] = spikePoint;
          break;
      } // </ switch >

      var canvas = $('<canvas width="'+ (numb($text.outerWidth(true)) + opts.strokeWidth*2) +'" height="'+ (numb($text.outerHeight(true)) + opts.strokeWidth*2) +'"></canvas>').appendTo($box).css({position: 'absolute', top: $text.btPosition().top, left: $text.btPosition().left, zIndex: opts.boxzIndex}).get(0);

      // if excanvas is set up, we need to initialize the new canvas element
      if (typeof G_vmlCanvasManager != 'undefined') {
        canvas = G_vmlCanvasManager.initElement(canvas);
      }

      if (opts.cornerRadius > 0) {
        // round the corners!
        var newPoints = new Array();
        var newPoint;
        for (var i=0; i<points.length; i++) {
          if (points[i].type == 'corner') {
            // create two new arc points
            // find point between this and previous (using modulo in case of ending)
            newPoint = betweenPoint(points[i], points[(i-1)%points.length], opts.cornerRadius);
            newPoint.type = 'arcStart';
            newPoints[newPoints.length] = newPoint;
            // the original corner point
            newPoints[newPoints.length] = points[i];
            // find point between this and next
            newPoint = betweenPoint(points[i], points[(i+1)%points.length], opts.cornerRadius);
            newPoint.type = 'arcEnd';
            newPoints[newPoints.length] = newPoint;
          }
          else {
            newPoints[newPoints.length] = points[i];
          }
        }
        // overwrite points with new version
        points = newPoints;

      }

      var ctx = canvas.getContext("2d");
      drawIt.apply(ctx, [points], opts.strokeWidth);
      ctx.fillStyle = opts.fill;
      if (opts.shadow) {
        ctx.shadowOffsetX = 2;
        ctx.shadowOffsetY = 2;
        ctx.shadowBlur = 5;
        ctx.shadowColor =  opts.shadowColor;
      }
      ctx.closePath();
      ctx.fill();
      if (opts.strokeWidth > 0) {
        ctx.shadowColor = 'rgba(0, 0, 0, 0)';
        ctx.lineWidth = opts.strokeWidth;
        ctx.strokeStyle = opts.strokeStyle;
        ctx.beginPath();
        drawIt.apply(ctx, [points], opts.strokeWidth);
        ctx.closePath();
        ctx.stroke();
      }

      if (opts.animate) {
        $box.css({opacity: 0.1});
      }

      $box.css({visibility: 'visible'});

      if (opts.overlay) {
        // EXPERIMENTAL!!!!
        var overlay = $('<div class="bt-overlay"></div>').css({
            position: 'absolute',
            backgroundColor: 'blue',
            top: top,
            left: left,
            width: width,
            height: height,
            opacity: '.2'
          }).appendTo(offsetParent);
        $(this).data('overlay', overlay);
      }

      var animParams = {opacity: 1};
      if (opts.animate) {
        switch (position) {
          case 'top':
            animParams.top = $box.btPosition().top + opts.distance;
            break;
          case 'left':
            animParams.left = $box.btPosition().left + opts.distance;
            break;
          case 'bottom':
            animParams.top = $box.btPosition().top - opts.distance;
            break;
          case 'right':
            animParams.left = $box.btPosition().left - opts.distance;
            break;
        }
        $box.animate(animParams, {duration: opts.speed, easing: opts.easing});
      }
      
      if ((opts.ajaxPath != null && opts.ajaxCache == false) || ajaxTimeout) {
        // if ajaxCache is not enabled or if there was a server timeout,
        // remove the content variable so it will be loaded again from server
        content = false;
      }
      
      // stick this element into the clickAnywhereToClose stack
      if (opts.clickAnywhereToClose) {
        jQuery.bt.vars.clickAnywhereStack.push(this);
        $(document).click(jQuery.bt.docClick);
      }
      
      // stick this element into the closeWhenOthersOpen stack
      if (opts.closeWhenOthersOpen) {
        jQuery.bt.vars.closeWhenOpenStack.push(this);
      }

      // trigger postShow function
      opts.postShow.apply(this);


    }; // </ turnOn() >

    this.btOff = function() {

      // trigger preHide function
      opts.preHide.apply(this);

      var box = $(this).data('bt-box');
      var overlay = $(this).data('bt-overlay');
      if (typeof box == 'object') {
        $(box).remove();
        $(this).removeData('bt-box');
      }
      if (typeof overlay == 'object') {
        $(overlay).remove();
        $(this).removeData('bt-overlay');
      }
      
      // remove this from the stacks
      jQuery.bt.vars.clickAnywhereStack = arrayRemove(jQuery.bt.vars.clickAnywhereStack, this);
      jQuery.bt.vars.closeWhenOpenStack = arrayRemove(jQuery.bt.vars.closeWhenOpenStack, this);

      // trigger postHide function
      opts.postHide.apply(this);
      
      // remove the 'bt-active' and activeClass classes from target
      $(this).removeClass('bt-active ' + opts.activeClass);

    }; // </ turnOff() >

    var refresh = this.btRefresh = function() {
      this.btOff();
      this.btOn();
    };


  }); // </ this.each() >


  function drawIt(points, strokeWidth) {
    this.moveTo(points[0].x, points[0].y);
    for (i=1;i<points.length;i++) {
      if (points[i-1].type == 'arcStart') {
        // if we're creating a rounded corner
        //ctx.arc(round5(points[i].x), round5(points[i].y), points[i].startAngle, points[i].endAngle, opts.cornerRadius, false);
        this.quadraticCurveTo(round5(points[i].x, strokeWidth), round5(points[i].y, strokeWidth), round5(points[(i+1)%points.length].x, strokeWidth), round5(points[(i+1)%points.length].y, strokeWidth));
        i++;
        //ctx.moveTo(round5(points[i].x), round5(points[i].y));
      }
      else {
        this.lineTo(round5(points[i].x, strokeWidth), round5(points[i].y, strokeWidth));
      }
    }
  }; // </ drawIt() >

  /**
   * For odd stroke widths, round to the nearest .5 pixel to avoid antialiasing
   * http://developer.mozilla.org/en/Canvas_tutorial/Applying_styles_and_colors
   */
  function round5(num, strokeWidth) {
    var ret;
    strokeWidth = numb(strokeWidth);
    if (strokeWidth%2) {
      ret = num;
    }
    else {
      ret = Math.round(num - .5) + .5;
    }
    return ret;
  }; // </ round5() >

  /**
   * Ensure that a number is a number... or zero
   */
  function numb(num) {
    return parseInt(num) || 0;
  }; // </ numb() >
  
  /**
   * Remove an element from an array
   */ 
  function arrayRemove(arr, elem) {
    var x, newArr = new Array();
    for (x in arr) {
      if (arr[x] != elem) {
        newArr.push(arr[x]);
      }
    }
    return newArr;
  }; // </ arrayRemove() >

  /**
   * Given two points, find a point which is dist pixels from point1 on a line to point2
   */
  function betweenPoint(point1, point2, dist) {
    // figure out if we're horizontal or vertical
    var y, x;
    if (point1.x == point2.x) {
      // vertical
      y = point1.y < point2.y ? point1.y + dist : point1.y - dist;
      return {x: point1.x, y: y};
    }
    else if (point1.y == point2.y) {
      // horizontal
      x = point1.x < point2.x ? point1.x + dist : point1.x - dist;
      return {x:x, y: point1.y};
    }
  }; // </ betweenPoint() >

  function centerPoint(arcStart, corner, arcEnd) {
    var x = corner.x == arcStart.x ? arcEnd.x : arcStart.x;
    var y = corner.y == arcStart.y ? arcEnd.y : arcStart.y;
    var startAngle, endAngle;
    if (arcStart.x < arcEnd.x) {
      if (arcStart.y > arcEnd.y) {
        // arc is on upper left
        startAngle = (Math.PI/180)*180;
        endAngle = (Math.PI/180)*90;
      }
      else {
        // arc is on upper right
        startAngle = (Math.PI/180)*90;
        endAngle = 0;
      }
    }
    else {
      if (arcStart.y > arcEnd.y) {
        // arc is on lower left
        startAngle = (Math.PI/180)*270;
        endAngle = (Math.PI/180)*180;
      }
      else {
        // arc is on lower right
        startAngle = 0;
        endAngle = (Math.PI/180)*270;
      }
    }
    return {x: x, y: y, type: 'center', startAngle: startAngle, endAngle: endAngle};
  }; // </ centerPoint() >

  /**
   * Find the intersection point of two lines, each defined by two points
   * arguments are x1, y1 and x2, y2 for r1 (line 1) and r2 (line 2)
   * It's like an algebra party!!!
   */
  function findIntersect(r1x1, r1y1, r1x2, r1y2, r2x1, r2y1, r2x2, r2y2) {

    if (r2x1 == r2x2) {
      return findIntersectY(r1x1, r1y1, r1x2, r1y2, r2x1);
    }
    if (r2y1 == r2y2) {
      return findIntersectX(r1x1, r1y1, r1x2, r1y2, r2y1);
    }

    // m = (y1 - y2) / (x1 - x2)  // <-- how to find the slope
    // y = mx + b                 // the 'classic' linear equation
    // b = y - mx                 // how to find b (the y-intersect)
    // x = (y - b)/m              // how to find x
    var r1m = (r1y1 - r1y2) / (r1x1 - r1x2);
    var r1b = r1y1 - (r1m * r1x1);
    var r2m = (r2y1 - r2y2) / (r2x1 - r2x2);
    var r2b = r2y1 - (r2m * r2x1);

    var x = (r2b - r1b) / (r1m - r2m);
	  var y = r1m * x + r1b;

	  return {x: x, y: y};
  }; // </ findIntersect() >

  /**
   * Find the y intersection point of a line and given x vertical
   */
  function findIntersectY(r1x1, r1y1, r1x2, r1y2, x) {
    if (r1y1 == r1y2) {
      return {x: x, y: r1y1};
    }
    var r1m = (r1y1 - r1y2) / (r1x1 - r1x2);
    var r1b = r1y1 - (r1m * r1x1);

    var y = r1m * x + r1b;

    return {x: x, y: y};
  }; // </ findIntersectY() >

  /**
   * Find the x intersection point of a line and given y horizontal
   */
  function findIntersectX(r1x1, r1y1, r1x2, r1y2, y) {
    if (r1x1 == r1x2) {
      return {x: r1x1, y: y};
    }
    var r1m = (r1y1 - r1y2) / (r1x1 - r1x2);
    var r1b = r1y1 - (r1m * r1x1);

    // y = mx + b     // your old friend, linear equation
    // x = (y - b)/m  // linear equation solved for x
    var x = (y - r1b) / r1m;

    return {x: x, y: y};

  }; // </ findIntersectX() >

}; // </ jQuery.fn.bt() >

/**
 * jQuery's compat.js (used in Drupal's jQuery upgrade module, overrides the $().position() function
 *  this is a copy of that function to allow the plugin to work when compat.js is present
 *  once compat.js is fixed to not override existing functions, this function can be removed
 *  and .btPosion() can be replaced with .position() above...
 */
jQuery.fn.btPosition = function() {

  function num(elem, prop) {
    return elem[0] && parseInt( jQuery.curCSS(elem[0], prop, true), 10 ) || 0;
  };

  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;
}; // </ jQuery.fn.btPosition() >


/**
 * A convenience function to run btOn() (if available)
 * for each selected item
 */
jQuery.fn.btOn = function() {
  return this.each(function(index){
    if ($.isFunction(this.btOn)) {
      this.btOn();
    }
  });
}; // </ $().btOn() >

/**
 * 
 * A convenience function to run btOff() (if available)
 * for each selected item
 */
jQuery.fn.btOff = function() {
  return this.each(function(index){
    if ($.isFunction(this.btOff)) {
      this.btOff();
    }
  });
}; // </ $().btOff() >

jQuery.bt = {};
jQuery.bt.vars = {clickAnywhereStack: [], closeWhenOpenStack: []};

/**
 * This function gets bound to the document's click event
 * It turns off all of the tips in the click-anywhere-to-close stack
 */
jQuery.bt.docClick = function(e) {
  if (!e) {
    var e = window.event;
  };  
  if (!$(e.target).parents().andSelf().filter('.bt-wrapper, .bt-active').length) {
    // if clicked element isn't inside tip, close tips in stack
    $(jQuery.bt.vars.clickAnywhereStack).btOff();
    $(document).unbind('click', jQuery.bt.docClick);
  }
}; // </ docClick() >

/**
 * Defaults for the beauty tips
 *
 * Note this is a variable definition and not a function. So defaults can be
 * written for an entire page by simply redefining attributes like so:
 *
 *   jQuery.bt.defaults.width = 400;
 *
 * This would make all Beauty Tips boxes 400px wide.
 *
 * Each of these options may also be overridden during
 *
 * Can be overriden globally or at time of call.
 *
 */
jQuery.bt.defaults = {
  trigger:         'hover',                // trigger to show/hide tip
                                           // use [on, off] to define separate on/off triggers
                                           // also use space character to allow multiple  to trigger
                                           // examples:
                                           //   ['focus', 'blur'] // focus displays, blur hides
                                           //   'dblclick'        // dblclick toggles on/off
                                           //   ['focus mouseover', 'blur mouseout'] // multiple triggers
                                           //   'now'             // shows/hides tip without event
                                           //   'none'            // use $('#selector').btOn(); and ...btOff();
                                           //   'hoverIntent'     // hover using hoverIntent plugin (settings below)
                                           // note:
                                           //   hoverIntent becomes default if available
                                           
  clickAnywhereToClose: true,              // clicking anywhere outside of the tip will close it 
  closeWhenOthersOpen: false,              // tip will be closed before another opens - stop >= 2 tips being on
                                           
  width:            '200px',               // width of tooltip box
                                           //   when combined with cssStyles: {width: 'auto'}, this becomes a max-width for the text
  padding:          '10px',                // padding for content (get more fine grained with cssStyles)
  spikeGirth:       10,                    // width of spike
  spikeLength:      15,                    // length of spike
  overlap:          0,                     // spike overlap (px) onto target (can cause problems with 'hover' trigger)
  overlay:          false,                 // display overlay on target (use CSS to style) -- BUGGY!
  killTitle:        true,                  // kill title tags to avoid double tooltips

  textzIndex:       9999,                  // z-index for the text
  boxzIndex:        9998,                  // z-index for the "talk" box (should always be less than textzIndex)
  wrapperzIndex:    9997,
  positions:        ['most'],              // preference of positions for tip (will use first with available space)
                                           // possible values 'top', 'bottom', 'left', 'right' as an array in order of
                                           // preference. Last value will be used if others don't have enough space.
                                           // or use 'most' to use the area with the most space
  fill:             "rgb(255, 255, 102)",  // fill color for the tooltip box
  
  windowMargin:     10,                    // space (px) to leave between text box and browser edge

  strokeWidth:      1,                     // width of stroke around box, **set to 0 for no stroke**
  strokeStyle:      "#000",                // color/alpha of stroke

  cornerRadius:     5,                     // radius of corners (px), set to 0 for square corners
  
                    // following values are on a scale of 0 to 1 with .5 being centered
  
  centerPointX:     .5,                    // the spike extends from center of the target edge to this point
  centerPointY:     .5,                    // defined by percentage horizontal (x) and vertical (y)
    
  shadow:           false,                 // use drop shadow? (only displays in Safari and FF 3.1) - experimental
  shadowOffsetX:    2,                     // shadow offset x (px)
  shadowOffsetY:    2,                     // shadow offset y (px)
  shadowBlur:       3,                     // shadow blur (px)
  shadowColor:      "#000",                // shadow color/alpha

  animate:          false,                 // animate show/hide of box - EXPERIMENTAL (buggy in IE)
  distance:         15,                    // distance of animation movement (px)
  easing:           'swing',               // animation easing
  speed:            200,                   // speed (ms) of animation

  cssClass:         '',                    // CSS class to add to the box wrapper div (of the TIP)
  cssStyles:        {},                    // styles to add the text box
                                           //   example: {fontFamily: 'Georgia, Times, serif', fontWeight: 'bold'}
                                               
  activeClass:      'bt-active',           // class added to TARGET element when its BeautyTip is active

  contentSelector:  "$(this).attr('title')", // if there is no content argument, use this selector to retrieve the title

  ajaxPath:         null,                  // if using ajax request for content, this contains url and (opt) selector
                                           // this will override content and contentSelector
                                           // examples (see jQuery load() function):
                                           //   '/demo.html'
                                           //   '/help/ajax/snip'
                                           //   '/help/existing/full div#content'
                                           
                                           // ajaxPath can also be defined as an array
                                           // in which case, the first value will be parsed as a jQuery selector
                                           // the result of which will be used as the ajaxPath
                                           // the second (optional) value is the content selector as above
                                           // examples:
                                           //    ["$(this).attr('href')", 'div#content']
                                           //    ["$(this).parents('.wrapper').find('.title').attr('href')"]
                                           //    ["$('#some-element').val()"]
                                           
  ajaxError:        '<strong>ERROR:</strong> <em>%error</em>',
                                           // error text, use "%error" to insert error from server
  ajaxLoading:     '<blink>Loading...</blink>',  // yes folks, it's the blink tag!
  ajaxData:         {},                    // key/value pairs
  ajaxType:         'GET',                 // 'GET' or 'POST'
  ajaxCache:        true,                  // cache ajax results and do not send request to same url multiple times
  ajaxOpts:         {},                    // any other ajax options - timeout, passwords, processing functions, etc...
                                           // see http://docs.jquery.com/Ajax/jQuery.ajax#options
                                    
  preShow:          function(){return;},       // function to run before popup is built and displayed
  postShow:         function(){return;},       // function to run after popup is built and displayed
  preHide:          function(){return;},       // function to run before popup is removed
  postHide:         function(){return;},       // function to run after popup is removed
  
  hoverIntentOpts:  {                          // options for hoverIntent (if installed)
                      interval: 300,           // http://cherne.net/brian/resources/jquery.hoverIntent.html
                      timeout: 500
                    }
                                               
}; // </ jQuery.bt.defaults >


// @todo
// use larger canvas (extend to edge of page when windowMargin is active)
// add options to shift position of tip vert/horiz and position of spike tip
// create drawn (canvas) shadows
// use overlay to allow overlap with hover
// experiment with making tooltip a subelement of the target
// rework animation system

/* - ++resource++autoresize.js - */
/*
 * jQuery autoResize (textarea auto-resizer)
 * @copyright James Padolsey http://james.padolsey.com
 * @version 1.04
 */

(function(a){a.fn.autoResize=function(j){var b=a.extend({onResize:function(){},animate:true,animateDuration:150,animateCallback:function(){},extraSpace:20,limit:1000},j);this.filter('textarea').each(function(){var c=a(this).css({resize:'none','overflow-y':'hidden'}),k=c.height(),f=(function(){var l=['height','width','lineHeight','textDecoration','letterSpacing'],h={};a.each(l,function(d,e){h[e]=c.css(e)});return c.clone().removeAttr('id').removeAttr('name').css({position:'absolute',top:0,left:-9999}).css(h).attr('tabIndex','-1').insertBefore(c)})(),i=null,g=function(){f.height(0).val(a(this).val()).scrollTop(10000);var d=Math.max(f.scrollTop(),k)+b.extraSpace,e=a(this).add(f);if(i===d){return}i=d;if(d>=b.limit){a(this).css('overflow-y','');return}b.onResize.call(this);b.animate&&c.css('display')==='block'?e.stop().animate({height:d},b.animateDuration,b.animateCallback):e.height(d)};c.unbind('.dynSiz').bind('keyup.dynSiz',g).bind('keydown.dynSiz',g).bind('change.dynSiz',g)});return this}})(jQuery);

/* - ++resource++cyninautocomplete.js - */
// http://www.signhealthintranet.org.uk/portal_javascripts/++resource++cyninautocomplete.js?original=1
eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}(';(3($){$.31.1o({12:3(b,d){5 c=Y b=="1w";d=$.1o({},$.D.1L,{11:c?b:14,w:c?14:b,1D:c?$.D.1L.1D:10,Z:d&&!d.1x?10:3U},d);d.1t=d.1t||3(a){6 a};d.1q=d.1q||d.1K;6 I.K(3(){1E $.D(I,d)})},M:3(a){6 I.X("M",a)},1y:3(a){6 I.15("1y",[a])},20:3(){6 I.15("20")},1Y:3(a){6 I.15("1Y",[a])},1X:3(){6 I.15("1X")}});$.D=3(o,r){5 t={2N:38,2I:40,2D:46,2x:9,2v:13,2q:27,2d:3x,2j:33,2o:34,2e:8};5 u=$(o).3f("12","3c").P(r.24);5 p;5 m="";5 n=$.D.2W(r);5 s=0;5 k;5 h={1z:B};5 l=$.D.2Q(r,o,1U,h);5 j;$.1T.2L&&$(o.2K).X("3S.12",3(){4(j){j=B;6 B}});u.X(($.1T.2L?"3Q":"3N")+".12",3(a){k=a.2F;3L(a.2F){Q t.2N:a.1d();4(l.L()){l.2y()}A{W(0,C)}N;Q t.2I:a.1d();4(l.L()){l.2u()}A{W(0,C)}N;Q t.2j:a.1d();4(l.L()){l.2t()}A{W(0,C)}N;Q t.2o:a.1d();4(l.L()){l.2s()}A{W(0,C)}N;Q r.19&&$.1p(r.R)==","&&t.2d:Q t.2x:Q t.2v:4(1U()){a.1d();j=C;6 B}N;Q t.2q:l.U();N;3A:1I(p);p=1H(W,r.1D);N}}).1G(3(){s++}).3v(3(){s=0;4(!h.1z){2k()}}).2i(3(){4(s++>1&&!l.L()){W(0,C)}}).X("1y",3(){5 c=(1n.7>1)?1n[1]:14;3 23(q,a){5 b;4(a&&a.7){16(5 i=0;i<a.7;i++){4(a[i].M.O()==q.O()){b=a[i];N}}}4(Y c=="3")c(b);A u.15("M",b&&[b.w,b.H])}$.K(1g(u.J()),3(i,a){1R(a,23,23)})}).X("20",3(){n.18()}).X("1Y",3(){$.1o(r,1n[1]);4("w"2G 1n[1])n.1f()}).X("1X",3(){l.1u();u.1u();$(o.2K).1u(".12")});3 1U(){5 b=l.26();4(!b)6 B;5 v=b.M;m=v;4(r.19){5 a=1g(u.J());4(a.7>1){v=a.17(0,a.7-1).2Z(r.R)+r.R+v}v+=r.R}u.J(v);1l();u.15("M",[b.w,b.H]);6 C}3 W(b,c){4(k==t.2D){l.U();6}5 a=u.J();4(!c&&a==m)6;m=a;a=1k(a);4(a.7>=r.22){u.P(r.21);4(!r.1C)a=a.O();1R(a,2V,1l)}A{1B();l.U()}};3 1g(b){4(!b){6[""]}5 d=b.1Z(r.R);5 c=[];$.K(d,3(i,a){4($.1p(a))c[i]=$.1p(a)});6 c}3 1k(a){4(!r.19)6 a;5 b=1g(a);6 b[b.7-1]}3 1A(q,a){4(r.1A&&(1k(u.J()).O()==q.O())&&k!=t.2e){u.J(u.J()+a.48(1k(m).7));$.D.1N(o,m.7,m.7+a.7)}};3 2k(){1I(p);p=1H(1l,47)};3 1l(){5 c=l.L();l.U();1I(p);1B();4(r.2U){u.1y(3(a){4(!a){4(r.19){5 b=1g(u.J()).17(0,-1);u.J(b.2Z(r.R)+(b.7?r.R:""))}A u.J("")}})}4(c)$.D.1N(o,o.H.7,o.H.7)};3 2V(q,a){4(a&&a.7&&s){1B();l.2T(a,q);1A(q,a[0].H);l.1W()}A{1l()}};3 1R(f,d,g){4(!r.1C)f=f.O();5 e=n.2S(f);4(e&&e.7){d(f,e)}A 4((Y r.11=="1w")&&(r.11.7>0)){5 c={45:+1E 44()};$.K(r.2R,3(a,b){c[a]=Y b=="3"?b():b});$.43({42:"41",3Z:"12"+o.3Y,2M:r.2M,11:r.11,w:$.1o({q:1k(f),3X:r.Z},c),3W:3(a){5 b=r.1r&&r.1r(a)||1r(a);n.1h(f,b);d(f,b)}})}A{l.2J();g(f)}};3 1r(c){5 d=[];5 b=c.1Z("\\n");16(5 i=0;i<b.7;i++){5 a=$.1p(b[i]);4(a){a=a.1Z("|");d[d.7]={w:a,H:a[0],M:r.1v&&r.1v(a,a[0])||a[0]}}}6 d};3 1B(){u.1e(r.21)}};$.D.1L={24:"3R",2H:"3P",21:"3O",22:1,1D:3M,1C:B,1a:C,1V:B,1j:10,Z:3K,2U:B,2R:{},1S:C,1K:3(a){6 a[0]},1q:14,1A:B,E:0,19:B,R:", ",1t:3(b,a){6 b.2C(1E 3J("(?![^&;]+;)(?!<[^<>]*)("+a.2C(/([\\^\\$\\(\\)\\[\\]\\{\\}\\*\\.\\+\\?\\|\\\\])/2A,"\\\\$1")+")(?![^<>]*>)(?![^&;]+;)","2A"),"<2z>$1</2z>")},1x:C,1s:3I};$.D.2W=3(g){5 h={};5 j=0;3 1a(s,a){4(!g.1C)s=s.O();5 i=s.3H(a);4(i==-1)6 B;6 i==0||g.1V};3 1h(q,a){4(j>g.1j){18()}4(!h[q]){j++}h[q]=a}3 1f(){4(!g.w)6 B;5 f={},2w=0;4(!g.11)g.1j=1;f[""]=[];16(5 i=0,30=g.w.7;i<30;i++){5 c=g.w[i];c=(Y c=="1w")?[c]:c;5 d=g.1q(c,i+1,g.w.7);4(d===B)1P;5 e=d.3G(0).O();4(!f[e])f[e]=[];5 b={H:d,w:c,M:g.1v&&g.1v(c)||d};f[e].1O(b);4(2w++<g.Z){f[""].1O(b)}};$.K(f,3(i,a){g.1j++;1h(i,a)})}1H(1f,25);3 18(){h={};j=0}6{18:18,1h:1h,1f:1f,2S:3(q){4(!g.1j||!j)6 14;4(!g.11&&g.1V){5 a=[];16(5 k 2G h){4(k.7>0){5 c=h[k];$.K(c,3(i,x){4(1a(x.H,q)){a.1O(x)}})}}6 a}A 4(h[q]){6 h[q]}A 4(g.1a){16(5 i=q.7-1;i>=g.22;i--){5 c=h[q.3F(0,i)];4(c){5 a=[];$.K(c,3(i,x){4(1a(x.H,q)){a[a.7]=x}});6 a}}}6 14}}};$.D.2Q=3(e,g,f,k){5 h={G:"3E"};5 j,y=-1,w,1m="",1M=C,F,z;3 2r(){4(!1M)6;F=$("<3D/>").U().P(e.2H).T("3C","3B").1J(2p.2n);z=$("<3z/>").1J(F).3y(3(a){4(V(a).2m&&V(a).2m.3w()==\'2l\'){y=$("1F",z).1e(h.G).3u(V(a));$(V(a)).P(h.G)}}).2i(3(a){$(V(a)).P(h.G);f();g.1G();6 B}).3t(3(){k.1z=C}).3s(3(){k.1z=B});4(e.E>0)F.T("E",e.E);1M=B}3 V(a){5 b=a.V;3r(b&&b.3q!="2l")b=b.3p;4(!b)6[];6 b}3 S(b){j.17(y,y+1).1e(h.G);2h(b);5 a=j.17(y,y+1).P(h.G);4(e.1x){5 c=0;j.17(0,y).K(3(){c+=I.1i});4((c+a[0].1i-z.1c())>z[0].3o){z.1c(c+a[0].1i-z.3n())}A 4(c<z.1c()){z.1c(c)}}};3 2h(a){y+=a;4(y<0){y=j.1b()-1}A 4(y>=j.1b()){y=0}}3 2g(a){6 e.Z&&e.Z<a?e.Z:a}3 2f(){z.2B();5 b=2g(w.7);16(5 i=0;i<b;i++){4(!w[i])1P;5 a=e.1K(w[i].w,i+1,b,w[i].H,1m);4(a===B)1P;5 c=$("<1F/>").3m(e.1t(a,1m)).P(i%2==0?"3l":"3k").1J(z)[0];$.w(c,"2c",w[i])}j=z.3j("1F");4(e.1S){j.17(0,1).P(h.G);y=0}4($.31.2b)z.2b()}6{2T:3(d,q){2r();w=d;1m=q;2f()},2u:3(){S(1)},2y:3(){S(-1)},2t:3(){4(y!=0&&y-8<0){S(-y)}A{S(-8)}},2s:3(){4(y!=j.1b()-1&&y+8>j.1b()){S(j.1b()-1-y)}A{S(8)}},U:3(){F&&F.U();j&&j.1e(h.G);y=-1},L:3(){6 F&&F.3i(":L")},3h:3(){6 I.L()&&(j.2a("."+h.G)[0]||e.1S&&j[0])},1W:3(){5 a=$(g).3g();F.T({E:Y e.E=="1w"||e.E>0?e.E:$(g).E(),2E:a.2E+g.1i,1Q:a.1Q}).1W();4(e.1x){z.1c(0);z.T({29:e.1s,3e:\'3d\'});4($.1T.3b&&Y 2p.2n.3T.29==="3a"){5 c=0;j.K(3(){c+=I.1i});5 b=c>e.1s;z.T(\'3V\',b?e.1s:c);4(!b){j.E(z.E()-28(j.T("32-1Q"))-28(j.T("32-39")))}}}},26:3(){5 a=j&&j.2a("."+h.G).1e(h.G);6 a&&a.7&&$.w(a[0],"2c")},2J:3(){z&&z.2B()},1u:3(){F&&F.37()}}};$.D.1N=3(b,a,c){4(b.2O){5 d=b.2O();d.36(C);d.35("2P",a);d.4c("2P",c);d.4b()}A 4(b.2Y){b.2Y(a,c)}A{4(b.2X){b.2X=a;b.4a=c}}b.1G()}})(49);',62,261,'|||function|if|var|return|length|||||||||||||||||||||||||data||active|list|else|false|true|Autocompleter|width|element|ACTIVE|value|this|val|each|visible|result|break|toLowerCase|addClass|case|multipleSeparator|moveSelect|css|hide|target|onChange|bind|typeof|max||url|autocomplete||null|trigger|for|slice|flush|multiple|matchSubset|size|scrollTop|preventDefault|removeClass|populate|trimWords|add|offsetHeight|cacheLength|lastWord|hideResultsNow|term|arguments|extend|trim|formatMatch|parse|scrollHeight|highlight|unbind|formatResult|string|scroll|search|mouseDownOnSelect|autoFill|stopLoading|matchCase|delay|new|li|focus|setTimeout|clearTimeout|appendTo|formatItem|defaults|needsInit|Selection|push|continue|left|request|selectFirst|browser|selectCurrent|matchContains|show|unautocomplete|setOptions|split|flushCache|loadingClass|minChars|findValueCallback|inputClass||selected||parseInt|maxHeight|filter|bgiframe|ac_data|COMMA|BACKSPACE|fillList|limitNumberOfItems|movePosition|click|PAGEUP|hideResults|LI|nodeName|body|PAGEDOWN|document|ESC|init|pageDown|pageUp|next|RETURN|nullData|TAB|prev|strong|gi|empty|replace|DEL|top|keyCode|in|resultsClass|DOWN|emptyList|form|opera|dataType|UP|createTextRange|character|Select|extraParams|load|display|mustMatch|receiveData|Cache|selectionStart|setSelectionRange|join|ol|fn|padding|||moveStart|collapse|remove||right|undefined|msie|off|auto|overflow|attr|offset|current|is|find|ac_odd|ac_even|html|innerHeight|clientHeight|parentNode|tagName|while|mouseup|mousedown|index|blur|toUpperCase|188|mouseover|ul|default|absolute|position|div|ac_over|substr|charAt|indexOf|180|RegExp|100|switch|400|keydown|ac_loading|ac_results|keypress|ac_input|submit|style|150|height|success|limit|name|port||abort|mode|ajax|Date|timestamp||200|substring|jQuery|selectionEnd|select|moveEnd'.split('|'),0,{}))

