/*!
 * jQuery Form Plugin
 * version: 2.52 (07-DEC-2010)
 * @requires jQuery v1.3.2 or later
 *
 * Examples and documentation at: http://malsup.com/jquery/form/
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 */
;(function($) {

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

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

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

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

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

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

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

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

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

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

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

	var n,v,a = this.formToArray(options.semantic);
	if (options.data) {
		options.extraData = options.data;
		for (n in options.data) {
			if(options.data[n] instanceof Array) {
				for (var k in options.data[n]) {
					a.push( { name: n, value: options.data[n][k] } );
				}
			}
			else {
				v = options.data[n];
				v = $.isFunction(v) ? v() : v; // if value is fn, invoke it
				a.push( { name: n, value: v } );
			}
		}
	}

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

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

	var q = $.param(a);

	if (options.type.toUpperCase() == 'GET') {
		options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
		options.data = null;  // data is null for 'get'
	}
	else {
		options.data = q; // data is the query string for 'post'
	}

	var $form = this, callbacks = [];
	if (options.resetForm) {
		callbacks.push(function() { $form.resetForm(); });
	}
	if (options.clearForm) {
		callbacks.push(function() { $form.clearForm(); });
	}

	// perform a load on the target only if dataType is not provided
	if (!options.dataType && options.target) {
		var oldSuccess = options.success || function(){};
		callbacks.push(function(data) {
			var fn = options.replaceTarget ? 'replaceWith' : 'html';
			$(options.target)[fn](data).each(oldSuccess, arguments);
		});
	}
	else if (options.success) {
		callbacks.push(options.success);
	}

	options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg
		var context = options.context || options;   // jQuery 1.4+ supports scope context 
		for (var i=0, max=callbacks.length; i < max; i++) {
			callbacks[i].apply(context, [data, status, xhr || $form, $form]);
		}
	};

	// are there files to upload?
	var fileInputs = $('input:file', this).length > 0;
	var mp = 'multipart/form-data';
	var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);

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

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


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

		if ($(':input[name=submit],:input[id=submit]', form).length) {
			// if there is an input with a name or id of 'submit' then we won't be
			// able to invoke the submit fn on the form (at least not x-browser)
			alert('Error: Form elements must not have name or id of "submit".');
			return;
		}
		
		var s = $.extend(true, {}, $.ajaxSettings, options);
		s.context = s.context || s;
		var id = 'jqFormIO' + (new Date().getTime()), fn = '_'+id;
		window[fn] = function() {
			var f = $io.data('form-plugin-onload');
			if (f) {
				f();
				window[fn] = undefined;
				try { delete window[fn]; } catch(e){}
			}
		}
		var $io = $('<iframe id="' + id + '" name="' + id + '" src="'+ s.iframeSrc +'" onload="window[\'_\'+this.id]()" />');
		var io = $io[0];

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

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

		var g = s.global;
		// trigger ajax global events so that activity/block indicators work like normal
		if (g && ! $.active++) {
			$.event.trigger("ajaxStart");
		}
		if (g) {
			$.event.trigger("ajaxSend", [xhr, s]);
		}

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

		var cbInvoked = false;
		var timedOut = 0;

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

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

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

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

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

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

				// add iframe to doc and submit the form
				$io.appendTo('body');
				$io.data('form-plugin-onload', cb);
				form.submit();
			}
			finally {
				// reset attrs and remove "extra" input elements
				form.setAttribute('action',a);
				if(t) {
					form.setAttribute('target', t);
				} else {
					$form.removeAttr('target');
				}
				$(extraInputs).remove();
			}
		}

		if (s.forceSync) {
			doSubmit();
		}
		else {
			setTimeout(doSubmit, 10); // this lets dom updates render
		}
	
		var data, doc, domCheckCount = 50;

		function cb() {
			if (cbInvoked) {
				return;
			}

			$io.removeData('form-plugin-onload');
			
			var ok = true;
			try {
				if (timedOut) {
					throw 'timeout';
				}
				// extract the server response from the iframe
				doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document;
				
				var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);
				log('isXml='+isXml);
				if (!isXml && window.opera && (doc.body == null || doc.body.innerHTML == '')) {
					if (--domCheckCount) {
						// in some browsers (Opera) the iframe DOM is not always traversable when
						// the onload callback fires, so we loop a bit to accommodate
						log('requeing onLoad callback, DOM not available');
						setTimeout(cb, 250);
						return;
					}
					// let this fall through because server response could be an empty document
					//log('Could not access iframe DOM after mutiple tries.');
					//throw 'DOMException: not available';
				}

				//log('response detected');
				cbInvoked = true;
				xhr.responseText = doc.documentElement ? doc.documentElement.innerHTML : null; 
				xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
				xhr.getResponseHeader = function(header){
					var headers = {'content-type': s.dataType};
					return headers[header];
				};

				var scr = /(json|script)/.test(s.dataType);
				if (scr || s.textarea) {
					// see if user embedded response in textarea
					var ta = doc.getElementsByTagName('textarea')[0];
					if (ta) {
						xhr.responseText = ta.value;
					}
					else if (scr) {
						// account for browsers injecting pre around json response
						var pre = doc.getElementsByTagName('pre')[0];
						var b = doc.getElementsByTagName('body')[0];
						if (pre) {
							xhr.responseText = pre.textContent;
						}
						else if (b) {
							xhr.responseText = b.innerHTML;
						}
					}			  
				}
				else if (s.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) {
					xhr.responseXML = toXml(xhr.responseText);
				}
				data = $.httpData(xhr, s.dataType);
			}
			catch(e){
				log('error caught:',e);
				ok = false;
				xhr.error = e;
				$.handleError(s, xhr, 'error', e);
			}
			
			if (xhr.aborted) {
				log('upload aborted');
				ok = false;
			}

			// ordering of these callbacks/triggers is odd, but that's how $.ajax does it
			if (ok) {
				s.success.call(s.context, data, 'success', xhr);
				if (g) {
					$.event.trigger("ajaxSuccess", [xhr, s]);
				}
			}
			if (g) {
				$.event.trigger("ajaxComplete", [xhr, s]);
			}
			if (g && ! --$.active) {
				$.event.trigger("ajaxStop");
			}
			if (s.complete) {
				s.complete.call(s.context, xhr, ok ? 'success' : 'error');
			}

			// clean up
			setTimeout(function() {
				$io.removeData('form-plugin-onload');
				$io.remove();
				xhr.responseXML = null;
			}, 100);
		}

		function toXml(s, doc) {
			if (window.ActiveXObject) {
				doc = new ActiveXObject('Microsoft.XMLDOM');
				doc.async = 'false';
				doc.loadXML(s);
			}
			else {
				doc = (new DOMParser()).parseFromString(s, 'text/xml');
			}
			return (doc && doc.documentElement && doc.documentElement.tagName != 'parsererror') ? doc : null;
		}
	}
};

/**
 * ajaxForm() provides a mechanism for fully automating form submission.
 *
 * The advantages of using this method instead of ajaxSubmit() are:
 *
 * 1: This method will include coordinates for <input type="image" /> elements (if the element
 *	is used to submit the form).
 * 2. This method will include the submit element's name/value data (for the element that was
 *	used to submit the form).
 * 3. This method binds the submit() method to the form for you.
 *
 * The options argument for ajaxForm works exactly as it does for ajaxSubmit.  ajaxForm merely
 * passes the options argument along after properly binding events for submit elements and
 * the form itself.
 */
$.fn.ajaxForm = function(options) {
	// in jQuery 1.3+ we can fix mistakes with the ready state
	if (this.length === 0) {
		var o = { s: this.selector, c: this.context };
		if (!$.isReady && o.s) {
			log('DOM not ready, queuing ajaxForm');
			$(function() {
				$(o.s,o.c).ajaxForm(options);
			});
			return this;
		}
		// is your DOM ready?  http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
		log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)'));
		return this;
	}
	
	return this.ajaxFormUnbind().bind('submit.form-plugin', function(e) {
		if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed
			e.preventDefault();
			$(this).ajaxSubmit(options);
		}
	}).bind('click.form-plugin', function(e) {
		var target = e.target;
		var $el = $(target);
		if (!($el.is(":submit,input:image"))) {
			// is this a child element of the submit el?  (ex: a span within a button)
			var t = $el.closest(':submit');
			if (t.length == 0) {
				return;
			}
			target = t[0];
		}
		var form = this;
		form.clk = target;
		if (target.type == 'image') {
			if (e.offsetX != undefined) {
				form.clk_x = e.offsetX;
				form.clk_y = e.offsetY;
			} else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin
				var offset = $el.offset();
				form.clk_x = e.pageX - offset.left;
				form.clk_y = e.pageY - offset.top;
			} else {
				form.clk_x = e.pageX - target.offsetLeft;
				form.clk_y = e.pageY - target.offsetTop;
			}
		}
		// clear form vars
		setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100);
	});
};

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

/**
 * formToArray() gathers form element data into an array of objects that can
 * be passed to any of the following ajax functions: $.get, $.post, or load.
 * Each object in the array has both a 'name' and 'value' property.  An example of
 * an array for a simple login form might be:
 *
 * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
 *
 * It is this array that is passed to pre-submit callback functions provided to the
 * ajaxSubmit() and ajaxForm() methods.
 */
$.fn.formToArray = function(semantic) {
	var a = [];
	if (this.length === 0) {
		return a;
	}

	var form = this[0];
	var els = semantic ? form.getElementsByTagName('*') : form.elements;
	if (!els) {
		return a;
	}
	
	var i,j,n,v,el,max,jmax;
	for(i=0, max=els.length; i < max; i++) {
		el = els[i];
		n = el.name;
		if (!n) {
			continue;
		}

		if (semantic && form.clk && el.type == "image") {
			// handle image inputs on the fly when semantic == true
			if(!el.disabled && form.clk == el) {
				a.push({name: n, value: $(el).val()});
				a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
			}
			continue;
		}

		v = $.fieldValue(el, true);
		if (v && v.constructor == Array) {
			for(j=0, jmax=v.length; j < jmax; j++) {
				a.push({name: n, value: v[j]});
			}
		}
		else if (v !== null && typeof v != 'undefined') {
			a.push({name: n, value: v});
		}
	}

	if (!semantic && form.clk) {
		// input type=='image' are not found in elements array! handle it here
		var $input = $(form.clk), input = $input[0];
		n = input.name;
		if (n && !input.disabled && input.type == 'image') {
			a.push({name: n, value: $input.val()});
			a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
		}
	}
	return a;
};

/**
 * Serializes form data into a 'submittable' string. This method will return a string
 * in the format: name1=value1&amp;name2=value2
 */
$.fn.formSerialize = function(semantic) {
	//hand off to jQuery.param for proper encoding
	return $.param(this.formToArray(semantic));
};

/**
 * Serializes all field elements in the jQuery object into a query string.
 * This method will return a string in the format: name1=value1&amp;name2=value2
 */
$.fn.fieldSerialize = function(successful) {
	var a = [];
	this.each(function() {
		var n = this.name;
		if (!n) {
			return;
		}
		var v = $.fieldValue(this, successful);
		if (v && v.constructor == Array) {
			for (var i=0,max=v.length; i < max; i++) {
				a.push({name: n, value: v[i]});
			}
		}
		else if (v !== null && typeof v != 'undefined') {
			a.push({name: this.name, value: v});
		}
	});
	//hand off to jQuery.param for proper encoding
	return $.param(a);
};

/**
 * Returns the value(s) of the element in the matched set.  For example, consider the following form:
 *
 *  <form><fieldset>
 *	  <input name="A" type="text" />
 *	  <input name="A" type="text" />
 *	  <input name="B" type="checkbox" value="B1" />
 *	  <input name="B" type="checkbox" value="B2"/>
 *	  <input name="C" type="radio" value="C1" />
 *	  <input name="C" type="radio" value="C2" />
 *  </fieldset></form>
 *
 *  var v = $(':text').fieldValue();
 *  // if no values are entered into the text inputs
 *  v == ['','']
 *  // if values entered into the text inputs are 'foo' and 'bar'
 *  v == ['foo','bar']
 *
 *  var v = $(':checkbox').fieldValue();
 *  // if neither checkbox is checked
 *  v === undefined
 *  // if both checkboxes are checked
 *  v == ['B1', 'B2']
 *
 *  var v = $(':radio').fieldValue();
 *  // if neither radio is checked
 *  v === undefined
 *  // if first radio is checked
 *  v == ['C1']
 *
 * The successful argument controls whether or not the field element must be 'successful'
 * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
 * The default value of the successful argument is true.  If this value is false the value(s)
 * for each element is returned.
 *
 * Note: This method *always* returns an array.  If no valid value can be determined the
 *	   array will be empty, otherwise it will contain one or more values.
 */
$.fn.fieldValue = function(successful) {
	for (var val=[], i=0, max=this.length; i < max; i++) {
		var el = this[i];
		var v = $.fieldValue(el, successful);
		if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) {
			continue;
		}
		v.constructor == Array ? $.merge(val, v) : val.push(v);
	}
	return val;
};

/**
 * Returns the value of the field element.
 */
$.fieldValue = function(el, successful) {
	var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
	if (successful === undefined) {
		successful = true;
	}

	if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
		(t == 'checkbox' || t == 'radio') && !el.checked ||
		(t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
		tag == 'select' && el.selectedIndex == -1)) {
			return null;
	}

	if (tag == 'select') {
		var index = el.selectedIndex;
		if (index < 0) {
			return null;
		}
		var a = [], ops = el.options;
		var one = (t == 'select-one');
		var max = (one ? index+1 : ops.length);
		for(var i=(one ? index : 0); i < max; i++) {
			var op = ops[i];
			if (op.selected) {
				var v = op.value;
				if (!v) { // extra pain for IE...
					v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value;
				}
				if (one) {
					return v;
				}
				a.push(v);
			}
		}
		return a;
	}
	return $(el).val();
};

/**
 * Clears the form data.  Takes the following actions on the form's input fields:
 *  - input text fields will have their 'value' property set to the empty string
 *  - select elements will have their 'selectedIndex' property set to -1
 *  - checkbox and radio inputs will have their 'checked' property set to false
 *  - inputs of type submit, button, reset, and hidden will *not* be effected
 *  - button elements will *not* be effected
 */
$.fn.clearForm = function() {
	return this.each(function() {
		$('input,select,textarea', this).clearFields();
	});
};

/**
 * Clears the selected form elements.
 */
$.fn.clearFields = $.fn.clearInputs = function() {
	return this.each(function() {
		var t = this.type, tag = this.tagName.toLowerCase();
		if (t == 'text' || t == 'password' || tag == 'textarea') {
			this.value = '';
		}
		else if (t == 'checkbox' || t == 'radio') {
			this.checked = false;
		}
		else if (tag == 'select') {
			this.selectedIndex = -1;
		}
	});
};

/**
 * Resets the form data.  Causes all form elements to be reset to their original value.
 */
$.fn.resetForm = function() {
	return this.each(function() {
		// guard against an input with the name of 'reset'
		// note that IE reports the reset function as an 'object'
		if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) {
			this.reset();
		}
	});
};

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

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

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

})(jQuery);
 /*!
 * jQuery FN Google Map 3.0-alpha
 * http://code.google.com/p/jquery-ui-map/
 * Copyright (c) 2010 - 2011 Johan Säll Larsson
 * Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
 */
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($){$.a=3(a,b,c){j d=[];$[a]=$[a]||{};$[a][b]=3(a,b){6(P.I){2.1d(a,b)}};$[a][b].L=c;$.14[b]=3(c){j e=2.1i(\'p\');6(d[e]&&d[e][c]){7 d[e][c].1a(d[e],R.L.1f.1h(P,1))}m 6(29 c===\'28\'||!c){d[e]=l $[a][b](c,2);7 2}}};$.a("27","26",{n:{E:(9.8)?l 9.8.O(0.0,0.0):s,1o:\'25\',Y:5},24:3(a,b){c=2;6(!b){7 c.n[a]}m{c.S(a,b)}},1d:3(a,b){2.p=b.1i(\'p\');2.w=[];2.17=b;2.n=o.r(2.n,a);2.1b();6(2.1c){2.1c()}},1b:3(){2.n.E=2.z(2.n.E);j a=2.17;j b=2.w[2.p]={k:l 9.8.23(a[0],2.n),C:[],t:[],u:[]};j c=2;9.8.y.21(b.k,\'1Z\',3(){a.T(\'1U\',2);a.T(\'1S\',c)});7 $(b.k)},S:3(a,b){j d=2.4(\'k\');o.r(2.n,{\'E\':d.1R(),\'1o\':d.1N(),\'Y\':d.1G()});6(a&&b){2.n[a]=b}d.A(2.n);6(!(a&&b)){j c=d.1D();6(c){d.1B(c)}}},15:3(a){2.4(\'B\',l 9.8.2b()).r(2.z(a));2.4(\'k\').1A(2.4(\'B\'))},1y:3(a,b){2.4(\'k\').1w[b].K(2.D(a))},1u:3(a,b,c){j d=2.4(\'k\');j c=c||9.8.1s;a.N=(a.N)?2.z(a.N):s;j e=l c(o.r({\'k\':d,\'B\':1r},a));j f=2.4(\'C\',[]);6(e.p){f[e.p]=e}m{f.K(e)}6(e.B){2.15(e.1O())}2.x(b,d,e);7 $(e)},1q:3(a,b){j c=l 9.8.1l(a);2.x(b,c);7 $(c)},F:3(a){2.U(2.4(a));2.V(a,[])},U:3(a){G(b Q a){6(a[b]v 9.8.1e){9.8.y.1t(a[b]);a[b].M(s)}m 6(a[b]v R){2.U(a[b])}a[b]=s}},1v:3(a,b,c,d){j e=2.4(\'C\');G(f Q e){j g=(c&&e[f][a])?($.1x(b,e[f][a].J(c))>-1):(e[f][a]===b);2.x(d,e[f],g)}},4:3(a,b){j c=2.w[2.p];6(!c[a]){6(a.1z(\'>\')>-1){j e=a.18(/ /g,\'\').J(\'>\');G(j i=0;i<e.I;i++){6(!c[e[i]]){6(b){c[e[i]]=((i+1)<e.I)?[]:b}m{7 s}}c=c[e[i]]}7 c}m 6(b&&!c[a]){2.V(a,b)}}7 c[a]},1C:3(a,b){2.4(\'13\',l 9.8.1l).A(a);2.4(\'13\').1E(2.4(\'k\'),2.D(b))},V:3(a,b){2.w[2.p][a]=b},1F:3(){$(2.4(\'k\')).11(\'1H\');2.S()},1I:3(){2.F(\'C\');2.F(\'t\');2.F(\'u\');j a=2.w[2.p];G(b Q a){a[b]=s}},x:3(a){6($.1J(a)){a.1a(2,R.L.1f.1h(P,1))}},z:3(a){6(a v 9.8.O){7 a}m{j b=a.18(/ /g,\'\').J(\',\');7 l 9.8.O(b[0],b[1])}},D:3(a){6(!a){7 s}m 6(a v o){7 a[0]}m 6(a v 1K){7 a}7 $(\'#\'+a)[0]},1L:3(a,b){7 $(2.4(\'u > \'+a,[]).K(l 9.8[a](o.r({\'k\':2.4(\'k\')},b))))},1M:3(a,b){((!b)?2.4(\'u > H\',l 9.8.H()):2.4(\'u > H\',l 9.8.H(b,a))).A(o.r({\'k\':2.4(\'k\')},a))},1p:3(a,b,c){2.4(\'u > \'+a,l 9.8.1P(b,o.r({\'k\':2.4(\'k\')},c)))},1Q:3(a,b,c){j d=2;j e=2.4(\'t > Z\',l 9.8.Z());j f=2.4(\'t > X\',l 9.8.X());6(b){f.A(b)}e.1T(a,3(g,h){6(h===\'1V\'){f.1W(g);f.M(d.4(\'k\'))}m{f.M(s)}d.x(c,g,h)})},1X:3(a,b){2.4(\'k\').1Y(2.4(\'t > 1n\',l 9.8.1n(2.D(a),b)))},20:3(a,b){2.4(\'t > 1m\',l 9.8.1m()).22(a,b)}});o.14.r({1g:3(a,b){7 2.q(\'1g\',a,b)},10:3(a){7 2.q(\'10\',a)},W:3(a,b){7 2.q(\'W\',a,b)},19:3(a,b){7 2.q(\'19\',a,b)},16:3(a,b){7 2.q(\'16\',a,b)},12:3(a){7 2.q(\'12\',a)},1k:3(a){7 2.q(\'1k\',a)},11:3(a){9.8.y.T(2[0],a)},q:3(a,b,c){6(9.8&&2[0]v 9.8.1e){9.8.y.2a(2[0],a,b)}m{6(c){2.1j(a,b,c)}m{2.1j(a,b)}}7 2}})}(o));',62,136,'||this|function|get||if|return|maps|google||||||||||var|map|new|else|options|jQuery|id|addEventListener|extend|null|services|overlays|instanceof|instances|_call|event|_latLng|setOptions|bounds|markers|_unwrap|center|clear|for|FusionTablesLayer|length|split|push|prototype|setMap|position|LatLng|arguments|in|Array|_u|trigger|_c|set|dblclick|DirectionsRenderer|zoom|DirectionsService|rightclick|triggerEvent|drag|iw|fn|addBounds|mouseout|element|replace|mouseover|apply|_create|_init|_s|MVCObject|slice|click|call|attr|bind|dragend|InfoWindow|Geocoder|StreetViewPanorama|mapTypeId|loadKML|addInfoWindow|false|Marker|clearInstanceListeners|addMarker|findMarker|controls|inArray|addControl|indexOf|fitBounds|panToBounds|openInfoWindow|getBounds|open|refresh|getZoom|resize|destroy|isFunction|Object|addShape|loadFusion|getMapTypeId|getPosition|KmlLayer|displayDirections|getCenter|1337|route|init|OK|setDirections|displayStreetView|setStreetView|bounds_changed|search|addListenerOnce|geocode|Map|option|roadmap|gmap|ui|object|typeof|addListener|LatLngBounds'.split('|'),0,{}))/*
    http://www.JSON.org/json2.js
    2010-03-20

    Public Domain.

    NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.

    See http://www.JSON.org/js.html


    This code should be minified before deployment.
    See http://javascript.crockford.com/jsmin.html

    USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
    NOT CONTROL.


    This file creates a global JSON object containing two methods: stringify
    and parse.

        JSON.stringify(value, replacer, space)
            value       any JavaScript value, usually an object or array.

            replacer    an optional parameter that determines how object
                        values are stringified for objects. It can be a
                        function or an array of strings.

            space       an optional parameter that specifies the indentation
                        of nested structures. If it is omitted, the text will
                        be packed without extra whitespace. If it is a number,
                        it will specify the number of spaces to indent at each
                        level. If it is a string (such as '\t' or '&nbsp;'),
                        it contains the characters used to indent at each level.

            This method produces a JSON text from a JavaScript value.

            When an object value is found, if the object contains a toJSON
            method, its toJSON method will be called and the result will be
            stringified. A toJSON method does not serialize: it returns the
            value represented by the name/value pair that should be serialized,
            or undefined if nothing should be serialized. The toJSON method
            will be passed the key associated with the value, and this will be
            bound to the value

            For example, this would serialize Dates as ISO strings.

                Date.prototype.toJSON = function (key) {
                    function f(n) {
                        // Format integers to have at least two digits.
                        return n < 10 ? '0' + n : n;
                    }

                    return this.getUTCFullYear()   + '-' +
                         f(this.getUTCMonth() + 1) + '-' +
                         f(this.getUTCDate())      + 'T' +
                         f(this.getUTCHours())     + ':' +
                         f(this.getUTCMinutes())   + ':' +
                         f(this.getUTCSeconds())   + 'Z';
                };

            You can provide an optional replacer method. It will be passed the
            key and value of each member, with this bound to the containing
            object. The value that is returned from your method will be
            serialized. If your method returns undefined, then the member will
            be excluded from the serialization.

            If the replacer parameter is an array of strings, then it will be
            used to select the members to be serialized. It filters the results
            such that only members with keys listed in the replacer array are
            stringified.

            Values that do not have JSON representations, such as undefined or
            functions, will not be serialized. Such values in objects will be
            dropped; in arrays they will be replaced with null. You can use
            a replacer function to replace those with JSON values.
            JSON.stringify(undefined) returns undefined.

            The optional space parameter produces a stringification of the
            value that is filled with line breaks and indentation to make it
            easier to read.

            If the space parameter is a non-empty string, then that string will
            be used for indentation. If the space parameter is a number, then
            the indentation will be that many spaces.

            Example:

            text = JSON.stringify(['e', {pluribus: 'unum'}]);
            // text is '["e",{"pluribus":"unum"}]'


            text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
            // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'

            text = JSON.stringify([new Date()], function (key, value) {
                return this[key] instanceof Date ?
                    'Date(' + this[key] + ')' : value;
            });
            // text is '["Date(---current time---)"]'


        JSON.parse(text, reviver)
            This method parses a JSON text to produce an object or array.
            It can throw a SyntaxError exception.

            The optional reviver parameter is a function that can filter and
            transform the results. It receives each of the keys and values,
            and its return value is used instead of the original value.
            If it returns what it received, then the structure is not modified.
            If it returns undefined then the member is deleted.

            Example:

            // Parse the text. Values that look like ISO date strings will
            // be converted to Date objects.

            myData = JSON.parse(text, function (key, value) {
                var a;
                if (typeof value === 'string') {
                    a =
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
                    if (a) {
                        return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
                            +a[5], +a[6]));
                    }
                }
                return value;
            });

            myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
                var d;
                if (typeof value === 'string' &&
                        value.slice(0, 5) === 'Date(' &&
                        value.slice(-1) === ')') {
                    d = new Date(value.slice(5, -1));
                    if (d) {
                        return d;
                    }
                }
                return value;
            });


    This is a reference implementation. You are free to copy, modify, or
    redistribute.
*/

/*jslint evil: true, strict: false */

/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
    call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
    getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
    lastIndex, length, parse, prototype, push, replace, slice, stringify,
    test, toJSON, toString, valueOf
*/


// Create a JSON object only if one does not already exist. We create the
// methods in a closure to avoid creating global variables.

if (!this.JSON) {
    this.JSON = {};
}

(function () {

    function f(n) {
        // Format integers to have at least two digits.
        return n < 10 ? '0' + n : n;
    }

    if (typeof Date.prototype.toJSON !== 'function') {

        Date.prototype.toJSON = function (key) {

            return isFinite(this.valueOf()) ?
                   this.getUTCFullYear()   + '-' +
                 f(this.getUTCMonth() + 1) + '-' +
                 f(this.getUTCDate())      + 'T' +
                 f(this.getUTCHours())     + ':' +
                 f(this.getUTCMinutes())   + ':' +
                 f(this.getUTCSeconds())   + 'Z' : null;
        };

        String.prototype.toJSON =
        Number.prototype.toJSON =
        Boolean.prototype.toJSON = function (key) {
            return this.valueOf();
        };
    }

    var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
        escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
        gap,
        indent,
        meta = {    // table of character substitutions
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"' : '\\"',
            '\\': '\\\\'
        },
        rep;


    function quote(string) {

// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.

        escapable.lastIndex = 0;
        return escapable.test(string) ?
            '"' + string.replace(escapable, function (a) {
                var c = meta[a];
                return typeof c === 'string' ? c :
                    '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
            }) + '"' :
            '"' + string + '"';
    }


    function str(key, holder) {

// Produce a string from holder[key].

        var i,          // The loop counter.
            k,          // The member key.
            v,          // The member value.
            length,
            mind = gap,
            partial,
            value = holder[key];

// If the value has a toJSON method, call it to obtain a replacement value.

        if (value && typeof value === 'object' &&
                typeof value.toJSON === 'function') {
            value = value.toJSON(key);
        }

// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.

        if (typeof rep === 'function') {
            value = rep.call(holder, key, value);
        }

// What happens next depends on the value's type.

        switch (typeof value) {
        case 'string':
            return quote(value);

        case 'number':

// JSON numbers must be finite. Encode non-finite numbers as null.

            return isFinite(value) ? String(value) : 'null';

        case 'boolean':
        case 'null':

// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce 'null'. The case is included here in
// the remote chance that this gets fixed someday.

            return String(value);

// If the type is 'object', we might be dealing with an object or an array or
// null.

        case 'object':

// Due to a specification blunder in ECMAScript, typeof null is 'object',
// so watch out for that case.

            if (!value) {
                return 'null';
            }

// Make an array to hold the partial results of stringifying this object value.

            gap += indent;
            partial = [];

// Is the value an array?

            if (Object.prototype.toString.apply(value) === '[object Array]') {

// The value is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.

                length = value.length;
                for (i = 0; i < length; i += 1) {
                    partial[i] = str(i, value) || 'null';
                }

// Join all of the elements together, separated with commas, and wrap them in
// brackets.

                v = partial.length === 0 ? '[]' :
                    gap ? '[\n' + gap +
                            partial.join(',\n' + gap) + '\n' +
                                mind + ']' :
                          '[' + partial.join(',') + ']';
                gap = mind;
                return v;
            }

// If the replacer is an array, use it to select the members to be stringified.

            if (rep && typeof rep === 'object') {
                length = rep.length;
                for (i = 0; i < length; i += 1) {
                    k = rep[i];
                    if (typeof k === 'string') {
                        v = str(k, value);
                        if (v) {
                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
                        }
                    }
                }
            } else {

// Otherwise, iterate through all of the keys in the object.

                for (k in value) {
                    if (Object.hasOwnProperty.call(value, k)) {
                        v = str(k, value);
                        if (v) {
                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
                        }
                    }
                }
            }

// Join all of the member texts together, separated with commas,
// and wrap them in braces.

            v = partial.length === 0 ? '{}' :
                gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
                        mind + '}' : '{' + partial.join(',') + '}';
            gap = mind;
            return v;
        }
    }

// If the JSON object does not yet have a stringify method, give it one.

    if (typeof JSON.stringify !== 'function') {
        JSON.stringify = function (value, replacer, space) {

// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
// that can replace values, or an array of strings that will select the keys.
// A default replacer method can be provided. Use of the space parameter can
// produce text that is more easily readable.

            var i;
            gap = '';
            indent = '';

// If the space parameter is a number, make an indent string containing that
// many spaces.

            if (typeof space === 'number') {
                for (i = 0; i < space; i += 1) {
                    indent += ' ';
                }

// If the space parameter is a string, it will be used as the indent string.

            } else if (typeof space === 'string') {
                indent = space;
            }

// If there is a replacer, it must be a function or an array.
// Otherwise, throw an error.

            rep = replacer;
            if (replacer && typeof replacer !== 'function' &&
                    (typeof replacer !== 'object' ||
                     typeof replacer.length !== 'number')) {
                throw new Error('JSON.stringify');
            }

// Make a fake root object containing our value under the key of ''.
// Return the result of stringifying the value.

            return str('', {'': value});
        };
    }


// If the JSON object does not yet have a parse method, give it one.

    if (typeof JSON.parse !== 'function') {
        JSON.parse = function (text, reviver) {

// The parse method takes a text and an optional reviver function, and returns
// a JavaScript value if the text is a valid JSON text.

            var j;

            function walk(holder, key) {

// The walk method is used to recursively walk the resulting structure so
// that modifications can be made.

                var k, v, value = holder[key];
                if (value && typeof value === 'object') {
                    for (k in value) {
                        if (Object.hasOwnProperty.call(value, k)) {
                            v = walk(value, k);
                            if (v !== undefined) {
                                value[k] = v;
                            } else {
                                delete value[k];
                            }
                        }
                    }
                }
                return reviver.call(holder, key, value);
            }


// Parsing happens in four stages. In the first stage, we replace certain
// Unicode characters with escape sequences. JavaScript handles many characters
// incorrectly, either silently deleting them, or treating them as line endings.

            text = String(text);
            cx.lastIndex = 0;
            if (cx.test(text)) {
                text = text.replace(cx, function (a) {
                    return '\\u' +
                        ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
                });
            }

// In the second stage, we run the text against regular expressions that look
// for non-JSON patterns. We are especially concerned with '()' and 'new'
// because they can cause invocation, and '=' because it can cause mutation.
// But just to be safe, we want to reject all unexpected forms.

// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
// replace all simple value tokens with ']' characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.

            if (/^[\],:{}\s]*$/.
test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {

// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.

                j = eval('(' + text + ')');

// In the optional fourth stage, we recursively walk the new structure, passing
// each name/value pair to a reviver function for possible transformation.

                return typeof reviver === 'function' ?
                    walk({'': j}, '') : j;
            }

// If the text is not JSON parseable, then a SyntaxError is thrown.

            throw new SyntaxError('JSON.parse');
        };
    }
}());
/**
 * @version: 1.0 Alpha-1
 * @author: Coolite Inc. http://www.coolite.com/
 * @date: 2008-05-13
 * @copyright: Copyright (c) 2006-2008, Coolite Inc. (http://www.coolite.com/). All rights reserved.
 * @license: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/.
 * @website: http://www.datejs.com/
 */
Date.CultureInfo={name:"en-US",englishName:"English (United States)",nativeName:"English (United States)",dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],abbreviatedDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],shortestDayNames:["Su","Mo","Tu","We","Th","Fr","Sa"],firstLetterDayNames:["S","M","T","W","T","F","S"],monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],abbreviatedMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],amDesignator:"AM",pmDesignator:"PM",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"mdy",formatPatterns:{shortDate:"M/d/yyyy",longDate:"dddd, MMMM dd, yyyy",shortTime:"h:mm tt",longTime:"h:mm:ss tt",fullDateTime:"dddd, MMMM dd, yyyy h:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^jan(uary)?/i,feb:/^feb(ruary)?/i,mar:/^mar(ch)?/i,apr:/^apr(il)?/i,may:/^may/i,jun:/^jun(e)?/i,jul:/^jul(y)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^oct(ober)?/i,nov:/^nov(ember)?/i,dec:/^dec(ember)?/i,sun:/^su(n(day)?)?/i,mon:/^mo(n(day)?)?/i,tue:/^tu(e(s(day)?)?)?/i,wed:/^we(d(nesday)?)?/i,thu:/^th(u(r(s(day)?)?)?)?/i,fri:/^fr(i(day)?)?/i,sat:/^sa(t(urday)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\+|aft(er)?|from|hence)/i,subtract:/^(\-|bef(ore)?|ago)/i,yesterday:/^yes(terday)?/i,today:/^t(od(ay)?)?/i,tomorrow:/^tom(orrow)?/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^mn|min(ute)?s?/i,hour:/^h(our)?s?/i,week:/^w(eek)?s?/i,month:/^m(onth)?s?/i,day:/^d(ay)?s?/i,year:/^y(ear)?s?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\.?m?\.?|p\.?m?\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,ordinalSuffix:/^\s*(st|nd|rd|th)/i,timeContext:/^\s*(\:|a(?!u|p)|p)/i},timezones:[{name:"UTC",offset:"-000"},{name:"GMT",offset:"-000"},{name:"EST",offset:"-0500"},{name:"EDT",offset:"-0400"},{name:"CST",offset:"-0600"},{name:"CDT",offset:"-0500"},{name:"MST",offset:"-0700"},{name:"MDT",offset:"-0600"},{name:"PST",offset:"-0800"},{name:"PDT",offset:"-0700"}]};
(function(){var $D=Date,$P=$D.prototype,$C=$D.CultureInfo,p=function(s,l){if(!l){l=2;}
return("000"+s).slice(l*-1);};$P.clearTime=function(){this.setHours(0);this.setMinutes(0);this.setSeconds(0);this.setMilliseconds(0);return this;};$P.setTimeToNow=function(){var n=new Date();this.setHours(n.getHours());this.setMinutes(n.getMinutes());this.setSeconds(n.getSeconds());this.setMilliseconds(n.getMilliseconds());return this;};$D.today=function(){return new Date().clearTime();};$D.compare=function(date1,date2){if(isNaN(date1)||isNaN(date2)){throw new Error(date1+" - "+date2);}else if(date1 instanceof Date&&date2 instanceof Date){return(date1<date2)?-1:(date1>date2)?1:0;}else{throw new TypeError(date1+" - "+date2);}};$D.equals=function(date1,date2){return(date1.compareTo(date2)===0);};$D.getDayNumberFromName=function(name){var n=$C.dayNames,m=$C.abbreviatedDayNames,o=$C.shortestDayNames,s=name.toLowerCase();for(var i=0;i<n.length;i++){if(n[i].toLowerCase()==s||m[i].toLowerCase()==s||o[i].toLowerCase()==s){return i;}}
return-1;};$D.getMonthNumberFromName=function(name){var n=$C.monthNames,m=$C.abbreviatedMonthNames,s=name.toLowerCase();for(var i=0;i<n.length;i++){if(n[i].toLowerCase()==s||m[i].toLowerCase()==s){return i;}}
return-1;};$D.isLeapYear=function(year){return((year%4===0&&year%100!==0)||year%400===0);};$D.getDaysInMonth=function(year,month){return[31,($D.isLeapYear(year)?29:28),31,30,31,30,31,31,30,31,30,31][month];};$D.getTimezoneAbbreviation=function(offset){var z=$C.timezones,p;for(var i=0;i<z.length;i++){if(z[i].offset===offset){return z[i].name;}}
return null;};$D.getTimezoneOffset=function(name){var z=$C.timezones,p;for(var i=0;i<z.length;i++){if(z[i].name===name.toUpperCase()){return z[i].offset;}}
return null;};$P.clone=function(){return new Date(this.getTime());};$P.compareTo=function(date){return Date.compare(this,date);};$P.equals=function(date){return Date.equals(this,date||new Date());};$P.between=function(start,end){return this.getTime()>=start.getTime()&&this.getTime()<=end.getTime();};$P.isAfter=function(date){return this.compareTo(date||new Date())===1;};$P.isBefore=function(date){return(this.compareTo(date||new Date())===-1);};$P.isToday=function(){return this.isSameDay(new Date());};$P.isSameDay=function(date){return this.clone().clearTime().equals(date.clone().clearTime());};$P.addMilliseconds=function(value){this.setMilliseconds(this.getMilliseconds()+value);return this;};$P.addSeconds=function(value){return this.addMilliseconds(value*1000);};$P.addMinutes=function(value){return this.addMilliseconds(value*60000);};$P.addHours=function(value){return this.addMilliseconds(value*3600000);};$P.addDays=function(value){this.setDate(this.getDate()+value);return this;};$P.addWeeks=function(value){return this.addDays(value*7);};$P.addMonths=function(value){var n=this.getDate();this.setDate(1);this.setMonth(this.getMonth()+value);this.setDate(Math.min(n,$D.getDaysInMonth(this.getFullYear(),this.getMonth())));return this;};$P.addYears=function(value){return this.addMonths(value*12);};$P.add=function(config){if(typeof config=="number"){this._orient=config;return this;}
var x=config;if(x.milliseconds){this.addMilliseconds(x.milliseconds);}
if(x.seconds){this.addSeconds(x.seconds);}
if(x.minutes){this.addMinutes(x.minutes);}
if(x.hours){this.addHours(x.hours);}
if(x.weeks){this.addWeeks(x.weeks);}
if(x.months){this.addMonths(x.months);}
if(x.years){this.addYears(x.years);}
if(x.days){this.addDays(x.days);}
return this;};var $y,$m,$d;$P.getWeek=function(){var a,b,c,d,e,f,g,n,s,w;$y=(!$y)?this.getFullYear():$y;$m=(!$m)?this.getMonth()+1:$m;$d=(!$d)?this.getDate():$d;if($m<=2){a=$y-1;b=(a/4|0)-(a/100|0)+(a/400|0);c=((a-1)/4|0)-((a-1)/100|0)+((a-1)/400|0);s=b-c;e=0;f=$d-1+(31*($m-1));}else{a=$y;b=(a/4|0)-(a/100|0)+(a/400|0);c=((a-1)/4|0)-((a-1)/100|0)+((a-1)/400|0);s=b-c;e=s+1;f=$d+((153*($m-3)+2)/5)+58+s;}
g=(a+b)%7;d=(f+g-e)%7;n=(f+3-d)|0;if(n<0){w=53-((g-s)/5|0);}else if(n>364+s){w=1;}else{w=(n/7|0)+1;}
$y=$m=$d=null;return w;};$P.getISOWeek=function(){$y=this.getUTCFullYear();$m=this.getUTCMonth()+1;$d=this.getUTCDate();return p(this.getWeek());};$P.setWeek=function(n){return this.moveToDayOfWeek(1).addWeeks(n-this.getWeek());};$D._validate=function(n,min,max,name){if(typeof n=="undefined"){return false;}else if(typeof n!="number"){throw new TypeError(n+" is not a Number.");}else if(n<min||n>max){throw new RangeError(n+" is not a valid value for "+name+".");}
return true;};$D.validateMillisecond=function(value){return $D._validate(value,0,999,"millisecond");};$D.validateSecond=function(value){return $D._validate(value,0,59,"second");};$D.validateMinute=function(value){return $D._validate(value,0,59,"minute");};$D.validateHour=function(value){return $D._validate(value,0,23,"hour");};$D.validateDay=function(value,year,month){return $D._validate(value,1,$D.getDaysInMonth(year,month),"day");};$D.validateMonth=function(value){return $D._validate(value,0,11,"month");};$D.validateYear=function(value){return $D._validate(value,0,9999,"year");};$P.set=function(config){if($D.validateMillisecond(config.millisecond)){this.addMilliseconds(config.millisecond-this.getMilliseconds());}
if($D.validateSecond(config.second)){this.addSeconds(config.second-this.getSeconds());}
if($D.validateMinute(config.minute)){this.addMinutes(config.minute-this.getMinutes());}
if($D.validateHour(config.hour)){this.addHours(config.hour-this.getHours());}
if($D.validateMonth(config.month)){this.addMonths(config.month-this.getMonth());}
if($D.validateYear(config.year)){this.addYears(config.year-this.getFullYear());}
if($D.validateDay(config.day,this.getFullYear(),this.getMonth())){this.addDays(config.day-this.getDate());}
if(config.timezone){this.setTimezone(config.timezone);}
if(config.timezoneOffset){this.setTimezoneOffset(config.timezoneOffset);}
if(config.week&&$D._validate(config.week,0,53,"week")){this.setWeek(config.week);}
return this;};$P.moveToFirstDayOfMonth=function(){return this.set({day:1});};$P.moveToLastDayOfMonth=function(){return this.set({day:$D.getDaysInMonth(this.getFullYear(),this.getMonth())});};$P.moveToNthOccurrence=function(dayOfWeek,occurrence){var shift=0;if(occurrence>0){shift=occurrence-1;}
else if(occurrence===-1){this.moveToLastDayOfMonth();if(this.getDay()!==dayOfWeek){this.moveToDayOfWeek(dayOfWeek,-1);}
return this;}
return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek,+1).addWeeks(shift);};$P.moveToDayOfWeek=function(dayOfWeek,orient){var diff=(dayOfWeek-this.getDay()+7*(orient||+1))%7;return this.addDays((diff===0)?diff+=7*(orient||+1):diff);};$P.moveToMonth=function(month,orient){var diff=(month-this.getMonth()+12*(orient||+1))%12;return this.addMonths((diff===0)?diff+=12*(orient||+1):diff);};$P.getOrdinalNumber=function(){return Math.ceil((this.clone().clearTime()-new Date(this.getFullYear(),0,1))/86400000)+1;};$P.getTimezone=function(){return $D.getTimezoneAbbreviation(this.getUTCOffset());};$P.setTimezoneOffset=function(offset){var here=this.getTimezoneOffset(),there=Number(offset)*-6/10;return this.addMinutes(there-here);};$P.setTimezone=function(offset){return this.setTimezoneOffset($D.getTimezoneOffset(offset));};$P.hasDaylightSavingTime=function(){return(Date.today().set({month:0,day:1}).getTimezoneOffset()!==Date.today().set({month:6,day:1}).getTimezoneOffset());};$P.isDaylightSavingTime=function(){return(this.hasDaylightSavingTime()&&new Date().getTimezoneOffset()===Date.today().set({month:6,day:1}).getTimezoneOffset());};$P.getUTCOffset=function(){var n=this.getTimezoneOffset()*-10/6,r;if(n<0){r=(n-10000).toString();return r.charAt(0)+r.substr(2);}else{r=(n+10000).toString();return"+"+r.substr(1);}};$P.getElapsed=function(date){return(date||new Date())-this;};if(!$P.toISOString){$P.toISOString=function(){function f(n){return n<10?'0'+n:n;}
return'"'+this.getUTCFullYear()+'-'+
f(this.getUTCMonth()+1)+'-'+
f(this.getUTCDate())+'T'+
f(this.getUTCHours())+':'+
f(this.getUTCMinutes())+':'+
f(this.getUTCSeconds())+'Z"';};}
$P._toString=$P.toString;$P.toString=function(format){var x=this;if(format&&format.length==1){var c=$C.formatPatterns;x.t=x.toString;switch(format){case"d":return x.t(c.shortDate);case"D":return x.t(c.longDate);case"F":return x.t(c.fullDateTime);case"m":return x.t(c.monthDay);case"r":return x.t(c.rfc1123);case"s":return x.t(c.sortableDateTime);case"t":return x.t(c.shortTime);case"T":return x.t(c.longTime);case"u":return x.t(c.universalSortableDateTime);case"y":return x.t(c.yearMonth);}}
var ord=function(n){switch(n*1){case 1:case 21:case 31:return"st";case 2:case 22:return"nd";case 3:case 23:return"rd";default:return"th";}};return format?format.replace(/(\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S)/g,function(m){if(m.charAt(0)==="\\"){return m.replace("\\","");}
x.h=x.getHours;switch(m){case"hh":return p(x.h()<13?(x.h()===0?12:x.h()):(x.h()-12));case"h":return x.h()<13?(x.h()===0?12:x.h()):(x.h()-12);case"HH":return p(x.h());case"H":return x.h();case"mm":return p(x.getMinutes());case"m":return x.getMinutes();case"ss":return p(x.getSeconds());case"s":return x.getSeconds();case"yyyy":return p(x.getFullYear(),4);case"yy":return p(x.getFullYear());case"dddd":return $C.dayNames[x.getDay()];case"ddd":return $C.abbreviatedDayNames[x.getDay()];case"dd":return p(x.getDate());case"d":return x.getDate();case"MMMM":return $C.monthNames[x.getMonth()];case"MMM":return $C.abbreviatedMonthNames[x.getMonth()];case"MM":return p((x.getMonth()+1));case"M":return x.getMonth()+1;case"t":return x.h()<12?$C.amDesignator.substring(0,1):$C.pmDesignator.substring(0,1);case"tt":return x.h()<12?$C.amDesignator:$C.pmDesignator;case"S":return ord(x.getDate());default:return m;}}):this._toString();};}());
(function(){var $D=Date,$P=$D.prototype,$C=$D.CultureInfo,$N=Number.prototype;$P._orient=+1;$P._nth=null;$P._is=false;$P._same=false;$P._isSecond=false;$N._dateElement="day";$P.next=function(){this._orient=+1;return this;};$D.next=function(){return $D.today().next();};$P.last=$P.prev=$P.previous=function(){this._orient=-1;return this;};$D.last=$D.prev=$D.previous=function(){return $D.today().last();};$P.is=function(){this._is=true;return this;};$P.same=function(){this._same=true;this._isSecond=false;return this;};$P.today=function(){return this.same().day();};$P.weekday=function(){if(this._is){this._is=false;return(!this.is().sat()&&!this.is().sun());}
return false;};$P.at=function(time){return(typeof time==="string")?$D.parse(this.toString("d")+" "+time):this.set(time);};$N.fromNow=$N.after=function(date){var c={};c[this._dateElement]=this;return((!date)?new Date():date.clone()).add(c);};$N.ago=$N.before=function(date){var c={};c[this._dateElement]=this*-1;return((!date)?new Date():date.clone()).add(c);};var dx=("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),mx=("january february march april may june july august september october november december").split(/\s/),px=("Millisecond Second Minute Hour Day Week Month Year").split(/\s/),pxf=("Milliseconds Seconds Minutes Hours Date Week Month FullYear").split(/\s/),nth=("final first second third fourth fifth").split(/\s/),de;$P.toObject=function(){var o={};for(var i=0;i<px.length;i++){o[px[i].toLowerCase()]=this["get"+pxf[i]]();}
return o;};$D.fromObject=function(config){config.week=null;return Date.today().set(config);};var df=function(n){return function(){if(this._is){this._is=false;return this.getDay()==n;}
if(this._nth!==null){if(this._isSecond){this.addSeconds(this._orient*-1);}
this._isSecond=false;var ntemp=this._nth;this._nth=null;var temp=this.clone().moveToLastDayOfMonth();this.moveToNthOccurrence(n,ntemp);if(this>temp){throw new RangeError($D.getDayName(n)+" does not occur "+ntemp+" times in the month of "+$D.getMonthName(temp.getMonth())+" "+temp.getFullYear()+".");}
return this;}
return this.moveToDayOfWeek(n,this._orient);};};var sdf=function(n){return function(){var t=$D.today(),shift=n-t.getDay();if(n===0&&$C.firstDayOfWeek===1&&t.getDay()!==0){shift=shift+7;}
return t.addDays(shift);};};for(var i=0;i<dx.length;i++){$D[dx[i].toUpperCase()]=$D[dx[i].toUpperCase().substring(0,3)]=i;$D[dx[i]]=$D[dx[i].substring(0,3)]=sdf(i);$P[dx[i]]=$P[dx[i].substring(0,3)]=df(i);}
var mf=function(n){return function(){if(this._is){this._is=false;return this.getMonth()===n;}
return this.moveToMonth(n,this._orient);};};var smf=function(n){return function(){return $D.today().set({month:n,day:1});};};for(var j=0;j<mx.length;j++){$D[mx[j].toUpperCase()]=$D[mx[j].toUpperCase().substring(0,3)]=j;$D[mx[j]]=$D[mx[j].substring(0,3)]=smf(j);$P[mx[j]]=$P[mx[j].substring(0,3)]=mf(j);}
var ef=function(j){return function(){if(this._isSecond){this._isSecond=false;return this;}
if(this._same){this._same=this._is=false;var o1=this.toObject(),o2=(arguments[0]||new Date()).toObject(),v="",k=j.toLowerCase();for(var m=(px.length-1);m>-1;m--){v=px[m].toLowerCase();if(o1[v]!=o2[v]){return false;}
if(k==v){break;}}
return true;}
if(j.substring(j.length-1)!="s"){j+="s";}
return this["add"+j](this._orient);};};var nf=function(n){return function(){this._dateElement=n;return this;};};for(var k=0;k<px.length;k++){de=px[k].toLowerCase();$P[de]=$P[de+"s"]=ef(px[k]);$N[de]=$N[de+"s"]=nf(de);}
$P._ss=ef("Second");var nthfn=function(n){return function(dayOfWeek){if(this._same){return this._ss(arguments[0]);}
if(dayOfWeek||dayOfWeek===0){return this.moveToNthOccurrence(dayOfWeek,n);}
this._nth=n;if(n===2&&(dayOfWeek===undefined||dayOfWeek===null)){this._isSecond=true;return this.addSeconds(this._orient);}
return this;};};for(var l=0;l<nth.length;l++){$P[nth[l]]=(l===0)?nthfn(-1):nthfn(l);}}());
(function(){Date.Parsing={Exception:function(s){this.message="Parse error at '"+s.substring(0,10)+" ...'";}};var $P=Date.Parsing;var _=$P.Operators={rtoken:function(r){return function(s){var mx=s.match(r);if(mx){return([mx[0],s.substring(mx[0].length)]);}else{throw new $P.Exception(s);}};},token:function(s){return function(s){return _.rtoken(new RegExp("^\s*"+s+"\s*"))(s);};},stoken:function(s){return _.rtoken(new RegExp("^"+s));},until:function(p){return function(s){var qx=[],rx=null;while(s.length){try{rx=p.call(this,s);}catch(e){qx.push(rx[0]);s=rx[1];continue;}
break;}
return[qx,s];};},many:function(p){return function(s){var rx=[],r=null;while(s.length){try{r=p.call(this,s);}catch(e){return[rx,s];}
rx.push(r[0]);s=r[1];}
return[rx,s];};},optional:function(p){return function(s){var r=null;try{r=p.call(this,s);}catch(e){return[null,s];}
return[r[0],r[1]];};},not:function(p){return function(s){try{p.call(this,s);}catch(e){return[null,s];}
throw new $P.Exception(s);};},ignore:function(p){return p?function(s){var r=null;r=p.call(this,s);return[null,r[1]];}:null;},product:function(){var px=arguments[0],qx=Array.prototype.slice.call(arguments,1),rx=[];for(var i=0;i<px.length;i++){rx.push(_.each(px[i],qx));}
return rx;},cache:function(rule){var cache={},r=null;return function(s){try{r=cache[s]=(cache[s]||rule.call(this,s));}catch(e){r=cache[s]=e;}
if(r instanceof $P.Exception){throw r;}else{return r;}};},any:function(){var px=arguments;return function(s){var r=null;for(var i=0;i<px.length;i++){if(px[i]==null){continue;}
try{r=(px[i].call(this,s));}catch(e){r=null;}
if(r){return r;}}
throw new $P.Exception(s);};},each:function(){var px=arguments;return function(s){var rx=[],r=null;for(var i=0;i<px.length;i++){if(px[i]==null){continue;}
try{r=(px[i].call(this,s));}catch(e){throw new $P.Exception(s);}
rx.push(r[0]);s=r[1];}
return[rx,s];};},all:function(){var px=arguments,_=_;return _.each(_.optional(px));},sequence:function(px,d,c){d=d||_.rtoken(/^\s*/);c=c||null;if(px.length==1){return px[0];}
return function(s){var r=null,q=null;var rx=[];for(var i=0;i<px.length;i++){try{r=px[i].call(this,s);}catch(e){break;}
rx.push(r[0]);try{q=d.call(this,r[1]);}catch(ex){q=null;break;}
s=q[1];}
if(!r){throw new $P.Exception(s);}
if(q){throw new $P.Exception(q[1]);}
if(c){try{r=c.call(this,r[1]);}catch(ey){throw new $P.Exception(r[1]);}}
return[rx,(r?r[1]:s)];};},between:function(d1,p,d2){d2=d2||d1;var _fn=_.each(_.ignore(d1),p,_.ignore(d2));return function(s){var rx=_fn.call(this,s);return[[rx[0][0],r[0][2]],rx[1]];};},list:function(p,d,c){d=d||_.rtoken(/^\s*/);c=c||null;return(p instanceof Array?_.each(_.product(p.slice(0,-1),_.ignore(d)),p.slice(-1),_.ignore(c)):_.each(_.many(_.each(p,_.ignore(d))),px,_.ignore(c)));},set:function(px,d,c){d=d||_.rtoken(/^\s*/);c=c||null;return function(s){var r=null,p=null,q=null,rx=null,best=[[],s],last=false;for(var i=0;i<px.length;i++){q=null;p=null;r=null;last=(px.length==1);try{r=px[i].call(this,s);}catch(e){continue;}
rx=[[r[0]],r[1]];if(r[1].length>0&&!last){try{q=d.call(this,r[1]);}catch(ex){last=true;}}else{last=true;}
if(!last&&q[1].length===0){last=true;}
if(!last){var qx=[];for(var j=0;j<px.length;j++){if(i!=j){qx.push(px[j]);}}
p=_.set(qx,d).call(this,q[1]);if(p[0].length>0){rx[0]=rx[0].concat(p[0]);rx[1]=p[1];}}
if(rx[1].length<best[1].length){best=rx;}
if(best[1].length===0){break;}}
if(best[0].length===0){return best;}
if(c){try{q=c.call(this,best[1]);}catch(ey){throw new $P.Exception(best[1]);}
best[1]=q[1];}
return best;};},forward:function(gr,fname){return function(s){return gr[fname].call(this,s);};},replace:function(rule,repl){return function(s){var r=rule.call(this,s);return[repl,r[1]];};},process:function(rule,fn){return function(s){var r=rule.call(this,s);return[fn.call(this,r[0]),r[1]];};},min:function(min,rule){return function(s){var rx=rule.call(this,s);if(rx[0].length<min){throw new $P.Exception(s);}
return rx;};}};var _generator=function(op){return function(){var args=null,rx=[];if(arguments.length>1){args=Array.prototype.slice.call(arguments);}else if(arguments[0]instanceof Array){args=arguments[0];}
if(args){for(var i=0,px=args.shift();i<px.length;i++){args.unshift(px[i]);rx.push(op.apply(null,args));args.shift();return rx;}}else{return op.apply(null,arguments);}};};var gx="optional not ignore cache".split(/\s/);for(var i=0;i<gx.length;i++){_[gx[i]]=_generator(_[gx[i]]);}
var _vector=function(op){return function(){if(arguments[0]instanceof Array){return op.apply(null,arguments[0]);}else{return op.apply(null,arguments);}};};var vx="each any all".split(/\s/);for(var j=0;j<vx.length;j++){_[vx[j]]=_vector(_[vx[j]]);}}());(function(){var $D=Date,$P=$D.prototype,$C=$D.CultureInfo;var flattenAndCompact=function(ax){var rx=[];for(var i=0;i<ax.length;i++){if(ax[i]instanceof Array){rx=rx.concat(flattenAndCompact(ax[i]));}else{if(ax[i]){rx.push(ax[i]);}}}
return rx;};$D.Grammar={};$D.Translator={hour:function(s){return function(){this.hour=Number(s);};},minute:function(s){return function(){this.minute=Number(s);};},second:function(s){return function(){this.second=Number(s);};},meridian:function(s){return function(){this.meridian=s.slice(0,1).toLowerCase();};},timezone:function(s){return function(){var n=s.replace(/[^\d\+\-]/g,"");if(n.length){this.timezoneOffset=Number(n);}else{this.timezone=s.toLowerCase();}};},day:function(x){var s=x[0];return function(){this.day=Number(s.match(/\d+/)[0]);};},month:function(s){return function(){this.month=(s.length==3)?"jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4:Number(s)-1;};},year:function(s){return function(){var n=Number(s);this.year=((s.length>2)?n:(n+(((n+2000)<$C.twoDigitYearMax)?2000:1900)));};},rday:function(s){return function(){switch(s){case"yesterday":this.days=-1;break;case"tomorrow":this.days=1;break;case"today":this.days=0;break;case"now":this.days=0;this.now=true;break;}};},finishExact:function(x){x=(x instanceof Array)?x:[x];for(var i=0;i<x.length;i++){if(x[i]){x[i].call(this);}}
var now=new Date();if((this.hour||this.minute)&&(!this.month&&!this.year&&!this.day)){this.day=now.getDate();}
if(!this.year){this.year=now.getFullYear();}
if(!this.month&&this.month!==0){this.month=now.getMonth();}
if(!this.day){this.day=1;}
if(!this.hour){this.hour=0;}
if(!this.minute){this.minute=0;}
if(!this.second){this.second=0;}
if(this.meridian&&this.hour){if(this.meridian=="p"&&this.hour<12){this.hour=this.hour+12;}else if(this.meridian=="a"&&this.hour==12){this.hour=0;}}
if(this.day>$D.getDaysInMonth(this.year,this.month)){throw new RangeError(this.day+" is not a valid value for days.");}
var r=new Date(this.year,this.month,this.day,this.hour,this.minute,this.second);if(this.timezone){r.set({timezone:this.timezone});}else if(this.timezoneOffset){r.set({timezoneOffset:this.timezoneOffset});}
return r;},finish:function(x){x=(x instanceof Array)?flattenAndCompact(x):[x];if(x.length===0){return null;}
for(var i=0;i<x.length;i++){if(typeof x[i]=="function"){x[i].call(this);}}
var today=$D.today();if(this.now&&!this.unit&&!this.operator){return new Date();}else if(this.now){today=new Date();}
var expression=!!(this.days&&this.days!==null||this.orient||this.operator);var gap,mod,orient;orient=((this.orient=="past"||this.operator=="subtract")?-1:1);if(!this.now&&"hour minute second".indexOf(this.unit)!=-1){today.setTimeToNow();}
if(this.month||this.month===0){if("year day hour minute second".indexOf(this.unit)!=-1){this.value=this.month+1;this.month=null;expression=true;}}
if(!expression&&this.weekday&&!this.day&&!this.days){var temp=Date[this.weekday]();this.day=temp.getDate();if(!this.month){this.month=temp.getMonth();}
this.year=temp.getFullYear();}
if(expression&&this.weekday&&this.unit!="month"){this.unit="day";gap=($D.getDayNumberFromName(this.weekday)-today.getDay());mod=7;this.days=gap?((gap+(orient*mod))%mod):(orient*mod);}
if(this.month&&this.unit=="day"&&this.operator){this.value=(this.month+1);this.month=null;}
if(this.value!=null&&this.month!=null&&this.year!=null){this.day=this.value*1;}
if(this.month&&!this.day&&this.value){today.set({day:this.value*1});if(!expression){this.day=this.value*1;}}
if(!this.month&&this.value&&this.unit=="month"&&!this.now){this.month=this.value;expression=true;}
if(expression&&(this.month||this.month===0)&&this.unit!="year"){this.unit="month";gap=(this.month-today.getMonth());mod=12;this.months=gap?((gap+(orient*mod))%mod):(orient*mod);this.month=null;}
if(!this.unit){this.unit="day";}
if(!this.value&&this.operator&&this.operator!==null&&this[this.unit+"s"]&&this[this.unit+"s"]!==null){this[this.unit+"s"]=this[this.unit+"s"]+((this.operator=="add")?1:-1)+(this.value||0)*orient;}else if(this[this.unit+"s"]==null||this.operator!=null){if(!this.value){this.value=1;}
this[this.unit+"s"]=this.value*orient;}
if(this.meridian&&this.hour){if(this.meridian=="p"&&this.hour<12){this.hour=this.hour+12;}else if(this.meridian=="a"&&this.hour==12){this.hour=0;}}
if(this.weekday&&!this.day&&!this.days){var temp=Date[this.weekday]();this.day=temp.getDate();if(temp.getMonth()!==today.getMonth()){this.month=temp.getMonth();}}
if((this.month||this.month===0)&&!this.day){this.day=1;}
if(!this.orient&&!this.operator&&this.unit=="week"&&this.value&&!this.day&&!this.month){return Date.today().setWeek(this.value);}
if(expression&&this.timezone&&this.day&&this.days){this.day=this.days;}
return(expression)?today.add(this):today.set(this);}};var _=$D.Parsing.Operators,g=$D.Grammar,t=$D.Translator,_fn;g.datePartDelimiter=_.rtoken(/^([\s\-\.\,\/\x27]+)/);g.timePartDelimiter=_.stoken(":");g.whiteSpace=_.rtoken(/^\s*/);g.generalDelimiter=_.rtoken(/^(([\s\,]|at|@|on)+)/);var _C={};g.ctoken=function(keys){var fn=_C[keys];if(!fn){var c=$C.regexPatterns;var kx=keys.split(/\s+/),px=[];for(var i=0;i<kx.length;i++){px.push(_.replace(_.rtoken(c[kx[i]]),kx[i]));}
fn=_C[keys]=_.any.apply(null,px);}
return fn;};g.ctoken2=function(key){return _.rtoken($C.regexPatterns[key]);};g.h=_.cache(_.process(_.rtoken(/^(0[0-9]|1[0-2]|[1-9])/),t.hour));g.hh=_.cache(_.process(_.rtoken(/^(0[0-9]|1[0-2])/),t.hour));g.H=_.cache(_.process(_.rtoken(/^([0-1][0-9]|2[0-3]|[0-9])/),t.hour));g.HH=_.cache(_.process(_.rtoken(/^([0-1][0-9]|2[0-3])/),t.hour));g.m=_.cache(_.process(_.rtoken(/^([0-5][0-9]|[0-9])/),t.minute));g.mm=_.cache(_.process(_.rtoken(/^[0-5][0-9]/),t.minute));g.s=_.cache(_.process(_.rtoken(/^([0-5][0-9]|[0-9])/),t.second));g.ss=_.cache(_.process(_.rtoken(/^[0-5][0-9]/),t.second));g.hms=_.cache(_.sequence([g.H,g.m,g.s],g.timePartDelimiter));g.t=_.cache(_.process(g.ctoken2("shortMeridian"),t.meridian));g.tt=_.cache(_.process(g.ctoken2("longMeridian"),t.meridian));g.z=_.cache(_.process(_.rtoken(/^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/),t.timezone));g.zz=_.cache(_.process(_.rtoken(/^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/),t.timezone));g.zzz=_.cache(_.process(g.ctoken2("timezone"),t.timezone));g.timeSuffix=_.each(_.ignore(g.whiteSpace),_.set([g.tt,g.zzz]));g.time=_.each(_.optional(_.ignore(_.stoken("T"))),g.hms,g.timeSuffix);g.d=_.cache(_.process(_.each(_.rtoken(/^([0-2]\d|3[0-1]|\d)/),_.optional(g.ctoken2("ordinalSuffix"))),t.day));g.dd=_.cache(_.process(_.each(_.rtoken(/^([0-2]\d|3[0-1])/),_.optional(g.ctoken2("ordinalSuffix"))),t.day));g.ddd=g.dddd=_.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),function(s){return function(){this.weekday=s;};}));g.M=_.cache(_.process(_.rtoken(/^(1[0-2]|0\d|\d)/),t.month));g.MM=_.cache(_.process(_.rtoken(/^(1[0-2]|0\d)/),t.month));g.MMM=g.MMMM=_.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"),t.month));g.y=_.cache(_.process(_.rtoken(/^(\d\d?)/),t.year));g.yy=_.cache(_.process(_.rtoken(/^(\d\d)/),t.year));g.yyy=_.cache(_.process(_.rtoken(/^(\d\d?\d?\d?)/),t.year));g.yyyy=_.cache(_.process(_.rtoken(/^(\d\d\d\d)/),t.year));_fn=function(){return _.each(_.any.apply(null,arguments),_.not(g.ctoken2("timeContext")));};g.day=_fn(g.d,g.dd);g.month=_fn(g.M,g.MMM);g.year=_fn(g.yyyy,g.yy);g.orientation=_.process(g.ctoken("past future"),function(s){return function(){this.orient=s;};});g.operator=_.process(g.ctoken("add subtract"),function(s){return function(){this.operator=s;};});g.rday=_.process(g.ctoken("yesterday tomorrow today now"),t.rday);g.unit=_.process(g.ctoken("second minute hour day week month year"),function(s){return function(){this.unit=s;};});g.value=_.process(_.rtoken(/^\d\d?(st|nd|rd|th)?/),function(s){return function(){this.value=s.replace(/\D/g,"");};});g.expression=_.set([g.rday,g.operator,g.value,g.unit,g.orientation,g.ddd,g.MMM]);_fn=function(){return _.set(arguments,g.datePartDelimiter);};g.mdy=_fn(g.ddd,g.month,g.day,g.year);g.ymd=_fn(g.ddd,g.year,g.month,g.day);g.dmy=_fn(g.ddd,g.day,g.month,g.year);g.date=function(s){return((g[$C.dateElementOrder]||g.mdy).call(this,s));};g.format=_.process(_.many(_.any(_.process(_.rtoken(/^(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),function(fmt){if(g[fmt]){return g[fmt];}else{throw $D.Parsing.Exception(fmt);}}),_.process(_.rtoken(/^[^dMyhHmstz]+/),function(s){return _.ignore(_.stoken(s));}))),function(rules){return _.process(_.each.apply(null,rules),t.finishExact);});var _F={};var _get=function(f){return _F[f]=(_F[f]||g.format(f)[0]);};g.formats=function(fx){if(fx instanceof Array){var rx=[];for(var i=0;i<fx.length;i++){rx.push(_get(fx[i]));}
return _.any.apply(null,rx);}else{return _get(fx);}};g._formats=g.formats(["\"yyyy-MM-ddTHH:mm:ssZ\"","yyyy-MM-ddTHH:mm:ssZ","yyyy-MM-ddTHH:mm:ssz","yyyy-MM-ddTHH:mm:ss","yyyy-MM-ddTHH:mmZ","yyyy-MM-ddTHH:mmz","yyyy-MM-ddTHH:mm","ddd, MMM dd, yyyy H:mm:ss tt","ddd MMM d yyyy HH:mm:ss zzz","MMddyyyy","ddMMyyyy","Mddyyyy","ddMyyyy","Mdyyyy","dMyyyy","yyyy","Mdyy","dMyy","d"]);g._start=_.process(_.set([g.date,g.time,g.expression],g.generalDelimiter,g.whiteSpace),t.finish);g.start=function(s){try{var r=g._formats.call({},s);if(r[1].length===0){return r;}}catch(e){}
return g._start.call({},s);};$D._parse=$D.parse;$D.parse=function(s){var r=null;if(!s){return null;}
if(s instanceof Date){return s;}
try{r=$D.Grammar.start.call({},s.replace(/^\s*(\S*(\s+\S+)*)\s*$/,"$1"));}catch(e){return null;}
return((r[1].length===0)?r[0]:null);};$D.getParseFunction=function(fx){var fn=$D.Grammar.formats(fx);return function(s){var r=null;try{r=fn.call({},s);}catch(e){return null;}
return((r[1].length===0)?r[0]:null);};};$D.parseExact=function(s,fx){return $D.getParseFunction(fx)(s);};}());/*
 * jQuery validation plug-in 1.7
 *
 * http://bassistance.de/jquery-plugins/jquery-plugin-validation/
 * http://docs.jquery.com/Plugins/Validation
 *
 * Copyright (c) 2006 - 2008 JÃ¶rn Zaefferer
 *
 * $Id: jquery.validate.js 6403 2009-06-17 14:27:16Z joern.zaefferer $
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 */

(function($) {

$.extend($.fn, {
	// http://docs.jquery.com/Plugins/Validation/validate
	validate: function( options ) {

		// if nothing is selected, return nothing; can't chain anyway
		if (!this.length) {
			options && options.debug && window.console && console.warn( "nothing selected, can't validate, returning nothing" );
			return;
		}

		// check if a validator for this form was already created
		var validator = $.data(this[0], 'validator');
		if ( validator ) {
			return validator;
		}
		
		validator = new $.validator( options, this[0] );
		$.data(this[0], 'validator', validator); 
		
		if ( validator.settings.onsubmit ) {
		
			// allow suppresing validation by adding a cancel class to the submit button
			this.find("input, button").filter(".cancel").click(function() {
				validator.cancelSubmit = true;
			});
			
			// when a submitHandler is used, capture the submitting button
			if (validator.settings.submitHandler) {
				this.find("input, button").filter(":submit").click(function() {
					validator.submitButton = this;
				});
			}
		
			// validate the form on submit
			this.submit( function( event ) {
				if ( validator.settings.debug )
					// prevent form submit to be able to see console output
					event.preventDefault();
					
				function handle() {
					if ( validator.settings.submitHandler ) {
						if (validator.submitButton) {
							// insert a hidden input as a replacement for the missing submit button
							var hidden = $("<input type='hidden'/>").attr("name", validator.submitButton.name).val(validator.submitButton.value).appendTo(validator.currentForm);
						}
						validator.settings.submitHandler.call( validator, validator.currentForm );
						if (validator.submitButton) {
							// and clean up afterwards; thanks to no-block-scope, hidden can be referenced
							hidden.remove();
						}
						return false;
					}
					return true;
				}
					
				// prevent submit for invalid forms or custom submit handlers
				if ( validator.cancelSubmit ) {
					validator.cancelSubmit = false;
					return handle();
				}
				if ( validator.form() ) {
					if ( validator.pendingRequest ) {
						validator.formSubmitted = true;
						return false;
					}
					return handle();
				} else {
					validator.focusInvalid();
					return false;
				}
			});
		}
		
		return validator;
	},
	// http://docs.jquery.com/Plugins/Validation/valid
	valid: function() {
        if ( $(this[0]).is('form')) {
            return this.validate().form();
        } else {
            var valid = true;
            var validator = $(this[0].form).validate();
            this.each(function() {
				valid &= validator.element(this);
            });
            return valid;
        }
    },
	// attributes: space seperated list of attributes to retrieve and remove
	removeAttrs: function(attributes) {
		var result = {},
			$element = this;
		$.each(attributes.split(/\s/), function(index, value) {
			result[value] = $element.attr(value);
			$element.removeAttr(value);
		});
		return result;
	},
	// http://docs.jquery.com/Plugins/Validation/rules
	rules: function(command, argument) {
		var element = this[0];
		
		if (command) {
			var settings = $.data(element.form, 'validator').settings;
			var staticRules = settings.rules;
			var existingRules = $.validator.staticRules(element);
			switch(command) {
			case "add":
				$.extend(existingRules, $.validator.normalizeRule(argument));
				staticRules[element.name] = existingRules;
				if (argument.messages)
					settings.messages[element.name] = $.extend( settings.messages[element.name], argument.messages );
				break;
			case "remove":
				if (!argument) {
					delete staticRules[element.name];
					return existingRules;
				}
				var filtered = {};
				$.each(argument.split(/\s/), function(index, method) {
					filtered[method] = existingRules[method];
					delete existingRules[method];
				});
				return filtered;
			}
		}
		
		var data = $.validator.normalizeRules(
		$.extend(
			{},
			$.validator.metadataRules(element),
			$.validator.classRules(element),
			$.validator.attributeRules(element),
			$.validator.staticRules(element)
		), element);
		
		// make sure required is at front
		if (data.required) {
			var param = data.required;
			delete data.required;
			data = $.extend({required: param}, data);
		}
		
		return data;
	}
});

// Custom selectors
$.extend($.expr[":"], {
	// http://docs.jquery.com/Plugins/Validation/blank
	blank: function(a) {return !$.trim("" + a.value);},
	// http://docs.jquery.com/Plugins/Validation/filled
	filled: function(a) {return !!$.trim("" + a.value);},
	// http://docs.jquery.com/Plugins/Validation/unchecked
	unchecked: function(a) {return !a.checked;}
});

// constructor for validator
$.validator = function( options, form ) {
	this.settings = $.extend( true, {}, $.validator.defaults, options );
	this.currentForm = form;
	this.init();
};

$.validator.format = function(source, params) {
	if ( arguments.length == 1 ) 
		return function() {
			var args = $.makeArray(arguments);
			args.unshift(source);
			return $.validator.format.apply( this, args );
		};
	if ( arguments.length > 2 && params.constructor != Array  ) {
		params = $.makeArray(arguments).slice(1);
	}
	if ( params.constructor != Array ) {
		params = [ params ];
	}
	$.each(params, function(i, n) {
		source = source.replace(new RegExp("\\{" + i + "\\}", "g"), n);
	});
	return source;
};

$.extend($.validator, {
	
	defaults: {
		messages: {},
		groups: {},
		rules: {},
		errorClass: "error",
		validClass: "valid",
		errorElement: "label",
		focusInvalid: true,
		errorContainer: $( [] ),
		errorLabelContainer: $( [] ),
		onsubmit: true,
		ignore: [],
		ignoreTitle: false,
		onfocusin: function(element) {
			this.lastActive = element;
				
			// hide error label and remove error class on focus if enabled
			if ( this.settings.focusCleanup && !this.blockFocusCleanup ) {
				this.settings.unhighlight && this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass );
				this.errorsFor(element).hide();
			}
		},
		onfocusout: function(element) {
			if ( !this.checkable(element) && (element.name in this.submitted || !this.optional(element)) ) {
				this.element(element);
			}
		},
		onkeyup: function(element) {
			if ( element.name in this.submitted || element == this.lastElement ) {
				this.element(element);
			}
		},
		onclick: function(element) {
			// click on selects, radiobuttons and checkboxes
			if ( element.name in this.submitted )
				this.element(element);
			// or option elements, check parent select in that case
			else if (element.parentNode.name in this.submitted)
				this.element(element.parentNode);
		},
		highlight: function( element, errorClass, validClass ) {
			$(element).addClass(errorClass).removeClass(validClass);
		},
		unhighlight: function( element, errorClass, validClass ) {
			$(element).removeClass(errorClass).addClass(validClass);
		}
	},

	// http://docs.jquery.com/Plugins/Validation/Validator/setDefaults
	setDefaults: function(settings) {
		$.extend( $.validator.defaults, settings );
	},

	messages: {
		required: "This field is required.",
		remote: "Please fix this field.",
		email: "Please enter a valid email address.",
		url: "Please enter a valid URL.",
		date: "Please enter a valid date.",
		dateISO: "Please enter a valid date (ISO).",
		number: "Please enter a valid number.",
		digits: "Please enter only digits.",
		creditcard: "Please enter a valid credit card number.",
		equalTo: "Please enter the same value again.",
		accept: "Please enter a value with a valid extension.",
		maxlength: $.validator.format("Please enter no more than {0} characters."),
		minlength: $.validator.format("Please enter at least {0} characters."),
		rangelength: $.validator.format("Please enter a value between {0} and {1} characters long."),
		range: $.validator.format("Please enter a value between {0} and {1}."),
		max: $.validator.format("Please enter a value less than or equal to {0}."),
		min: $.validator.format("Please enter a value greater than or equal to {0}.")
	},
	
	autoCreateRanges: false,
	
	prototype: {
		
		init: function() {
			this.labelContainer = $(this.settings.errorLabelContainer);
			this.errorContext = this.labelContainer.length && this.labelContainer || $(this.currentForm);
			this.containers = $(this.settings.errorContainer).add( this.settings.errorLabelContainer );
			this.submitted = {};
			this.valueCache = {};
			this.pendingRequest = 0;
			this.pending = {};
			this.invalid = {};
			this.reset();
			
			var groups = (this.groups = {});
			$.each(this.settings.groups, function(key, value) {
				$.each(value.split(/\s/), function(index, name) {
					groups[name] = key;
				});
			});
			var rules = this.settings.rules;
			$.each(rules, function(key, value) {
				rules[key] = $.validator.normalizeRule(value);
			});
			
			function delegate(event) {
				var validator = $.data(this[0].form, "validator"),
					eventType = "on" + event.type.replace(/^validate/, "");
				validator.settings[eventType] && validator.settings[eventType].call(validator, this[0] );
			}
			$(this.currentForm)
				.validateDelegate(":text, :password, :file, select, textarea", "focusin focusout keyup", delegate)
				.validateDelegate(":radio, :checkbox, select, option", "click", delegate);

			if (this.settings.invalidHandler)
				$(this.currentForm).bind("invalid-form.validate", this.settings.invalidHandler);
		},

		// http://docs.jquery.com/Plugins/Validation/Validator/form
		form: function() {
			this.checkForm();
			$.extend(this.submitted, this.errorMap);
			this.invalid = $.extend({}, this.errorMap);
			if (!this.valid())
				$(this.currentForm).triggerHandler("invalid-form", [this]);
			this.showErrors();
			return this.valid();
		},
		
		checkForm: function() {
			this.prepareForm();
			for ( var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++ ) {
				this.check( elements[i] );
			}
			return this.valid(); 
		},
		
		// http://docs.jquery.com/Plugins/Validation/Validator/element
		element: function( element ) {
			element = this.clean( element );
			this.lastElement = element;
			this.prepareElement( element );
			this.currentElements = $(element);
			var result = this.check( element );
			if ( result ) {
				delete this.invalid[element.name];
			} else {
				this.invalid[element.name] = true;
			}
			if ( !this.numberOfInvalids() ) {
				// Hide error containers on last error
				this.toHide = this.toHide.add( this.containers );
			}
			this.showErrors();
			return result;
		},

		// http://docs.jquery.com/Plugins/Validation/Validator/showErrors
		showErrors: function(errors) {
			if(errors) {
				// add items to error list and map
				$.extend( this.errorMap, errors );
				this.errorList = [];
				for ( var name in errors ) {
					this.errorList.push({
						message: errors[name],
						element: this.findByName(name)[0]
					});
				}
				// remove items from success list
				this.successList = $.grep( this.successList, function(element) {
					return !(element.name in errors);
				});
			}
			this.settings.showErrors
				? this.settings.showErrors.call( this, this.errorMap, this.errorList )
				: this.defaultShowErrors();
		},
		
		// http://docs.jquery.com/Plugins/Validation/Validator/resetForm
		resetForm: function() {
			if ( $.fn.resetForm )
				$( this.currentForm ).resetForm();
			this.submitted = {};
			this.prepareForm();
			this.hideErrors();
			this.elements().removeClass( this.settings.errorClass );
		},
		
		numberOfInvalids: function() {
			return this.objectLength(this.invalid);
		},
		
		objectLength: function( obj ) {
			var count = 0;
			for ( var i in obj )
				count++;
			return count;
		},
		
		hideErrors: function() {
			this.addWrapper( this.toHide ).hide();
		},
		
		valid: function() {
			return this.size() == 0;
		},
		
		size: function() {
			return this.errorList.length;
		},
		
		focusInvalid: function() {
			if( this.settings.focusInvalid ) {
				try {
					$(this.findLastActive() || this.errorList.length && this.errorList[0].element || [])
					.filter(":visible")
					.focus()
					// manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find
					.trigger("focusin");
				} catch(e) {
					// ignore IE throwing errors when focusing hidden elements
				}
			}
		},
		
		findLastActive: function() {
			var lastActive = this.lastActive;
			return lastActive && $.grep(this.errorList, function(n) {
				return n.element.name == lastActive.name;
			}).length == 1 && lastActive;
		},
		
		elements: function() {
			var validator = this,
				rulesCache = {};
			
			// select all valid inputs inside the form (no submit or reset buttons)
			// workaround $Query([]).add until http://dev.jquery.com/ticket/2114 is solved
			return $([]).add(this.currentForm.elements)
			.filter(":input")
			.not(":submit, :reset, :image, [disabled]")
			.not( this.settings.ignore )
			.filter(function() {
				!this.name && validator.settings.debug && window.console && console.error( "%o has no name assigned", this);
			
				// select only the first element for each name, and only those with rules specified
				if ( this.name in rulesCache || !validator.objectLength($(this).rules()) )
					return false;
				
				rulesCache[this.name] = true;
				return true;
			});
		},
		
		clean: function( selector ) {
			return $( selector )[0];
		},
		
		errors: function() {
			return $( this.settings.errorElement + "." + this.settings.errorClass, this.errorContext );
		},
		
		reset: function() {
			this.successList = [];
			this.errorList = [];
			this.errorMap = {};
			this.toShow = $([]);
			this.toHide = $([]);
			this.currentElements = $([]);
		},
		
		prepareForm: function() {
			this.reset();
			this.toHide = this.errors().add( this.containers );
		},
		
		prepareElement: function( element ) {
			this.reset();
			this.toHide = this.errorsFor(element);
		},
	
		check: function( element ) {
			element = this.clean( element );
			
			// if radio/checkbox, validate first element in group instead
			if (this.checkable(element)) {
				element = this.findByName( element.name )[0];
			}
			
			var rules = $(element).rules();
			var dependencyMismatch = false;
			for( method in rules ) {
				var rule = { method: method, parameters: rules[method] };
				try {
					var result = $.validator.methods[method].call( this, element.value.replace(/\r/g, ""), element, rule.parameters );
					
					// if a method indicates that the field is optional and therefore valid,
					// don't mark it as valid when there are no other rules
					if ( result == "dependency-mismatch" ) {
						dependencyMismatch = true;
						continue;
					}
					dependencyMismatch = false;
					
					if ( result == "pending" ) {
						this.toHide = this.toHide.not( this.errorsFor(element) );
						return;
					}
					
					if( !result ) {
						this.formatAndAdd( element, rule );
						return false;
					}
				} catch(e) {
					this.settings.debug && window.console && console.log("exception occured when checking element " + element.id
						 + ", check the '" + rule.method + "' method", e);
					throw e;
				}
			}
			if (dependencyMismatch)
				return;
			if ( this.objectLength(rules) )
				this.successList.push(element);
			return true;
		},
		
		// return the custom message for the given element and validation method
		// specified in the element's "messages" metadata
		customMetaMessage: function(element, method) {
			if (!$.metadata)
				return;
			
			var meta = this.settings.meta
				? $(element).metadata()[this.settings.meta]
				: $(element).metadata();
			
			return meta && meta.messages && meta.messages[method];
		},
		
		// return the custom message for the given element name and validation method
		customMessage: function( name, method ) {
			var m = this.settings.messages[name];
			return m && (m.constructor == String
				? m
				: m[method]);
		},
		
		// return the first defined argument, allowing empty strings
		findDefined: function() {
			for(var i = 0; i < arguments.length; i++) {
				if (arguments[i] !== undefined)
					return arguments[i];
			}
			return undefined;
		},
		
		defaultMessage: function( element, method) {
			return this.findDefined(
				this.customMessage( element.name, method ),
				this.customMetaMessage( element, method ),
				// title is never undefined, so handle empty string as undefined
				!this.settings.ignoreTitle && element.title || undefined,
				$.validator.messages[method],
				"<strong>Warning: No message defined for " + element.name + "</strong>"
			);
		},
		
		formatAndAdd: function( element, rule ) {
			var message = this.defaultMessage( element, rule.method ),
				theregex = /\$?\{(\d+)\}/g;
			if ( typeof message == "function" ) {
				message = message.call(this, rule.parameters, element);
			} else if (theregex.test(message)) {
				message = jQuery.format(message.replace(theregex, '{$1}'), rule.parameters);
			}			
			this.errorList.push({
				message: message,
				element: element
			});
			
			this.errorMap[element.name] = message;
			this.submitted[element.name] = message;
		},
		
		addWrapper: function(toToggle) {
			if ( this.settings.wrapper )
				toToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) );
			return toToggle;
		},
		
		defaultShowErrors: function() {
			for ( var i = 0; this.errorList[i]; i++ ) {
				var error = this.errorList[i];
				this.settings.highlight && this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass );
				this.showLabel( error.element, error.message );
			}
			if( this.errorList.length ) {
				this.toShow = this.toShow.add( this.containers );
			}
			if (this.settings.success) {
				for ( var i = 0; this.successList[i]; i++ ) {
					this.showLabel( this.successList[i] );
				}
			}
			if (this.settings.unhighlight) {
				for ( var i = 0, elements = this.validElements(); elements[i]; i++ ) {
					this.settings.unhighlight.call( this, elements[i], this.settings.errorClass, this.settings.validClass );
				}
			}
			this.toHide = this.toHide.not( this.toShow );
			this.hideErrors();
			this.addWrapper( this.toShow ).show();
		},
		
		validElements: function() {
			return this.currentElements.not(this.invalidElements());
		},
		
		invalidElements: function() {
			return $(this.errorList).map(function() {
				return this.element;
			});
		},
		
		showLabel: function(element, message) {
			var label = this.errorsFor( element );
			if ( label.length ) {
				// refresh error/success class
				label.removeClass().addClass( this.settings.errorClass );
			
				// check if we have a generated label, replace the message then
				label.attr("generated") && label.html(message);
			} else {
				// create label
				label = $("<" + this.settings.errorElement + "/>")
					.attr({"for":  this.idOrName(element), generated: true})
					.addClass(this.settings.errorClass)
					.html(message || "");
				if ( this.settings.wrapper ) {
					// make sure the element is visible, even in IE
					// actually showing the wrapped element is handled elsewhere
					label = label.hide().show().wrap("<" + this.settings.wrapper + "/>").parent();
				}
				if ( !this.labelContainer.append(label).length )
					this.settings.errorPlacement
						? this.settings.errorPlacement(label, $(element) )
						: label.insertAfter(element);
			}
			if ( !message && this.settings.success ) {
				label.text("");
				typeof this.settings.success == "string"
					? label.addClass( this.settings.success )
					: this.settings.success( label );
			}
			this.toShow = this.toShow.add(label);
		},
		
		errorsFor: function(element) {
			var name = this.idOrName(element);
    		return this.errors().filter(function() {
				return $(this).attr('for') == name;
			});
		},
		
		idOrName: function(element) {
			return this.groups[element.name] || (this.checkable(element) ? element.name : element.id || element.name);
		},

		checkable: function( element ) {
			return /radio|checkbox/i.test(element.type);
		},
		
		findByName: function( name ) {
			// select by name and filter by form for performance over form.find("[name=...]")
			var form = this.currentForm;
			return $(document.getElementsByName(name)).map(function(index, element) {
				return element.form == form && element.name == name && element  || null;
			});
		},
		
		getLength: function(value, element) {
			switch( element.nodeName.toLowerCase() ) {
			case 'select':
				return $("option:selected", element).length;
			case 'input':
				if( this.checkable( element) )
					return this.findByName(element.name).filter(':checked').length;
			}
			return value.length;
		},
	
		depend: function(param, element) {
			return this.dependTypes[typeof param]
				? this.dependTypes[typeof param](param, element)
				: true;
		},
	
		dependTypes: {
			"boolean": function(param, element) {
				return param;
			},
			"string": function(param, element) {
				return !!$(param, element.form).length;
			},
			"function": function(param, element) {
				return param(element);
			}
		},
		
		optional: function(element) {
			return !$.validator.methods.required.call(this, $.trim(element.value), element) && "dependency-mismatch";
		},
		
		startRequest: function(element) {
			if (!this.pending[element.name]) {
				this.pendingRequest++;
				this.pending[element.name] = true;
			}
		},
		
		stopRequest: function(element, valid) {
			this.pendingRequest--;
			// sometimes synchronization fails, make sure pendingRequest is never < 0
			if (this.pendingRequest < 0)
				this.pendingRequest = 0;
			delete this.pending[element.name];
			if ( valid && this.pendingRequest == 0 && this.formSubmitted && this.form() ) {
				$(this.currentForm).submit();
				this.formSubmitted = false;
			} else if (!valid && this.pendingRequest == 0 && this.formSubmitted) {
				$(this.currentForm).triggerHandler("invalid-form", [this]);
				this.formSubmitted = false;
			}
		},
		
		previousValue: function(element) {
			return $.data(element, "previousValue") || $.data(element, "previousValue", {
				old: null,
				valid: true,
				message: this.defaultMessage( element, "remote" )
			});
		}
		
	},
	
	classRuleSettings: {
		required: {required: true},
		email: {email: true},
		url: {url: true},
		date: {date: true},
		dateISO: {dateISO: true},
		dateDE: {dateDE: true},
		number: {number: true},
		numberDE: {numberDE: true},
		digits: {digits: true},
		creditcard: {creditcard: true}
	},
	
	addClassRules: function(className, rules) {
		className.constructor == String ?
			this.classRuleSettings[className] = rules :
			$.extend(this.classRuleSettings, className);
	},
	
	classRules: function(element) {
		var rules = {};
		var classes = $(element).attr('class');
		classes && $.each(classes.split(' '), function() {
			if (this in $.validator.classRuleSettings) {
				$.extend(rules, $.validator.classRuleSettings[this]);
			}
		});
		return rules;
	},
	
	attributeRules: function(element) {
		var rules = {};
		var $element = $(element);
		
		for (method in $.validator.methods) {
			var value = $element.attr(method);
			if (value) {
				rules[method] = value;
			}
		}
		
		// maxlength may be returned as -1, 2147483647 (IE) and 524288 (safari) for text inputs
		if (rules.maxlength && /-1|2147483647|524288/.test(rules.maxlength)) {
			delete rules.maxlength;
		}
		
		return rules;
	},
	
	metadataRules: function(element) {
		if (!$.metadata) return {};
		
		var meta = $.data(element.form, 'validator').settings.meta;
		return meta ?
			$(element).metadata()[meta] :
			$(element).metadata();
	},
	
	staticRules: function(element) {
		var rules = {};
		var validator = $.data(element.form, 'validator');
		if (validator.settings.rules) {
			rules = $.validator.normalizeRule(validator.settings.rules[element.name]) || {};
		}
		return rules;
	},
	
	normalizeRules: function(rules, element) {
		// handle dependency check
		$.each(rules, function(prop, val) {
			// ignore rule when param is explicitly false, eg. required:false
			if (val === false) {
				delete rules[prop];
				return;
			}
			if (val.param || val.depends) {
				var keepRule = true;
				switch (typeof val.depends) {
					case "string":
						keepRule = !!$(val.depends, element.form).length;
						break;
					case "function":
						keepRule = val.depends.call(element, element);
						break;
				}
				if (keepRule) {
					rules[prop] = val.param !== undefined ? val.param : true;
				} else {
					delete rules[prop];
				}
			}
		});
		
		// evaluate parameters
		$.each(rules, function(rule, parameter) {
			rules[rule] = $.isFunction(parameter) ? parameter(element) : parameter;
		});
		
		// clean number parameters
		$.each(['minlength', 'maxlength', 'min', 'max'], function() {
			if (rules[this]) {
				rules[this] = Number(rules[this]);
			}
		});
		$.each(['rangelength', 'range'], function() {
			if (rules[this]) {
				rules[this] = [Number(rules[this][0]), Number(rules[this][1])];
			}
		});
		
		if ($.validator.autoCreateRanges) {
			// auto-create ranges
			if (rules.min && rules.max) {
				rules.range = [rules.min, rules.max];
				delete rules.min;
				delete rules.max;
			}
			if (rules.minlength && rules.maxlength) {
				rules.rangelength = [rules.minlength, rules.maxlength];
				delete rules.minlength;
				delete rules.maxlength;
			}
		}
		
		// To support custom messages in metadata ignore rule methods titled "messages"
		if (rules.messages) {
			delete rules.messages;
		}
		
		return rules;
	},
	
	// Converts a simple string to a {string: true} rule, e.g., "required" to {required:true}
	normalizeRule: function(data) {
		if( typeof data == "string" ) {
			var transformed = {};
			$.each(data.split(/\s/), function() {
				transformed[this] = true;
			});
			data = transformed;
		}
		return data;
	},
	
	// http://docs.jquery.com/Plugins/Validation/Validator/addMethod
	addMethod: function(name, method, message) {
		$.validator.methods[name] = method;
		$.validator.messages[name] = message != undefined ? message : $.validator.messages[name];
		if (method.length < 3) {
			$.validator.addClassRules(name, $.validator.normalizeRule(name));
		}
	},

	methods: {

		// http://docs.jquery.com/Plugins/Validation/Methods/required
		required: function(value, element, param) {
			// check if dependency is met
			if ( !this.depend(param, element) )
				return "dependency-mismatch";
			switch( element.nodeName.toLowerCase() ) {
			case 'select':
				// could be an array for select-multiple or a string, both are fine this way
				var val = $(element).val();
				return val && val.length > 0;
			case 'input':
				if ( this.checkable(element) )
					return this.getLength(value, element) > 0;
			default:
				return $.trim(value).length > 0;
			}
		},
		
		// http://docs.jquery.com/Plugins/Validation/Methods/remote
		remote: function(value, element, param) {
			if ( this.optional(element) )
				return "dependency-mismatch";
			
			var previous = this.previousValue(element);
			if (!this.settings.messages[element.name] )
				this.settings.messages[element.name] = {};
			previous.originalMessage = this.settings.messages[element.name].remote;
			this.settings.messages[element.name].remote = previous.message;
			
			param = typeof param == "string" && {url:param} || param; 
			
			if ( previous.old !== value ) {
				previous.old = value;
				var validator = this;
				this.startRequest(element);
				var data = {};
				data[element.name] = value;
				$.ajax($.extend(true, {
					url: param,
					mode: "abort",
					port: "validate" + element.name,
					dataType: "json",
					data: data,
					success: function(response) {
						validator.settings.messages[element.name].remote = previous.originalMessage;
						var valid = response === true;
						if ( valid ) {
							var submitted = validator.formSubmitted;
							validator.prepareElement(element);
							validator.formSubmitted = submitted;
							validator.successList.push(element);
							validator.showErrors();
						} else {
							var errors = {};
							var message = (previous.message = response || validator.defaultMessage( element, "remote" ));
							errors[element.name] = $.isFunction(message) ? message(value) : message;
							validator.showErrors(errors);
						}
						previous.valid = valid;
						validator.stopRequest(element, valid);
					}
				}, param));
				return "pending";
			} else if( this.pending[element.name] ) {
				return "pending";
			}
			return previous.valid;
		},

		// http://docs.jquery.com/Plugins/Validation/Methods/minlength
		minlength: function(value, element, param) {
			return this.optional(element) || this.getLength($.trim(value), element) >= param;
		},
		
		// http://docs.jquery.com/Plugins/Validation/Methods/maxlength
		maxlength: function(value, element, param) {
			return this.optional(element) || this.getLength($.trim(value), element) <= param;
		},
		
		// http://docs.jquery.com/Plugins/Validation/Methods/rangelength
		rangelength: function(value, element, param) {
			var length = this.getLength($.trim(value), element);
			return this.optional(element) || ( length >= param[0] && length <= param[1] );
		},
		
		// http://docs.jquery.com/Plugins/Validation/Methods/min
		min: function( value, element, param ) {
			return this.optional(element) || value >= param;
		},
		
		// http://docs.jquery.com/Plugins/Validation/Methods/max
		max: function( value, element, param ) {
			return this.optional(element) || value <= param;
		},
		
		// http://docs.jquery.com/Plugins/Validation/Methods/range
		range: function( value, element, param ) {
			return this.optional(element) || ( value >= param[0] && value <= param[1] );
		},
		
		// http://docs.jquery.com/Plugins/Validation/Methods/email
		email: function(value, element) {
			// contributed by Scott Gonzalez: http://projects.scottsplayground.com/email_address_validation/
			return this.optional(element) || /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i.test(value);
		},
	
		// http://docs.jquery.com/Plugins/Validation/Methods/url
		url: function(value, element) {
			// contributed by Scott Gonzalez: http://projects.scottsplayground.com/iri/
			return this.optional(element) || /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(value);
		},
        
		// http://docs.jquery.com/Plugins/Validation/Methods/date
		date: function(value, element) {
			return this.optional(element) || !/Invalid|NaN/.test(new Date(value));
		},
	
		// http://docs.jquery.com/Plugins/Validation/Methods/dateISO
		dateISO: function(value, element) {
			return this.optional(element) || /^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(value);
		},
	
		// http://docs.jquery.com/Plugins/Validation/Methods/number
		number: function(value, element) {
			return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/.test(value);
		},
	
		// http://docs.jquery.com/Plugins/Validation/Methods/digits
		digits: function(value, element) {
			return this.optional(element) || /^\d+$/.test(value);
		},
		
		// http://docs.jquery.com/Plugins/Validation/Methods/creditcard
		// based on http://en.wikipedia.org/wiki/Luhn
		creditcard: function(value, element) {
			if ( this.optional(element) )
				return "dependency-mismatch";
			// accept only digits and dashes
			if (/[^0-9-]+/.test(value))
				return false;
			var nCheck = 0,
				nDigit = 0,
				bEven = false;

			value = value.replace(/\D/g, "");

			for (var n = value.length - 1; n >= 0; n--) {
				var cDigit = value.charAt(n);
				var nDigit = parseInt(cDigit, 10);
				if (bEven) {
					if ((nDigit *= 2) > 9)
						nDigit -= 9;
				}
				nCheck += nDigit;
				bEven = !bEven;
			}

			return (nCheck % 10) == 0;
		},
		
		// http://docs.jquery.com/Plugins/Validation/Methods/accept
		accept: function(value, element, param) {
			param = typeof param == "string" ? param.replace(/,/g, '|') : "png|jpe?g|gif";
			return this.optional(element) || value.match(new RegExp(".(" + param + ")$", "i")); 
		},
		
		// http://docs.jquery.com/Plugins/Validation/Methods/equalTo
		equalTo: function(value, element, param) {
			// bind to the blur event of the target in order to revalidate whenever the target field is updated
			// TODO find a way to bind the event just once, avoiding the unbind-rebind overhead
			var target = $(param).unbind(".validate-equalTo").bind("blur.validate-equalTo", function() {
				$(element).valid();
			});
			return value == target.val();
		}
		
	}
	
});

// deprecated, use $.validator.format instead
$.format = $.validator.format;

})(jQuery);

// ajax mode: abort
// usage: $.ajax({ mode: "abort"[, port: "uniqueport"]});
// if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort() 
;(function($) {
	var ajax = $.ajax;
	var pendingRequests = {};
	$.ajax = function(settings) {
		// create settings for compatibility with ajaxSetup
		settings = $.extend(settings, $.extend({}, $.ajaxSettings, settings));
		var port = settings.port;
		if (settings.mode == "abort") {
			if ( pendingRequests[port] ) {
				pendingRequests[port].abort();
			}
			return (pendingRequests[port] = ajax.apply(this, arguments));
		}
		return ajax.apply(this, arguments);
	};
})(jQuery);

// provides cross-browser focusin and focusout events
// IE has native support, in other browsers, use event caputuring (neither bubbles)

// provides delegate(type: String, delegate: Selector, handler: Callback) plugin for easier event delegation
// handler is only called when $(event.target).is(delegate), in the scope of the jquery-object for event.target 
;(function($) {
	// only implement if not provided by jQuery core (since 1.4)
	// TODO verify if jQuery 1.4's implementation is compatible with older jQuery special-event APIs
	if (!jQuery.event.special.focusin && !jQuery.event.special.focusout && document.addEventListener) {
		$.each({
			focus: 'focusin',
			blur: 'focusout'	
		}, function( original, fix ){
			$.event.special[fix] = {
				setup:function() {
					this.addEventListener( original, handler, true );
				},
				teardown:function() {
					this.removeEventListener( original, handler, true );
				},
				handler: function(e) {
					arguments[0] = $.event.fix(e);
					arguments[0].type = fix;
					return $.event.handle.apply(this, arguments);
				}
			};
			function handler(e) {
				e = $.event.fix(e);
				e.type = fix;
				return $.event.handle.call(this, e);
			}
		});
	};
	$.extend($.fn, {
		validateDelegate: function(delegate, type, handler) {
			return this.bind(type, function(event) {
				var target = $(event.target);
				if (target.is(delegate)) {
					return handler.apply(target, arguments);
				}
			});
		}
	});
})(jQuery);
(function($){var textarea,staticOffset;var iLastMousePos=0;var iMin=32;var grip;$.fn.TextAreaResizer=function(){return this.each(function(){textarea=$(this).addClass('processed'),staticOffset=null;$(this).wrap('<div class="resizable-textarea"><span></span></div>').parent().append($('<div class="grippie"></div>').bind("mousedown",{el:this},startDrag));var grippie=$('div.grippie',$(this).parent())[0];grippie.style.marginRight=(grippie.offsetWidth-$(this)[0].offsetWidth)+'px'})};function startDrag(e){textarea=$(e.data.el);textarea.blur();iLastMousePos=mousePosition(e).y;staticOffset=textarea.height()-iLastMousePos;textarea.css('opacity',0.25);$(document).mousemove(performDrag).mouseup(endDrag);return false}function performDrag(e){var iThisMousePos=mousePosition(e).y;var iMousePos=staticOffset+iThisMousePos;if(iLastMousePos>=(iThisMousePos)){iMousePos-=5}iLastMousePos=iThisMousePos;iMousePos=Math.max(iMin,iMousePos);textarea.height(iMousePos+'px');if(iMousePos<iMin){endDrag(e)}return false}function endDrag(e){$(document).unbind('mousemove',performDrag).unbind('mouseup',endDrag);textarea.css('opacity',1);textarea.focus();textarea=null;staticOffset=null;iLastMousePos=0}function mousePosition(e){return{x:e.clientX+document.documentElement.scrollLeft,y:e.clientY+document.documentElement.scrollTop}}})(jQuery);/*
 * jQuery Autocomplete plugin 1.1
 *
 * Copyright (c) 2009 JÃ¶rn Zaefferer
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 * Revision: $Id: jquery.autocomplete.js 15 2009-08-22 10:30:27Z joern.zaefferer $
 */

;(function($) {
	
$.fn.extend({
	autocomplete: function(urlOrData, options) {
		var isUrl = typeof urlOrData == "string";
		options = $.extend({}, $.Autocompleter.defaults, {
			url: isUrl ? urlOrData : null,
			data: isUrl ? null : urlOrData,
			delay: isUrl ? $.Autocompleter.defaults.delay : 10,
			max: options && !options.scroll ? 10 : 150
		}, options);
		
		// if highlight is set to false, replace it with a do-nothing function
		options.highlight = options.highlight || function(value) { return value; };
		
		// if the formatMatch option is not specified, then use formatItem for backwards compatibility
		options.formatMatch = options.formatMatch || options.formatItem;
		
		return this.each(function() {
			new $.Autocompleter(this, options);
		});
	},
	result: function(handler) {
		return this.bind("result", handler);
	},
	search: function(handler) {
		return this.trigger("search", [handler]);
	},
	flushCache: function() {
		return this.trigger("flushCache");
	},
	setOptions: function(options){
		return this.trigger("setOptions", [options]);
	},
	unautocomplete: function() {
		return this.trigger("unautocomplete");
	}
});

$.Autocompleter = function(input, options) {

	var KEY = {
		UP: 38,
		DOWN: 40,
		DEL: 46,
		TAB: 9,
		RETURN: 13,
		ESC: 27,
		COMMA: 188,
		PAGEUP: 33,
		PAGEDOWN: 34,
		BACKSPACE: 8
	};

	// Create $ object for input element
	var $input = $(input).attr("autocomplete", "off").addClass(options.inputClass);

	var timeout;
	var previousValue = "";
	var cache = $.Autocompleter.Cache(options);
	var hasFocus = 0;
	var lastKeyPressCode;
	var config = {
		mouseDownOnSelect: false
	};
	var select = $.Autocompleter.Select(options, input, selectCurrent, config);
	
	var blockSubmit;
	
	// prevent form submit in opera when selecting with return key
	$.browser.opera && $(input.form).bind("submit.autocomplete", function() {
		if (blockSubmit) {
			blockSubmit = false;
			return false;
		}
	});
	
	// only opera doesn't trigger keydown multiple times while pressed, others don't work with keypress at all
	$input.bind(($.browser.opera ? "keypress" : "keydown") + ".autocomplete", function(event) {
		// a keypress means the input has focus
		// avoids issue where input had focus before the autocomplete was applied
		hasFocus = 1;
		// track last key pressed
		lastKeyPressCode = event.keyCode;
		switch(event.keyCode) {
		
			case KEY.UP:
				event.preventDefault();
				if ( select.visible() ) {
					select.prev();
				} else {
					onChange(0, true);
				}
				break;
				
			case KEY.DOWN:
				event.preventDefault();
				if ( select.visible() ) {
					select.next();
				} else {
					onChange(0, true);
				}
				break;
				
			case KEY.PAGEUP:
				event.preventDefault();
				if ( select.visible() ) {
					select.pageUp();
				} else {
					onChange(0, true);
				}
				break;
				
			case KEY.PAGEDOWN:
				event.preventDefault();
				if ( select.visible() ) {
					select.pageDown();
				} else {
					onChange(0, true);
				}
				break;
			
			// matches also semicolon
			case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA:
			case KEY.TAB:
			case KEY.RETURN:
				if( selectCurrent() ) {
					// stop default to prevent a form submit, Opera needs special handling
					event.preventDefault();
					blockSubmit = true;
					return false;
				}
				break;
				
			case KEY.ESC:
				select.hide();
				break;
				
			default:
				clearTimeout(timeout);
				timeout = setTimeout(onChange, options.delay);
				break;
		}
	}).focus(function(){
		// track whether the field has focus, we shouldn't process any
		// results if the field no longer has focus
		hasFocus++;
	}).blur(function() {
		hasFocus = 0;
		if (!config.mouseDownOnSelect) {
			hideResults();
		}
	}).click(function() {
		// show select when clicking in a focused field
		if ( hasFocus++ > 1 && !select.visible() ) {
			onChange(0, true);
		}
	}).bind("search", function() {
		// TODO why not just specifying both arguments?
		var fn = (arguments.length > 1) ? arguments[1] : null;
		function findValueCallback(q, data) {
			var result;
			if( data && data.length ) {
				for (var i=0; i < data.length; i++) {
					if( data[i].result.toLowerCase() == q.toLowerCase() ) {
						result = data[i];
						break;
					}
				}
			}
			if( typeof fn == "function" ) fn(result);
			else $input.trigger("result", result && [result.data, result.value]);
		}
		$.each(trimWords($input.val()), function(i, value) {
			request(value, findValueCallback, findValueCallback);
		});
	}).bind("flushCache", function() {
		cache.flush();
	}).bind("setOptions", function() {
		$.extend(options, arguments[1]);
		// if we've updated the data, repopulate
		if ( "data" in arguments[1] )
			cache.populate();
	}).bind("unautocomplete", function() {
		select.unbind();
		$input.unbind();
		$(input.form).unbind(".autocomplete");
	});
	
	
	function selectCurrent() {
		var selected = select.selected();
		if( !selected )
			return false;
		
		var v = selected.result;
		previousValue = v;
		
		if ( options.multiple ) {
			var words = trimWords($input.val());
			if ( words.length > 1 ) {
				var seperator = options.multipleSeparator.length;
				var cursorAt = $(input).selection().start;
				var wordAt, progress = 0;
				$.each(words, function(i, word) {
					progress += word.length;
					if (cursorAt <= progress) {
						wordAt = i;
						return false;
					}
					progress += seperator;
				});
				words[wordAt] = v;
				// TODO this should set the cursor to the right position, but it gets overriden somewhere
				//$.Autocompleter.Selection(input, progress + seperator, progress + seperator);
				v = words.join( options.multipleSeparator );
			}
			v += options.multipleSeparator;
		}
		
		$input.val(v);
		hideResultsNow();
		$input.trigger("result", [selected.data, selected.value]);
		return true;
	}
	
	function onChange(crap, skipPrevCheck) {
		if( lastKeyPressCode == KEY.DEL ) {
			select.hide();
			return;
		}
		
		var currentValue = $input.val();
		
		if ( !skipPrevCheck && currentValue == previousValue )
			return;
		
		previousValue = currentValue;
		
		currentValue = lastWord(currentValue);
		if ( currentValue.length >= options.minChars) {
			$input.addClass(options.loadingClass);
			if (!options.matchCase)
				currentValue = currentValue.toLowerCase();
			request(currentValue, receiveData, hideResultsNow);
		} else {
			stopLoading();
			select.hide();
		}
	};
	
	function trimWords(value) {
		if (!value)
			return [""];
		if (!options.multiple)
			return [$.trim(value)];
		return $.map(value.split(options.multipleSeparator), function(word) {
			return $.trim(value).length ? $.trim(word) : null;
		});
	}
	
	function lastWord(value) {
		if ( !options.multiple )
			return value;
		var words = trimWords(value);
		if (words.length == 1) 
			return words[0];
		var cursorAt = $(input).selection().start;
		if (cursorAt == value.length) {
			words = trimWords(value)
		} else {
			words = trimWords(value.replace(value.substring(cursorAt), ""));
		}
		return words[words.length - 1];
	}
	
	// fills in the input box w/the first match (assumed to be the best match)
	// q: the term entered
	// sValue: the first matching result
	function autoFill(q, sValue){
		// autofill in the complete box w/the first match as long as the user hasn't entered in more data
		// if the last user key pressed was backspace, don't autofill
		if( options.autoFill && (lastWord($input.val()).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != KEY.BACKSPACE ) {
			// fill in the value (keep the case the user has typed)
			$input.val($input.val() + sValue.substring(lastWord(previousValue).length));
			// select the portion of the value not typed by the user (so the next character will erase)
			$(input).selection(previousValue.length, previousValue.length + sValue.length);
		}
	};

	function hideResults() {
		clearTimeout(timeout);
		timeout = setTimeout(hideResultsNow, 200);
	};

	function hideResultsNow() {
		var wasVisible = select.visible();
		select.hide();
		clearTimeout(timeout);
		stopLoading();
		if (options.mustMatch) {
			// call search and run callback
			$input.search(
				function (result){
					// if no value found, clear the input box
					if( !result ) {
						if (options.multiple) {
							var words = trimWords($input.val()).slice(0, -1);
							$input.val( words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator : "") );
						}
						else {
							$input.val( "" );
							$input.trigger("result", null);
						}
					}
				}
			);
		}
	};

	function receiveData(q, data) {
		if ( data && data.length && hasFocus ) {
			stopLoading();
			select.display(data, q);
			autoFill(q, data[0].value);
			select.show();
		} else {
			hideResultsNow();
		}
	};

	function request(term, success, failure) {
		if (!options.matchCase)
			term = term.toLowerCase();
		var data = cache.load(term);
		// recieve the cached data
		if (data && data.length) {
			success(term, data);
		// if an AJAX url has been supplied, try loading the data now
		} else if( (typeof options.url == "string") && (options.url.length > 0) ){
			
			var extraParams = {
				timestamp: +new Date()
			};
			$.each(options.extraParams, function(key, param) {
				extraParams[key] = typeof param == "function" ? param() : param;
			});
			
			$.ajax({
				// try to leverage ajaxQueue plugin to abort previous requests
				mode: "abort",
				// limit abortion to this input
				port: "autocomplete" + input.name,
				dataType: options.dataType,
				url: options.url,
				data: $.extend({
					q: lastWord(term),
					limit: options.max
				}, extraParams),
				success: function(data) {
					var parsed = options.parse && options.parse(data) || parse(data);
					cache.add(term, parsed);
					success(term, parsed);
				}
			});
		} else {
			// if we have a failure, we need to empty the list -- this prevents the the [TAB] key from selecting the last successful match
			select.emptyList();
			failure(term);
		}
	};
	
	function parse(data) {
		var parsed = [];
		var rows = data.split("\n");
		for (var i=0; i < rows.length; i++) {
			var row = $.trim(rows[i]);
			if (row) {
				row = row.split("|");
				parsed[parsed.length] = {
					data: row,
					value: row[0],
					result: options.formatResult && options.formatResult(row, row[0]) || row[0]
				};
			}
		}
		return parsed;
	};

	function stopLoading() {
		$input.removeClass(options.loadingClass);
	};

};

$.Autocompleter.defaults = {
	inputClass: "ac_input",
	resultsClass: "ac_results",
	loadingClass: "ac_loading",
	minChars: 1,
	delay: 400,
	matchCase: false,
	matchSubset: true,
	matchContains: false,
	cacheLength: 10,
	max: 100,
	mustMatch: false,
	extraParams: {},
	selectFirst: true,
	formatItem: function(row) { return row[0]; },
	formatMatch: null,
	autoFill: false,
	width: 0,
	multiple: false,
	multipleSeparator: ", ",
	highlight: function(value, term) {
		return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
	},
    scroll: true,
    scrollHeight: 180
};

$.Autocompleter.Cache = function(options) {

	var data = {};
	var length = 0;
	
	function matchSubset(s, sub) {
		if (!options.matchCase) 
			s = s.toLowerCase();
		var i = s.indexOf(sub);
		if (options.matchContains == "word"){
			i = s.toLowerCase().search("\\b" + sub.toLowerCase());
		}
		if (i == -1) return false;
		return i == 0 || options.matchContains;
	};
	
	function add(q, value) {
		if (length > options.cacheLength){
			flush();
		}
		if (!data[q]){ 
			length++;
		}
		data[q] = value;
	}
	
	function populate(){
		if( !options.data ) return false;
		// track the matches
		var stMatchSets = {},
			nullData = 0;

		// no url was specified, we need to adjust the cache length to make sure it fits the local data store
		if( !options.url ) options.cacheLength = 1;
		
		// track all options for minChars = 0
		stMatchSets[""] = [];
		
		// loop through the array and create a lookup structure
		for ( var i = 0, ol = options.data.length; i < ol; i++ ) {
			var rawValue = options.data[i];
			// if rawValue is a string, make an array otherwise just reference the array
			rawValue = (typeof rawValue == "string") ? [rawValue] : rawValue;
			
			var value = options.formatMatch(rawValue, i+1, options.data.length);
			if ( value === false )
				continue;
				
			var firstChar = value.charAt(0).toLowerCase();
			// if no lookup array for this character exists, look it up now
			if( !stMatchSets[firstChar] ) 
				stMatchSets[firstChar] = [];

			// if the match is a string
			var row = {
				value: value,
				data: rawValue,
				result: options.formatResult && options.formatResult(rawValue) || value
			};
			
			// push the current match into the set list
			stMatchSets[firstChar].push(row);

			// keep track of minChars zero items
			if ( nullData++ < options.max ) {
				stMatchSets[""].push(row);
			}
		};

		// add the data items to the cache
		$.each(stMatchSets, function(i, value) {
			// increase the cache size
			options.cacheLength++;
			// add to the cache
			add(i, value);
		});
	}
	
	// populate any existing data
	setTimeout(populate, 25);
	
	function flush(){
		data = {};
		length = 0;
	}
	
	return {
		flush: flush,
		add: add,
		populate: populate,
		load: function(q) {
			if (!options.cacheLength || !length)
				return null;
			/* 
			 * if dealing w/local data and matchContains than we must make sure
			 * to loop through all the data collections looking for matches
			 */
			if( !options.url && options.matchContains ){
				// track all matches
				var csub = [];
				// loop through all the data grids for matches
				for( var k in data ){
					// don't search through the stMatchSets[""] (minChars: 0) cache
					// this prevents duplicates
					if( k.length > 0 ){
						var c = data[k];
						$.each(c, function(i, x) {
							// if we've got a match, add it to the array
							if (matchSubset(x.value, q)) {
								csub.push(x);
							}
						});
					}
				}				
				return csub;
			} else 
			// if the exact item exists, use it
			if (data[q]){
				return data[q];
			} else
			if (options.matchSubset) {
				for (var i = q.length - 1; i >= options.minChars; i--) {
					var c = data[q.substr(0, i)];
					if (c) {
						var csub = [];
						$.each(c, function(i, x) {
							if (matchSubset(x.value, q)) {
								csub[csub.length] = x;
							}
						});
						return csub;
					}
				}
			}
			return null;
		}
	};
};

$.Autocompleter.Select = function (options, input, select, config) {
	var CLASSES = {
		ACTIVE: "ac_over"
	};
	
	var listItems,
		active = -1,
		data,
		term = "",
		needsInit = true,
		element,
		list;
	
	// Create results
	function init() {
		if (!needsInit)
			return;
		element = $("<div/>")
		.hide()
		.addClass(options.resultsClass)
		.css("position", "absolute")
		.appendTo(document.body);
	
		list = $("<ul/>").appendTo(element).mouseover( function(event) {
			if(target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') {
	            active = $("li", list).removeClass(CLASSES.ACTIVE).index(target(event));
			    $(target(event)).addClass(CLASSES.ACTIVE);            
	        }
		}).click(function(event) {
			$(target(event)).addClass(CLASSES.ACTIVE);
			select();
			// TODO provide option to avoid setting focus again after selection? useful for cleanup-on-focus
			input.focus();
			return false;
		}).mousedown(function() {
			config.mouseDownOnSelect = true;
		}).mouseup(function() {
			config.mouseDownOnSelect = false;
		});
		
		if( options.width > 0 )
			element.css("width", options.width);
			
		needsInit = false;
	} 
	
	function target(event) {
		var element = event.target;
		while(element && element.tagName != "LI")
			element = element.parentNode;
		// more fun with IE, sometimes event.target is empty, just ignore it then
		if(!element)
			return [];
		return element;
	}

	function moveSelect(step) {
		listItems.slice(active, active + 1).removeClass(CLASSES.ACTIVE);
		movePosition(step);
        var activeItem = listItems.slice(active, active + 1).addClass(CLASSES.ACTIVE);
        if(options.scroll) {
            var offset = 0;
            listItems.slice(0, active).each(function() {
				offset += this.offsetHeight;
			});
            if((offset + activeItem[0].offsetHeight - list.scrollTop()) > list[0].clientHeight) {
                list.scrollTop(offset + activeItem[0].offsetHeight - list.innerHeight());
            } else if(offset < list.scrollTop()) {
                list.scrollTop(offset);
            }
        }
	};
	
	function movePosition(step) {
		active += step;
		if (active < 0) {
			active = listItems.size() - 1;
		} else if (active >= listItems.size()) {
			active = 0;
		}
	}
	
	function limitNumberOfItems(available) {
		return options.max && options.max < available
			? options.max
			: available;
	}
	
	function fillList() {
		list.empty();
		var max = limitNumberOfItems(data.length);
		for (var i=0; i < max; i++) {
			if (!data[i])
				continue;
			var formatted = options.formatItem(data[i].data, i+1, max, data[i].value, term);
			if ( formatted === false )
				continue;
			var li = $("<li/>").html( options.highlight(formatted, term) ).addClass(i%2 == 0 ? "ac_even" : "ac_odd").appendTo(list)[0];
			$.data(li, "ac_data", data[i]);
		}
		listItems = list.find("li");
		if ( options.selectFirst ) {
			listItems.slice(0, 1).addClass(CLASSES.ACTIVE);
			active = 0;
		}
		// apply bgiframe if available
		if ( $.fn.bgiframe )
			list.bgiframe();
	}
	
	return {
		display: function(d, q) {
			init();
			data = d;
			term = q;
			fillList();
		},
		next: function() {
			moveSelect(1);
		},
		prev: function() {
			moveSelect(-1);
		},
		pageUp: function() {
			if (active != 0 && active - 8 < 0) {
				moveSelect( -active );
			} else {
				moveSelect(-8);
			}
		},
		pageDown: function() {
			if (active != listItems.size() - 1 && active + 8 > listItems.size()) {
				moveSelect( listItems.size() - 1 - active );
			} else {
				moveSelect(8);
			}
		},
		hide: function() {
			element && element.hide();
			listItems && listItems.removeClass(CLASSES.ACTIVE);
			active = -1;
		},
		visible : function() {
			return element && element.is(":visible");
		},
		current: function() {
			return this.visible() && (listItems.filter("." + CLASSES.ACTIVE)[0] || options.selectFirst && listItems[0]);
		},
		show: function() {
			var offset = $(input).offset();
			element.css({
				width: typeof options.width == "string" || options.width > 0 ? options.width : $(input).width(),
				top: offset.top + input.offsetHeight,
				left: offset.left
			}).show();
            if(options.scroll) {
                list.scrollTop(0);
                list.css({
					maxHeight: options.scrollHeight,
					overflow: 'auto'
				});
				
                if($.browser.msie && typeof document.body.style.maxHeight === "undefined") {
					var listHeight = 0;
					listItems.each(function() {
						listHeight += this.offsetHeight;
					});
					var scrollbarsVisible = listHeight > options.scrollHeight;
                    list.css('height', scrollbarsVisible ? options.scrollHeight : listHeight );
					if (!scrollbarsVisible) {
						// IE doesn't recalculate width when scrollbar disappears
						listItems.width( list.width() - parseInt(listItems.css("padding-left")) - parseInt(listItems.css("padding-right")) );
					}
                }
                
            }
		},
		selected: function() {
			var selected = listItems && listItems.filter("." + CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);
			return selected && selected.length && $.data(selected[0], "ac_data");
		},
		emptyList: function (){
			list && list.empty();
		},
		unbind: function() {
			element && element.remove();
		}
	};
};

$.fn.selection = function(start, end) {
	if (start !== undefined) {
		return this.each(function() {
			if( this.createTextRange ){
				var selRange = this.createTextRange();
				if (end === undefined || start == end) {
					selRange.move("character", start);
					selRange.select();
				} else {
					selRange.collapse(true);
					selRange.moveStart("character", start);
					selRange.moveEnd("character", end);
					selRange.select();
				}
			} else if( this.setSelectionRange ){
				this.setSelectionRange(start, end);
			} else if( this.selectionStart ){
				this.selectionStart = start;
				this.selectionEnd = end;
			}
		});
	}
	var field = this[0];
	if ( field.createTextRange ) {
		var range = document.selection.createRange(),
			orig = field.value,
			teststring = "<->",
			textLength = range.text.length;
		range.text = teststring;
		var caretAt = field.value.indexOf(teststring);
		field.value = orig;
		this.selection(caretAt, caretAt + textLength);
		return {
			start: caretAt,
			end: caretAt + textLength
		}
	} else if( field.selectionStart !== undefined ){
		return {
			start: field.selectionStart,
			end: field.selectionEnd
		}
	}
};

})(jQuery);/*
 * Poshy Tip jQuery plugin v1.0
 * http://vadikom.com/tools/poshy-tip-jquery-plugin-for-stylish-tooltips/
 * Copyright 2010, Vasil Dinkov, http://vadikom.com/
 */

(function(e){var a=[],d=/^url\(["']?([^"'\)]*)["']?\);?$/i,c=/\.png$/i,b=e.browser.msie&&e.browser.version==6;function f(){e.each(a,function(){this.refresh(true)})}e(window).resize(f);e.Poshytip=function(h,g){this.$elm=e(h);this.opts=e.extend({},e.fn.poshytip.defaults,g);this.$tip=e(['<div class="',this.opts.className,'">','<div class="tip-inner tip-bg-image"></div>','<div class="tip-arrow tip-arrow-top tip-arrow-right tip-arrow-bottom tip-arrow-left"></div>',"</div>"].join(""));this.$arrow=this.$tip.find("div.tip-arrow");this.$inner=this.$tip.find("div.tip-inner");this.disabled=false;this.init()};e.Poshytip.prototype={init:function(){a.push(this);this.$elm.data("title.poshytip",this.$elm.attr("title")).data("poshytip",this);switch(this.opts.showOn){case"hover":this.$elm.bind({"mouseenter.poshytip":e.proxy(this.mouseenter,this),"mouseleave.poshytip":e.proxy(this.mouseleave,this)});if(this.opts.alignTo=="cursor"){this.$elm.bind("mousemove.poshytip",e.proxy(this.mousemove,this))}if(this.opts.allowTipHover){this.$tip.hover(e.proxy(this.clearTimeouts,this),e.proxy(this.hide,this))}break;case"focus":this.$elm.bind({"focus.poshytip":e.proxy(this.show,this),"blur.poshytip":e.proxy(this.hide,this)});break}},mouseenter:function(g){if(this.disabled){return true}this.clearTimeouts();this.$elm.attr("title","");this.showTimeout=setTimeout(e.proxy(this.show,this),this.opts.showTimeout)},mouseleave:function(){if(this.disabled){return true}this.clearTimeouts();this.$elm.attr("title",this.$elm.data("title.poshytip"));this.hideTimeout=setTimeout(e.proxy(this.hide,this),this.opts.hideTimeout)},mousemove:function(g){if(this.disabled){return true}this.eventX=g.pageX;this.eventY=g.pageY;if(this.opts.followCursor&&this.$tip.data("active")){this.calcPos();this.$tip.css({left:this.pos.l,top:this.pos.t});if(this.pos.arrow){this.$arrow[0].className="tip-arrow tip-arrow-"+this.pos.arrow}}},show:function(){if(this.disabled||this.$tip.data("active")){return}this.reset();this.update();this.display()},hide:function(){if(this.disabled||!this.$tip.data("active")){return}this.display(true)},reset:function(){this.$tip.queue([]).detach().css("visibility","hidden").data("active",false);this.$inner.find("*").poshytip("hide");if(this.opts.fade){this.$tip.css("opacity",this.opacity)}this.$arrow[0].className="tip-arrow tip-arrow-top tip-arrow-right tip-arrow-bottom tip-arrow-left"},update:function(i){if(this.disabled){return}var h=i!==undefined;if(h){if(!this.$tip.data("active")){return}}else{i=this.opts.content}this.$inner.contents().detach();var g=this;this.$inner.append(typeof i=="function"?i.call(this.$elm[0],function(j){g.update(j)}):i=="[title]"?this.$elm.data("title.poshytip"):i);this.refresh(h)},refresh:function(h){if(this.disabled){return}if(h){if(!this.$tip.data("active")){return}var k={left:this.$tip.css("left"),top:this.$tip.css("top")}}this.$tip.css({left:0,top:0}).appendTo(document.body);if(this.opacity===undefined){this.opacity=this.$tip.css("opacity")}var l=this.$tip.css("background-image").match(d),m=this.$arrow.css("background-image").match(d);if(l){var i=c.test(l[1]);if(b&&i){this.$tip.css("background-image","none");this.$inner.css({margin:0,border:0,padding:0});l=i=false}else{this.$tip.prepend('<table border="0" cellpadding="0" cellspacing="0"><tr><td class="tip-top tip-bg-image" colspan="2"><span></span></td><td class="tip-right tip-bg-image" rowspan="2"><span></span></td></tr><tr><td class="tip-left tip-bg-image" rowspan="2"><span></span></td><td></td></tr><tr><td class="tip-bottom tip-bg-image" colspan="2"><span></span></td></tr></table>').css({border:0,padding:0,"background-image":"none","background-color":"transparent"}).find(".tip-bg-image").css("background-image",'url("'+l[1]+'")').end().find("td").eq(3).append(this.$inner)}if(i&&!e.support.opacity){this.opts.fade=false}}if(m&&!e.support.opacity){if(b&&c.test(m[1])){m=false;this.$arrow.css("background-image","none")}this.opts.fade=false}var o=this.$tip.find("table");if(b){this.$tip[0].style.width="";o.width("auto").find("td").eq(3).width("auto");var n=this.$tip.width(),j=parseInt(this.$tip.css("min-width")),g=parseInt(this.$tip.css("max-width"));if(!isNaN(j)&&n<j){n=j}else{if(!isNaN(g)&&n>g){n=g}}this.$tip.add(o).width(n).eq(0).find("td").eq(3).width("100%")}else{if(o[0]){o.width("auto").find("td").eq(3).width("auto").end().end().width(this.$tip.width()).find("td").eq(3).width("100%")}}this.tipOuterW=this.$tip.outerWidth();this.tipOuterH=this.$tip.outerHeight();this.calcPos();if(m&&this.pos.arrow){this.$arrow[0].className="tip-arrow tip-arrow-"+this.pos.arrow;this.$arrow.css("visibility","inherit")}if(h){this.$tip.css(k).animate({left:this.pos.l,top:this.pos.t},200)}else{this.$tip.css({left:this.pos.l,top:this.pos.t})}},display:function(h){var i=this.$tip.data("active");if(i&&!h||!i&&h){return}this.$tip.stop();if((this.opts.slide&&this.pos.arrow||this.opts.fade)&&(h&&this.opts.hideAniDuration||!h&&this.opts.showAniDuration)){var m={},l={};if(this.opts.slide&&this.pos.arrow){var k,g;if(this.pos.arrow=="bottom"||this.pos.arrow=="top"){k="top";g="bottom"}else{k="left";g="right"}var j=parseInt(this.$tip.css(k));m[k]=j+(h?0:this.opts.slideOffset*(this.pos.arrow==g?-1:1));l[k]=j+(h?this.opts.slideOffset*(this.pos.arrow==g?1:-1):0)}if(this.opts.fade){m.opacity=h?this.$tip.css("opacity"):0;l.opacity=h?0:this.opacity}this.$tip.css(m).animate(l,this.opts[h?"hideAniDuration":"showAniDuration"])}h?this.$tip.queue(e.proxy(this.reset,this)):this.$tip.css("visibility","inherit");this.$tip.data("active",!i)},disable:function(){this.reset();this.disabled=true},enable:function(){this.disabled=false},destroy:function(){this.reset();this.$tip.remove();this.$elm.unbind("poshytip").removeData("title.poshytip").removeData("poshytip");a.splice(e.inArray(this,a),1)},clearTimeouts:function(){if(this.showTimeout){clearTimeout(this.showTimeout);this.showTimeout=0}if(this.hideTimeout){clearTimeout(this.hideTimeout);this.hideTimeout=0}},calcPos:function(){var n={l:0,t:0,arrow:""},h=e(window),k={l:h.scrollLeft(),t:h.scrollTop(),w:h.width(),h:h.height()},p,j,m,i,q,g;if(this.opts.alignTo=="cursor"){p=j=m=this.eventX;i=q=g=this.eventY}else{var o=this.$elm.offset(),l={l:o.left,t:o.top,w:this.$elm.outerWidth(),h:this.$elm.outerHeight()};p=l.l+(this.opts.alignX!="inner-right"?0:l.w);j=p+Math.floor(l.w/2);m=p+(this.opts.alignX!="inner-left"?l.w:0);i=l.t+(this.opts.alignY!="inner-bottom"?0:l.h);q=i+Math.floor(l.h/2);g=i+(this.opts.alignY!="inner-top"?l.h:0)}switch(this.opts.alignX){case"right":case"inner-left":n.l=m+this.opts.offsetX;if(n.l+this.tipOuterW>k.l+k.w){n.l=k.l+k.w-this.tipOuterW}if(this.opts.alignX=="right"||this.opts.alignY=="center"){n.arrow="left"}break;case"center":n.l=j-Math.floor(this.tipOuterW/2);if(n.l+this.tipOuterW>k.l+k.w){n.l=k.l+k.w-this.tipOuterW}else{if(n.l<k.l){n.l=k.l}}break;default:n.l=p-this.tipOuterW-this.opts.offsetX;if(n.l<k.l){n.l=k.l}if(this.opts.alignX=="left"||this.opts.alignY=="center"){n.arrow="right"}}switch(this.opts.alignY){case"bottom":case"inner-top":n.t=g+this.opts.offsetY;if(!n.arrow||this.opts.alignTo=="cursor"){n.arrow="top"}if(n.t+this.tipOuterH>k.t+k.h){n.t=i-this.tipOuterH-this.opts.offsetY;if(n.arrow=="top"){n.arrow="bottom"}}break;case"center":n.t=q-Math.floor(this.tipOuterH/2);if(n.t+this.tipOuterH>k.t+k.h){n.t=k.t+k.h-this.tipOuterH}else{if(n.t<k.t){n.t=k.t}}break;default:n.t=i-this.tipOuterH-this.opts.offsetY;if(!n.arrow||this.opts.alignTo=="cursor"){n.arrow="bottom"}if(n.t<k.t){n.t=g+this.opts.offsetY;if(n.arrow=="bottom"){n.arrow="top"}}}this.pos=n}};e.fn.poshytip=function(g){if(typeof g=="string"){return this.each(function(){var i=e(this).data("poshytip");if(i&&i[g]){i[g]()}})}var h=e.extend({},e.fn.poshytip.defaults,g);if(!e("#poshytip-css-"+h.className)[0]){e(['<style id="poshytip-css-',h.className,'" type="text/css">',"div.",h.className,"{visibility:hidden;position:absolute;top:0;left:0;}","div.",h.className," table, div.",h.className," td{margin:0;font-family:inherit;font-size:inherit;font-weight:inherit;font-style:inherit;font-variant:inherit;}","div.",h.className," td.tip-bg-image span{display:block;font:1px/1px sans-serif;height:",h.bgImageFrameSize,"px;width:",h.bgImageFrameSize,"px;overflow:hidden;}","div.",h.className," td.tip-right{background-position:100% 0;}","div.",h.className," td.tip-bottom{background-position:100% 100%;}","div.",h.className," td.tip-left{background-position:0 100%;}","div.",h.className," div.tip-inner{background-position:-",h.bgImageFrameSize,"px -",h.bgImageFrameSize,"px;}","div.",h.className," div.tip-arrow{visibility:hidden;position:absolute;overflow:hidden;font:1px/1px sans-serif;}","</style>"].join("")).appendTo("head")}return this.each(function(){new e.Poshytip(this,h)})};e.fn.poshytip.defaults={content:"[title]",className:"tip-yellow",bgImageFrameSize:10,showTimeout:500,hideTimeout:100,showOn:"hover",alignTo:"cursor",alignX:"right",alignY:"top",offsetX:-22,offsetY:18,allowTipHover:true,followCursor:false,fade:true,slide:true,slideOffset:8,showAniDuration:300,hideAniDuration:300}})(jQuery);/*
 * FancyBox - jQuery Plugin
 * Simple and fancy lightbox alternative
 *
 * Examples and documentation at: http://fancybox.net
 * 
 * Copyright (c) 2008 - 2010 Janis Skarnelis
 * That said, it is hardly a one-person project. Many people have submitted bugs, code, and offered their advice freely. Their support is greatly appreciated.
 * 
 * Version: 1.3.4 (11/11/2010)
 * Requires: jQuery v1.3+
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 */

;(function(b){var m,t,u,f,D,j,E,n,z,A,q=0,e={},o=[],p=0,d={},l=[],G=null,v=new Image,J=/\.(jpg|gif|png|bmp|jpeg)(.*)?$/i,W=/[^\.]\.(swf)\s*$/i,K,L=1,y=0,s="",r,i,h=false,B=b.extend(b("<div/>")[0],{prop:0}),M=b.browser.msie&&b.browser.version<7&&!window.XMLHttpRequest,N=function(){t.hide();v.onerror=v.onload=null;G&&G.abort();m.empty()},O=function(){if(false===e.onError(o,q,e)){t.hide();h=false}else{e.titleShow=false;e.width="auto";e.height="auto";m.html('<p id="fancybox-error">The requested content cannot be loaded.<br />Please try again later.</p>');
F()}},I=function(){var a=o[q],c,g,k,C,P,w;N();e=b.extend({},b.fn.fancybox.defaults,typeof b(a).data("fancybox")=="undefined"?e:b(a).data("fancybox"));w=e.onStart(o,q,e);if(w===false)h=false;else{if(typeof w=="object")e=b.extend(e,w);k=e.title||(a.nodeName?b(a).attr("title"):a.title)||"";if(a.nodeName&&!e.orig)e.orig=b(a).children("img:first").length?b(a).children("img:first"):b(a);if(k===""&&e.orig&&e.titleFromAlt)k=e.orig.attr("alt");c=e.href||(a.nodeName?b(a).attr("href"):a.href)||null;if(/^(?:javascript)/i.test(c)||
c=="#")c=null;if(e.type){g=e.type;if(!c)c=e.content}else if(e.content)g="html";else if(c)g=c.match(J)?"image":c.match(W)?"swf":b(a).hasClass("iframe")?"iframe":c.indexOf("#")===0?"inline":"ajax";if(g){if(g=="inline"){a=c.substr(c.indexOf("#"));g=b(a).length>0?"inline":"ajax"}e.type=g;e.href=c;e.title=k;if(e.autoDimensions)if(e.type=="html"||e.type=="inline"||e.type=="ajax"){e.width="auto";e.height="auto"}else e.autoDimensions=false;if(e.modal){e.overlayShow=true;e.hideOnOverlayClick=false;e.hideOnContentClick=
false;e.enableEscapeButton=false;e.showCloseButton=false}e.padding=parseInt(e.padding,10);e.margin=parseInt(e.margin,10);m.css("padding",e.padding+e.margin);b(".fancybox-inline-tmp").unbind("fancybox-cancel").bind("fancybox-change",function(){b(this).replaceWith(j.children())});switch(g){case "html":m.html(e.content);F();break;case "inline":if(b(a).parent().is("#fancybox-content")===true){h=false;break}b('<div class="fancybox-inline-tmp" />').hide().insertBefore(b(a)).bind("fancybox-cleanup",function(){b(this).replaceWith(j.children())}).bind("fancybox-cancel",
function(){b(this).replaceWith(m.children())});b(a).appendTo(m);F();break;case "image":h=false;b.fancybox.showActivity();v=new Image;v.onerror=function(){O()};v.onload=function(){h=true;v.onerror=v.onload=null;e.width=v.width;e.height=v.height;b("<img />").attr({id:"fancybox-img",src:v.src,alt:e.title}).appendTo(m);Q()};v.src=c;break;case "swf":e.scrolling="no";C='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="'+e.width+'" height="'+e.height+'"><param name="movie" value="'+c+
'"></param>';P="";b.each(e.swf,function(x,H){C+='<param name="'+x+'" value="'+H+'"></param>';P+=" "+x+'="'+H+'"'});C+='<embed src="'+c+'" type="application/x-shockwave-flash" width="'+e.width+'" height="'+e.height+'"'+P+"></embed></object>";m.html(C);F();break;case "ajax":h=false;b.fancybox.showActivity();e.ajax.win=e.ajax.success;G=b.ajax(b.extend({},e.ajax,{url:c,data:e.ajax.data||{},error:function(x){x.status>0&&O()},success:function(x,H,R){if((typeof R=="object"?R:G).status==200){if(typeof e.ajax.win==
"function"){w=e.ajax.win(c,x,H,R);if(w===false){t.hide();return}else if(typeof w=="string"||typeof w=="object")x=w}m.html(x);F()}}}));break;case "iframe":Q()}}else O()}},F=function(){var a=e.width,c=e.height;a=a.toString().indexOf("%")>-1?parseInt((b(window).width()-e.margin*2)*parseFloat(a)/100,10)+"px":a=="auto"?"auto":a+"px";c=c.toString().indexOf("%")>-1?parseInt((b(window).height()-e.margin*2)*parseFloat(c)/100,10)+"px":c=="auto"?"auto":c+"px";m.wrapInner('<div style="width:'+a+";height:"+c+
";overflow: "+(e.scrolling=="auto"?"auto":e.scrolling=="yes"?"scroll":"hidden")+';position:relative;"></div>');e.width=m.width();e.height=m.height();Q()},Q=function(){var a,c;t.hide();if(f.is(":visible")&&false===d.onCleanup(l,p,d)){b.event.trigger("fancybox-cancel");h=false}else{h=true;b(j.add(u)).unbind();b(window).unbind("resize.fb scroll.fb");b(document).unbind("keydown.fb");f.is(":visible")&&d.titlePosition!=="outside"&&f.css("height",f.height());l=o;p=q;d=e;if(d.overlayShow){u.css({"background-color":d.overlayColor,
opacity:d.overlayOpacity,cursor:d.hideOnOverlayClick?"pointer":"auto",height:b(document).height()});if(!u.is(":visible")){M&&b("select:not(#fancybox-tmp select)").filter(function(){return this.style.visibility!=="hidden"}).css({visibility:"hidden"}).one("fancybox-cleanup",function(){this.style.visibility="inherit"});u.show()}}else u.hide();i=X();s=d.title||"";y=0;n.empty().removeAttr("style").removeClass();if(d.titleShow!==false){if(b.isFunction(d.titleFormat))a=d.titleFormat(s,l,p,d);else a=s&&s.length?
d.titlePosition=="float"?'<table id="fancybox-title-float-wrap" cellpadding="0" cellspacing="0"><tr><td id="fancybox-title-float-left"></td><td id="fancybox-title-float-main">'+s+'</td><td id="fancybox-title-float-right"></td></tr></table>':'<div id="fancybox-title-'+d.titlePosition+'">'+s+"</div>":false;s=a;if(!(!s||s==="")){n.addClass("fancybox-title-"+d.titlePosition).html(s).appendTo("body").show();switch(d.titlePosition){case "inside":n.css({width:i.width-d.padding*2,marginLeft:d.padding,marginRight:d.padding});
y=n.outerHeight(true);n.appendTo(D);i.height+=y;break;case "over":n.css({marginLeft:d.padding,width:i.width-d.padding*2,bottom:d.padding}).appendTo(D);break;case "float":n.css("left",parseInt((n.width()-i.width-40)/2,10)*-1).appendTo(f);break;default:n.css({width:i.width-d.padding*2,paddingLeft:d.padding,paddingRight:d.padding}).appendTo(f)}}}n.hide();if(f.is(":visible")){b(E.add(z).add(A)).hide();a=f.position();r={top:a.top,left:a.left,width:f.width(),height:f.height()};c=r.width==i.width&&r.height==
i.height;j.fadeTo(d.changeFade,0.3,function(){var g=function(){j.html(m.contents()).fadeTo(d.changeFade,1,S)};b.event.trigger("fancybox-change");j.empty().removeAttr("filter").css({"border-width":d.padding,width:i.width-d.padding*2,height:e.autoDimensions?"auto":i.height-y-d.padding*2});if(c)g();else{B.prop=0;b(B).animate({prop:1},{duration:d.changeSpeed,easing:d.easingChange,step:T,complete:g})}})}else{f.removeAttr("style");j.css("border-width",d.padding);if(d.transitionIn=="elastic"){r=V();j.html(m.contents());
f.show();if(d.opacity)i.opacity=0;B.prop=0;b(B).animate({prop:1},{duration:d.speedIn,easing:d.easingIn,step:T,complete:S})}else{d.titlePosition=="inside"&&y>0&&n.show();j.css({width:i.width-d.padding*2,height:e.autoDimensions?"auto":i.height-y-d.padding*2}).html(m.contents());f.css(i).fadeIn(d.transitionIn=="none"?0:d.speedIn,S)}}}},Y=function(){if(d.enableEscapeButton||d.enableKeyboardNav)b(document).bind("keydown.fb",function(a){if(a.keyCode==27&&d.enableEscapeButton){a.preventDefault();b.fancybox.close()}else if((a.keyCode==
37||a.keyCode==39)&&d.enableKeyboardNav&&a.target.tagName!=="INPUT"&&a.target.tagName!=="TEXTAREA"&&a.target.tagName!=="SELECT"){a.preventDefault();b.fancybox[a.keyCode==37?"prev":"next"]()}});if(d.showNavArrows){if(d.cyclic&&l.length>1||p!==0)z.show();if(d.cyclic&&l.length>1||p!=l.length-1)A.show()}else{z.hide();A.hide()}},S=function(){if(!b.support.opacity){j.get(0).style.removeAttribute("filter");f.get(0).style.removeAttribute("filter")}e.autoDimensions&&j.css("height","auto");f.css("height","auto");
s&&s.length&&n.show();d.showCloseButton&&E.show();Y();d.hideOnContentClick&&j.bind("click",b.fancybox.close);d.hideOnOverlayClick&&u.bind("click",b.fancybox.close);b(window).bind("resize.fb",b.fancybox.resize);d.centerOnScroll&&b(window).bind("scroll.fb",b.fancybox.center);if(d.type=="iframe")b('<iframe id="fancybox-frame" name="fancybox-frame'+(new Date).getTime()+'" frameborder="0" hspace="0" '+(b.browser.msie?'allowtransparency="true""':"")+' scrolling="'+e.scrolling+'" src="'+d.href+'"></iframe>').appendTo(j);
f.show();h=false;b.fancybox.center();d.onComplete(l,p,d);var a,c;if(l.length-1>p){a=l[p+1].href;if(typeof a!=="undefined"&&a.match(J)){c=new Image;c.src=a}}if(p>0){a=l[p-1].href;if(typeof a!=="undefined"&&a.match(J)){c=new Image;c.src=a}}},T=function(a){var c={width:parseInt(r.width+(i.width-r.width)*a,10),height:parseInt(r.height+(i.height-r.height)*a,10),top:parseInt(r.top+(i.top-r.top)*a,10),left:parseInt(r.left+(i.left-r.left)*a,10)};if(typeof i.opacity!=="undefined")c.opacity=a<0.5?0.5:a;f.css(c);
j.css({width:c.width-d.padding*2,height:c.height-y*a-d.padding*2})},U=function(){return[b(window).width()-d.margin*2,b(window).height()-d.margin*2,b(document).scrollLeft()+d.margin,b(document).scrollTop()+d.margin]},X=function(){var a=U(),c={},g=d.autoScale,k=d.padding*2;c.width=d.width.toString().indexOf("%")>-1?parseInt(a[0]*parseFloat(d.width)/100,10):d.width+k;c.height=d.height.toString().indexOf("%")>-1?parseInt(a[1]*parseFloat(d.height)/100,10):d.height+k;if(g&&(c.width>a[0]||c.height>a[1]))if(e.type==
"image"||e.type=="swf"){g=d.width/d.height;if(c.width>a[0]){c.width=a[0];c.height=parseInt((c.width-k)/g+k,10)}if(c.height>a[1]){c.height=a[1];c.width=parseInt((c.height-k)*g+k,10)}}else{c.width=Math.min(c.width,a[0]);c.height=Math.min(c.height,a[1])}c.top=parseInt(Math.max(a[3]-20,a[3]+(a[1]-c.height-40)*0.5),10);c.left=parseInt(Math.max(a[2]-20,a[2]+(a[0]-c.width-40)*0.5),10);return c},V=function(){var a=e.orig?b(e.orig):false,c={};if(a&&a.length){c=a.offset();c.top+=parseInt(a.css("paddingTop"),
10)||0;c.left+=parseInt(a.css("paddingLeft"),10)||0;c.top+=parseInt(a.css("border-top-width"),10)||0;c.left+=parseInt(a.css("border-left-width"),10)||0;c.width=a.width();c.height=a.height();c={width:c.width+d.padding*2,height:c.height+d.padding*2,top:c.top-d.padding-20,left:c.left-d.padding-20}}else{a=U();c={width:d.padding*2,height:d.padding*2,top:parseInt(a[3]+a[1]*0.5,10),left:parseInt(a[2]+a[0]*0.5,10)}}return c},Z=function(){if(t.is(":visible")){b("div",t).css("top",L*-40+"px");L=(L+1)%12}else clearInterval(K)};
b.fn.fancybox=function(a){if(!b(this).length)return this;b(this).data("fancybox",b.extend({},a,b.metadata?b(this).metadata():{})).unbind("click.fb").bind("click.fb",function(c){c.preventDefault();if(!h){h=true;b(this).blur();o=[];q=0;c=b(this).attr("rel")||"";if(!c||c==""||c==="nofollow")o.push(this);else{o=b("a[rel="+c+"], area[rel="+c+"]");q=o.index(this)}I()}});return this};b.fancybox=function(a,c){var g;if(!h){h=true;g=typeof c!=="undefined"?c:{};o=[];q=parseInt(g.index,10)||0;if(b.isArray(a)){for(var k=
0,C=a.length;k<C;k++)if(typeof a[k]=="object")b(a[k]).data("fancybox",b.extend({},g,a[k]));else a[k]=b({}).data("fancybox",b.extend({content:a[k]},g));o=jQuery.merge(o,a)}else{if(typeof a=="object")b(a).data("fancybox",b.extend({},g,a));else a=b({}).data("fancybox",b.extend({content:a},g));o.push(a)}if(q>o.length||q<0)q=0;I()}};b.fancybox.showActivity=function(){clearInterval(K);t.show();K=setInterval(Z,66)};b.fancybox.hideActivity=function(){t.hide()};b.fancybox.next=function(){return b.fancybox.pos(p+
1)};b.fancybox.prev=function(){return b.fancybox.pos(p-1)};b.fancybox.pos=function(a){if(!h){a=parseInt(a);o=l;if(a>-1&&a<l.length){q=a;I()}else if(d.cyclic&&l.length>1){q=a>=l.length?0:l.length-1;I()}}};b.fancybox.cancel=function(){if(!h){h=true;b.event.trigger("fancybox-cancel");N();e.onCancel(o,q,e);h=false}};b.fancybox.close=function(){function a(){u.fadeOut("fast");n.empty().hide();f.hide();b.event.trigger("fancybox-cleanup");j.empty();d.onClosed(l,p,d);l=e=[];p=q=0;d=e={};h=false}if(!(h||f.is(":hidden"))){h=
true;if(d&&false===d.onCleanup(l,p,d))h=false;else{N();b(E.add(z).add(A)).hide();b(j.add(u)).unbind();b(window).unbind("resize.fb scroll.fb");b(document).unbind("keydown.fb");j.find("iframe").attr("src",M&&/^https/i.test(window.location.href||"")?"javascript:void(false)":"about:blank");d.titlePosition!=="inside"&&n.empty();f.stop();if(d.transitionOut=="elastic"){r=V();var c=f.position();i={top:c.top,left:c.left,width:f.width(),height:f.height()};if(d.opacity)i.opacity=1;n.empty().hide();B.prop=1;
b(B).animate({prop:0},{duration:d.speedOut,easing:d.easingOut,step:T,complete:a})}else f.fadeOut(d.transitionOut=="none"?0:d.speedOut,a)}}};b.fancybox.resize=function(){u.is(":visible")&&u.css("height",b(document).height());b.fancybox.center(true)};b.fancybox.center=function(a){var c,g;if(!h){g=a===true?1:0;c=U();!g&&(f.width()>c[0]||f.height()>c[1])||f.stop().animate({top:parseInt(Math.max(c[3]-20,c[3]+(c[1]-j.height()-40)*0.5-d.padding)),left:parseInt(Math.max(c[2]-20,c[2]+(c[0]-j.width()-40)*0.5-
d.padding))},typeof a=="number"?a:200)}};b.fancybox.init=function(){if(!b("#fancybox-wrap").length){b("body").append(m=b('<div id="fancybox-tmp"></div>'),t=b('<div id="fancybox-loading"><div></div></div>'),u=b('<div id="fancybox-overlay"></div>'),f=b('<div id="fancybox-wrap"></div>'));D=b('<div id="fancybox-outer"></div>').append('<div class="fancybox-bg" id="fancybox-bg-n"></div><div class="fancybox-bg" id="fancybox-bg-ne"></div><div class="fancybox-bg" id="fancybox-bg-e"></div><div class="fancybox-bg" id="fancybox-bg-se"></div><div class="fancybox-bg" id="fancybox-bg-s"></div><div class="fancybox-bg" id="fancybox-bg-sw"></div><div class="fancybox-bg" id="fancybox-bg-w"></div><div class="fancybox-bg" id="fancybox-bg-nw"></div>').appendTo(f);
D.append(j=b('<div id="fancybox-content"></div>'),E=b('<a id="fancybox-close"></a>'),n=b('<div id="fancybox-title"></div>'),z=b('<a href="javascript:;" id="fancybox-left"><span class="fancy-ico" id="fancybox-left-ico"></span></a>'),A=b('<a href="javascript:;" id="fancybox-right"><span class="fancy-ico" id="fancybox-right-ico"></span></a>'));E.click(b.fancybox.close);t.click(b.fancybox.cancel);z.click(function(a){a.preventDefault();b.fancybox.prev()});A.click(function(a){a.preventDefault();b.fancybox.next()});
b.fn.mousewheel&&f.bind("mousewheel.fb",function(a,c){if(h)a.preventDefault();else if(b(a.target).get(0).clientHeight==0||b(a.target).get(0).scrollHeight===b(a.target).get(0).clientHeight){a.preventDefault();b.fancybox[c>0?"prev":"next"]()}});b.support.opacity||f.addClass("fancybox-ie");if(M){t.addClass("fancybox-ie6");f.addClass("fancybox-ie6");b('<iframe id="fancybox-hide-sel-frame" src="'+(/^https/i.test(window.location.href||"")?"javascript:void(false)":"about:blank")+'" scrolling="no" border="0" frameborder="0" tabindex="-1"></iframe>').prependTo(D)}}};
b.fn.fancybox.defaults={padding:10,margin:40,opacity:false,modal:false,cyclic:false,scrolling:"auto",width:560,height:340,autoScale:true,autoDimensions:true,centerOnScroll:false,ajax:{},swf:{wmode:"transparent"},hideOnOverlayClick:true,hideOnContentClick:false,overlayShow:true,overlayOpacity:0.7,overlayColor:"#777",titleShow:true,titlePosition:"float",titleFormat:null,titleFromAlt:false,transitionIn:"fade",transitionOut:"fade",speedIn:300,speedOut:300,changeSpeed:300,changeFade:"fast",easingIn:"swing",
easingOut:"swing",showCloseButton:true,showNavArrows:true,enableEscapeButton:true,enableKeyboardNav:true,onStart:function(){},onCancel:function(){},onComplete:function(){},onCleanup:function(){},onClosed:function(){},onError:function(){}};b(document).ready(function(){b.fancybox.init()})})(jQuery);/**
 * jQuery.ScrollTo - Easy element scrolling using jQuery.
 * Copyright (c) 2007-2009 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
 * Dual licensed under MIT and GPL.
 * Date: 5/25/2009
 * @author Ariel Flesler
 * @version 1.4.2
 *
 * http://flesler.blogspot.com/2007/10/jqueryscrollto.html
 */
;(function(d){var k=d.scrollTo=function(a,i,e){d(window).scrollTo(a,i,e)};k.defaults={axis:'xy',duration:parseFloat(d.fn.jquery)>=1.3?0:1};k.window=function(a){return d(window)._scrollable()};d.fn._scrollable=function(){return this.map(function(){var a=this,i=!a.nodeName||d.inArray(a.nodeName.toLowerCase(),['iframe','#document','html','body'])!=-1;if(!i)return a;var e=(a.contentWindow||a).document||a.ownerDocument||a;return d.browser.safari||e.compatMode=='BackCompat'?e.body:e.documentElement})};d.fn.scrollTo=function(n,j,b){if(typeof j=='object'){b=j;j=0}if(typeof b=='function')b={onAfter:b};if(n=='max')n=9e9;b=d.extend({},k.defaults,b);j=j||b.speed||b.duration;b.queue=b.queue&&b.axis.length>1;if(b.queue)j/=2;b.offset=p(b.offset);b.over=p(b.over);return this._scrollable().each(function(){var q=this,r=d(q),f=n,s,g={},u=r.is('html,body');switch(typeof f){case'number':case'string':if(/^([+-]=)?\d+(\.\d+)?(px|%)?$/.test(f)){f=p(f);break}f=d(f,this);case'object':if(f.is||f.style)s=(f=d(f)).offset()}d.each(b.axis.split(''),function(a,i){var e=i=='x'?'Left':'Top',h=e.toLowerCase(),c='scroll'+e,l=q[c],m=k.max(q,i);if(s){g[c]=s[h]+(u?0:l-r.offset()[h]);if(b.margin){g[c]-=parseInt(f.css('margin'+e))||0;g[c]-=parseInt(f.css('border'+e+'Width'))||0}g[c]+=b.offset[h]||0;if(b.over[h])g[c]+=f[i=='x'?'width':'height']()*b.over[h]}else{var o=f[h];g[c]=o.slice&&o.slice(-1)=='%'?parseFloat(o)/100*m:o}if(/^\d+$/.test(g[c]))g[c]=g[c]<=0?0:Math.min(g[c],m);if(!a&&b.queue){if(l!=g[c])t(b.onAfterFirst);delete g[c]}});t(b.onAfter);function t(a){r.animate(g,j,b.easing,a&&function(){a.call(this,n,b)})}}).end()};k.max=function(a,i){var e=i=='x'?'Width':'Height',h='scroll'+e;if(!d(a).is('html,body'))return a[h]-d(a)[e.toLowerCase()]();var c='client'+e,l=a.ownerDocument.documentElement,m=a.ownerDocument.body;return Math.max(l[h],m[h])-Math.min(l[c],m[c])};function p(a){return typeof a=='object'?a:{top:a,left:a}}})(jQuery);;(function($){var L=$.loading=function(show,opts){return $('body').loading(show,opts,true);};$.fn.loading=function(show,opts,page){opts=toOpts(show,opts);var base=page?$.extend(true,{},L,L.pageOptions):L;return this.each(function(){var $el=$(this),l=$.extend(true,{},base,$.metadata?$el.metadata():null,opts);if(typeof l.onAjax=="boolean"){L.setAjax.call($el,l);}else{L.toggle.call($el,l);}});};var fixed={position:$.browser.msie?'absolute':'fixed'};$.extend(L,{version:"1.6.4",align:'top-left',pulse:'working error',mask:false,img:null,element:null,text:'Loading...',onAjax:undefined,delay:0,max:0,classname:'loading',imgClass:'loading-img',elementClass:'loading-element',maskClass:'loading-mask',css:{position:'absolute',whiteSpace:'nowrap',zIndex:1001},maskCss:{position:'absolute',opacity:.15,background:'#333',zIndex:101,display:'block',cursor:'wait'},cloneEvents:true,pageOptions:{page:true,align:'top-center',css:fixed,maskCss:fixed},html:'<div></div>',maskHtml:'<div></div>',maskedClass:'loading-masked',maskEvents:'mousedown mouseup keydown keypress',resizeEvents:'resize',working:{time:10000,text:'Still working...',run:function(l){var w=l.working,self=this;w.timeout=setTimeout(function(){self.height('auto').width('auto').text(l.text=w.text);l.place.call(self,l);},w.time);}},error:{time:100000,text:'Task may have failed...',classname:'loading-error',run:function(l){var e=l.error,self=this;e.timeout=setTimeout(function(){self.height('auto').width('auto').text(l.text=e.text).addClass(e.classname);l.place.call(self,l);},e.time);}},fade:{time:800,speed:'slow',run:function(l){var f=l.fade,s=f.speed,self=this;f.interval=setInterval(function(){self.fadeOut(s).fadeIn(s);},f.time);}},ellipsis:{time:300,run:function(l){var e=l.ellipsis,self=this;e.interval=setInterval(function(){var et=self.text(),t=l.text,i=dotIndex(t);self.text((et.length-i)<3?et+'.':t.substring(0,i));},e.time);function dotIndex(t){var x=t.indexOf('.');return x<0?t.length:x;}}},type:{time:100,run:function(l){var t=l.type,self=this;t.interval=setInterval(function(){var e=self.text(),el=e.length,txt=l.text;self.text(el==txt.length?txt.charAt(0):txt.substring(0,el+1));},t.time);}},toggle:function(l){var old=this.data('loading');if(old){if(l.show!==true)old.off.call(this,old,l);}else{if(l.show!==false)l.on.call(this,l);}},setAjax:function(l){if(l.onAjax){var self=this,count=0,A=l.ajax={start:function(){if(!count++)l.on.call(self,l);},stop:function(){if(!--count)l.off.call(self,l,l);}};this.bind('ajaxStart.loading',A.start).bind('ajaxStop.loading',A.stop);}else{this.unbind('ajaxStart.loading ajaxStop.loading');}},on:function(l,force){var p=l.parent=this.data('loading',l);if(l.max)l.maxout=setTimeout(function(){l.off.call(p,l,l);},l.max);if(l.delay&&!force){return l.timeout=setTimeout(function(){delete l.timeout;l.on.call(p,l,true);},l.delay);}
if(l.mask)l.mask=l.createMask.call(p,l);l.display=l.create.call(p,l);if(l.img){l.initImg.call(p,l);}else if(l.element){l.initElement.call(p,l);}else{l.init.call(p,l);}
p.trigger('loadingStart',[l]);},initImg:function(l){var self=this;l.imgElement=$('<img src="'+l.img+'"/>').bind('load',function(){l.init.call(self,l);});l.display.addClass(l.imgClass).append(l.imgElement);},initElement:function(l){l.element=$(l.element).clone(l.cloneEvents).show();l.display.addClass(l.elementClass).append(l.element);l.init.call(this,l);},init:function(l){l.place.call(l.display,l);if(l.pulse)l.initPulse.call(this,l);},initPulse:function(l){$.each(l.pulse.split(' '),function(){l[this].run.call(l.display,l);});},create:function(l){var el=$(l.html).addClass(l.classname).css(l.css).appendTo(this);if(l.text&&!l.img&&!l.element)el.text(l.originalText=l.text);$(window).bind(l.resizeEvents,l.resizer=function(){l.resize(l);});return el;},resize:function(l){l.parent.box=null;if(l.mask)l.mask.hide();l.place.call(l.display.hide(),l);if(l.mask)l.mask.show().css(l.parent.box);},createMask:function(l){var box=l.measure.call(this.addClass(l.maskedClass),l);l.handler=function(e){return l.maskHandler(e,l);};$(document).bind(l.maskEvents,l.handler);return $(l.maskHtml).addClass(l.maskClass).css(box).css(l.maskCss).appendTo(this);},maskHandler:function(e,l){var $els=$(e.target).parents().andSelf();if($els.filter('.'+l.classname).length!=0)return true;return!l.page&&$els.filter('.'+l.maskedClass).length==0;},place:function(l){var box=l.align,v='top',h='left';if(typeof box=="object"){box=$.extend(l.calc.call(this,v,h,l),box);}else{if(box!='top-left'){var s=box.split('-');if(s.length==1){v=h=s[0];}else{v=s[0];h=s[1];}}
if(!this.hasClass(v))this.addClass(v);if(!this.hasClass(h))this.addClass(h);box=l.calc.call(this,v,h,l);}
this.show().css(l.box=box);},calc:function(v,h,l){var box=$.extend({},l.measure.call(l.parent,l)),H=$.boxModel?this.height():this.innerHeight(),W=$.boxModel?this.width():this.innerWidth();if(v!='top'){var d=box.height-H;if(v=='center'){d/=2;}else if(v!='bottom'){d=0;}else if($.boxModel){d-=css(this,'paddingTop')+css(this,'paddingBottom');}
box.top+=d;}
if(h!='left'){var d=box.width-W;if(h=='center'){d/=2;}else if(h!='right'){d=0;}else if($.boxModel){d-=css(this,'paddingLeft')+css(this,'paddingRight');}
box.left+=d;}
box.height=H;box.width=W;return box;},measure:function(l){return this.box||(this.box=l.page?l.pageBox(l):l.elementBox(this,l));},elementBox:function(e,l){if(e.css('position')=='absolute'){var box={top:0,left:0};}else{var box=e.position();box.top+=css(e,'marginTop');box.left+=css(e,'marginLeft');}
box.height=e.outerHeight();box.width=e.outerWidth();return box;},pageBox:function(l){var full=$.boxModel&&l.css.position!='fixed';return{top:0,left:0,height:get(full,'Height'),width:get(full,'Width')};function get(full,side){var doc=document;if(full){var s=side.toLowerCase(),d=$(doc)[s](),w=$(window)[s]();return d-css($(doc.body),'marginTop')>w?d:w;}
var c='client'+side;return Math.max(doc.documentElement[c],doc.body[c]);}},off:function(old,l){this.data('loading',null);if(old.maxout)clearTimeout(old.maxout);if(old.timeout)return clearTimeout(old.timeout);if(old.pulse)old.stopPulse.call(this,old,l);if(old.originalText)old.text=old.originalText;if(old.mask)old.stopMask.call(this,old,l);$(window).unbind(old.resizeEvents,old.resizer);if(old.display)old.display.remove();if(old.parent)old.parent.trigger('loadingEnd',[old]);},stopPulse:function(old,l){$.each(old.pulse.split(' '),function(){var p=old[this];if(p.end)p.end.call(l.display,old,l);if(p.interval)clearInterval(p.interval);if(p.timeout)clearTimeout(p.timeout);});},stopMask:function(old,l){this.removeClass(l.maskedClass);$(document).unbind(old.maskEvents,old.handler);old.mask.remove();}});function toOpts(s,l){if(l===undefined){l=(typeof s=="boolean")?{show:s}:s;}else{l.show=s;}
if(l&&(l.img||l.element)&&!l.pulse)l.pulse=false;if(l&&l.onAjax!==undefined&&l.show===undefined)l.show=false;return l;}
function css(el,prop){var val=el.css(prop);return val=='auto'?0:parseFloat(val,10);}})(jQuery);/**
 * Jcrop v.0.9.8 (minimized)
 * (c) 2008 Kelly Hallman and DeepLiquid.com
 * More information: http://deepliquid.com/content/Jcrop.html
 * Released under MIT License - this header must remain with code
 */


(function($){$.Jcrop=function(obj,opt)
{var obj=obj,opt=opt;if(typeof(obj)!=='object')obj=$(obj)[0];if(typeof(opt)!=='object')opt={};if(!('trackDocument'in opt))
{opt.trackDocument=$.browser.msie?false:true;if($.browser.msie&&$.browser.version.split('.')[0]=='8')
opt.trackDocument=true;}
if(!('keySupport'in opt))
opt.keySupport=$.browser.msie?false:true;var defaults={trackDocument:false,baseClass:'jcrop',addClass:null,bgColor:'black',bgOpacity:.6,borderOpacity:.4,handleOpacity:.5,handlePad:5,handleSize:9,handleOffset:5,edgeMargin:14,aspectRatio:0,keySupport:true,cornerHandles:true,sideHandles:true,drawBorders:true,dragEdges:true,boxWidth:0,boxHeight:0,boundary:8,animationDelay:20,swingSpeed:3,allowSelect:true,allowMove:true,allowResize:true,minSelect:[0,0],maxSize:[0,0],minSize:[0,0],onChange:function(){},onSelect:function(){}};var options=defaults;setOptions(opt);var $origimg=$(obj);var $img=$origimg.clone().removeAttr('id').css({position:'absolute'});$img.width($origimg.width());$img.height($origimg.height());$origimg.after($img).hide();presize($img,options.boxWidth,options.boxHeight);var boundx=$img.width(),boundy=$img.height(),$div=$('<div />').width(boundx).height(boundy).addClass(cssClass('holder')).css({position:'relative',backgroundColor:options.bgColor}).insertAfter($origimg).append($img);;if(options.addClass)$div.addClass(options.addClass);var $img2=$('<img />').attr('src',$img.attr('src')).css('position','absolute').width(boundx).height(boundy);var $img_holder=$('<div />').width(pct(100)).height(pct(100)).css({zIndex:310,position:'absolute',overflow:'hidden'}).append($img2);var $hdl_holder=$('<div />').width(pct(100)).height(pct(100)).css('zIndex',320);var $sel=$('<div />').css({position:'absolute',zIndex:300}).insertBefore($img).append($img_holder,$hdl_holder);var bound=options.boundary;var $trk=newTracker().width(boundx+(bound*2)).height(boundy+(bound*2)).css({position:'absolute',top:px(-bound),left:px(-bound),zIndex:290}).mousedown(newSelection);var xlimit,ylimit,xmin,ymin;var xscale,yscale,enabled=true;var docOffset=getPos($img),btndown,lastcurs,dimmed,animating,shift_down;var Coords=function()
{var x1=0,y1=0,x2=0,y2=0,ox,oy;function setPressed(pos)
{var pos=rebound(pos);x2=x1=pos[0];y2=y1=pos[1];};function setCurrent(pos)
{var pos=rebound(pos);ox=pos[0]-x2;oy=pos[1]-y2;x2=pos[0];y2=pos[1];};function getOffset()
{return[ox,oy];};function moveOffset(offset)
{var ox=offset[0],oy=offset[1];if(0>x1+ox)ox-=ox+x1;if(0>y1+oy)oy-=oy+y1;if(boundy<y2+oy)oy+=boundy-(y2+oy);if(boundx<x2+ox)ox+=boundx-(x2+ox);x1+=ox;x2+=ox;y1+=oy;y2+=oy;};function getCorner(ord)
{var c=getFixed();switch(ord)
{case'ne':return[c.x2,c.y];case'nw':return[c.x,c.y];case'se':return[c.x2,c.y2];case'sw':return[c.x,c.y2];}};function getFixed()
{if(!options.aspectRatio)return getRect();var aspect=options.aspectRatio,min_x=options.minSize[0]/xscale,min_y=options.minSize[1]/yscale,max_x=options.maxSize[0]/xscale,max_y=options.maxSize[1]/yscale,rw=x2-x1,rh=y2-y1,rwa=Math.abs(rw),rha=Math.abs(rh),real_ratio=rwa/rha,xx,yy;if(max_x==0){max_x=boundx*10}
if(max_y==0){max_y=boundy*10}
if(real_ratio<aspect)
{yy=y2;w=rha*aspect;xx=rw<0?x1-w:w+x1;if(xx<0)
{xx=0;h=Math.abs((xx-x1)/aspect);yy=rh<0?y1-h:h+y1;}
else if(xx>boundx)
{xx=boundx;h=Math.abs((xx-x1)/aspect);yy=rh<0?y1-h:h+y1;}}
else
{xx=x2;h=rwa/aspect;yy=rh<0?y1-h:y1+h;if(yy<0)
{yy=0;w=Math.abs((yy-y1)*aspect);xx=rw<0?x1-w:w+x1;}
else if(yy>boundy)
{yy=boundy;w=Math.abs(yy-y1)*aspect;xx=rw<0?x1-w:w+x1;}}
if(xx>x1){if(xx-x1<min_x){xx=x1+min_x;}else if(xx-x1>max_x){xx=x1+max_x;}
if(yy>y1){yy=y1+(xx-x1)/aspect;}else{yy=y1-(xx-x1)/aspect;}}else if(xx<x1){if(x1-xx<min_x){xx=x1-min_x}else if(x1-xx>max_x){xx=x1-max_x;}
if(yy>y1){yy=y1+(x1-xx)/aspect;}else{yy=y1-(x1-xx)/aspect;}}
if(xx<0){x1-=xx;xx=0;}else if(xx>boundx){x1-=xx-boundx;xx=boundx;}
if(yy<0){y1-=yy;yy=0;}else if(yy>boundy){y1-=yy-boundy;yy=boundy;}
return last=makeObj(flipCoords(x1,y1,xx,yy));};function rebound(p)
{if(p[0]<0)p[0]=0;if(p[1]<0)p[1]=0;if(p[0]>boundx)p[0]=boundx;if(p[1]>boundy)p[1]=boundy;return[p[0],p[1]];};function flipCoords(x1,y1,x2,y2)
{var xa=x1,xb=x2,ya=y1,yb=y2;if(x2<x1)
{xa=x2;xb=x1;}
if(y2<y1)
{ya=y2;yb=y1;}
return[Math.round(xa),Math.round(ya),Math.round(xb),Math.round(yb)];};function getRect()
{var xsize=x2-x1;var ysize=y2-y1;if(xlimit&&(Math.abs(xsize)>xlimit))
x2=(xsize>0)?(x1+xlimit):(x1-xlimit);if(ylimit&&(Math.abs(ysize)>ylimit))
y2=(ysize>0)?(y1+ylimit):(y1-ylimit);if(ymin&&(Math.abs(ysize)<ymin))
y2=(ysize>0)?(y1+ymin):(y1-ymin);if(xmin&&(Math.abs(xsize)<xmin))
x2=(xsize>0)?(x1+xmin):(x1-xmin);if(x1<0){x2-=x1;x1-=x1;}
if(y1<0){y2-=y1;y1-=y1;}
if(x2<0){x1-=x2;x2-=x2;}
if(y2<0){y1-=y2;y2-=y2;}
if(x2>boundx){var delta=x2-boundx;x1-=delta;x2-=delta;}
if(y2>boundy){var delta=y2-boundy;y1-=delta;y2-=delta;}
if(x1>boundx){var delta=x1-boundy;y2-=delta;y1-=delta;}
if(y1>boundy){var delta=y1-boundy;y2-=delta;y1-=delta;}
return makeObj(flipCoords(x1,y1,x2,y2));};function makeObj(a)
{return{x:a[0],y:a[1],x2:a[2],y2:a[3],w:a[2]-a[0],h:a[3]-a[1]};};return{flipCoords:flipCoords,setPressed:setPressed,setCurrent:setCurrent,getOffset:getOffset,moveOffset:moveOffset,getCorner:getCorner,getFixed:getFixed};}();var Selection=function()
{var start,end,dragmode,awake,hdep=370;var borders={};var handle={};var seehandles=false;var hhs=options.handleOffset;if(options.drawBorders){borders={top:insertBorder('hline').css('top',$.browser.msie?px(-1):px(0)),bottom:insertBorder('hline'),left:insertBorder('vline'),right:insertBorder('vline')};}
if(options.dragEdges){handle.t=insertDragbar('n');handle.b=insertDragbar('s');handle.r=insertDragbar('e');handle.l=insertDragbar('w');}
options.sideHandles&&createHandles(['n','s','e','w']);options.cornerHandles&&createHandles(['sw','nw','ne','se']);function insertBorder(type)
{var jq=$('<div />').css({position:'absolute',opacity:options.borderOpacity}).addClass(cssClass(type));$img_holder.append(jq);return jq;};function dragDiv(ord,zi)
{var jq=$('<div />').mousedown(createDragger(ord)).css({cursor:ord+'-resize',position:'absolute',zIndex:zi});$hdl_holder.append(jq);return jq;};function insertHandle(ord)
{return dragDiv(ord,hdep++).css({top:px(-hhs+1),left:px(-hhs+1),opacity:options.handleOpacity}).addClass(cssClass('handle'));};function insertDragbar(ord)
{var s=options.handleSize,o=hhs,h=s,w=s,t=o,l=o;switch(ord)
{case'n':case's':w=pct(100);break;case'e':case'w':h=pct(100);break;}
return dragDiv(ord,hdep++).width(w).height(h).css({top:px(-t+1),left:px(-l+1)});};function createHandles(li)
{for(i in li)handle[li[i]]=insertHandle(li[i]);};function moveHandles(c)
{var midvert=Math.round((c.h/2)-hhs),midhoriz=Math.round((c.w/2)-hhs),north=west=-hhs+1,east=c.w-hhs,south=c.h-hhs,x,y;'e'in handle&&handle.e.css({top:px(midvert),left:px(east)})&&handle.w.css({top:px(midvert)})&&handle.s.css({top:px(south),left:px(midhoriz)})&&handle.n.css({left:px(midhoriz)});'ne'in handle&&handle.ne.css({left:px(east)})&&handle.se.css({top:px(south),left:px(east)})&&handle.sw.css({top:px(south)});'b'in handle&&handle.b.css({top:px(south)})&&handle.r.css({left:px(east)});};function moveto(x,y)
{$img2.css({top:px(-y),left:px(-x)});$sel.css({top:px(y),left:px(x)});};function resize(w,h)
{$sel.width(w).height(h);};function refresh()
{var c=Coords.getFixed();Coords.setPressed([c.x,c.y]);Coords.setCurrent([c.x2,c.y2]);updateVisible();};function updateVisible()
{if(awake)return update();};function update()
{var c=Coords.getFixed();resize(c.w,c.h);moveto(c.x,c.y);options.drawBorders&&borders['right'].css({left:px(c.w-1)})&&borders['bottom'].css({top:px(c.h-1)});seehandles&&moveHandles(c);awake||show();options.onChange(unscale(c));};function show()
{$sel.show();$img.css('opacity',options.bgOpacity);awake=true;};function release()
{disableHandles();$sel.hide();$img.css('opacity',1);awake=false;};function showHandles()
{if(seehandles)
{moveHandles(Coords.getFixed());$hdl_holder.show();}};function enableHandles()
{seehandles=true;if(options.allowResize)
{moveHandles(Coords.getFixed());$hdl_holder.show();return true;}};function disableHandles()
{seehandles=false;$hdl_holder.hide();};function animMode(v)
{(animating=v)?disableHandles():enableHandles();};function done()
{animMode(false);refresh();};var $track=newTracker().mousedown(createDragger('move')).css({cursor:'move',position:'absolute',zIndex:360})
$img_holder.append($track);disableHandles();return{updateVisible:updateVisible,update:update,release:release,refresh:refresh,setCursor:function(cursor){$track.css('cursor',cursor);},enableHandles:enableHandles,enableOnly:function(){seehandles=true;},showHandles:showHandles,disableHandles:disableHandles,animMode:animMode,done:done};}();var Tracker=function()
{var onMove=function(){},onDone=function(){},trackDoc=options.trackDocument;if(!trackDoc)
{$trk.mousemove(trackMove).mouseup(trackUp).mouseout(trackUp);}
function toFront()
{$trk.css({zIndex:450});if(trackDoc)
{$(document).mousemove(trackMove).mouseup(trackUp);}}
function toBack()
{$trk.css({zIndex:290});if(trackDoc)
{$(document).unbind('mousemove',trackMove).unbind('mouseup',trackUp);}}
function trackMove(e)
{onMove(mouseAbs(e));};function trackUp(e)
{e.preventDefault();e.stopPropagation();if(btndown)
{btndown=false;onDone(mouseAbs(e));options.onSelect(unscale(Coords.getFixed()));toBack();onMove=function(){};onDone=function(){};}
return false;};function activateHandlers(move,done)
{btndown=true;onMove=move;onDone=done;toFront();return false;};function setCursor(t){$trk.css('cursor',t);};$img.before($trk);return{activateHandlers:activateHandlers,setCursor:setCursor};}();var KeyManager=function()
{var $keymgr=$('<input type="radio" />').css({position:'absolute',left:'-30px'}).keypress(parseKey).blur(onBlur),$keywrap=$('<div />').css({position:'absolute',overflow:'hidden'}).append($keymgr);function watchKeys()
{if(options.keySupport)
{$keymgr.show();$keymgr.focus();}};function onBlur(e)
{$keymgr.hide();};function doNudge(e,x,y)
{if(options.allowMove){Coords.moveOffset([x,y]);Selection.updateVisible();};e.preventDefault();e.stopPropagation();};function parseKey(e)
{if(e.ctrlKey)return true;shift_down=e.shiftKey?true:false;var nudge=shift_down?10:1;switch(e.keyCode)
{case 37:doNudge(e,-nudge,0);break;case 39:doNudge(e,nudge,0);break;case 38:doNudge(e,0,-nudge);break;case 40:doNudge(e,0,nudge);break;case 27:Selection.release();break;case 9:return true;}
return nothing(e);};if(options.keySupport)$keywrap.insertBefore($img);return{watchKeys:watchKeys};}();function px(n){return''+parseInt(n)+'px';};function pct(n){return''+parseInt(n)+'%';};function cssClass(cl){return options.baseClass+'-'+cl;};function getPos(obj)
{var pos=$(obj).offset();return[pos.left,pos.top];};function mouseAbs(e)
{return[(e.pageX-docOffset[0]),(e.pageY-docOffset[1])];};function myCursor(type)
{if(type!=lastcurs)
{Tracker.setCursor(type);lastcurs=type;}};function startDragMode(mode,pos)
{docOffset=getPos($img);Tracker.setCursor(mode=='move'?mode:mode+'-resize');if(mode=='move')
return Tracker.activateHandlers(createMover(pos),doneSelect);var fc=Coords.getFixed();var opp=oppLockCorner(mode);var opc=Coords.getCorner(oppLockCorner(opp));Coords.setPressed(Coords.getCorner(opp));Coords.setCurrent(opc);Tracker.activateHandlers(dragmodeHandler(mode,fc),doneSelect);};function dragmodeHandler(mode,f)
{return function(pos){if(!options.aspectRatio)switch(mode)
{case'e':pos[1]=f.y2;break;case'w':pos[1]=f.y2;break;case'n':pos[0]=f.x2;break;case's':pos[0]=f.x2;break;}
else switch(mode)
{case'e':pos[1]=f.y+1;break;case'w':pos[1]=f.y+1;break;case'n':pos[0]=f.x+1;break;case's':pos[0]=f.x+1;break;}
Coords.setCurrent(pos);Selection.update();};};function createMover(pos)
{var lloc=pos;KeyManager.watchKeys();return function(pos)
{Coords.moveOffset([pos[0]-lloc[0],pos[1]-lloc[1]]);lloc=pos;Selection.update();};};function oppLockCorner(ord)
{switch(ord)
{case'n':return'sw';case's':return'nw';case'e':return'nw';case'w':return'ne';case'ne':return'sw';case'nw':return'se';case'se':return'nw';case'sw':return'ne';};};function createDragger(ord)
{return function(e){if(options.disabled)return false;if((ord=='move')&&!options.allowMove)return false;btndown=true;startDragMode(ord,mouseAbs(e));e.stopPropagation();e.preventDefault();return false;};};function presize($obj,w,h)
{var nw=$obj.width(),nh=$obj.height();if((nw>w)&&w>0)
{nw=w;nh=(w/$obj.width())*$obj.height();}
if((nh>h)&&h>0)
{nh=h;nw=(h/$obj.height())*$obj.width();}
xscale=$obj.width()/nw;yscale=$obj.height()/nh;$obj.width(nw).height(nh);};function unscale(c)
{return{x:parseInt(c.x*xscale),y:parseInt(c.y*yscale),x2:parseInt(c.x2*xscale),y2:parseInt(c.y2*yscale),w:parseInt(c.w*xscale),h:parseInt(c.h*yscale)};};function doneSelect(pos)
{var c=Coords.getFixed();if(c.w>options.minSelect[0]&&c.h>options.minSelect[1])
{Selection.enableHandles();Selection.done();}
else
{Selection.release();}
Tracker.setCursor(options.allowSelect?'crosshair':'default');};function newSelection(e)
{if(options.disabled)return false;if(!options.allowSelect)return false;btndown=true;docOffset=getPos($img);Selection.disableHandles();myCursor('crosshair');var pos=mouseAbs(e);Coords.setPressed(pos);Tracker.activateHandlers(selectDrag,doneSelect);KeyManager.watchKeys();Selection.update();e.stopPropagation();e.preventDefault();return false;};function selectDrag(pos)
{Coords.setCurrent(pos);Selection.update();};function newTracker()
{var trk=$('<div></div>').addClass(cssClass('tracker'));$.browser.msie&&trk.css({opacity:0,backgroundColor:'white'});return trk;};function animateTo(a)
{var x1=a[0]/xscale,y1=a[1]/yscale,x2=a[2]/xscale,y2=a[3]/yscale;if(animating)return;var animto=Coords.flipCoords(x1,y1,x2,y2);var c=Coords.getFixed();var animat=initcr=[c.x,c.y,c.x2,c.y2];var interv=options.animationDelay;var x=animat[0];var y=animat[1];var x2=animat[2];var y2=animat[3];var ix1=animto[0]-initcr[0];var iy1=animto[1]-initcr[1];var ix2=animto[2]-initcr[2];var iy2=animto[3]-initcr[3];var pcent=0;var velocity=options.swingSpeed;Selection.animMode(true);var animator=function()
{return function()
{pcent+=(100-pcent)/velocity;animat[0]=x+((pcent/100)*ix1);animat[1]=y+((pcent/100)*iy1);animat[2]=x2+((pcent/100)*ix2);animat[3]=y2+((pcent/100)*iy2);if(pcent<100)animateStart();else Selection.done();if(pcent>=99.8)pcent=100;setSelectRaw(animat);};}();function animateStart()
{window.setTimeout(animator,interv);};animateStart();};function setSelect(rect)
{setSelectRaw([rect[0]/xscale,rect[1]/yscale,rect[2]/xscale,rect[3]/yscale]);};function setSelectRaw(l)
{Coords.setPressed([l[0],l[1]]);Coords.setCurrent([l[2],l[3]]);Selection.update();};function setOptions(opt)
{if(typeof(opt)!='object')opt={};options=$.extend(options,opt);if(typeof(options.onChange)!=='function')
options.onChange=function(){};if(typeof(options.onSelect)!=='function')
options.onSelect=function(){};};function tellSelect()
{return unscale(Coords.getFixed());};function tellScaled()
{return Coords.getFixed();};function setOptionsNew(opt)
{setOptions(opt);interfaceUpdate();};function disableCrop()
{options.disabled=true;Selection.disableHandles();Selection.setCursor('default');Tracker.setCursor('default');};function enableCrop()
{options.disabled=false;interfaceUpdate();};function cancelCrop()
{Selection.done();Tracker.activateHandlers(null,null);};function destroy()
{$div.remove();$origimg.show();};function interfaceUpdate(alt)
{options.allowResize?alt?Selection.enableOnly():Selection.enableHandles():Selection.disableHandles();Tracker.setCursor(options.allowSelect?'crosshair':'default');Selection.setCursor(options.allowMove?'move':'default');$div.css('backgroundColor',options.bgColor);if('setSelect'in options){setSelect(opt.setSelect);Selection.done();delete(options.setSelect);}
if('trueSize'in options){xscale=options.trueSize[0]/boundx;yscale=options.trueSize[1]/boundy;}
xlimit=options.maxSize[0]||0;ylimit=options.maxSize[1]||0;xmin=options.minSize[0]||0;ymin=options.minSize[1]||0;if('outerImage'in options)
{$img.attr('src',options.outerImage);delete(options.outerImage);}
Selection.refresh();};$hdl_holder.hide();interfaceUpdate(true);var api={animateTo:animateTo,setSelect:setSelect,setOptions:setOptionsNew,tellSelect:tellSelect,tellScaled:tellScaled,disable:disableCrop,enable:enableCrop,cancel:cancelCrop,focus:KeyManager.watchKeys,getBounds:function(){return[boundx*xscale,boundy*yscale];},getWidgetSize:function(){return[boundx,boundy];},release:Selection.release,destroy:destroy};$origimg.data('Jcrop',api);return api;};$.fn.Jcrop=function(options)
{function attachWhenDone(from)
{var loadsrc=options.useImg||from.src;var img=new Image();img.onload=function(){$.Jcrop(from,options);};img.src=loadsrc;};if(typeof(options)!=='object')options={};this.each(function()
{if($(this).data('Jcrop'))
{if(options=='api')return $(this).data('Jcrop');else $(this).data('Jcrop').setOptions(options);}
else attachWhenDone(this);});return this;};})(jQuery);/***********************************************************/
/*                    LiveFilter Plugin                    */
/*                      Version: 1.4                       */
/*                      Mike Merritt                       */
/*             	   Updated: Mar 04, 2011                   */
/***********************************************************/

(function($){
	$.fn.liveFilter = function (options) {

		// Default settings
		var defaults = {
			delay: 0,
			defaultText: 'Type to Filter:',
			hideDefault: false,
			zebra: false,
			zBase: false,
			addInputs: false

		};

		// Overwrite default settings with user provided ones.
		var options = $.extend({}, defaults, options);
		
		// Cache our wrapper element and determine what target we are going to be filtering,
		// also declare a couple more vars for global use.
		var wrap = $(this);
		var filterTarget = wrap.find('ul, ol, table');
		var keyDelay;
		var filter;
		var child;

		// Determine what sub elements we are going to be showing/hiding depending on 
		// what our filter target is.
		if (filterTarget.is('ul') || filterTarget.is('ol')) {
			child = 'li';
		} else if (filterTarget.is('table')) {
			child = 'tbody tr';
		}

		// Hide the list/table by default. If not being hidden apply zebra striping if needed.
		if (options.hideDefault === true) {
			$(filterTarget).find(child).hide()
		} else if (options.hideDefault === false && options.zebra != false) {
			zebraStriping();
		}

		// Cache all of our list/table elements so we don't have to select them over and over again.
		var cache = $(filterTarget).find(child);
		
		// Text input keyup event
		wrap.find('input[type="text"]').keyup(function() {

			// For use in the following callback.
			var input = $(this);

			// Used to reset the timeout so we can start over again if another key is pressed
			// before our current timeout has expired.
			clearTimeout(keyDelay);

			// Adding a timeout before we do any iterating or showing/hiding to help with performance
			// when the user types very quickly.
			keyDelay = setTimeout(function () { 

				// Getting the text to filter.
				filter = input.val().toLowerCase();
				
				// Iterate through our cache of elements and match our supplied filter to the text of the element.
				cache.each(function(i) {
					text = $(this).text().toLowerCase();
					if (text.indexOf(filter) >= 0) {
						$(this).show();
					} else {
						$(this).hide();
					}
				});

				if(options.zebra != false) {
					zebraStriping();
				}

				clearTimeout(keyDelay);

			}, options.delay);
			

		});

		// Used to reset our text input and show all items in the filtered list
		wrap.find('input[type="reset"]').click(function() {

			if (options.defaultText === false) {

				wrap.find('input[type="text"]').attr('value', '');

				if (options.hideDefault === false) {
					cache.each(function(i) {
						$(this).show();
					});
				} else if (options.hideDefault === true) {
					cache.each(function(i) {
						$(this).hide();
					});
				}

			} else {

				wrap.find('input[type="text"]').attr('value', options.defaultText);

				if (options.hideDefault === false) {
					cache.each(function(i) {
						$(this).show();
					});
				} else if (options.hideDefault === true) {
					cache.each(function(i) {
						$(this).hide();
					});
				}

			}
			
			return false;

		});


		// Used to set the default text of the text input if there is any
		if (options.defaultText != false) {
			var input = wrap.find('input[type="text"]');

			input.attr('value', options.defaultText);

			input.focus(function() {
				
				var curVal = $(this).attr('value');

				if (curVal === options.defaultText) {
					$(this).attr('value', '');
				}

			});

			input.blur(function() {
				
				var curVal = $(this).attr('value');

				if (curVal === '') {
					$(this).attr('value', options.defaultText);
				}

			});

		}

		// Used to add inputs to the wrapping div if set to true.
		if (options.addInputs === true) {
			var markup = '<input class="filter" type="text" value="" /><input class="reset" type="reset" value="Reset!" />';
			wrap.prepend(markup);
		}

		// Used for zebra striping list/table.
		function zebraStriping() {

			$(filterTarget).find(child + ':visible:odd').css({ background: options.zebra });
			$(filterTarget).find(child + ':visible:even').css({ background: options.zBase });
		}

	}
})(jQuery);$(function(){
	initCufon();
	initCustomForms();
	hoverForIE6(".comment-list li, .invite-list li", "hover");
	clearInputs();
	//testCallback();
});

//test change for selects. Comment this out for production
/*function testCallback(){
	$('select').change(function(){
		alert("change detected!!!!!");
	});
}*/

function initCufon() {
	Cufon.replace('#main h1', {fontFamily: 'NeoTech'});
	Cufon.replace('.main-container h2', {fontFamily: 'NeoTech'});
	Cufon.replace('.main-container h2.title', {fontFamily: 'NeoTech Medium'});
	Cufon.replace('.main-container h4 ', {fontFamily: 'NeoTech Medium'});
	Cufon.replace('.main-container h5 ', {fontFamily: 'NeoTech Medium'});
}	

//ie6 hover
function hoverForIE6(h_list, h_class){
	if($.browser.msie && $.browser.version < 7){
		if(!h_class) var h_class = 'hover';
		$(h_list).mouseenter(function(){
			$(this).addClass(h_class);
		}).mouseleave(function(){
			$(this).removeClass(h_class);
		});
	}
}

//clear inputs
function clearInputs(){
	$('.clear-input input:text, .clear-input input:password, .clear-input textarea').each(function(){

                /* Add the 'placeholder' style to the input elements, and remove them on value change.
                 * Need to be careful to make sure that during editing, the placeholder class is removed. */
                $(this).addClass('placeholder');

		var _el = $(this);
		var _val = _el.val();
		_el.bind('focus', function(){
                        _el.removeClass('placeholder');
			if(this.value == _val) {
                            this.value = '';
                        }
		}).bind('blur', function(){
                        _el.addClass('placeholder');
			if (this.value == '') {
                            this.value = _val;
                        } else {
                            /* User-provided value means that its no longer a placeholder */
                            _el.removeClass('placeholder');
                        }
		});
	});
}

// custom forms init
function initCustomForms() {
	$("select[name!='credits']").customSelect();
	//$('input:radio').customRadio();
	$('input:checkbox').customCheckbox();
}

// custom forms plugin
;(function(jQuery){
	// custom checkboxes module
	jQuery.fn.customCheckbox = function(_options){
		var _options = jQuery.extend({
			checkboxStructure: '<div></div>',
			checkboxDisabled: 'disabled',
			checkboxDefault: 'checkboxArea',
			checkboxChecked: 'checkboxAreaChecked',
			filterClass:'default'
		}, _options);
		return this.each(function(){
			var checkbox = jQuery(this);
			if(!checkbox.hasClass('outtaHere') && checkbox.is(':checkbox') && !checkbox.hasClass(_options.filterClass)){
				var replaced = jQuery(_options.checkboxStructure);
				this._replaced = replaced;
				if(checkbox.is(':disabled')) replaced.addClass(_options.checkboxDisabled);
				else if(checkbox.is(':checked')) replaced.addClass(_options.checkboxChecked);
				else replaced.addClass(_options.checkboxDefault);

				replaced.click(function(){
					if(checkbox.is(':checked')) checkbox.removeAttr('checked');
					else checkbox.attr('checked', 'checked');
					changeCheckbox(checkbox);
				});
				checkbox.click(function(){
					changeCheckbox(checkbox);
				});
				replaced.insertBefore(checkbox);
				checkbox.addClass('outtaHere');
			}
		});
		function changeCheckbox(_this){
			_this.change();
			if(_this.is(':checked')) _this.get(0)._replaced.removeClass().addClass(_options.checkboxChecked);
			else _this.get(0)._replaced.removeClass().addClass(_options.checkboxDefault);
		}
	}

	// custom radios module
	jQuery.fn.customRadio = function(_options){
		var _options = jQuery.extend({
			radioStructure: '<div></div>',
			radioDisabled: 'disabled',
			radioDefault: 'radioArea',
			radioChecked: 'radioAreaChecked',
			filterClass:'default'
		}, _options);
		return this.each(function(){
			var radio = jQuery(this);
			if(!radio.hasClass('outtaHere') && radio.is(':radio') && !radio.hasClass(_options.filterClass)){
				var replaced = jQuery(_options.radioStructure);
				this._replaced = replaced;
				if(radio.is(':disabled')) replaced.addClass(_options.radioDisabled);
				else if(radio.is(':checked')) replaced.addClass(_options.radioChecked);
				else replaced.addClass(_options.radioDefault);
				replaced.click(function(){
					if(jQuery(this).hasClass(_options.radioDefault)){
						radio.attr('checked', 'checked');
						changeRadio(radio.get(0));
					}
				});
				radio.click(function(){
					changeRadio(this);
				});
				replaced.insertBefore(radio);
				radio.addClass('outtaHere');
			}
		});
		function changeRadio(_this){
			jQuery(_this).change();
			jQuery('input:radio[name='+jQuery(_this).attr("name")+']').not(_this).each(function(){
				if(this._replaced && !jQuery(this).is(':disabled')) this._replaced.removeClass().addClass(_options.radioDefault);
			});
			_this._replaced.removeClass().addClass(_options.radioChecked);
		}
	}

	// custom selects module
	jQuery.fn.customSelect = function(_options) {
		var _options = jQuery.extend({
			selectStructure: '<div class="selectArea"><span class="left"></span><span class="center"></span><a href="#" class="selectButton"></a><div class="disabled"></div></div>',
			hideOnMouseOut: false,
			copyClass: true,
			selectText: '.center',
			selectBtn: '.selectButton',
			selectDisabled: '.disabled',
			optStructure: '<div class="optionsDivVisible"><div class="select-top"></div><div class="select-center"><ul></ul><div class="select-bottom"></div></div>',
			optList: 'ul',
			filterClass:'default'
		}, _options);
		return this.each(function() {
			var select = jQuery(this);
			if(!select.hasClass('outtaHere') && !select.hasClass(_options.filterClass)) {
				if(select.is(':visible')) {
					var hideOnMouseOut = _options.hideOnMouseOut;
					var copyClass = _options.copyClass;
					var replaced = jQuery(_options.selectStructure);
					var selectText = replaced.find(_options.selectText);
					var selectBtn = replaced.find(_options.selectBtn);
					var selectDisabled = replaced.find(_options.selectDisabled).hide();
					var optHolder = jQuery(_options.optStructure);
					var optList = optHolder.find(_options.optList);
					if(copyClass) optHolder.addClass('drop-'+select.attr('class'));

					if(select.attr('disabled')) selectDisabled.show();
					select.find('option').each(function(){
						var selOpt = jQuery(this);
						var _opt = jQuery('<li><a href="#">' + selOpt.html() + '</a></li>');
						if(selOpt.attr('selected')) {
							selectText.html(selOpt.html());
							_opt.addClass('selected');
						}
						_opt.children('a').click(function() {
							optList.find('li').removeClass('selected');
							select.find('option').removeAttr('selected');
							jQuery(this).parent().addClass('selected');
							selOpt.attr('selected', 'selected');
							selectText.html(selOpt.html());
							select.change();
							optHolder.hide();
							return false;
						});
						optList.append(_opt);
					});
					replaced.width(select.outerWidth());
					replaced.insertBefore(select);
					optHolder.css({
						width: select.outerWidth(),
						display: 'none',
						position: 'absolute'
					});
					jQuery(document.body).append(optHolder);

					var optTimer;
					replaced.hover(function() {
						if(optTimer) clearTimeout(optTimer);
					}, function() {
						if(hideOnMouseOut) {
							optTimer = setTimeout(function() {
								optHolder.hide();
							}, 200);
						}
					});
					optHolder.hover(function(){
						if(optTimer) clearTimeout(optTimer);
					}, function() {
						if(hideOnMouseOut) {
							optTimer = setTimeout(function() {
								optHolder.hide();
							}, 200);
						}
					});
					selectBtn.click(function() {
						if(optHolder.is(':visible')) {
							optHolder.hide();
						}
						else{
							if(_activeDrop) _activeDrop.hide();
							optHolder.children('ul').css({height:'auto', overflow:'hidden'});
							optHolder.css({
								top: replaced.offset().top + replaced.outerHeight(),
								left: replaced.offset().left,
								display: 'block'
							});
							if(optHolder.children('ul').height() > 200) optHolder.children('ul').css({height:200, overflow:'auto'});
							_activeDrop = optHolder;
						}
						return false;
					});
					replaced.addClass(select.attr('class'));
					select.addClass('outtaHere');
				}
			}
		});
	}

	// event handler on DOM ready
	var _activeDrop;
	jQuery(function(){
		jQuery('body').click(hideOptionsClick)
		jQuery(window).resize(hideOptions)
	});
	function hideOptions() {
		if(_activeDrop && _activeDrop.length) {
			_activeDrop.hide();
			_activeDrop = null;
		}
	}
	function hideOptionsClick(e) {
		if(_activeDrop && _activeDrop.length) {
			var f = false;
			jQuery(e.target).parents().each(function(){
				if(this == _activeDrop) f=true;
			});
			if(!f) {
				_activeDrop.hide();
				_activeDrop = null;
			}
		}
	}
})(jQuery);

/*
 * Copyright (c) 2009 Simo Kinnunen.
 * Licensed under the MIT license.
 *
 * @version 1.09
 */
var Cufon=(function(){var m=function(){return m.replace.apply(null,arguments)};var x=m.DOM={ready:(function(){var C=false,E={loaded:1,complete:1};var B=[],D=function(){if(C){return}C=true;for(var F;F=B.shift();F()){}};if(document.addEventListener){document.addEventListener("DOMContentLoaded",D,false);window.addEventListener("pageshow",D,false)}if(!window.opera&&document.readyState){(function(){E[document.readyState]?D():setTimeout(arguments.callee,10)})()}if(document.readyState&&document.createStyleSheet){(function(){try{document.body.doScroll("left");D()}catch(F){setTimeout(arguments.callee,1)}})()}q(window,"load",D);return function(F){if(!arguments.length){D()}else{C?F():B.push(F)}}})(),root:function(){return document.documentElement||document.body}};var n=m.CSS={Size:function(C,B){this.value=parseFloat(C);this.unit=String(C).match(/[a-z%]*$/)[0]||"px";this.convert=function(D){return D/B*this.value};this.convertFrom=function(D){return D/this.value*B};this.toString=function(){return this.value+this.unit}},addClass:function(C,B){var D=C.className;C.className=D+(D&&" ")+B;return C},color:j(function(C){var B={};B.color=C.replace(/^rgba\((.*?),\s*([\d.]+)\)/,function(E,D,F){B.opacity=parseFloat(F);return"rgb("+D+")"});return B}),fontStretch:j(function(B){if(typeof B=="number"){return B}if(/%$/.test(B)){return parseFloat(B)/100}return{"ultra-condensed":0.5,"extra-condensed":0.625,condensed:0.75,"semi-condensed":0.875,"semi-expanded":1.125,expanded:1.25,"extra-expanded":1.5,"ultra-expanded":2}[B]||1}),getStyle:function(C){var B=document.defaultView;if(B&&B.getComputedStyle){return new a(B.getComputedStyle(C,null))}if(C.currentStyle){return new a(C.currentStyle)}return new a(C.style)},gradient:j(function(F){var G={id:F,type:F.match(/^-([a-z]+)-gradient\(/)[1],stops:[]},C=F.substr(F.indexOf("(")).match(/([\d.]+=)?(#[a-f0-9]+|[a-z]+\(.*?\)|[a-z]+)/ig);for(var E=0,B=C.length,D;E<B;++E){D=C[E].split("=",2).reverse();G.stops.push([D[1]||E/(B-1),D[0]])}return G}),quotedList:j(function(E){var D=[],C=/\s*((["'])([\s\S]*?[^\\])\2|[^,]+)\s*/g,B;while(B=C.exec(E)){D.push(B[3]||B[1])}return D}),recognizesMedia:j(function(G){var E=document.createElement("style"),D,C,B;E.type="text/css";E.media=G;try{E.appendChild(document.createTextNode("/**/"))}catch(F){}C=g("head")[0];C.insertBefore(E,C.firstChild);D=(E.sheet||E.styleSheet);B=D&&!D.disabled;C.removeChild(E);return B}),removeClass:function(D,C){var B=RegExp("(?:^|\\s+)"+C+"(?=\\s|$)","g");D.className=D.className.replace(B,"");return D},supports:function(D,C){var B=document.createElement("span").style;if(B[D]===undefined){return false}B[D]=C;return B[D]===C},textAlign:function(E,D,B,C){if(D.get("textAlign")=="right"){if(B>0){E=" "+E}}else{if(B<C-1){E+=" "}}return E},textShadow:j(function(F){if(F=="none"){return null}var E=[],G={},B,C=0;var D=/(#[a-f0-9]+|[a-z]+\(.*?\)|[a-z]+)|(-?[\d.]+[a-z%]*)|,/ig;while(B=D.exec(F)){if(B[0]==","){E.push(G);G={};C=0}else{if(B[1]){G.color=B[1]}else{G[["offX","offY","blur"][C++]]=B[2]}}}E.push(G);return E}),textTransform:(function(){var B={uppercase:function(C){return C.toUpperCase()},lowercase:function(C){return C.toLowerCase()},capitalize:function(C){return C.replace(/\b./g,function(D){return D.toUpperCase()})}};return function(E,D){var C=B[D.get("textTransform")];return C?C(E):E}})(),whiteSpace:(function(){var D={inline:1,"inline-block":1,"run-in":1};var C=/^\s+/,B=/\s+$/;return function(H,F,G,E){if(E){if(E.nodeName.toLowerCase()=="br"){H=H.replace(C,"")}}if(D[F.get("display")]){return H}if(!G.previousSibling){H=H.replace(C,"")}if(!G.nextSibling){H=H.replace(B,"")}return H}})()};n.ready=(function(){var B=!n.recognizesMedia("all"),E=false;var D=[],H=function(){B=true;for(var K;K=D.shift();K()){}};var I=g("link"),J=g("style");function C(K){return K.disabled||G(K.sheet,K.media||"screen")}function G(M,P){if(!n.recognizesMedia(P||"all")){return true}if(!M||M.disabled){return false}try{var Q=M.cssRules,O;if(Q){search:for(var L=0,K=Q.length;O=Q[L],L<K;++L){switch(O.type){case 2:break;case 3:if(!G(O.styleSheet,O.media.mediaText)){return false}break;default:break search}}}}catch(N){}return true}function F(){if(document.createStyleSheet){return true}var L,K;for(K=0;L=I[K];++K){if(L.rel.toLowerCase()=="stylesheet"&&!C(L)){return false}}for(K=0;L=J[K];++K){if(!C(L)){return false}}return true}x.ready(function(){if(!E){E=n.getStyle(document.body).isUsable()}if(B||(E&&F())){H()}else{setTimeout(arguments.callee,10)}});return function(K){if(B){K()}else{D.push(K)}}})();function s(D){var C=this.face=D.face,B={"\u0020":1,"\u00a0":1,"\u3000":1};this.glyphs=D.glyphs;this.w=D.w;this.baseSize=parseInt(C["units-per-em"],10);this.family=C["font-family"].toLowerCase();this.weight=C["font-weight"];this.style=C["font-style"]||"normal";this.viewBox=(function(){var F=C.bbox.split(/\s+/);var E={minX:parseInt(F[0],10),minY:parseInt(F[1],10),maxX:parseInt(F[2],10),maxY:parseInt(F[3],10)};E.width=E.maxX-E.minX;E.height=E.maxY-E.minY;E.toString=function(){return[this.minX,this.minY,this.width,this.height].join(" ")};return E})();this.ascent=-parseInt(C.ascent,10);this.descent=-parseInt(C.descent,10);this.height=-this.ascent+this.descent;this.spacing=function(L,N,E){var O=this.glyphs,M,K,G,P=[],F=0,J=-1,I=-1,H;while(H=L[++J]){M=O[H]||this.missingGlyph;if(!M){continue}if(K){F-=G=K[H]||0;P[I]-=G}F+=P[++I]=~~(M.w||this.w)+N+(B[H]?E:0);K=M.k}P.total=F;return P}}function f(){var C={},B={oblique:"italic",italic:"oblique"};this.add=function(D){(C[D.style]||(C[D.style]={}))[D.weight]=D};this.get=function(H,I){var G=C[H]||C[B[H]]||C.normal||C.italic||C.oblique;if(!G){return null}I={normal:400,bold:700}[I]||parseInt(I,10);if(G[I]){return G[I]}var E={1:1,99:0}[I%100],K=[],F,D;if(E===undefined){E=I>400}if(I==500){I=400}for(var J in G){if(!k(G,J)){continue}J=parseInt(J,10);if(!F||J<F){F=J}if(!D||J>D){D=J}K.push(J)}if(I<F){I=F}if(I>D){I=D}K.sort(function(M,L){return(E?(M>=I&&L>=I)?M<L:M>L:(M<=I&&L<=I)?M>L:M<L)?-1:1});return G[K[0]]}}function r(){function D(F,G){if(F.contains){return F.contains(G)}return F.compareDocumentPosition(G)&16}function B(G){var F=G.relatedTarget;if(!F||D(this,F)){return}C(this,G.type=="mouseover")}function E(F){C(this,F.type=="mouseenter")}function C(F,G){setTimeout(function(){var H=d.get(F).options;m.replace(F,G?h(H,H.hover):H,true)},10)}this.attach=function(F){if(F.onmouseenter===undefined){q(F,"mouseover",B);q(F,"mouseout",B)}else{q(F,"mouseenter",E);q(F,"mouseleave",E)}}}function u(){var C=[],D={};function B(H){var E=[],G;for(var F=0;G=H[F];++F){E[F]=C[D[G]]}return E}this.add=function(F,E){D[F]=C.push(E)-1};this.repeat=function(){var E=arguments.length?B(arguments):C,F;for(var G=0;F=E[G++];){m.replace(F[0],F[1],true)}}}function A(){var D={},B=0;function C(E){return E.cufid||(E.cufid=++B)}this.get=function(E){var F=C(E);return D[F]||(D[F]={})}}function a(B){var D={},C={};this.extend=function(E){for(var F in E){if(k(E,F)){D[F]=E[F]}}return this};this.get=function(E){return D[E]!=undefined?D[E]:B[E]};this.getSize=function(F,E){return C[F]||(C[F]=new n.Size(this.get(F),E))};this.isUsable=function(){return !!B}}function q(C,B,D){if(C.addEventListener){C.addEventListener(B,D,false)}else{if(C.attachEvent){C.attachEvent("on"+B,function(){return D.call(C,window.event)})}}}function v(C,B){var D=d.get(C);if(D.options){return C}if(B.hover&&B.hoverables[C.nodeName.toLowerCase()]){b.attach(C)}D.options=B;return C}function j(B){var C={};return function(D){if(!k(C,D)){C[D]=B.apply(null,arguments)}return C[D]}}function c(F,E){var B=n.quotedList(E.get("fontFamily").toLowerCase()),D;for(var C=0;D=B[C];++C){if(i[D]){return i[D].get(E.get("fontStyle"),E.get("fontWeight"))}}return null}function g(B){return document.getElementsByTagName(B)}function k(C,B){return C.hasOwnProperty(B)}function h(){var C={},B,F;for(var E=0,D=arguments.length;B=arguments[E],E<D;++E){for(F in B){if(k(B,F)){C[F]=B[F]}}}return C}function o(E,M,C,N,F,D){var K=document.createDocumentFragment(),H;if(M===""){return K}var L=N.separate;var I=M.split(p[L]),B=(L=="words");if(B&&t){if(/^\s/.test(M)){I.unshift("")}if(/\s$/.test(M)){I.push("")}}for(var J=0,G=I.length;J<G;++J){H=z[N.engine](E,B?n.textAlign(I[J],C,J,G):I[J],C,N,F,D,J<G-1);if(H){K.appendChild(H)}}return K}function l(D,M){var C=D.nodeName.toLowerCase();if(M.ignore[C]){return}var E=!M.textless[C];var B=n.getStyle(v(D,M)).extend(M);var F=c(D,B),G,K,I,H,L,J;if(!F){return}for(G=D.firstChild;G;G=I){K=G.nodeType;I=G.nextSibling;if(E&&K==3){if(H){H.appendData(G.data);D.removeChild(G)}else{H=G}if(I){continue}}if(H){D.replaceChild(o(F,n.whiteSpace(H.data,B,H,J),B,M,G,D),H);H=null}if(K==1){if(G.firstChild){if(G.nodeName.toLowerCase()=="cufon"){z[M.engine](F,null,B,M,G,D)}else{arguments.callee(G,M)}}J=G}}}var t=" ".split(/\s+/).length==0;var d=new A();var b=new r();var y=new u();var e=false;var z={},i={},w={autoDetect:false,engine:null,forceHitArea:false,hover:false,hoverables:{a:true},ignore:{applet:1,canvas:1,col:1,colgroup:1,head:1,iframe:1,map:1,optgroup:1,option:1,script:1,select:1,style:1,textarea:1,title:1,pre:1},printable:true,selector:(window.Sizzle||(window.jQuery&&function(B){return jQuery(B)})||(window.dojo&&dojo.query)||(window.Ext&&Ext.query)||(window.YAHOO&&YAHOO.util&&YAHOO.util.Selector&&YAHOO.util.Selector.query)||(window.$$&&function(B){return $$(B)})||(window.$&&function(B){return $(B)})||(document.querySelectorAll&&function(B){return document.querySelectorAll(B)})||g),separate:"words",textless:{dl:1,html:1,ol:1,table:1,tbody:1,thead:1,tfoot:1,tr:1,ul:1},textShadow:"none"};var p={words:/\s/.test("\u00a0")?/[^\S\u00a0]+/:/\s+/,characters:"",none:/^/};m.now=function(){x.ready();return m};m.refresh=function(){y.repeat.apply(y,arguments);return m};m.registerEngine=function(C,B){if(!B){return m}z[C]=B;return m.set("engine",C)};m.registerFont=function(D){if(!D){return m}var B=new s(D),C=B.family;if(!i[C]){i[C]=new f()}i[C].add(B);return m.set("fontFamily",'"'+C+'"')};m.replace=function(D,C,B){C=h(w,C);if(!C.engine){return m}if(!e){n.addClass(x.root(),"cufon-active cufon-loading");n.ready(function(){n.addClass(n.removeClass(x.root(),"cufon-loading"),"cufon-ready")});e=true}if(C.hover){C.forceHitArea=true}if(C.autoDetect){delete C.fontFamily}if(typeof C.textShadow=="string"){C.textShadow=n.textShadow(C.textShadow)}if(typeof C.color=="string"&&/^-/.test(C.color)){C.textGradient=n.gradient(C.color)}else{delete C.textGradient}if(!B){y.add(D,arguments)}if(D.nodeType||typeof D=="string"){D=[D]}n.ready(function(){for(var F=0,E=D.length;F<E;++F){var G=D[F];if(typeof G=="string"){m.replace(C.selector(G),C,true)}else{l(G,C)}}});return m};m.set=function(B,C){w[B]=C;return m};return m})();Cufon.registerEngine("canvas",(function(){var b=document.createElement("canvas");if(!b||!b.getContext||!b.getContext.apply){return}b=null;var a=Cufon.CSS.supports("display","inline-block");var e=!a&&(document.compatMode=="BackCompat"||/frameset|transitional/i.test(document.doctype.publicId));var f=document.createElement("style");f.type="text/css";f.appendChild(document.createTextNode(("cufon{text-indent:0;}@media screen,projection{cufon{display:inline;display:inline-block;position:relative;vertical-align:middle;"+(e?"":"font-size:1px;line-height:1px;")+"}cufon cufontext{display:-moz-inline-box;display:inline-block;width:0;height:0;overflow:hidden;text-indent:-10000in;}"+(a?"cufon canvas{position:relative;}":"cufon canvas{position:absolute;}")+"}@media print{cufon{padding:0;}cufon canvas{display:none;}}").replace(/;/g,"!important;")));document.getElementsByTagName("head")[0].appendChild(f);function d(p,h){var n=0,m=0;var g=[],o=/([mrvxe])([^a-z]*)/g,k;generate:for(var j=0;k=o.exec(p);++j){var l=k[2].split(",");switch(k[1]){case"v":g[j]={m:"bezierCurveTo",a:[n+~~l[0],m+~~l[1],n+~~l[2],m+~~l[3],n+=~~l[4],m+=~~l[5]]};break;case"r":g[j]={m:"lineTo",a:[n+=~~l[0],m+=~~l[1]]};break;case"m":g[j]={m:"moveTo",a:[n=~~l[0],m=~~l[1]]};break;case"x":g[j]={m:"closePath"};break;case"e":break generate}h[g[j].m].apply(h,g[j].a)}return g}function c(m,k){for(var j=0,h=m.length;j<h;++j){var g=m[j];k[g.m].apply(k,g.a)}}return function(V,w,P,t,C,W){var k=(w===null);if(k){w=C.getAttribute("alt")}var A=V.viewBox;var m=P.getSize("fontSize",V.baseSize);var B=0,O=0,N=0,u=0;var z=t.textShadow,L=[];if(z){for(var U=z.length;U--;){var F=z[U];var K=m.convertFrom(parseFloat(F.offX));var I=m.convertFrom(parseFloat(F.offY));L[U]=[K,I];if(I<B){B=I}if(K>O){O=K}if(I>N){N=I}if(K<u){u=K}}}var Z=Cufon.CSS.textTransform(w,P).split("");var E=V.spacing(Z,~~m.convertFrom(parseFloat(P.get("letterSpacing"))||0),~~m.convertFrom(parseFloat(P.get("wordSpacing"))||0));if(!E.length){return null}var h=E.total;O+=A.width-E[E.length-1];u+=A.minX;var s,n;if(k){s=C;n=C.firstChild}else{s=document.createElement("cufon");s.className="cufon cufon-canvas";s.setAttribute("alt",w);n=document.createElement("canvas");s.appendChild(n);if(t.printable){var S=document.createElement("cufontext");S.appendChild(document.createTextNode(w));s.appendChild(S)}}var aa=s.style;var H=n.style;var j=m.convert(A.height);var Y=Math.ceil(j);var M=Y/j;var G=M*Cufon.CSS.fontStretch(P.get("fontStretch"));var J=h*G;var Q=Math.ceil(m.convert(J+O-u));var o=Math.ceil(m.convert(A.height-B+N));n.width=Q;n.height=o;H.width=Q+"px";H.height=o+"px";B+=A.minY;H.top=Math.round(m.convert(B-V.ascent))+"px";H.left=Math.round(m.convert(u))+"px";var r=Math.max(Math.ceil(m.convert(J)),0)+"px";if(a){aa.width=r;aa.height=m.convert(V.height)+"px"}else{aa.paddingLeft=r;aa.paddingBottom=(m.convert(V.height)-1)+"px"}var X=n.getContext("2d"),D=j/A.height;X.scale(D,D*M);X.translate(-u,-B);X.save();function T(){var x=V.glyphs,ab,l=-1,g=-1,y;X.scale(G,1);while(y=Z[++l]){var ab=x[Z[l]]||V.missingGlyph;if(!ab){continue}if(ab.d){X.beginPath();if(ab.code){c(ab.code,X)}else{ab.code=d("m"+ab.d,X)}X.fill()}X.translate(E[++g],0)}X.restore()}if(z){for(var U=z.length;U--;){var F=z[U];X.save();X.fillStyle=F.color;X.translate.apply(X,L[U]);T()}}var q=t.textGradient;if(q){var v=q.stops,p=X.createLinearGradient(0,A.minY,0,A.maxY);for(var U=0,R=v.length;U<R;++U){p.addColorStop.apply(p,v[U])}X.fillStyle=p}else{X.fillStyle=P.get("color")}T();return s}})());Cufon.registerEngine("vml",(function(){var e=document.namespaces;if(!e){return}e.add("cvml","urn:schemas-microsoft-com:vml");e=null;var b=document.createElement("cvml:shape");b.style.behavior="url(#default#VML)";if(!b.coordsize){return}b=null;var h=(document.documentMode||0)<8;document.write(('<style type="text/css">cufoncanvas{text-indent:0;}@media screen{cvml\\:shape,cvml\\:rect,cvml\\:fill,cvml\\:shadow{behavior:url(#default#VML);display:block;antialias:true;position:absolute;}cufoncanvas{position:absolute;text-align:left;}cufon{display:inline-block;position:relative;vertical-align:'+(h?"middle":"text-bottom")+";}cufon cufontext{position:absolute;left:-10000in;font-size:1px;}a cufon{cursor:pointer}}@media print{cufon cufoncanvas{display:none;}}</style>").replace(/;/g,"!important;"));function c(i,j){return a(i,/(?:em|ex|%)$|^[a-z-]+$/i.test(j)?"1em":j)}function a(l,m){if(m==="0"){return 0}if(/px$/i.test(m)){return parseFloat(m)}var k=l.style.left,j=l.runtimeStyle.left;l.runtimeStyle.left=l.currentStyle.left;l.style.left=m.replace("%","em");var i=l.style.pixelLeft;l.style.left=k;l.runtimeStyle.left=j;return i}function f(l,k,j,n){var i="computed"+n,m=k[i];if(isNaN(m)){m=k.get(n);k[i]=m=(m=="normal")?0:~~j.convertFrom(a(l,m))}return m}var g={};function d(p){var q=p.id;if(!g[q]){var n=p.stops,o=document.createElement("cvml:fill"),i=[];o.type="gradient";o.angle=180;o.focus="0";o.method="sigma";o.color=n[0][1];for(var m=1,l=n.length-1;m<l;++m){i.push(n[m][0]*100+"% "+n[m][1])}o.colors=i.join(",");o.color2=n[l][1];g[q]=o}return g[q]}return function(ac,G,Y,C,K,ad,W){var n=(G===null);if(n){G=K.alt}var I=ac.viewBox;var p=Y.computedFontSize||(Y.computedFontSize=new Cufon.CSS.Size(c(ad,Y.get("fontSize"))+"px",ac.baseSize));var y,q;if(n){y=K;q=K.firstChild}else{y=document.createElement("cufon");y.className="cufon cufon-vml";y.alt=G;q=document.createElement("cufoncanvas");y.appendChild(q);if(C.printable){var Z=document.createElement("cufontext");Z.appendChild(document.createTextNode(G));y.appendChild(Z)}if(!W){y.appendChild(document.createElement("cvml:shape"))}}var ai=y.style;var R=q.style;var l=p.convert(I.height),af=Math.ceil(l);var V=af/l;var P=V*Cufon.CSS.fontStretch(Y.get("fontStretch"));var U=I.minX,T=I.minY;R.height=af;R.top=Math.round(p.convert(T-ac.ascent));R.left=Math.round(p.convert(U));ai.height=p.convert(ac.height)+"px";var F=Y.get("color");var ag=Cufon.CSS.textTransform(G,Y).split("");var L=ac.spacing(ag,f(ad,Y,p,"letterSpacing"),f(ad,Y,p,"wordSpacing"));if(!L.length){return null}var k=L.total;var x=-U+k+(I.width-L[L.length-1]);var ah=p.convert(x*P),X=Math.round(ah);var O=x+","+I.height,m;var J="r"+O+"ns";var u=C.textGradient&&d(C.textGradient);var o=ac.glyphs,S=0;var H=C.textShadow;var ab=-1,aa=0,w;while(w=ag[++ab]){var D=o[ag[ab]]||ac.missingGlyph,v;if(!D){continue}if(n){v=q.childNodes[aa];while(v.firstChild){v.removeChild(v.firstChild)}}else{v=document.createElement("cvml:shape");q.appendChild(v)}v.stroked="f";v.coordsize=O;v.coordorigin=m=(U-S)+","+T;v.path=(D.d?"m"+D.d+"xe":"")+"m"+m+J;v.fillcolor=F;if(u){v.appendChild(u.cloneNode(false))}var ae=v.style;ae.width=X;ae.height=af;if(H){var s=H[0],r=H[1];var B=Cufon.CSS.color(s.color),z;var N=document.createElement("cvml:shadow");N.on="t";N.color=B.color;N.offset=s.offX+","+s.offY;if(r){z=Cufon.CSS.color(r.color);N.type="double";N.color2=z.color;N.offset2=r.offX+","+r.offY}N.opacity=B.opacity||(z&&z.opacity)||1;v.appendChild(N)}S+=L[aa++]}var M=v.nextSibling,t,A;if(C.forceHitArea){if(!M){M=document.createElement("cvml:rect");M.stroked="f";M.className="cufon-vml-cover";t=document.createElement("cvml:fill");t.opacity=0;M.appendChild(t);q.appendChild(M)}A=M.style;A.width=X;A.height=af}else{if(M){q.removeChild(M)}}ai.width=Math.max(Math.ceil(p.convert(k*P)),0);if(h){var Q=Y.computedYAdjust;if(Q===undefined){var E=Y.get("lineHeight");if(E=="normal"){E="1em"}else{if(!isNaN(E)){E+="em"}}Y.computedYAdjust=Q=0.5*(a(ad,E)-parseFloat(ai.height))}if(Q){ai.marginTop=Math.ceil(Q)+"px";ai.marginBottom=Q+"px"}}return y}})());

// cufon fonts
Cufon.registerFont({"w":217,"face":{"font-family":"NeoTech","font-weight":400,"font-stretch":"normal","units-per-em":"360","panose-1":"2 0 5 6 2 0 0 2 0 4","ascent":"288","descent":"-72","x-height":"3","bbox":"-11.934 -307.937 392 79.4789","underline-thickness":"18","underline-position":"-18","stemh":"26","stemv":"23","unicode-range":"U+0020-U+2122"},"glyphs":{" ":{"w":98},"!":{"d":"55,-264r-2,187v0,9,-11,7,-20,7v-4,0,-7,-3,-7,-7r-3,-187v0,-10,15,-6,25,-7v4,0,7,3,7,7xm55,-41v-1,20,9,48,-24,41v-13,-2,-7,-27,-7,-41v0,-10,14,-6,24,-7v4,0,7,3,7,7","w":78},"$":{"d":"190,-69v0,31,-14,63,-66,70v-1,20,9,48,-24,41v-13,-2,-5,-26,-7,-39v-21,0,-38,-4,-52,-6v-11,-2,-4,-12,-6,-21v0,-4,3,-6,7,-6v45,7,124,8,114,-39v0,-52,-128,-71,-128,-137v0,-37,24,-58,65,-63v1,-20,-7,-44,24,-38v13,3,5,24,7,37v19,1,41,3,53,5v9,1,5,12,6,21v0,4,-2,6,-7,6v-38,-2,-121,-15,-115,32v7,49,143,75,129,137"},"%":{"d":"270,-89v0,50,-7,92,-49,92v-42,0,-48,-43,-48,-92v0,-40,18,-59,48,-59v30,0,49,19,49,59xm213,-267v7,1,25,-4,19,6r-150,255v-3,11,-19,8,-29,5v46,-90,102,-172,151,-260v3,-5,5,-6,9,-6xm113,-212v0,49,-6,92,-48,92v-42,0,-49,-42,-49,-92v0,-40,19,-58,49,-58v30,0,48,18,48,58xm221,-18v27,0,26,-40,26,-71v0,-27,-10,-38,-26,-38v-27,0,-26,40,-26,71v0,27,10,38,26,38xm65,-141v27,0,26,-40,26,-71v0,-27,-10,-38,-26,-38v-27,0,-26,40,-26,71v0,27,10,38,26,38","w":285},"&":{"d":"216,-150v10,2,9,29,0,28r-33,0r0,115v0,3,-3,7,-6,7v-82,8,-157,9,-159,-81v0,-22,9,-42,22,-55v-13,-15,-22,-36,-22,-58v0,-60,36,-76,90,-76v41,0,62,4,71,6v7,2,7,23,-2,25v-54,5,-127,-20,-127,45v0,15,6,32,15,44r151,0xm152,-28r0,-94r-87,0v-33,35,-8,105,43,94r44,0","w":228},"\u2019":{"d":"31,-271v9,1,29,-5,25,7r-22,68v0,10,-20,10,-24,3r14,-71v1,-5,3,-7,7,-7","w":66},"(":{"d":"101,-268v-62,91,-65,250,0,340v-4,5,-24,6,-29,-1v-66,-79,-66,-257,0,-338v5,-7,22,-5,29,-1","w":109},")":{"d":"14,72v64,-90,63,-250,0,-340v4,-5,24,-6,29,1v66,79,66,258,0,338v-5,6,-22,5,-29,1","w":109},"*":{"d":"143,-231v6,2,12,18,3,21r-45,14v9,17,44,41,16,55v-15,-10,-21,-29,-33,-42v-12,13,-18,32,-33,42v-5,-4,-18,-8,-12,-17r28,-38v-16,-9,-60,-5,-46,-32v1,-5,4,-3,7,-2r45,14r0,-47v-1,-9,8,-7,16,-7v13,7,2,37,5,54","w":167},",":{"d":"35,-46v9,1,29,-4,25,6r-27,68v-1,10,-21,10,-26,3r21,-71v1,-5,3,-6,7,-6","w":77},"-":{"d":"96,-119v11,1,10,27,0,27r-72,0v-10,1,-7,-11,-7,-20v0,-4,3,-7,7,-7r72,0","w":119},".":{"d":"54,-41v-1,21,8,48,-24,41v-13,-3,-7,-27,-7,-41v0,-10,14,-6,24,-7v4,0,7,3,7,7","w":77},"0":{"d":"197,-109v0,80,-34,112,-88,112v-54,0,-88,-32,-88,-112r0,-49v0,-80,34,-112,88,-112v54,0,88,32,88,112r0,49xm109,-25v50,0,56,-67,56,-133v0,-61,-22,-84,-56,-84v-50,0,-55,68,-55,133v0,61,21,84,55,84"},"1":{"d":"105,-7v0,11,-16,6,-26,7v-4,0,-6,-3,-6,-7r0,-227r-51,22v-6,-1,-7,-24,0,-27v26,-9,41,-29,77,-28v4,0,6,2,6,6r0,254","w":154},"2":{"d":"32,-244v-3,-35,46,-24,71,-26v102,-9,110,92,40,134v-39,23,-96,56,-85,108r121,0v10,-1,6,13,7,22v0,4,-3,6,-7,6r-143,0v-13,-1,-5,-24,-7,-36v-6,-52,50,-94,91,-119v31,-19,37,-29,37,-51v0,-49,-75,-37,-119,-31v-4,0,-6,-3,-6,-7"},"3":{"d":"30,-243v-3,-35,40,-25,68,-27v55,-4,92,18,90,75v0,24,-13,45,-35,56v28,16,35,36,35,64v0,78,-86,88,-151,70v-10,0,-11,-24,-1,-25v53,6,118,17,118,-52v0,-19,-9,-44,-42,-44r-62,0v-9,1,-7,-11,-7,-19v0,-4,3,-7,7,-7r62,0v37,-1,42,-24,42,-48v0,-53,-71,-45,-118,-37v-4,0,-6,-2,-6,-6"},"4":{"d":"197,-99v11,1,10,29,0,28r-31,0r0,64v0,12,-17,6,-27,7v-4,0,-6,-3,-6,-7r0,-64r-104,0v-21,3,-19,-29,-11,-41r107,-150v4,-7,38,-10,41,2r0,161r31,0xm133,-99r-2,-125r-87,123v24,6,61,0,89,2"},"5":{"d":"190,-87v0,83,-80,103,-155,83v-9,0,-7,-11,-7,-20v0,-5,2,-6,7,-6v61,11,129,11,122,-57v7,-50,-61,-50,-118,-48v-3,0,-6,-3,-6,-6r10,-120v0,-4,3,-6,7,-6r124,0v10,-1,6,12,7,21v0,4,-3,6,-7,6r-103,0r-6,78v72,-2,125,11,125,75"},"6":{"d":"116,-270v34,0,56,-1,70,13v0,9,3,22,-9,20v-18,-4,-38,-6,-61,-6v-57,0,-62,35,-62,84v62,-15,143,-11,143,70v0,57,-29,92,-88,92v-54,0,-87,-32,-87,-103r0,-63v0,-77,32,-107,94,-107xm109,-24v34,1,56,-18,55,-67v0,-61,-66,-51,-110,-43v-4,61,9,119,55,110"},"7":{"d":"152,-267v30,0,31,22,22,41r-104,221v-4,8,-30,8,-35,0r110,-232v-36,-7,-85,1,-125,-2v-10,0,-7,-13,-7,-22v0,-4,3,-6,7,-6r132,0","w":189},"8":{"d":"198,-81v2,59,-38,85,-91,84v-50,0,-90,-27,-87,-84v0,-22,12,-46,35,-59v-24,-13,-35,-32,-34,-59v0,-51,38,-72,90,-71v50,0,88,22,87,74v0,24,-12,44,-35,56v23,13,35,37,35,59xm98,-153v42,0,68,-13,68,-46v0,-30,-21,-45,-59,-44v-37,0,-56,15,-55,47v0,22,13,43,46,43xm107,-25v41,1,59,-19,59,-56v0,-28,-26,-50,-68,-46v-35,4,-45,25,-45,52v0,31,18,50,54,50"},"9":{"d":"193,-105v8,105,-76,120,-156,101v-11,0,-7,-10,-8,-20v0,-5,3,-8,8,-7v18,4,39,6,62,6v58,0,62,-35,62,-84v-62,15,-143,11,-143,-70v0,-57,29,-91,88,-91v54,0,87,31,87,102r0,63xm161,-134v4,-60,-9,-118,-55,-109v-35,-1,-57,17,-56,66v0,62,67,52,111,43"},":":{"d":"55,-191v-1,20,9,48,-24,41v-13,-2,-7,-27,-7,-41v0,-10,14,-6,24,-7v4,0,7,3,7,7xm55,-41v-1,20,9,48,-24,41v-13,-2,-7,-27,-7,-41v0,-10,14,-6,24,-7v4,0,7,3,7,7","w":78},";":{"d":"55,-191v-1,20,9,48,-24,41v-13,-2,-7,-27,-7,-41v0,-10,14,-6,24,-7v4,0,7,3,7,7xm31,-46v9,1,30,-4,25,7r-27,68v-1,10,-22,11,-26,2r21,-70v1,-5,3,-7,7,-7","w":78},"?":{"d":"139,-216v12,45,-75,76,-68,139v1,10,-14,6,-23,7v-10,0,-6,-14,-7,-24v-8,-48,63,-75,63,-122v0,-36,-56,-22,-87,-22v-8,0,-9,-24,1,-27v52,-10,123,-10,121,49xm64,-48v12,6,11,45,0,48v-10,-1,-24,3,-24,-7v1,-21,-8,-48,24,-41","w":160},"@":{"d":"143,-175v18,0,49,-3,54,14r-11,113v45,-6,52,-39,52,-84v0,-45,-29,-83,-88,-83v-92,-2,-111,70,-112,157v0,43,29,77,91,77v18,1,41,-5,55,0v-1,7,3,18,-6,17v-84,14,-170,-17,-163,-105v7,-95,34,-167,136,-167v74,0,111,50,111,104v0,88,-45,111,-131,113v-58,1,-62,-47,-54,-99v6,-37,27,-57,66,-57xm165,-147v-30,-5,-57,-2,-58,30v-1,33,-17,79,33,72v5,0,11,0,16,-1","w":276},"A":{"d":"204,-7v0,11,-17,6,-27,7v-4,0,-6,-3,-6,-7r0,-107r-110,0r0,107v0,11,-16,6,-26,7v-4,0,-7,-3,-7,-7r0,-188v-1,-63,35,-75,98,-75v51,0,78,20,78,75r0,188xm171,-143v0,-48,10,-98,-45,-98v-41,0,-65,0,-65,46r0,52r110,0","w":231},"B":{"d":"28,-254v5,-24,37,-16,69,-16v59,0,105,15,105,75v0,27,-14,48,-38,57v27,10,40,31,40,64v0,81,-93,82,-164,73v-8,-1,-12,-4,-12,-13r0,-240xm117,-152v45,-1,53,-20,53,-49v0,-47,-61,-42,-109,-40r0,89r56,0xm61,-27v54,4,110,6,110,-53v0,-24,-12,-46,-54,-46r-56,0r0,99","w":221},"C":{"d":"184,-9v-13,15,-31,12,-67,12v-44,0,-95,-25,-95,-112r0,-50v4,-116,74,-119,155,-105v10,-1,5,15,6,23v-9,10,-42,1,-66,1v-35,0,-63,20,-63,81r0,50v-1,90,57,86,124,79v9,0,5,13,6,21","w":196},"D":{"d":"28,-257v7,-19,38,-10,73,-13v85,-6,109,62,109,161v0,77,-42,112,-109,112v-35,0,-66,6,-73,-13r0,-247xm177,-109r0,-49v-1,-83,-49,-88,-116,-83r0,215v66,3,116,0,116,-83","w":230},"E":{"d":"175,-27v8,3,5,26,0,28v-14,1,-49,2,-70,2v-50,0,-77,-19,-77,-67r0,-139v-7,-75,81,-69,147,-65v6,2,7,25,0,28v-45,3,-124,-15,-114,37r0,50r110,0v10,0,8,11,8,21v0,4,-4,7,-8,7r-110,0v5,47,-21,98,44,98r70,0","w":198},"F":{"d":"171,-153v11,0,12,28,0,28r-110,0r0,118v0,11,-16,6,-26,7v-4,0,-7,-3,-7,-7r0,-196v-7,-75,81,-69,147,-65v6,2,7,25,0,28v-45,3,-124,-15,-114,37r0,50r110,0","w":198},"G":{"d":"192,-11v0,4,-2,7,-6,8v-81,15,-166,10,-165,-106r0,-49v1,-119,83,-119,165,-107v10,-1,5,15,6,23v0,3,-3,4,-6,4v-68,-3,-134,-18,-132,80r0,49v-1,81,46,88,105,80r0,-103v0,-11,16,-6,26,-7v4,0,7,3,7,7r0,121","w":220},"H":{"d":"217,-7v0,11,-16,6,-26,7v-4,0,-7,-3,-7,-7r0,-120r-123,0r0,120v0,11,-16,6,-26,7v-4,0,-7,-3,-7,-7r0,-253v0,-11,16,-6,26,-7v4,0,7,3,7,7r0,104r123,0r0,-104v0,-11,16,-6,26,-7v4,0,7,3,7,7r0,253","w":244},"I":{"d":"64,-7v0,11,-16,6,-26,7v-4,0,-6,-3,-6,-7r0,-254v0,-11,17,-4,26,-6v4,0,6,2,6,6r0,254","w":96},"J":{"d":"63,-40v3,47,-19,70,-33,101v-6,13,-24,11,-35,6v10,-38,35,-56,35,-107r0,-221v0,-9,30,-10,33,0r0,221","w":94},"K":{"d":"202,-6v2,3,0,6,-3,6v-13,-1,-29,4,-36,-4r-102,-124r0,121v0,11,-16,6,-26,7v-4,0,-7,-3,-7,-7r0,-254v1,-9,30,-10,33,0r0,116r104,-119v6,-5,32,-6,38,1r-110,125","w":218},"L":{"d":"175,-27v8,2,5,25,0,26v-9,1,-36,4,-70,4v-39,0,-77,-8,-77,-67r0,-196v0,-11,16,-6,26,-7v4,0,7,3,7,7r0,196v-10,52,69,34,114,37","w":185},"M":{"d":"246,-7v0,11,-16,6,-26,7v-3,0,-6,-2,-6,-6r-2,-230v-21,34,-31,80,-49,118v-4,22,-44,21,-52,0r-48,-118v-1,0,-3,0,-3,4r0,226v-1,10,-32,11,-32,-1r0,-235v0,-30,16,-24,38,-25v16,0,19,5,27,24r44,112v18,-33,29,-76,44,-112v10,-24,16,-25,41,-24v14,0,24,1,24,25r0,235","w":274},"N":{"d":"213,-7v0,12,-17,6,-27,7v-4,0,-6,-3,-6,-7r0,-159v6,-88,-55,-78,-119,-73r0,232v0,11,-16,6,-26,7v-4,0,-7,-3,-7,-7r0,-246v0,-9,3,-12,10,-13v94,-9,175,-14,175,100r0,159","w":238},"O":{"d":"216,-111v0,80,-40,114,-97,114v-73,0,-97,-65,-97,-160v0,-80,40,-113,97,-113v57,0,97,33,97,113r0,46xm119,-27v55,0,64,-61,64,-130v0,-60,-24,-83,-64,-83v-55,0,-64,60,-64,129v0,60,24,84,64,84","w":237},"P":{"d":"28,-258v7,-18,42,-12,68,-12v60,0,101,21,101,83v0,73,-64,85,-137,79r0,101v0,11,-15,6,-25,7v-4,0,-7,-3,-7,-7r0,-251xm60,-135v57,5,114,-2,105,-57v5,-48,-53,-54,-105,-49r0,106","w":213},"Q":{"d":"216,-157v0,86,-18,157,-81,158r0,58v1,12,-16,7,-26,8v-14,-10,-2,-46,-6,-66v-62,-2,-81,-71,-81,-158v0,-80,40,-113,97,-113v57,0,97,33,97,113xm119,-27v55,0,64,-61,64,-130v0,-60,-24,-83,-64,-83v-55,0,-64,60,-64,129v0,60,24,84,64,84","w":237},"R":{"d":"211,-7v2,11,-18,6,-29,7v-4,0,-5,0,-8,-5r-65,-107r-49,-1r0,106v0,11,-15,6,-25,7v-4,0,-7,-3,-7,-7r0,-252v0,-5,3,-7,9,-8v75,-8,164,-7,164,77v0,40,-24,64,-57,73xm60,-141v54,3,114,4,108,-52v5,-50,-57,-49,-108,-46r0,98","w":225},"S":{"d":"180,-69v0,35,-18,72,-89,72v-25,0,-44,-4,-60,-6v-11,-1,-5,-11,-7,-20v9,-15,48,0,67,-4v43,0,55,-17,55,-42v0,-52,-135,-71,-128,-137v-8,-66,86,-69,149,-60v9,1,10,28,0,28v-43,2,-121,-15,-116,32v6,49,142,76,129,137","w":198},"T":{"d":"193,-267v12,1,10,28,0,28r-70,0r0,232v0,11,-17,6,-27,7v-4,0,-6,-3,-6,-7r0,-232r-70,0v-10,1,-6,-13,-7,-22v0,-4,3,-6,7,-6r173,0","w":212},"U":{"d":"210,-13v0,9,-3,11,-10,12v-94,9,-175,14,-175,-100r0,-159v0,-11,17,-6,27,-7v4,0,6,3,6,7r0,159v-6,88,55,76,119,73r0,-232v0,-11,17,-6,27,-7v4,0,6,3,6,7r0,247","w":238},"V":{"d":"186,-262v6,-9,36,-9,33,3r-66,234v-14,40,-63,40,-74,0r-67,-236v1,-10,29,-9,34,-1r63,229v1,10,11,10,14,0","w":231},"W":{"d":"252,-261v4,-11,34,-9,33,1r-40,243v-3,28,-52,24,-59,0r-38,-136v-15,42,-26,91,-37,136v-6,23,-54,29,-58,0r-40,-244v1,-9,31,-11,33,0r36,234v16,-42,27,-93,38,-138v5,-22,51,-23,57,0r38,138","w":297},"X":{"d":"216,-9v2,4,2,9,-4,9v-12,-1,-26,4,-31,-5r-65,-105r-65,105v-5,10,-18,3,-29,5v-6,0,-6,-5,-4,-9r80,-127r-81,-126v2,-9,28,-7,36,-2r64,103r63,-103v5,-5,37,-7,33,5r-78,124","w":232},"Y":{"d":"172,-267v11,1,33,-4,27,9r-75,149r0,102v0,11,-17,6,-27,7v-4,0,-6,-3,-6,-7r0,-102r-77,-154v3,-7,31,-7,35,1r58,122r59,-122v1,-3,3,-5,6,-5","w":214},"Z":{"d":"188,-30v12,1,10,30,0,30r-138,0v-29,0,-38,-26,-25,-45r130,-191v-35,-6,-84,-2,-123,-2v-11,0,-6,-14,-7,-23v0,-4,3,-6,7,-6r128,0v31,-1,38,25,25,45r-130,190v38,6,91,0,133,2","w":213},"[":{"d":"102,44v11,0,10,27,0,26r-67,0v-4,0,-6,-3,-6,-7r0,-324v0,-4,2,-6,6,-6r67,0v9,0,7,11,7,19v-4,14,-33,4,-48,7r0,285r41,0","w":117},"]":{"d":"89,63v0,4,-2,7,-6,7r-67,0v-9,0,-7,-11,-7,-19v4,-14,33,-4,48,-7r0,-285v-19,-4,-54,12,-48,-19v0,-4,3,-7,7,-7r67,0v4,0,6,2,6,6r0,324","w":117},"\u2018":{"d":"40,-271v7,0,21,-2,16,7r-13,68v-1,12,-18,5,-29,7v-5,1,-4,-4,-3,-7r22,-68v1,-5,3,-7,7,-7","w":66},"a":{"d":"170,-14v0,5,-1,7,-7,8v-19,5,-45,9,-67,9v-63,0,-78,-47,-78,-115v0,-54,24,-89,78,-89v22,0,48,4,67,9v6,1,7,3,7,8r0,170xm139,-28r0,-142v-10,-2,-28,-4,-43,-4v-45,-2,-46,41,-46,88v0,38,10,62,46,62v15,0,33,-2,43,-4","w":194},"b":{"d":"177,-112v0,68,-15,115,-79,115v-22,0,-44,-3,-66,-7v-6,-1,-8,-3,-8,-8r0,-252v0,-10,15,-6,25,-7v4,0,7,3,7,7r0,67v71,-16,121,11,121,85xm98,-25v46,2,47,-39,47,-87v0,-59,-37,-68,-89,-58r0,143v12,1,30,2,42,2","w":194},"c":{"d":"147,-22v5,33,-28,24,-52,25v-58,3,-77,-48,-77,-116v0,-72,54,-99,122,-84v11,2,6,12,7,21v0,5,-3,6,-8,6v-50,-8,-89,-5,-89,57v0,47,6,88,45,88v19,0,29,-2,46,-3v3,0,6,2,6,6","w":162},"d":{"d":"170,-12v0,5,-1,7,-7,8v-22,4,-45,7,-67,7v-63,0,-78,-47,-78,-115v0,-75,49,-101,121,-85r0,-67v0,-11,15,-6,25,-7v4,0,6,3,6,7r0,252xm139,-27r0,-143v-51,-9,-89,-2,-89,58v0,47,0,90,46,87v12,0,31,-1,43,-2","w":194},"e":{"d":"178,-112v0,9,2,23,-7,23r-121,0v-7,72,61,70,116,60v8,-1,6,10,6,17v0,5,-1,7,-7,8v-72,14,-141,15,-146,-82v-3,-66,20,-114,80,-115v53,0,79,38,79,89xm50,-113v31,-2,69,4,96,-2v0,-39,-15,-58,-47,-58v-32,0,-50,22,-49,60","w":195},"f":{"d":"80,-273v22,0,44,-6,40,20v-12,17,-72,-14,-64,30r0,25r56,0v9,-1,7,11,7,19v0,4,-3,6,-7,6r-56,0r0,166v0,10,-14,6,-24,7v-4,0,-8,-3,-8,-7r0,-216v0,-39,22,-50,56,-50","w":128},"g":{"d":"170,0v0,54,-24,71,-73,71v-27,0,-51,-4,-61,-7v-9,0,-7,-9,-7,-18v0,-4,3,-5,7,-5v40,1,116,23,103,-44v-73,21,-121,-10,-121,-109v0,-90,74,-101,145,-80v6,1,7,3,7,8r0,184xm139,-28r0,-142v-47,-10,-89,-6,-89,58v0,50,6,88,48,88v10,0,30,-1,41,-4","w":194},"h":{"d":"176,-7v0,10,-14,6,-24,7v-4,0,-8,-3,-8,-7v-8,-64,28,-169,-46,-167v-14,0,-31,3,-42,6r0,161v0,10,-14,6,-24,7v-4,0,-8,-3,-8,-7r0,-257v0,-10,15,-6,25,-7v4,0,7,3,7,7r0,69v59,-19,120,8,120,67r0,121","w":200},"i":{"d":"54,-273v12,4,11,42,0,43v-10,-1,-26,4,-26,-7v0,-13,-6,-36,7,-36r19,0xm60,-7v0,10,-14,6,-24,7v-4,0,-8,-3,-8,-7r0,-184v0,-10,32,-12,32,0r0,184","w":88},"j":{"d":"54,-273v12,4,11,42,0,43v-10,-1,-26,4,-26,-7v0,-13,-6,-36,7,-36r19,0xm15,71v-15,0,-31,0,-26,-21v7,-14,47,8,39,-27r0,-214v0,-10,32,-12,32,0r0,214v0,37,-16,48,-45,48","w":88},"k":{"d":"165,-8v3,12,-17,7,-29,8v-4,0,-5,-1,-8,-5r-72,-88r0,86v0,10,-14,6,-24,7v-4,0,-8,-3,-8,-7r0,-257v0,-10,32,-12,32,0r0,150r72,-81v5,-5,43,-7,36,5r-79,86","w":178},"l":{"d":"60,-7v0,10,-15,6,-25,7v-4,0,-7,-3,-7,-7r0,-257v0,-10,15,-6,25,-7v4,0,7,3,7,7r0,257","w":87},"m":{"d":"263,-7v0,10,-15,6,-25,7v-4,0,-7,-3,-7,-7r0,-131v-1,-35,-15,-35,-41,-35v-23,0,-31,4,-31,25r0,141v0,11,-15,6,-25,7v-4,0,-6,-3,-6,-7r0,-141v1,-24,-14,-26,-39,-25v-19,0,-33,4,-33,35r0,131v0,11,-15,6,-25,7v-4,0,-7,-3,-7,-7v6,-85,-30,-194,73,-194v22,0,36,3,47,13v12,-11,30,-13,55,-13v93,0,58,113,64,194","w":287},"n":{"d":"176,-7v0,11,-15,6,-25,7v-4,0,-7,-3,-7,-7r0,-129v3,-39,-23,-38,-57,-37v-24,0,-31,10,-31,37r0,129v0,11,-15,6,-25,7v-4,0,-7,-3,-7,-7r0,-129v6,-67,41,-66,89,-65v24,0,63,10,63,65r0,129","w":200},"o":{"d":"178,-113v0,68,-17,116,-80,116v-63,0,-80,-48,-80,-116v0,-53,27,-88,80,-88v53,0,80,35,80,88xm98,-25v43,0,49,-40,49,-88v0,-37,-15,-60,-49,-60v-43,0,-48,40,-48,88v0,37,14,60,48,60","w":196},"p":{"d":"177,-112v0,88,-36,131,-121,111r0,65v0,10,-15,6,-25,7v-4,0,-7,-3,-7,-7r0,-248v0,-5,2,-7,8,-8v19,-5,44,-9,66,-9v54,0,79,35,79,89xm98,-24v44,2,47,-40,47,-88v0,-38,-11,-62,-47,-62v-15,0,-32,2,-42,4r0,142v12,2,30,4,42,4","w":194},"q":{"d":"170,64v0,11,-15,6,-25,7v-4,0,-6,-3,-6,-7r0,-65v-81,19,-121,-19,-121,-111v0,-54,24,-89,78,-89v22,0,48,4,67,9v6,1,7,3,7,8r0,248xm139,-28r0,-142v-10,-2,-28,-4,-43,-4v-45,-2,-46,41,-46,88v0,60,37,70,89,58","w":194},"r":{"d":"24,-182v14,-20,50,-17,82,-19v12,-2,7,13,8,22v0,4,-1,6,-8,6v-24,0,-36,1,-50,4r0,162v0,11,-15,6,-25,7v-4,0,-7,-3,-7,-7r0,-175","w":127},"s":{"d":"82,3v-16,-4,-71,8,-64,-26v22,-16,100,21,100,-27v0,-41,-100,-48,-100,-103v0,-57,73,-51,121,-43v10,1,6,10,7,19v0,4,-2,6,-7,6v-24,1,-90,-17,-89,18v9,39,100,54,100,103v0,37,-28,53,-68,53","w":167},"t":{"d":"120,-18v4,26,-20,21,-42,21v-34,0,-54,-12,-54,-51r0,-185v2,-9,32,-16,32,-3r0,38r56,0v9,-1,7,11,7,19v0,4,-3,6,-7,6r-56,0r0,125v-4,33,29,24,56,25v5,0,8,1,8,5","w":128},"u":{"d":"176,-82v-2,72,-48,85,-77,85v-24,0,-75,-14,-75,-85r0,-109v0,-11,16,-6,26,-7v4,0,6,3,6,7v3,61,-18,174,46,166v58,6,39,-107,42,-166v0,-11,16,-6,26,-7v4,0,6,3,6,7r0,109","w":200},"v":{"d":"151,-198v11,1,29,-4,25,9r-46,163v-13,41,-59,40,-70,0r-46,-166v0,-9,30,-11,32,1r41,156v3,16,13,15,17,0r40,-156v1,-5,4,-7,7,-7","w":190},"w":{"d":"265,-78v-1,87,-62,90,-120,72v-58,19,-121,14,-121,-72r0,-113v0,-10,30,-12,32,0v4,72,-25,198,73,162r0,-162v0,-10,15,-6,25,-7v4,0,7,3,7,7r0,162v40,12,73,4,73,-49r0,-113v0,-10,14,-6,24,-7v4,0,7,3,7,7r0,113","w":289},"x":{"d":"177,-8v3,3,3,8,-3,8v-10,0,-25,3,-30,-3r-51,-75r-52,74v-4,6,-27,7,-32,0r67,-97v-20,-32,-46,-58,-63,-93v4,-7,30,-8,36,1r45,68r46,-68v5,-10,17,-3,29,-5v6,0,6,5,3,9r-61,86","w":186},"y":{"d":"176,0v0,57,-24,71,-73,71v-27,0,-52,-5,-60,-6v-9,-2,-7,-8,-7,-17v8,-17,40,-2,67,-2v33,0,42,-10,42,-48v-58,12,-120,6,-121,-70r0,-119v0,-10,32,-12,32,0r0,119v-2,56,46,51,88,43r0,-162v0,-10,32,-12,32,0r0,191","w":200},"z":{"d":"148,-27v12,0,12,28,0,27r-95,0v-33,7,-43,-31,-27,-50r94,-119v-25,-6,-62,0,-91,-2v-8,0,-7,-11,-7,-20v0,-4,3,-7,7,-7r89,0v36,-3,45,25,28,47r-96,121v25,9,67,0,98,3","w":173},"{":{"d":"102,44v11,0,10,26,0,26v-48,0,-73,-5,-73,-50v0,-44,11,-91,-22,-108r0,-21v60,-28,-37,-158,95,-158v9,0,7,11,7,19v-6,18,-57,-6,-48,30v-2,50,9,100,-26,120v35,20,26,69,26,118v0,26,17,24,41,24","w":119},"}":{"d":"112,-88v-60,28,37,158,-95,158v-9,0,-7,-11,-7,-19v7,-17,57,5,48,-31v2,-49,-9,-99,26,-118v-35,-20,-26,-70,-26,-120v0,-26,-17,-23,-41,-23v-9,0,-7,-11,-7,-19v0,-10,15,-6,25,-7v100,-14,20,117,77,158r0,21","w":119},"\u00a1":{"d":"55,-191v-1,20,9,48,-24,41v-13,-2,-7,-27,-7,-41v0,-10,14,-6,24,-7v4,0,7,3,7,7xm56,66v0,11,-16,6,-26,7v-4,0,-7,-3,-7,-7r3,-187v0,-9,11,-7,20,-7v4,0,7,3,7,7","w":78},"\u00a2":{"d":"132,-200v21,4,47,-6,42,24v-9,14,-34,-1,-53,3v-38,-4,-45,40,-45,88v0,62,40,65,91,57v8,-1,8,11,7,19v-2,14,-25,7,-42,11v-2,18,10,46,-21,40v-14,-3,-6,-27,-8,-41v-79,-8,-81,-189,0,-200v1,-19,-9,-47,22,-40v13,2,5,26,7,39"},"\u00a3":{"d":"32,-5v-2,-29,15,-36,15,-65r0,-55v-9,-1,-25,4,-25,-6v1,-9,-3,-23,7,-22r18,0v-3,-70,9,-116,79,-114v19,0,43,3,56,5v12,-1,9,23,2,27v-56,-3,-113,-20,-104,59r0,23r77,0v10,-1,6,13,7,22v0,4,-3,6,-7,6r-77,0v0,37,3,78,-13,98r115,0v11,-1,6,13,7,21v0,4,-3,6,-7,6r-144,0v-4,0,-6,-2,-6,-5"},"\u00a5":{"d":"198,-101v10,0,11,26,0,25r-72,0r0,69v0,11,-17,6,-27,7v-4,0,-6,-3,-6,-7r0,-69r-73,0v-8,0,-7,-10,-7,-18v0,-4,3,-7,7,-7r73,0v-1,-21,-14,-31,-20,-47r-53,0v-10,0,-10,-26,0,-26r40,0v-14,-30,-32,-57,-44,-89v3,-7,31,-7,35,1r58,122r58,-122v3,-8,30,-8,35,0v-13,31,-30,58,-44,88v19,3,54,-11,47,18v-4,17,-41,4,-60,8v-6,16,-18,26,-19,47r72,0"},"\u0192":{"d":"166,-274v21,0,35,-3,30,19v-11,16,-57,-8,-55,30r-10,71r52,0v10,0,4,13,4,20v-9,13,-41,3,-60,6r-18,129v-5,37,-27,49,-57,49v-21,0,-35,3,-30,-19v11,-16,57,8,55,-30r18,-129r-46,0v-10,0,-4,-13,-4,-20v7,-13,37,-3,54,-6r10,-71v5,-37,27,-49,57,-49"},"\u00a7":{"d":"103,-270v30,3,77,-11,70,27v0,4,-3,6,-7,6v-40,-2,-121,-14,-115,30v6,49,144,76,129,138v0,14,-3,27,-11,39v27,52,9,108,-78,108v-32,0,-71,11,-68,-27v0,-4,4,-6,8,-6v46,6,124,8,114,-39v1,-54,-128,-72,-128,-138v0,-15,6,-27,13,-38v-30,-46,-8,-108,73,-100xm144,-53v20,-52,-60,-70,-93,-99v-19,59,60,70,93,99","w":196},"\u201c":{"d":"94,-271v7,0,21,-2,16,7r-13,68v-1,12,-18,5,-29,7v-5,1,-4,-4,-3,-7r22,-68v1,-5,3,-7,7,-7xm40,-271v7,0,21,-2,16,7r-13,68v-1,12,-18,5,-29,7v-5,1,-4,-4,-3,-7r22,-68v1,-5,3,-7,7,-7","w":120},"\u00ab":{"d":"199,-33v2,2,6,8,-1,8v-11,-1,-22,3,-29,-4r-61,-61v-6,-7,-5,-13,0,-20r61,-61v7,-5,26,-5,33,0v-20,26,-45,47,-67,71xm106,-33v2,2,4,9,-2,8v-11,-1,-22,2,-28,-4r-61,-61v-6,-7,-6,-14,0,-20v23,-21,41,-47,68,-64v9,1,33,-2,23,8r-64,66","w":221},"\u2039":{"d":"106,-33v2,2,4,9,-2,8v-11,-1,-22,2,-28,-4r-61,-61v-6,-7,-6,-14,0,-20v23,-21,41,-47,68,-64v9,1,33,-2,23,8r-64,66","w":127},"\u203a":{"d":"113,-110v6,7,6,14,0,20v-23,22,-42,48,-69,65v-9,0,-32,3,-22,-8r64,-67r-67,-71v5,-6,25,-5,33,0","w":127},"\u2013":{"d":"131,-115v12,0,10,26,0,26r-109,0v-10,1,-7,-11,-7,-20v0,-4,3,-6,7,-6r109,0","w":153},"\u2020":{"d":"125,-200v12,1,10,28,0,28r-39,0r0,165v0,11,-16,6,-26,7v-4,0,-6,-3,-6,-7r0,-165v-19,-2,-48,10,-41,-22v3,-12,28,-3,41,-6r0,-64v0,-11,16,-6,26,-7v4,0,6,3,6,7r0,64r39,0","w":145},"\u2021":{"d":"132,-119v-1,9,3,23,-7,22r-39,0r0,90v0,11,-16,6,-26,7v-4,0,-6,-3,-6,-7r0,-90v-19,-2,-50,10,-41,-22v3,-11,28,-3,41,-5r0,-48v-19,-2,-48,10,-41,-22v3,-12,28,-3,41,-6r0,-64v0,-11,16,-6,26,-7v4,0,6,3,6,7r0,64v20,3,55,-11,46,22v-3,13,-31,3,-46,6r0,48v15,2,40,-6,46,5","w":145},"\u00b6":{"d":"201,63v0,7,-7,8,-15,7v-4,0,-6,-3,-6,-7r0,-311r-21,0r0,311v1,7,-7,7,-14,7v-4,0,-6,-3,-6,-7r0,-158v-75,6,-123,-15,-123,-92v0,-52,35,-80,85,-80r94,0v4,0,6,2,6,6r0,324","w":223},"\u201d":{"d":"85,-271v9,1,29,-5,25,7r-22,68v0,10,-20,10,-24,3r14,-71v1,-5,3,-7,7,-7xm31,-271v9,1,29,-5,25,7r-22,68v0,10,-20,10,-24,3r14,-71v1,-5,3,-7,7,-7","w":120},"\u00bb":{"d":"206,-110v6,7,6,14,0,20v-23,22,-42,47,-68,65v-9,-1,-33,2,-23,-8r64,-67v-21,-24,-47,-44,-66,-71v4,-5,26,-6,32,0xm113,-110v6,7,6,14,0,20v-23,22,-42,48,-69,65v-9,0,-32,3,-22,-8r64,-67r-67,-71v5,-6,25,-5,33,0","w":221},"\u2030":{"d":"392,-89v0,49,-6,92,-48,92v-42,0,-49,-42,-49,-92v0,-40,19,-59,49,-59v30,0,48,19,48,59xm270,-89v0,50,-7,92,-49,92v-42,0,-48,-43,-48,-92v0,-40,18,-59,48,-59v30,0,49,19,49,59xm213,-267v7,1,25,-4,19,6r-150,255v-3,11,-20,8,-30,5r152,-260v3,-5,5,-6,9,-6xm113,-212v0,49,-6,92,-48,92v-42,0,-49,-42,-49,-92v0,-40,19,-58,49,-58v30,0,48,18,48,58xm344,-18v27,0,26,-40,26,-71v0,-27,-10,-38,-26,-38v-27,0,-26,40,-26,71v0,27,10,38,26,38xm221,-18v27,0,26,-40,26,-71v0,-27,-10,-38,-26,-38v-27,0,-26,40,-26,71v0,27,10,38,26,38xm65,-141v27,0,26,-40,26,-71v0,-27,-10,-38,-26,-38v-27,0,-26,40,-26,71v0,27,10,38,26,38","w":408},"\u00bf":{"d":"118,-191v-1,21,8,48,-24,41v-13,-3,-7,-27,-7,-41v0,-10,14,-6,24,-7v4,0,7,3,7,7xm140,41v11,2,9,26,0,27v-54,9,-126,9,-121,-54v-9,-39,76,-76,68,-135v-1,-10,14,-6,23,-7v10,0,6,15,7,25v7,47,-63,75,-63,121v0,36,55,26,86,23","w":160},"\u2014":{"d":"178,-115v12,0,10,26,0,26r-156,0v-10,1,-7,-11,-7,-20v0,-4,3,-6,7,-6r156,0","w":200},"\u00c6":{"d":"318,-27v6,4,4,23,0,26v-9,1,-36,3,-70,3v-71,0,-83,-45,-77,-116r-110,0r0,107v0,11,-16,6,-26,7v-4,0,-7,-3,-7,-7r0,-188v-1,-63,35,-75,98,-75v27,0,47,5,60,18v14,-27,108,-18,132,-15v5,3,5,22,0,26v-48,5,-123,-20,-114,41r0,46r110,0v9,0,7,12,7,21v0,4,-3,7,-7,7r-110,0v5,48,-20,99,44,99r70,0xm171,-143v-1,-47,11,-98,-45,-98v-41,0,-65,0,-65,46r0,52r110,0","w":341},"\u00aa":{"d":"95,-162v-18,20,-94,14,-84,-27v-2,-26,25,-35,62,-33v7,-34,-27,-29,-50,-26v-6,0,-5,-6,-5,-12v21,-18,86,-11,77,33r0,65xm74,-170r0,-37v-23,0,-46,1,-42,20v-5,20,25,21,42,17","w":108},"\u00d8":{"d":"205,-269v8,1,29,-2,22,7r-26,36v17,25,15,72,15,115v0,112,-96,140,-163,91v-8,12,-14,28,-39,23v-4,0,-5,-4,-3,-7r26,-36v-17,-25,-15,-73,-15,-117v0,-112,96,-139,163,-90v7,-7,10,-19,20,-22xm166,-221v-43,-39,-116,-20,-111,64v2,29,-2,62,4,85xm119,-27v68,0,72,-97,60,-168r-107,149v11,13,27,19,47,19","w":237},"\u0152":{"d":"330,-27v8,3,6,26,0,27v-9,2,-36,3,-70,3v-34,0,-57,-9,-68,-30v-60,59,-179,32,-170,-84r0,-46v-8,-117,110,-141,170,-83v11,-21,34,-30,68,-30v46,0,78,-15,74,25v0,3,-1,5,-4,5v-45,3,-124,-14,-114,37r0,50r111,0v9,0,7,12,7,21v0,4,-3,7,-7,7r-111,0v5,48,-20,98,45,98r69,0xm119,-27v69,-1,66,-65,65,-131v0,-44,-14,-82,-65,-82v-56,0,-64,60,-64,129v0,60,24,84,64,84","w":353},"\u00ba":{"d":"105,-216v0,39,-12,64,-47,64v-35,0,-46,-25,-46,-64v0,-33,15,-53,46,-53v31,0,47,20,47,53xm58,-170v22,1,25,-20,25,-46v0,-22,-7,-33,-25,-33v-22,0,-25,19,-25,45v0,22,7,34,25,34","w":115},"\u00e6":{"d":"131,-118v11,-68,-47,-56,-96,-53v-9,1,-5,-11,-6,-18v0,-4,2,-6,7,-7v36,-8,104,-9,116,21v13,-16,33,-26,59,-26v58,1,81,44,78,104v0,5,-3,8,-7,8r-120,0v-3,43,12,66,53,65v22,0,44,-3,63,-5v8,-1,6,10,6,17v0,5,-1,7,-7,8v-42,8,-102,15,-126,-15v-41,35,-134,32,-134,-41v0,-49,48,-62,114,-58xm162,-113v31,-2,69,4,96,-2v0,-39,-15,-59,-47,-59v-32,0,-50,23,-49,61xm131,-34r0,-61v-43,-1,-91,-1,-82,38v-1,43,57,40,82,23","w":307},"\u00f8":{"d":"169,-210v8,1,27,-2,20,7r-26,34v32,60,21,172,-65,172v-21,0,-37,-6,-50,-16v-8,12,-20,36,-42,23v6,-16,19,-25,27,-39v-32,-59,-21,-172,65,-172v21,0,37,6,50,16v7,-8,12,-21,21,-25xm130,-162v-33,-26,-86,-3,-80,49v2,19,-2,41,3,56xm98,-25v54,0,55,-67,45,-116r-77,105v8,7,18,11,32,11","w":196},"\u0153":{"d":"306,-112v0,9,2,23,-7,23r-120,0v-6,73,58,70,116,60v8,-1,6,10,6,17v0,5,-2,7,-8,8v-49,9,-103,15,-130,-24v-13,19,-34,31,-64,31v-63,0,-80,-48,-80,-116v0,-53,27,-88,80,-88v30,0,52,12,65,31v13,-19,35,-31,63,-31v53,0,79,38,79,89xm179,-113v30,-2,69,4,95,-2v0,-39,-15,-59,-47,-59v-32,0,-49,23,-48,61xm99,-25v43,0,49,-40,49,-88v0,-37,-15,-60,-49,-60v-43,0,-49,40,-49,88v0,37,15,60,49,60","w":324},"\u00df":{"d":"190,-82v1,66,-47,92,-103,83v-10,1,-6,-12,-7,-21v0,-8,13,-3,19,-4v37,1,59,-13,59,-58v0,-30,-26,-51,-69,-47v-8,0,-9,-8,-8,-17v0,-9,12,-7,21,-7v38,-1,50,-21,50,-49v0,-26,-14,-43,-47,-43v-33,0,-50,18,-50,60r0,177v1,12,-15,7,-25,8v-4,0,-7,-4,-7,-8r0,-177v0,-60,32,-88,82,-88v48,0,81,23,79,76v0,26,-17,46,-38,55v25,9,44,31,44,60","w":209},"\u2122":{"d":"269,-125v-1,6,-20,7,-22,0r0,-86v0,-28,-3,-37,-38,-37r0,123v0,6,-20,7,-22,0r0,-123v-15,0,-28,1,-38,2r0,121v-1,6,-20,7,-22,0r0,-133v0,-5,1,-7,5,-7v59,-4,137,-21,137,54r0,86xm114,-262v5,22,-24,12,-41,14r0,121v0,7,-9,6,-17,6v-3,0,-6,-3,-6,-6r0,-121v-15,-4,-45,11,-41,-14v0,-3,3,-5,6,-5r93,0v3,0,6,2,6,5","w":284},"\u00ae":{"d":"205,-174v0,54,-43,96,-97,96v-54,0,-97,-42,-97,-96v0,-54,43,-97,97,-97v54,0,97,43,97,97xm190,-174v0,-45,-37,-83,-82,-83v-45,0,-82,38,-82,83v0,45,37,81,82,81v45,0,82,-36,82,-81xm152,-122v4,8,-5,9,-13,8v-17,-12,-21,-37,-37,-51r-16,0v-4,18,12,53,-14,51v-3,0,-4,-3,-4,-6r0,-109v0,-15,21,-7,34,-9v51,-10,63,60,23,71xm86,-180v23,1,48,0,45,-21v2,-20,-22,-21,-45,-20r0,41","w":215},"\u00a9":{"d":"252,-135v0,64,-53,117,-117,117v-64,0,-117,-53,-117,-117v0,-64,53,-117,117,-117v64,0,117,53,117,117xm236,-135v0,-56,-45,-102,-101,-102v-56,0,-102,46,-102,102v0,56,46,101,102,101v56,0,101,-45,101,-101xm166,-80v6,0,8,21,0,20v-46,7,-88,-1,-88,-64v0,-71,29,-103,88,-87v7,-1,5,9,5,15v-22,12,-71,-15,-71,48v0,37,7,76,33,70v12,0,25,-1,33,-2","w":270},"\u00c7":{"d":"184,-9v-13,15,-31,12,-67,12v-44,0,-95,-25,-95,-112r0,-50v4,-116,74,-119,155,-105v10,-1,5,15,6,23v-9,10,-42,1,-66,1v-35,0,-63,20,-63,81r0,50v-1,90,57,86,124,79v9,0,5,13,6,21xm109,12v9,2,31,-5,27,5v-17,16,-30,37,-49,51v-7,-1,-28,3,-21,-6r34,-45v3,-4,5,-5,9,-5","w":196},"\u00e5":{"d":"170,-14v0,5,-1,7,-7,8v-19,5,-45,9,-67,9v-63,0,-78,-47,-78,-115v0,-54,24,-89,78,-89v22,0,48,4,67,9v6,1,7,3,7,8r0,170xm139,-28r0,-142v-10,-2,-28,-4,-43,-4v-45,-2,-46,41,-46,88v0,38,10,62,46,62v15,0,33,-2,43,-4xm136,-253v0,20,-16,36,-36,36v-20,0,-37,-16,-37,-36v0,-20,17,-37,37,-37v20,0,36,17,36,37xm119,-253v0,-10,-9,-19,-19,-19v-10,0,-19,9,-19,19v0,10,9,19,19,19v10,0,19,-9,19,-19","w":194},"\u00e7":{"d":"147,-22v5,33,-28,24,-52,25v-58,3,-77,-48,-77,-116v0,-72,54,-99,122,-84v11,2,6,12,7,21v0,5,-3,6,-8,6v-50,-8,-89,-5,-89,57v0,47,6,88,45,88v19,0,29,-2,46,-3v3,0,6,2,6,6xm88,12v8,1,33,-3,26,5v-15,17,-29,37,-48,51v-8,-1,-26,4,-22,-6r35,-45v3,-4,5,-5,9,-5","w":162},"\u00e9":{"d":"178,-112v0,9,2,23,-7,23r-121,0v-7,72,61,70,116,60v8,-1,6,10,6,17v0,5,-1,7,-7,8v-72,14,-141,15,-146,-82v-3,-66,20,-114,80,-115v53,0,79,38,79,89xm50,-113v31,-2,69,4,96,-2v0,-39,-15,-58,-47,-58v-32,0,-50,22,-49,60xm129,-280v8,2,30,-4,26,5v-17,16,-30,37,-49,51v-7,-1,-28,3,-21,-6r35,-45v3,-4,5,-5,9,-5","w":195},"\u00fc":{"d":"176,-82v-2,72,-48,85,-77,85v-24,0,-75,-14,-75,-85r0,-109v0,-11,16,-6,26,-7v4,0,6,3,6,7v3,61,-18,174,46,166v58,6,39,-107,42,-166v0,-11,16,-6,26,-7v4,0,6,3,6,7r0,109xm139,-274v14,9,13,54,-14,43v-16,-6,-14,-53,14,-43xm76,-274v14,9,13,54,-14,43v-16,-6,-14,-53,14,-43","w":200},"\u00a0":{"w":98}}});
Cufon.registerFont({"w":226,"face":{"font-family":"NeoTech Medium","font-weight":500,"font-stretch":"normal","units-per-em":"360","panose-1":"2 0 6 6 4 0 0 2 0 4","ascent":"288","descent":"-72","x-height":"3","bbox":"-12.5 -278.163 302 72.1422","underline-thickness":"18","underline-position":"-18","stemh":"39","stemv":"48","unicode-range":"U+0020-U+007A"},"glyphs":{" ":{"w":90},"&":{"d":"218,-155v13,4,11,40,0,40r-26,0r0,108v0,4,-3,7,-7,7v-82,6,-169,11,-168,-80v0,-21,7,-41,22,-56v-14,-17,-23,-35,-23,-57v1,-89,98,-81,172,-72v9,5,2,25,4,36v-35,15,-127,-21,-126,36v0,14,5,29,11,38r141,0xm145,-41r0,-74r-68,0v-7,10,-11,21,-11,35v-1,43,39,39,79,39","w":234},"(":{"d":"68,-102v0,76,21,127,41,169v-7,6,-35,7,-42,-2v-64,-74,-63,-252,0,-327v7,-8,32,-8,42,-2v-19,42,-41,89,-41,162","w":119},")":{"d":"51,-95v0,-75,-20,-127,-40,-169v7,-6,35,-7,42,2v64,74,63,252,0,327v-7,8,-32,8,-42,2v19,-42,40,-89,40,-162","w":119},",":{"d":"33,-55v13,2,44,-5,39,7r-31,76v-3,12,-20,5,-32,7v-4,0,-5,-3,-5,-7r22,-76v1,-4,3,-7,7,-7","w":93},"-":{"d":"93,-129v12,3,11,36,0,36r-70,0v-13,1,-7,-18,-8,-29v0,-4,4,-7,8,-7r70,0","w":115},".":{"d":"70,-48v-3,16,7,44,-7,48v-14,-2,-37,6,-40,-7v3,-16,-7,-45,8,-48v13,2,37,-6,39,7","w":93},"0":{"d":"207,-147v0,95,-27,150,-94,150v-66,0,-94,-53,-94,-150v0,-90,36,-123,94,-123v58,0,94,33,94,123xm113,-38v32,10,44,-50,44,-109v0,-65,-19,-83,-44,-83v-32,-10,-44,51,-44,110v0,65,19,82,44,82"},"1":{"d":"128,-7v-3,14,-29,4,-43,7v-4,0,-7,-3,-7,-7r0,-210v-16,6,-30,14,-47,19v-7,-5,-6,-32,-1,-40v29,-11,47,-33,91,-29v4,0,7,2,7,6r0,254","w":176},"2":{"d":"110,-270v108,0,109,96,43,135v-34,20,-88,52,-83,94r118,0v13,1,5,22,7,34v0,4,-3,7,-7,7r-152,0v-15,-2,-7,-28,-8,-42v-2,-59,50,-94,91,-119v28,-17,33,-23,33,-43v1,-41,-77,-22,-115,-22v-9,0,-11,-32,0,-35v19,-5,50,-9,73,-9"},"3":{"d":"197,-82v0,87,-89,94,-160,76v-10,-3,-12,-33,0,-36v55,5,110,20,110,-40v0,-19,-7,-37,-34,-37r-63,0v-11,0,-12,-33,0,-36v43,-1,97,11,97,-41v0,-18,-8,-35,-41,-35v-26,0,-37,5,-69,5v-12,0,-5,-19,-7,-29v0,-4,3,-5,7,-6v67,-18,160,-16,160,71v0,25,-12,43,-31,53v20,11,31,32,31,55"},"4":{"d":"206,-104v13,3,10,40,0,40r-27,0r0,57v-3,14,-29,4,-43,7v-4,0,-7,-3,-7,-7r0,-57r-108,0v-12,-4,-11,-37,-3,-48r111,-149v7,-11,28,-4,43,-6v4,0,7,3,7,7r0,156r27,0xm130,-104r-1,-94r-67,92v17,6,47,0,68,2"},"5":{"d":"199,-87v5,83,-84,105,-162,81v-10,-1,-12,-33,0,-36v58,7,117,17,112,-45v7,-46,-64,-40,-113,-40v-2,0,-4,-3,-4,-6r12,-128v0,-4,3,-6,7,-6r131,0v13,1,5,22,7,34v0,4,-3,7,-7,7r-98,0r-5,59v59,-1,116,9,120,80"},"6":{"d":"209,-90v0,57,-33,90,-93,93v-68,3,-94,-61,-94,-153v0,-87,33,-120,99,-120v31,0,55,3,67,6v13,0,12,34,1,38v-61,-4,-124,-22,-118,61v65,-11,138,-4,138,75xm116,-36v25,1,45,-13,44,-54v-1,-50,-48,-45,-89,-39v-4,56,13,102,45,93"},"7":{"d":"178,-267v22,2,15,34,8,50r-97,210v-7,14,-30,4,-47,7v-5,0,-5,-4,-5,-9r104,-216v-35,-3,-76,0,-113,-1v-13,-1,-5,-23,-7,-35v0,-4,3,-6,7,-6r150,0","w":211},"8":{"d":"208,-81v1,61,-43,85,-96,84v-50,0,-95,-24,-93,-84v0,-24,14,-44,33,-58v-23,-15,-31,-34,-31,-58v0,-55,43,-74,94,-73v50,0,93,19,92,75v0,22,-10,42,-32,56v19,14,33,34,33,58xm106,-157v34,0,54,-11,54,-38v0,-25,-15,-40,-48,-39v-32,0,-45,15,-45,40v0,21,11,37,39,37xm112,-35v32,1,47,-18,47,-46v0,-22,-18,-43,-53,-39v-29,3,-39,22,-38,43v0,24,15,42,44,42"},"9":{"d":"205,-159v0,98,-19,162,-100,162v-31,0,-54,-4,-66,-7v-14,0,-8,-17,-9,-29v0,-6,3,-9,9,-8v14,2,44,5,66,5v36,0,50,-17,51,-66v-66,11,-138,3,-138,-79v0,-53,34,-89,93,-89v54,0,94,33,94,111xm156,-138v4,-56,-13,-102,-45,-93v-25,-1,-45,13,-44,54v1,50,48,45,89,39"},"A":{"d":"217,-7v-3,14,-29,4,-43,7v-4,0,-7,-3,-7,-7r0,-95r-90,0r0,95v-3,14,-29,4,-43,7v-4,0,-7,-3,-7,-7r0,-186v0,-70,43,-76,107,-76v50,0,83,16,83,76r0,186xm167,-144v-3,-37,13,-82,-33,-82v-32,0,-57,-3,-57,33r0,49r90,0","w":243},"B":{"d":"27,-247v4,-33,32,-23,76,-23v68,0,111,19,111,80v0,24,-11,45,-33,54v24,10,35,30,35,61v0,57,-42,78,-109,78v-44,0,-80,9,-80,-24r0,-226xm77,-155v42,2,99,1,89,-39v7,-33,-46,-38,-89,-34r0,73xm77,-39v47,2,100,-2,90,-41v7,-37,-48,-42,-90,-38r0,79","w":234},"C":{"d":"122,-270v48,0,69,-9,64,38v0,4,-2,7,-7,7v-56,-5,-113,-14,-109,65r0,53v-3,78,52,69,109,64v12,1,5,20,7,32v-6,17,-27,14,-64,14v-43,0,-102,-21,-102,-110r0,-53v0,-90,59,-110,102,-110","w":202},"D":{"d":"27,-255v5,-23,46,-13,80,-15v92,-5,113,63,113,163v0,71,-41,110,-113,110v-35,0,-75,8,-80,-16r0,-242xm171,-107r0,-53v0,-67,-41,-71,-94,-67r0,187v52,4,94,0,94,-67","w":240},"E":{"d":"179,-40v12,3,10,37,0,38v-12,2,-26,5,-69,5v-47,0,-83,-13,-83,-74r0,-126v0,-61,36,-73,83,-73v43,0,57,4,69,5v11,1,12,35,0,37v-39,7,-106,-20,-102,31r0,39r97,0v11,2,12,37,0,41r-97,0v2,33,-11,77,28,77r74,0","w":207},"F":{"d":"179,-265v13,3,10,36,0,37v-40,5,-106,-20,-102,31r0,39r97,0v11,2,12,37,0,41r-97,0r0,110v-3,13,-29,5,-43,7v-4,0,-7,-3,-7,-7r0,-190v0,-61,36,-73,83,-73v43,0,57,3,69,5","w":207},"G":{"d":"202,-12v0,5,-2,8,-7,9v-81,13,-172,16,-175,-105r0,-51v0,-121,94,-117,175,-105v12,2,5,20,7,32v0,5,-3,7,-9,7v-17,-1,-41,-3,-76,-3v-24,0,-47,18,-47,69r0,51v4,69,30,72,82,67r0,-92v3,-14,28,-4,42,-7v4,0,8,3,8,7r0,121","w":228},"H":{"d":"229,-7v-3,14,-29,4,-43,7v-4,0,-7,-3,-7,-7r0,-110r-102,0r0,110v-3,14,-29,4,-43,7v-4,0,-7,-3,-7,-7r0,-254v4,-12,29,-3,43,-6v4,0,7,2,7,6r0,100r102,0r0,-100v4,-12,29,-3,43,-6v4,0,7,2,7,6r0,254","w":256},"I":{"d":"77,-7v-3,14,-29,4,-43,7v-4,0,-7,-3,-7,-7r0,-254v4,-12,29,-3,43,-6v4,0,7,2,7,6r0,254","w":104},"J":{"d":"77,-40v3,45,-17,73,-33,102v-8,15,-29,5,-47,8v-6,0,-6,-6,-3,-10v13,-31,33,-55,33,-100r0,-221v4,-13,30,-3,44,-6v4,0,6,2,6,6r0,221","w":104},"K":{"d":"220,-8v1,5,3,8,-4,8v-19,-2,-45,5,-57,-4r-82,-123r0,120v-3,14,-29,4,-43,7v-4,0,-7,-3,-7,-7r0,-253v3,-14,29,-4,43,-7v4,0,7,3,7,7r0,114r88,-118v11,-7,34,-1,50,-3v9,-1,6,6,4,10r-92,119","w":231},"L":{"d":"179,-33v10,47,-36,36,-69,36v-47,0,-83,-13,-83,-74r0,-189v3,-14,29,-4,43,-7v4,0,7,3,7,7r0,189v-4,49,56,26,94,31v4,0,8,3,8,7","w":185},"M":{"d":"258,-5v-5,11,-29,2,-42,5v-3,0,-6,-3,-6,-7r-1,-171v-14,22,-24,48,-37,71v-9,10,-47,10,-59,0r-37,-71v-3,53,2,116,-1,171v-1,14,-28,4,-42,7v-3,0,-6,-1,-6,-5r0,-248v-1,-21,49,-21,57,-6r59,115v22,-35,38,-78,58,-115v7,-12,57,-16,57,6r0,248","w":285},"N":{"d":"226,-7v-3,14,-30,4,-44,7v-4,0,-6,-3,-6,-7r0,-163v7,-64,-51,-60,-99,-54r0,217v-3,14,-29,4,-43,7v-4,0,-7,-3,-7,-7r0,-239v0,-13,4,-16,15,-18v90,-12,184,-17,184,94r0,163","w":251},"O":{"d":"225,-109v0,79,-44,112,-103,112v-59,0,-102,-33,-102,-112r0,-49v0,-79,43,-112,102,-112v59,0,103,33,103,112r0,49xm122,-41v53,0,53,-59,53,-117v0,-48,-18,-69,-53,-69v-53,0,-52,60,-52,118v0,48,17,68,52,68","w":244},"P":{"d":"213,-187v0,78,-63,92,-136,86r0,94v-3,14,-29,4,-43,7v-4,0,-7,-3,-7,-7r0,-248v0,-7,5,-10,12,-11v77,-9,174,-11,174,79xm77,-142v45,4,93,-1,86,-45v4,-41,-43,-45,-86,-41r0,86","w":225},"Q":{"d":"226,-153v0,85,-22,149,-79,153r0,56v-2,13,-28,5,-41,7v-4,0,-7,-3,-7,-7r0,-56v-57,-5,-79,-67,-79,-153v0,-86,46,-117,103,-117v57,0,103,31,103,117xm123,-42v45,0,53,-52,53,-111v0,-54,-21,-72,-53,-72v-45,0,-52,52,-52,110v0,54,20,73,52,73","w":246},"R":{"d":"221,-7v1,3,0,8,-4,7v-17,-3,-44,7,-51,-7r-52,-96r-37,-2r0,98v-3,14,-29,4,-43,7v-4,0,-7,-3,-7,-7r0,-248v0,-7,5,-10,12,-11v77,-9,174,-11,174,80v0,38,-19,62,-49,74xm77,-145v45,3,92,3,86,-44v4,-38,-46,-43,-86,-37r0,81","w":235},"S":{"d":"106,-270v39,0,87,-11,76,40v0,4,-2,6,-7,6v-37,-2,-109,-16,-109,22v-1,24,52,44,73,56v39,23,50,46,50,74v0,36,-23,75,-95,75v-27,0,-46,-3,-63,-7v-11,-2,-12,-36,0,-40v37,3,113,15,106,-28v-8,-49,-121,-65,-121,-130v0,-40,23,-68,90,-68","w":205},"T":{"d":"199,-261v-2,12,6,35,-7,35r-63,0r0,219v-3,14,-29,4,-43,7v-4,0,-7,-3,-7,-7r0,-219r-63,0v-13,-1,-5,-23,-7,-35v0,-4,3,-6,7,-6r176,0v4,0,7,2,7,6","w":208},"U":{"d":"223,-25v-2,39,-61,28,-100,28v-58,0,-98,-24,-98,-101r0,-163v4,-12,29,-3,43,-6v4,0,7,2,7,6r0,163v-8,64,44,62,98,57r0,-220v4,-12,29,-3,43,-6v4,0,7,2,7,6r0,236","w":249},"V":{"d":"176,-261v7,-12,54,-9,51,1r-59,226v-9,33,-35,37,-50,37v-15,0,-41,-4,-50,-37r-59,-227v5,-11,43,-10,51,0r52,216v0,8,10,8,12,0","w":236},"W":{"d":"257,-267v15,3,41,-6,45,6r-34,235v-3,31,-23,30,-52,29v-16,0,-25,-8,-30,-29r-30,-123v-15,36,-21,83,-31,123v-8,29,-21,30,-50,29v-19,0,-29,-6,-32,-29r-34,-236v6,-11,30,-3,44,-5v3,0,6,2,6,6r28,220v13,-41,22,-88,33,-131v1,-17,26,-18,48,-17v15,0,20,8,22,17r34,131r27,-220v0,-4,3,-6,6,-6","w":310},"X":{"d":"223,-7v3,4,0,7,-5,7v-18,-2,-44,6,-52,-7r-53,-85r-49,85v-8,14,-31,4,-49,7v-5,0,-7,-4,-5,-7r77,-128r-80,-128v10,-8,47,-8,58,2r52,84r49,-84v7,-12,32,-4,49,-6v4,0,5,2,5,6r-76,127","w":230},"Y":{"d":"168,-267v15,3,49,-8,46,8r-77,153r0,99v-3,14,-30,4,-44,7v-4,0,-6,-3,-6,-7r0,-99r-78,-157v8,-9,32,-2,47,-4v3,0,5,2,6,5r50,106r50,-106v1,-3,3,-5,6,-5","w":223},"Z":{"d":"192,-44v12,5,11,44,0,44r-157,0v-24,4,-24,-32,-14,-47r115,-174v-27,-9,-71,0,-104,-3v-12,-2,-3,-25,-6,-37v0,-4,2,-6,6,-6r145,0v26,-4,25,33,15,49r-114,172v32,6,78,0,114,2","w":215},"a":{"d":"184,-16v0,5,-1,8,-9,10v-22,6,-50,9,-73,9v-68,0,-86,-46,-86,-118v0,-56,28,-91,86,-91v23,0,51,4,73,10v8,2,9,5,9,10r0,170xm137,-39r0,-125v-7,-1,-22,-3,-35,-3v-41,-1,-38,40,-38,80v0,30,7,51,38,51v13,0,28,-2,35,-3","w":207},"b":{"d":"192,-115v0,72,-18,118,-87,118v-23,0,-50,-3,-72,-9v-8,-2,-10,-5,-10,-10r0,-251v3,-13,27,-5,41,-7v4,0,7,3,7,7r0,64v73,-14,121,19,121,88xm105,-36v41,1,39,-39,39,-79v0,-46,-29,-59,-73,-49r0,125v7,1,21,3,34,3","w":207},"c":{"d":"152,-35v5,43,-16,36,-54,38v-58,2,-82,-47,-82,-121v0,-79,66,-97,129,-83v13,3,5,21,7,33v0,4,-3,5,-7,5v-38,-2,-81,-15,-81,45v0,39,6,88,34,81v24,0,33,-1,48,-3v4,0,6,1,6,5","w":168},"d":{"d":"184,-16v0,5,-1,8,-9,10v-22,6,-50,9,-73,9v-68,0,-86,-46,-86,-118v0,-69,48,-102,121,-88r0,-64v2,-13,27,-5,40,-7v4,0,7,3,7,7r0,251xm137,-39r0,-125v-56,-14,-73,13,-73,77v0,30,7,51,38,51v13,0,28,-2,35,-3","w":207},"e":{"d":"189,-114v0,11,4,29,-7,29r-117,1v0,21,8,48,43,46r67,-4v11,0,12,36,-1,39v-82,18,-157,8,-157,-111v0,-56,32,-92,87,-92v55,0,85,38,85,92xm65,-120v22,2,54,2,76,0v0,-28,-15,-45,-37,-45v-22,0,-39,17,-39,45","w":206},"f":{"d":"82,-278v12,0,40,-2,45,8v-2,9,5,28,-5,28v-32,0,-62,-7,-53,39r51,0v11,0,12,33,0,36r-51,0r0,159v-2,14,-26,6,-40,8v-4,0,-7,-4,-7,-8r0,-213v0,-46,27,-57,60,-57","w":136},"g":{"d":"184,-1v0,51,-26,73,-81,73v-30,0,-54,-5,-67,-9v-11,0,-12,-32,0,-33v35,-3,111,24,101,-31v-80,17,-121,-23,-121,-114v0,-56,28,-91,86,-91v23,0,51,4,73,10v8,2,9,5,9,10r0,185xm137,-39r0,-124v-7,-1,-22,-4,-35,-4v-41,-1,-38,40,-38,80v0,47,30,58,73,48","w":207},"h":{"d":"190,-8v-2,15,-27,6,-41,8v-4,0,-7,-4,-7,-8r0,-122v6,-39,-41,-39,-71,-33r0,155v-2,14,-26,6,-40,8v-4,0,-8,-4,-8,-8r0,-259v3,-13,27,-5,41,-7v4,0,7,3,7,7r0,65v63,-16,119,15,119,72r0,122","w":213},"i":{"d":"73,-269v-2,13,6,37,-7,39v-15,-2,-39,6,-43,-7v2,-14,-6,-37,8,-39v14,2,39,-6,42,7xm72,-8v-2,14,-26,6,-40,8v-4,0,-8,-4,-8,-8r0,-188v3,-13,27,-5,41,-7v4,0,7,3,7,7r0,188","w":96},"j":{"d":"73,-269v-2,13,6,37,-7,39v-14,-2,-39,6,-42,-7v2,-13,-6,-37,7,-39v14,2,39,-6,42,7xm19,72v-10,0,-30,2,-31,-9v2,-11,-6,-29,8,-29v0,0,28,4,28,-19r0,-211v3,-13,27,-5,41,-7v4,0,7,3,7,7r0,211v0,44,-20,57,-53,57","w":96},"k":{"d":"186,-7v3,3,0,7,-4,7v-19,-2,-46,6,-55,-7r-56,-82r0,81v-2,14,-26,6,-40,8v-4,0,-8,-4,-8,-8r0,-259v3,-13,27,-5,41,-7v4,0,7,3,7,7r0,150r61,-82v11,-9,32,-2,49,-4v6,-1,6,4,4,8r-72,88","w":197},"l":{"d":"73,-8v-2,15,-27,6,-41,8v-4,0,-7,-4,-7,-8r0,-259v2,-13,28,-5,41,-7v4,0,7,3,7,7r0,259","w":97},"m":{"d":"282,-8v-2,15,-27,6,-41,8v-4,0,-7,-4,-7,-8r0,-129v0,-28,-11,-30,-34,-29v-21,0,-24,11,-24,29r0,129v-1,15,-27,5,-41,8v-4,0,-6,-4,-6,-8r0,-129v2,-22,-8,-29,-33,-29v-17,0,-25,5,-25,29r0,129v-2,15,-27,6,-41,8v-4,0,-7,-4,-7,-8r0,-129v-9,-67,84,-87,129,-54v43,-32,130,-15,130,54r0,129","w":304},"n":{"d":"188,-8v0,15,-27,6,-41,8v-4,0,-7,-4,-7,-8r0,-124v4,-28,-16,-34,-46,-34v-21,0,-25,16,-25,34r0,124v-2,15,-27,6,-41,8v-4,0,-6,-4,-6,-8v3,-96,-26,-198,94,-198v95,0,72,111,72,198","w":209},"o":{"d":"189,-116v0,70,-18,119,-86,119v-68,0,-86,-49,-86,-119v0,-51,29,-90,86,-90v57,0,86,39,86,90xm103,-38v35,0,39,-37,39,-78v0,-30,-14,-49,-39,-49v-35,0,-38,38,-38,78v0,30,13,49,38,49","w":206},"p":{"d":"192,-115v0,86,-35,132,-121,115r0,64v-2,13,-27,5,-40,7v-4,0,-8,-3,-8,-7r0,-250v0,-5,2,-8,10,-10v22,-6,49,-10,72,-10v58,0,87,35,87,91xm105,-36v41,1,40,-39,39,-79v0,-30,-8,-52,-39,-52v-13,0,-27,2,-34,3r0,125v10,1,25,3,34,3","w":207},"q":{"d":"184,64v-2,13,-27,5,-40,7v-4,0,-7,-3,-7,-7r0,-64v-84,16,-121,-25,-121,-115v0,-56,28,-91,86,-91v23,0,51,4,73,10v8,2,9,5,9,10r0,250xm137,-39r0,-125v-7,-1,-22,-3,-35,-3v-41,-1,-38,40,-38,80v0,47,30,58,73,48","w":207},"r":{"d":"117,-199v-3,14,8,35,-11,33v-12,0,-26,1,-35,3r0,155v-2,14,-26,6,-40,8v-4,0,-8,-4,-8,-8r0,-176v0,-5,4,-9,10,-11v23,-8,42,-11,73,-11v4,0,11,2,11,7","w":125},"s":{"d":"89,3v-21,0,-84,9,-71,-37v15,-19,93,18,94,-19v-18,-39,-96,-42,-96,-99v0,-61,88,-60,133,-46v9,2,11,35,-1,36v-14,2,-84,-18,-84,10v19,31,96,51,96,99v0,31,-24,56,-71,56","w":176},"t":{"d":"127,-6v-4,12,-30,9,-49,9v-36,0,-56,-12,-56,-54r0,-182v5,-13,28,-9,41,-13v11,4,4,29,6,43r51,0v11,0,11,33,0,36r-51,0r0,116v-2,24,30,17,51,17v13,0,5,18,7,28","w":136},"u":{"d":"188,-84v-1,79,-60,87,-84,87v-21,0,-82,-9,-82,-87r0,-111v1,-15,27,-5,40,-8v4,0,7,4,7,8r0,111v0,38,14,46,37,46v21,0,34,-9,34,-46r0,-111v2,-15,27,-6,41,-8v4,0,7,4,7,8r0,111","w":209},"v":{"d":"148,-203v14,2,44,-6,41,8r-45,164v-15,48,-77,48,-90,0r-45,-166v3,-13,28,-3,41,-6v3,0,7,2,8,7r34,151v2,13,12,12,14,0r34,-151v1,-5,5,-7,8,-7","w":198},"w":{"d":"288,-90v0,97,-66,104,-132,84v-66,21,-132,12,-133,-84r0,-106v3,-13,26,-5,40,-7v4,0,7,3,7,7r0,106v2,59,24,51,62,52r0,-158v2,-13,27,-5,40,-7v4,0,8,3,8,7r0,158v38,-1,61,7,61,-52r0,-106v2,-13,27,-5,40,-7v4,0,7,3,7,7r0,106","w":311},"x":{"d":"193,-7v3,3,0,7,-4,7v-19,-3,-43,8,-52,-7r-41,-64r-39,64v-7,15,-30,4,-47,7v-4,0,-5,-4,-3,-7r65,-98r-62,-94v10,-7,47,-9,56,3r37,56r33,-56v8,-14,30,-4,48,-7v6,0,4,5,2,7r-59,91","w":200},"y":{"d":"192,-1v0,51,-26,73,-81,73v-30,0,-55,-5,-68,-9v-11,0,-12,-32,0,-33v38,-3,110,24,101,-31v-69,16,-121,-16,-121,-86r0,-109v3,-13,27,-5,41,-7v4,0,7,3,7,7v6,71,-31,185,73,157r0,-157v2,-13,27,-5,40,-7v4,0,8,3,8,7r0,195","w":214},"z":{"d":"162,-36v-2,12,6,36,-7,36r-126,0v-18,1,-19,-30,-10,-41r88,-122v-22,-6,-57,-2,-83,-2v-13,0,-5,-20,-7,-31v0,-4,3,-7,7,-7r123,0v18,0,16,29,12,44r-84,116v24,3,55,0,81,1v4,0,6,2,6,6","w":176},"\u00a0":{"w":90}}});
/**
 * --------------------------------------------------------------------------------------------
 *
 * Contains convenience methods, utilities and functionality that may be used across the application.
 * The point of the functions here is not to be binding functionality to specific elements,
 * but to provide re-usable functions that may bind behaviour to any element.
 *
 * --------------------------------------------------------------------------------------------
 */




/* Sometimes, a response data packet from the server (usually in response to some AJAX POST operation)
 * will contain experiment HTML and/or notification HTML. This intent of this is to tell the 
 * client-side that theres a notification message to show as a result of the action taken,
 * or an experiment to run that has been triggered by the operation.
 * 
 * This function checks the given data packet (expected to be the server JSON response)
 * and displays the notification / runs the experiment.
 */
function notificationAndExperimentResponse(data) {
    var experiment_html = data.experiment_html;
    var notification_html = data.notification_html;
    if (notification_html != undefined) {
        /* We have a notification message to display - is there
         * already the HTML for this in the DOM? If so, replace */
        if ($("span.notification-message").length) {
            $("span.notification-message").replaceWith(notification_html);
        } else {
            $("body").append(notification_html);
        }

        /* Display the notification message */
        displayNotificationMessage();
    }

    if (experiment_html != undefined) {
        /* We have an experiment to run */
        if ($("div.experiment").length) {
            $("div.experiment").replaceWith(experiment_html);
        } else {
            $("body").append(experiment_html);
        }
        /* If the experiment is configured to be currently running for this user,
         * invoke it.
         */
        if (isExperimentRunning('share_on_mob_rsvp')) {

            /* See if we've got the HTML for the mob sharing lightbox
             * already attached to the data. If so, pass it to the function in the
             * params hash.
             */
            params = {};
            if (data.share_mob_lightbox_html != undefined) {
                params.share_mob_lightbox_html = data.share_mob_lightbox_html;
            }
            runExperiment('share_on_mob_rsvp', params);
        }
    }
}



/**
 * Replaces the contents of the given element (jquery element object) with the loading spinner
 * div.
 *
 * @param <jQuery element> element_to_replace The element to replace with a loading spinner
 * @param <bool> maintain_dimensions Whether or not we are to maintain the CSS height and width for the element to replace with
 *               the loading spinner div when we do. i.e do we copy the CSS height and width to the spinner div (defaults to false).
 * @param <bool> fadeout Whether or not to provide a fadeout effect for the existing content before we display the spinner (defaults to false).
 */
function displayLoadingSpinner(element_to_replace, maintain_dimensions, fadeout) {

    /* Default to not fading out the original content */
    if (fadeout == null) {
        fadeout = false;
    }

    /* Default to not maintaining dimensions and letting the div autosize
     * to its content */
    if (maintain_dimensions == null) {
        maintain_dimensions = false;
    }

    var loading_spinner_div = $('div#ajax_loading_div_to_clone').clone();

    /* Make it displayable, and change its ID to the proper one */
    loading_spinner_div.css( {
        'display' : 'block'
    } );
    if (maintain_dimensions) {
        loading_spinner_div.css( {
            'height' : element_to_replace.css('height'),
            'width' : element_to_replace.css('width')
        });
    }

    new_id = element_to_replace.attr('id') + '_ajax_loading';
    loading_spinner_div.attr('id', new_id);

    /* replace the element, with the optional animation */
    if (fadeout) {
        element_to_replace.animate({
            'opacity' : '0.0'
        }, 'slow',
        function() {
            element_to_replace.html(loading_spinner_div);
            element_to_replace.css({
                'opacity' : '1.0'
            });
        });
    } else {
        element_to_replace.html(loading_spinner_div);
        element_to_replace.css({
            'opacity' : '1.0'
        });
    }
}


/* Replaces the mobstream by templating the given data against the HTML template used to render the mobstream,
 * before replacing the mobstream element with the resultant HTML.
 *
 * This means that the data parameter provided has to exhibit the same structure as the JSON structure returned from
 * the server on a mobstream request.
 */
function replaceMobstream(data) {

    if ($("div#mobstream").length && $("#mobstream_html_template").length) {
        var replaceable_element = $("#mobstream_html_template").tmpl(data);
        replaceable_element.css({
            'opacity' : '0.0'
        });
        $("div#mobstream").replaceWith(replaceable_element);
        $("div#mobstream").animate({
            'opacity' : '1.0'
        }, 'slow');
        mobstreamSharingButtons();
        seeAllMobsLinks();
    }

}



/**
 * If there's the expected HTML structure in the document (indicating
 * a notification message to display), do so. Otherwise, this method does
 * nothing.
 *
 */
function displayNotificationMessage() {
    if ($("span.notification-message").length) {
        /* We only take the first one */
        var notification_span = $('body').find("span.notification-message");
        var notification_bar = $('<div id="notification_bar"/>');
        var message = notification_span.text();

        /* If we haven't got a message, abort here. */
        if (message == null || message == '' ) {
            return;
        }

        /* Copy the text and CSS classes of the span in the HTML over to the
         * div to display the notification message */
        notification_bar.text(message);
        notification_bar.attr('class', notification_span.attr('class'));

        notification_bar.bind('click', function() {
            $(this).slideUp(200);
        });
        $(document.body).append(notification_bar);

        /* Show the notification bar half a second after page load - hide it 4 seconds later */
        setTimeout(function() {
            $("#notification_bar").slideDown("slow");
        }, 500);

        /* Slide the message back up out of sight, and delete the element from the DOM once the animation
         * is over */
        setTimeout(function() {
            notification_bar.slideUp("slow", function() {
                $("div#notification_bar").remove();
            });
        }, 4500);
    }
}




/**
 * User history event registering.
 *
 * @param key The key of the user history event to register
 * @param value The value of the user history event to register
 * @return bool true if successful, false otherwise.
 */
function registerUserHistoryEvent(key, value) {
    $.post(USER_HISTORY_URL, {
        "user_history" : [ {
            "key" : key,
            "value" : value
        }]
    },
    function(data) {
        if (data.result == "success") {
            return true;
        }
        return false;
    }, 'json');
}






/**
 * Author - Rudolf Naprstek
 * Website - http://www.thimbleopensource.com/tutorials-snippets/jquery-plugin-filter-text-input
 * Version - 1.2.0
 * Release - 20th November 2010
 *
 * Thanks to Niko Halink from ARGH!media for bugfix!
 *
 */

(function($){
    $.fn.extend({

        filter_input: function(options) {

            var defaults = {
                regex:".*",
                live:false
            }

            var options =  $.extend(defaults, options);
            var regex = new RegExp(options.regex);

            function filter_input_function(event) {

                var key = event.charCode ? event.charCode : event.keyCode ? event.keyCode : 0;

                // 8 = backspace, 9 = tab, 13 = enter, 35 = end, 36 = home, 37 = left, 39 = right, 46 = delete
                if (key == 8 || key == 9 || key == 13 || key == 35 || key == 36|| key == 37 || key == 39 || key == 46) {

                    if ($.browser.mozilla) {

                        // if charCode = key & keyCode = 0
                        // 35 = #, 36 = $, 37 = %, 39 = ', 46 = .

                        if (event.charCode == 0 && event.keyCode == key) {
                            return true;
                        }

                    }
                }


                var string = String.fromCharCode(key);
                if (regex.test(string)) {
                    return true;
                }
                return false;
            }

            if (options.live) {
                $(this).live('keypress', filter_input_function);
            } else {
                return this.each(function() {
                    var input = $(this);
                    input.unbind('keypress').keypress(filter_input_function);
                });
            }

        }
    });

})(jQuery);/**
 * ------------------------------------------------------------------------------------------------------------------------------
 *
 * Contains behaviour and logic used generally throughout the site
 *
 * ------------------------------------------------------------------------------------------------------------------------------
 */

/**
 * Attaches the twitter-styled tooltip (using the poshytip plugin)
 * to all elements matching the given selector string.
 **/
function attachToolTips(selector_string, class_name) {
    var show_in = 100;
    $("" + selector_string).each(function() {
        var text = $(this).attr('alt');
        $(this).poshytip({
            className: class_name,
            slide: false,
            showAniDuration: 50,
            alignX: 'center',
            alignY: 'top',
            showTimeout: show_in,
            showOn: 'hover',
            content: text
        });
    });
}

function attachFlagTips(selector_string, class_name) {
    var show_in = 100;
    $("" + selector_string).each(function() {
        var text = $(this).attr('title');
        $(this).poshytip({
            className: class_name,
            slide: false,
            showAniDuration: 100,
            alignX: 'right',
            offsetX:10 ,
            offsetY: -37,
            alignTo: 'target', 
            showTimeout: show_in,
            showOn: 'hover',
            content: '<b>Mob</b>Pass holders get deals on workouts. <br/> <a class="pass-store-link" href="http://mobpass.trainingmobs.com">Get a <b>Mob</b>Pass now!</a>'
        });
    });
}

/**
 * If we're on the find mobs page, this function will asynchronously load the mobstream from the server and
 * display it.
 */
function loadMobstream() {

    /** Whether or not we're serving the mobstream on the find mobs page using
     * AJAX or embedded into the server-provided HTML. If we've got the mobstream_form available,
     * we serve with AJAX.
     */
    if ($("div.find-mobs-page").length && $("form#mobstream_form").length) {

        var mobstream_element = $('div#mobstream');
        /* Display the AJAX loading spinner */
        displayLoadingSpinner(mobstream_element);

        /* The action we use is the mobstream URL with the format query param to tell
         * it to give us back HTML */
        var mobstream_action = $("form#mobstream_form").attr('action') + '&format=json';
        /* Make the request to get the mobstream */
        $.getJSON(mobstream_action,
            null,
            function(data) {

                /* Store the mobstream data response in the DOM for use by other logic on this page */
                $('body').data('mobstream_data_response', data);

                /* Initialize the filtering map (if filtering is enabled - if not, we won't have
                 * this function) */
                if (typeof initializeLocationFilterMap == 'function') {
                    initializeLocationFilterMap();
                }
                
                /* Call the worker in charge of actually replacing the mobstream and re-attaching
                 * the sharing button logic.
                 */
                replaceMobstream(data);
            }
        );
    }
}


/**
 * Attaches logic to the 'see all mobs' links at the bottom of each day block in the mobstream
 * to show an expanded list of mobs for the day.
 */
function seeAllMobsLinks() {
    /* Attach logic to the 'see all mobs' links at the bottom of each mobstream day section */
    var base_mobstream_day_url = $("form#mobstream_day_url_form").attr('action');
    $("div.find-mobs-page .see-all-mobs a").each(function() {
        $(this).click(function(e) {
            e.preventDefault();

            /* Grab the mobs for this day in the mobstream */
            var day_identifier = $(this).attr('data-day-identifier');
            var mobstream_day_url = base_mobstream_day_url + day_identifier;
            var replacement_selector = 'div[data-mobstream-day-identifier="' + day_identifier + '"]';
            displayLoadingSpinner($(replacement_selector), true, true);

            /* Display the loading animation */
            $.getJSON(mobstream_day_url, null, function(data) {

                /* Need to build the data we provide to the template. We augment
                 * the data array provided with some worked out variables that the
                 * template needs */
                data.day_label = data.day_identifiers_to_labels[day_identifier];
                data.day_identifier = day_identifier;
                data.day_mobs = data.mobs_by_day[data.day_label];
                if (data.day_label == undefined || data.day_identifier == undefined || data.day_mobs == undefined) {
                    throw Error("Could not update returned data array from [ " + mobstream_day_url + " ] - templated HTML will break");
                }
                var replaceable_element = $("#mobstream_day_html_template").tmpl(data);
                replaceable_element.css({
                    'opacity' : '0.0'
                });
                $(replacement_selector).replaceWith(replaceable_element);
                $(replacement_selector).animate({
                    'opacity' : '1.0'
                }, 'slow');
                mobstreamSharingButtons();
            });

        });
    });
}


/* Initializes every autocomplete field on the site. If its on the current page, and it needs autocomplete functionality,
 * it should be here
 */
function initializeAutocomplete() {

    /* The response from the top tags endpoints aren't what we need for the autocomplete plugin - need
     * to Array-ify it.
     */
    function processTopTagsData(response_text) {
        var top_tags = jQuery.trim(response_text);
        var tags_data = new Array();
        var pieces = top_tags.split('\n');
        for (var curr_piece in pieces) {
            var id_and_name = jQuery.trim(pieces[curr_piece]).split('|');
            tags_data.push([jQuery.trim(id_and_name[0]), jQuery.trim(id_and_name[1])]);
        }
        return tags_data;
    }


    var multi_autocomplete_params = {
        formatItem : function(item)
        {
            return item[0];
        },
        autoFill : false,
        formatResult : function(item)
        {
            return item[0];
        },
        minChars : 3,
        selectFirst : true,
        multiple: true,
        matchContains : true,
        delay: 50,
        max: 5
    };

    var single_autocomplete_params = {
        formatItem : function(item)
        {
            return item[1];
        },
        autoFill : false,
        formatResult : function(item)
        {
            return item[1];
        },
        minChars : 3,
        selectFirst : true,
        multiple: false,
        matchContains : true,
        delay: 50,
        max: 5
    };


    /* Attach the autocomplete functionality on the user activities field */
    if ($("input#user_activities").length) {

        /* Fire off the call to grab the top user activities tags for the
         * autocomplete field. Give it 2 seconds to do its thing (bind to the
         * autocomplete field).
         */
        var top_user_activities = null;

        if ($("form#top_user_activities_form").length) {
            var request_url = $("form#top_user_activities_form").attr('action');
            $.ajax({
                url: request_url,
                data: null,
                success: function(response_text)
                {
                    top_user_activities = jQuery.trim(response_text);
                    var activities_data = processTopTagsData(top_user_activities);
                    multi_autocomplete_params.max = 7;
                    multi_autocomplete_params.minChars = 1;
                    $("input#user_activities").autocomplete(activities_data, multi_autocomplete_params);
                },
                dataType: 'text',
                timeout: 2000
            });
        }
        setTimeout( function()
        {
            /* Check if we haven't got the top user activities (either cause its not enabled or took too long).
              * Fallback functionality is the per-request autocomplete based on what the user typed.
              */
            if (top_user_activities == null) {
                var autocomplete_user_activities_url = $("input#autocomplete_user_activities_url").val();
                $("input#user_activities").autocomplete(autocomplete_user_activities_url, multi_autocomplete_params);
            }
        }, 2000);
    }

    /* Attach the autocomplete functionality on the mob tags field */
    if ($("input#tags").length) {

        /* Fire off the call to grab the top mob tags for the
         * autocomplete field. Give it 2 seconds to do its thing (bind to the
         * autocomplete field).
         */
        var top_mob_tags = null;

        if ($("form#top_mob_tags_form").length) {
            var tags_request_url = $("form#top_mob_tags_form").attr('action');
            $.ajax({
                url: tags_request_url,
                data: null,
                success: function(response_text)
                {
                    top_mob_tags = jQuery.trim(response_text);
                    var mob_tags_data = processTopTagsData(top_mob_tags);
                    multi_autocomplete_params.max = 7;
                    multi_autocomplete_params.minChars = 1;
                    $("input#tags").autocomplete(mob_tags_data, multi_autocomplete_params);
                },
                dataType: 'text',
                timeout: 2000
            });
        }
        setTimeout( function()
        {
            /* Check if we haven't got the top mob tags (either cause its not enabled or took too long).
              * Fallback functionality is the per-request autocomplete based on what the user typed.
              */
            if (top_mob_tags == null) {
                var autocomplete_mob_tags_url = $("input#autocomplete_mob_tags_url").val();
                $("input#tags").autocomplete(autocomplete_mob_tags_url, multi_autocomplete_params);
            }
        }, 2000);
    }


    /* Attach the autocomplete functionality on the mob type field */
    if ($("input#type").length) {

        /* Fire off the call to grab the top mob type tags for the
         * autocomplete field. Give it 2 seconds to do its thing (bind to the
         * autocomplete field).
         */
        var top_mob_types = null;

        if ($("form#top_mob_types_form").length) {
            var types_request_url = $("form#top_mob_types_form").attr('action');
            $.ajax({
                url: types_request_url,
                data: null,
                success: function(response_text)
                {
                    top_mob_types = jQuery.trim(response_text);
                    var mob_types_data = processTopTagsData(top_mob_types);
                    single_autocomplete_params.minChars = 1;
                    $("input#type").autocomplete(mob_types_data, single_autocomplete_params);
                },
                dataType: 'text',
                timeout: 2000
            });
        }
        setTimeout( function()
        {
            /* Check if we haven't got the top mob types (either cause its not enabled or took too long).
              * Fallback functionality is the per-request autocomplete based on what the user typed.
              */
            if (top_mob_types == null) {
                var autocomplete_mob_types_url = $("input#autocomplete_mob_types_url").val();
                $("input#type").autocomplete(autocomplete_mob_types_url, single_autocomplete_params);
            }
        }, 2000);
    }

}



/* ------------------ On-boarding ------------------ */

function onboardingMobstreamMessage() {
    setTimeout( function() {
        $("#onboarding_mobstream").animate({
            "height": "toggle"
        }, {
            duration: 500
        });
    }, 500 );
    $("#onboarding_mobstream .close-onboarding-message a").click( function(e) {
        e.preventDefault();
        $("#onboarding_mobstream").animate({
            "height": "toggle"
        }, {
            duration: 500
        });

        /* Register the user history event of dismissing this message, so that it isn't displayed again to this user */
        registerUserHistoryEvent("dismissed_mobstream_info", "true");

    });
}
function onboardingSocialInviteMessage(show_mobstream_info) {
    setTimeout( function() {
        var message_content = $("#onboarding_social_invite").clone().css({
            "display" : "block"
        });

        /* Need to attach the close button handler to the cloned element (IE7 craps itself
             * otherwise) */
        message_content.find(".close-onboarding-message a").click( function(e) {
            e.preventDefault();
            $("#social_invite_panel").poshytip('hide');

            /* Register the user history event of dismissing this message, so that it isn't displayed again to this user */
            registerUserHistoryEvent("dismissed_social_invite_info", "true");

            if (show_mobstream_info) {
                onboardingMobstreamMessage();
            }
        });

        $("#social_invite_panel").poshytip({
            className: 'tip-onboarding-message',
            content: message_content,
            showOn: 'none',
            alignTo: 'target',
            alignX: 'center',
            offsetX: 0,
            offsetY: 10
        });
        $("#social_invite_panel").poshytip('show');

    }, 500 );
}

/* Start the onboarding fornt-end work from the intro message. This is the intro
     * message that users see the first time they log into trainingmobs.com */
function onboardingIntroMessage(show_social_invite_info, show_mobstream_info) {

    /* Attach the lightbox closing logic to the
         * 'next' button on the info lightbox */
    $('form#close_intro_message_form').submit( function(e) {
        e.preventDefault();
        $.fancybox.close();
    });

    $('a#intro_message_link').fancybox(
    {
        onClosed : function() {

            registerUserHistoryEvent("dismissed_onboarding_intro", "true");

            /* Once the user closes the intro message, we fire off the first onboarding message */
            if (show_social_invite_info) {
                onboardingSocialInviteMessage(show_mobstream_info);
            }
        }
    });
    $('a#intro_message_link').trigger('click');
}

/* Perform the onboarding (if required) */
function onboarding() {
    var show_mobstream_info = true;
    var show_social_invite_info = true;
    var show_intro_lightbox = true;

    $.getJSON(USER_HISTORY_URL,
        null,
        function(data)
        {
            var history = data.user_history;
            var login_count = 0;
            for (var index in history) {
                var record = history[index];
                if (record.key == 'dismissed_mobstream_info') {
                    show_mobstream_info = false;
                }
                if (record.key == 'dismissed_social_invite_info') {
                    show_social_invite_info = false;
                }
                if (record.key == 'dismissed_onboarding_intro') {
                    show_intro_lightbox = false;
                }
            }

            /* Decide what we show / where we start the onboarding logic from */
            if (show_intro_lightbox) {
                return onboardingIntroMessage(show_social_invite_info, show_mobstream_info);
            } else if (show_social_invite_info) {
                return onboardingSocialInviteMessage(show_mobstream_info);
            } else if (show_mobstream_info) {
                return onboardingMobstreamMessage();
            }
        });

}





$(document).ready( function() {

    loadMobstream();
    initializeAutocomplete();

    /* If theres a notification message rendered in the HTML, display it */
    displayNotificationMessage();

    /* Attach a pretty twitter-style tooltip to every image and button element requesting it (with the
     * 'alt-tip' class)
     */
    attachToolTips("img.alt-tip", "tip-twitter");
    attachToolTips("button.alt-tip", "tip-twitter");





    /* Give focus to the first input field that requests it (should only be one per page) */
    $("input.first-focus").first().focus();
    

    /* Make textareas vertically resizable */
    if ($('.resizable-textarea textarea').length) {
        $('.resizable-textarea textarea').each( function() {
            $(this).TextAreaResizer();
        });
    }

    /* Track when the user has clicked the 'invite my friends using facebook' button */
    if ($('a#invite_friends_facebook_button').length) {
        $('a#invite_friends_facebook_button').click( function() {
            mpmetrics.track('invite_friends_facebook_button_clicked', {
                'user_public_name' : USER_PUBLIC_NAME
            });
        });
        
    }

    /* Track when the user has clicked the 'invite my friends using gmail' button */
    if ($('a#invite_friends_gmail_button').length) {
        $('a#invite_friends_gmail_button').click( function() {
            mpmetrics.track('invite_friends_gmail_button_clicked', {
                'user_public_name' : USER_PUBLIC_NAME
            });
        });
        
    }

    /* Track when the user has clicked the 'invite my friends using yahoo' button */
    if ($('a#invite_friends_yahoo_button').length) {
        $('a#invite_friends_yahoo_button').click( function() {
            mpmetrics.track('invite_friends_yahoo_button_clicked', {
                'user_public_name' : USER_PUBLIC_NAME
            });
        });

    }

    /* Track when the user has clicked the 'invite my friends using live' button */
    if ($('a#invite_friends_live_button').length) {
        $('a#invite_friends_live_button').click( function() {
            mpmetrics.track('invite_friends_live_button_clicked', {
                'user_public_name' : USER_PUBLIC_NAME
            });
        });
    }



    /* Track when the user has viewed the find mobs page */
    if ($("div.find-mobs-page").length) {
        mpmetrics.track("find_mobs_page_displayed", {
            'user_public_name' : USER_PUBLIC_NAME
        });
    }

    /* Track when users are clicking through to people's profiles from
     * the facepile */
    if ($("a.facepile-link").length) {
        $("a.facepile-link").click( function() {
            var user_name = $(this).find('img').attr('alt');
            mpmetrics.track("facepile_image_clicked", {
                'user' : user_name
            });
        })
    }

    /* Track when a user's profile has been visited */
    if ($("div.user-profile-page").length) {
        mpmetrics.track("user_profile_visited");
    }


    /**
     * Soup up the textareas into WYSIWYG HTML editors.
     */
    if ($("textarea.cl-editor").length) {
        $("textarea.cl-editor").each( function() {
            var width = $(this).width();
            var height = $(this).height();

            var bodyStyles = '';
            var styles = [ "margin-top", "margin-left", "margin-right", "margin-bottom", "color", "vertical-align",
            "background-color", "padding-left", "padding-right", "padding-top", "padding-bottom",
            "font-family", "font-size", 'line-height', 'letter-spacing' ];
            for (var i = 0; i < styles.length; i++) {
                bodyStyles = bodyStyles + styles[i] + " : " + $(this).css('' + styles[i]) + "; ";
            }

            $(this).cleditor({
                width : width,
                height : height + 80,
                controls : "bold italic | image link",
                bodyStyle : bodyStyles
            });
        });
    }

    

    /* Add an opacity animation to buttons to indicate that they can be clicked */
    if ($('input[type="submit"]').length != 0) {
        $('input[type="submit"]').each( function() {
            $(this).hover(function() {
                $(this).css({
                    opacity : 0.7
                });
            }, function() {
                $(this).css({
                    opacity : 1
                });
            });
        });
    }
    if ($('a.button').length != 0) {
        $('a.button').each( function() {
            $(this).hover(function() {
                $(this).css({
                    opacity : 0.7
                });
            }, function() {
                $(this).css({
                    opacity : 1
                });
            });
        });
    }
    if ($('.lightbox-button').length != 0) {
        $('.lightbox-button').each( function() {
            $(this).hover(function() {
                $(this).css({
                    opacity : 0.7
                });
            }, function() {
                $(this).css({
                    opacity : 1
                });
            });
        });
    }


    /* Attach submission logic to the search bar's search form(s) */
    if ($('input#search_submit').length) {
        $('form#search_form').submit( function(e) {
            e.preventDefault();
            /* Find out what kind of search we're performing - users or mobs and change the location
             * of the document to the built URL.
             *
             *  NOTE here that we change the URL inside a callback to the MixPanel tracking method, since
             *  we need to provide it time to return before we change location.
             */
            var search_type = $('select#search_type_select option:selected').attr('value');
            if (search_type == 'mobs') {

                /* [url]/?context=[mob search context]&search_term=[search term] */
                var search_url = $('form#search_form').attr('action')
                + '?context=' + $('input#search_context').attr('value')
                + '&search_term=' + $('input#search_term').val();

                mpmetrics.track('mobs_search', {
                    'search_term' : $('input#search_term').val()
                },
                function() {
                    document.location = search_url;
                });
                
            } else if (search_type == 'users') {
                /* [url]/?search_term=[search term] */
                var search_url = $('form#users_search_form').attr('action') + '?search_term=' + $('input#search_term').val();
                mpmetrics.track('users_search', {
                    'search_term' : $('input#search_term').val()
                },
                function() {
                    document.location = search_url;
                });
                
            }

        })
    }











    

    /* If we have the link to open up the intro message lightbox and start off the
     * onboarding chain, invoke this functionality. */
    if ($("a#intro_message_link").length) {
        onboarding();
    }

});


/*
 * Contains the client-side validation code for the form submissions that have
 * been enabled with it. This file will also contain the submission logic for those forms
 * which have been AJAX-enabled to provide client-side validation.
 */
$(document).ready( function() {

    /* Attach popup validation messages show/hide logic on the register form input fields
     * and their labels */
    var validation_label_positions = [];
    validation_label_positions['name'] = 'left';
    validation_label_positions['email_address'] = 'left';
    validation_label_positions['prefslug'] = 'left';
    validation_label_positions['password'] = 'left';
    validation_label_positions['password_conf'] = 'right';
    validation_label_positions['city'] = 'left';
    validation_label_positions['state'] = 'right';
    validation_label_positions['country'] = 'left';
    validation_label_positions['dob'] = 'left';
    validation_label_positions['sex'] = 'right';

    if( typeof( proRegistration ) != "undefined" && proRegistration == true )
    {
        validation_label_positions['cc_first_name'] = 'left';
        validation_label_positions['cc_last_name'] = 'right';
        validation_label_positions['cc_number'] = 'left';
        validation_label_positions['cc_month'] = 'left';
        validation_label_positions['cc_year'] = 'right';
        validation_label_positions['cc_type'] = 'left';
        validation_label_positions['proaccount_type'] = 'right';
    }

    var register_button_text = null;

    var doRegisterSubmission = function() {
        var submit_action = $("form#register").attr('action');

        var register_data = {
            name : $("#name").val(),
            prefslug: $("#prefslug").val(),
            email_address : $("#email_address").val(),
            password : $("#password").val(),
            password_conf : $("#password_conf").val(),
            city : $("#city").val(),
            state : $("#state").val(),
            country : $("#country").val(),
            sex : $("select#sex option:selected").val()
        };

        /* Fields that may not always be present... */
        if ($("#dob").length) {
            register_data.dob = $("#dob").val();
        }
        if ($("#invite_code").length) {
            register_data.invite_code = $("#invite_code").val();
        }
        if ($("#at_sxsw").length) {
            register_data.at_sxsw = $("#at_sxsw").val();
        }

        /* Fields that are only relevant in the case of Pro registration... */
        if( typeof( proRegistration ) != "undefined" && proRegistration == true ) {
            register_data.proaccount_type = $("#proaccount_type").val();
        }
        
        /* Submit the registration form */
        $.post(submit_action, register_data, function(data) {
            /* Clear the error displays */
            $("span#error-holder").html('<div></div>');

            mpmetrics.track("register_user_attempt");

            if (data.result == 'failure' && data.errors != undefined) {

                $('form#register input[type="submit"]').attr('value', register_button_text);
                $('form#register input[type="submit"]').removeAttr('disabled');
                $('form#register input[type="submit"]').css({
                    opacity : 1
                });

                /* We don't want to send the user's password and other sensitive data to mixpanel */
                var input_to_track = { name : register_data.name,
                                       email_address : register_data.email_address,
                                       city : register_data.city,
                                       state : register_data.state,
                                       country : register_data.country };

                mpmetrics.track("register_user_validation_failure", { 'input' : JSON.stringify(input_to_track),
                                                                      'errors' : JSON.stringify(data.errors) });

                /* Display the errors */
                if (data.errors != undefined && data.errors.length != 0) {
                    /* Build the HTML to insert */
                    var html = '<div class="row"><div class="error-block"><ul>';
                    for (var key in data.errors) {
                        html = html + '<li>' + data.errors[key] + '</li>';
                    }
                    html = html + '</ul></div></div>';
                    $("span#error-holder").html(html);
                }

                /* Scroll to the top of the page so the user is aware
	         * of the validation errors.
	         */
                $('body').scrollTo(0, 500, {
                    axis : 'y',
                    easing: 'swing'
                });
            } else if (data.result == 'success') {
                mpmetrics.track('register_user_success', {}, function() {
                    window.location.replace(data.redirect);
                });
                setTimeout(function() {
                    window.location.replace(data.redirect);
                }, 1000);
            } else {
                // This is unexpected behaviour - should probably do something about it!
            }
        }, 'json');
    };


    /* Method invoked to submit user registration form */
    var registerSubmit = function(form) {

        /* Notify the user of the operation in progress by changing the text on the button
         * and disabling it */
        register_button_text = $('form#register input[type="submit"]').attr('value');
        $('form#register input[type="submit"]').attr('value', 'Working...');
        $('form#register input[type="submit"]').css({
            opacity : 0.7
        });
        $('form#register input[type="submit"]').attr('disabled', 'disabled');



        /* If the feature flag for the SXSW registration prompt is activated, display the prompt. */
        if ($("a#sxsw_registration_prompt_link").length) {

            /* Attach the logic for what happens if the user clicks the "I'm at SXSW!"
             * button - we set the value of the hidden input (so we can grab it during form submission)
             * and we set the city and country right before we submit the registration form.
             */
            $("#sxsw_registration_yes").click( function(e) {
                e.preventDefault();

                $("#city").val("Austin, Texas");
                $("#country").val("United States");
                $("#at_sxsw").val("true");
                $.fancybox.close();
            });

            /* Attach the 'No, not at SXSW' logic - just close the box */
            $("#sxsw_registration_no").click( function(e) {
                e.preventDefault();
                $.fancybox.close();
            });


            /* Attach the lightbox. We submit the registration form upon closing of the lightbox. */
            $('a#sxsw_registration_prompt_link').fancybox(
            {
                onClosed : doRegisterSubmission
            });
            /* Open it up */
            $('a#sxsw_registration_prompt_link').click();

        } else {
            doRegisterSubmission();
        }
    };

    var rulesArray = {
        name : {
            required : true
        },
        prefslug : {

        },
        city : {
            required : true
        },
        state : {
            required : true
        },
        country : {
            required : true
        },
        email_address : {
            required : true,
            email : true
        },
        password : {
            required : true,
            minlength : 6
        },
        password_conf : {
            required : true,
            minlength : 6,
            equalTo : "#password"
        },
        sex : "required"
    };
    if ($("#dob").length) {
        rulesArray.dob = { required : true };
    }


    var messagesArray =
    {
        name : {
            required : "We need to know your name"
        },
        prefslug : {

        },
        city : {
            required : "Where are you?"
        },
        state : {
            required : "Which state or province do you live in?"
        },
        country : {
            required : "Which country do you live in?"
        },
        email_address : {
            required : "We need your email address",
            email : "Hmmm... are you sure this is right?"
        },
        password : {
            required : "You need to choose a password",
            minlength : "Your password is too short (6 character minimum)"
        },
        password_conf : {
            required : "Don't forget to confirm your password!",
            minlength : "This can't be your password - its too short",
            equalTo : "Doesn't match your password - try again"
        },
        sex : {
            required : "We need to know if you're a boy or a girl"
        }
    };
    if ($("#dob").length) {
        messagesArray.dob = { required : "We wish we didn't have to ask, but you need to be of a minimum age to use Training Mobs. This is all we need it for - it won't be visible anywhere" };
    }



    if( typeof( proRegistration ) != "undefined" && proRegistration == true )
    {
        rulesArray.cc_first_name = {
            required : true
        };
        rulesArray.cc_last_name = {
            required : true
        };
        rulesArray.cc_number = {
            required : true,
            minlength : 16
        };
        rulesArray.cc_year = {
            required : true
        };
        rulesArray.cc_month = {
            required : true
        };
        rulesArray.cc_type = {
            required : true
        };
        rulesArray.proaccount_type = {
            required : true
        };
		
        messagesArray.cc_first_name = {
            required : "We need your first name"
        };
        messagesArray.cc_last_name = {
            required : "We need your last name"
        };
        messagesArray.cc_number = {
            required : "We need your credit card number",
            minlength : "This credit card number is too short"
        };
        messagesArray.cc_year = {
            required : "We need the expiration year from your credit card"
        };
        messagesArray.cc_month = {
            required : "We need the expiration month from your credit card"
        };
        messagesArray.cc_type = {
            required : "We need to know the type of credit card you're using"
        };
        messagesArray.proaccount_type = {
            required : "Pro account type is required"
        };
    }

    /* Attach client-side validation to the registration form */
    $("form#register").validate({
        onkeyup: false,
        errorClass : 'invalid',
        /* Remove the tooltip on successful validation */
        success : function(label) {
            var input_id = label.attr('for');
            $('form#register input#' + input_id).poshytip('disable');
        },
        /* On invalid form submit, we hide the validation message <label> elements */
        showErrors : function(errorMap, errorList) {
            this.defaultShowErrors();

            $('label[generated="true"][class*="invalid"]').each( function() {
                $(this).css( {
                    'display' : 'none'
                });
            });
        },
        /* Display an error tooltip on failed validation */
        errorPlacement : function(error, element) {
            var label_text = error.text();
            if (label_text == '') {
                return;
            }
            var input_id = error.attr('for');
            $('form#register input#' + input_id).poshytip('disable');
            $('form#register input#' + input_id).poshytip({
                className: 'tip-yellowsimple',
                showOn: 'none',
                alignTo: 'target',
                offsetX: 10,
                alignX: validation_label_positions[input_id],
                alignY: 'center',
                content: label_text
            });
            $('form#register input#' + input_id).poshytip('show');

        },
        rules : rulesArray,
        messages : messagesArray, 
        submitHandler : registerSubmit
    });
});



/** Binds all necessary view logic to the sharing buttons on the mobstream (facebook and twitter mob sharing) */
function mobstreamSharingButtons() {
    /* Mobstream sharing buttons - getting the hover logic right. */
    if ($('ul.highlight-on-hover li .mobrow-social').length) {
        $('ul.highlight-on-hover li .mobrow-social').each( function() {
            $(this).find('.twitter img').each( function() {
                var twitter_img = $(this).attr('src');
                var rollover_image = $(this).parent().siblings('img.twitter-rollover').attr('src');
                $(this).hover( function() {
                    $(this).attr('src', rollover_image);
                }, function() {
                    $(this).attr('src', twitter_img);
                });
            });

            $(this).find('.facebook img').each( function() {
                var facebook_img = $(this).attr('src');
                var rollover_image = $(this).parent().siblings('img.facebook-rollover').attr('src');
                $(this).hover( function() {
                    $(this).attr('src', rollover_image);
                }, function() {
                    $(this).attr('src', facebook_img);
                });
            });
        });
    }

    /* Give them pretty twitter-style tooltips (if they've requested them with the alt-tip class) */
    /*attachToolTips(".right-buttons img.alt-tip", "tip-twitter");*/
     mobstreamPassFlags();
}


function mobstreamPassFlags() {
    attachFlagTips("div.pass-flag", "tip-pass-flag");
}

/** Function to bind to the facebook and twitter sharing buttons - those that currently exist and those to come.
 * Only call this method once, since it uses the jQuery live() functionality to bind to these buttons,
 * whether they exist at the time of the call to this method or not.
 */
function socialSharingButtons() {

    /* Attach to the social sharing buttons */
    $("a.facebook").live('click', function(e) {
        e.preventDefault();

        /* If we've got the extra data provided in the element we expect, we can use the facebook javascript SDK to share this mob */
        if ($(this).find(".facebook-share-info").length) {
            /* Build the data we need for the SDK call. */
            var share_data = $(this).find(".facebook-share-info");
            var link = share_data.attr('data-url');
            var text = share_data.attr('data-text');
            var picture = share_data.attr('data-picture');
            var caption = share_data.attr('data-caption');
            var name = share_data.attr('data-name');

            FB.ui({
                method: 'feed',
                name: name,
                link: link,
                picture: picture,
                caption: caption,
                description: text,
                actions: [{
                    name: "Join this Mob!",
                    link: link
                }]
            }, function() {
                mpmetrics.track('share_mob_facebook', {
                    'user_public_name' : USER_PUBLIC_NAME
                });
            });
        } else {
            mpmetrics.track('share_mob_facebook', {
                'user_public_name' : USER_PUBLIC_NAME
            });

            var width  = 575,
            height = 400,
            left   = ($(window).width()  - width)  / 2 + 200,
            top    = ($(window).height() - height) / 2;

            var share_url = $(this).attr('href');
            window.open(share_url, 'facebook', ['status=1,width=',width,',height=',height,',top=',top,',left=',left].join(''));
        }

        

    });

    $("a.twitter").live('click', function(e) {
        e.preventDefault();

        mpmetrics.track('share_mob_twitter', {
            'user_public_name' : USER_PUBLIC_NAME
        });

        /* Open the twitter share box - we take care of this manually to get a custom L&F for the
             * share button (i.e we don't use twitter's widgets.js replacement method).
             *
             *  Check out http://dev.twitter.com/pages/tweet_button for information.
             */
        var width  = 680,
        height = 400,
        left   = ($(window).width()  - width)  / 2 + 200,
        top    = ($(window).height() - height) / 2;

        /* We build the href to use using the data-X <a> element's attributes, piggy-backing from the twitter-expected
             * format, so we can switch between the default twitter javascript-provided method and the custom method we use
             * here */
        var params = [
        {
            name : "url",
            value : $(this).attr('data-url')
        },

        {
            name : "text",
            value : $(this).attr('data-text')
        },

        {
            name : "related",
            value : $(this).attr('data-related')
        },

        {
            name : "counturl",
            value : $(this).attr('data-counturl')
        },

        {
            name : "count",
            value : $(this).attr('data-count')
        }
        ];

        /* String up the query params and launch the window */
        var share_url = this.href + '?' + $.param(params);
        window.open(share_url, 'twitter', ['status=1,width=',width,',height=',height,',top=',top,',left=',left].join(''));
    });
}




/**
 * Binds functionality to the mobstream buttons
 */
function mobstreamButtons() {


    /* Actually performs the RSVP submit (AJAX POST)
     * operation, updating the mobrow as part of the
     * callback. */
    function submitRSVP(mobrow, url) {

        /* Have a little fade out animation right before
         * we make the submit
         */
        mobrow.fadeTo('slow', 0.1, function() {
            $.post(url, null, function(data) {

                /* Update the mobrow */
                updateMobrow(mobrow);

                /* Finally, check if there are notification messages
                 * and/or experiments to run */
                notificationAndExperimentResponse(data);

            }, 'json');
        });
    }




    /* Provide functionality for the quick-RSVP buttons on the mob rows */
    $("a.attending").live('click', function(e) {
        e.preventDefault();

        /* Clicking the mobrow button when it
             * is in the 'attending' state means that we switch
             * it to the 'not-attending' state, while making the call
             * to actually change the user's attendance */
        var url = $(this).parent().siblings("form#unattend_mob_form").attr('action');
        var mobrow = $(this).parent().parent('li');

        mpmetrics.track('attending_to_not_attending_mobrow_rsvp', {
            'user_public_name' : USER_PUBLIC_NAME
        });

        /*mobrow.fadeTo('slow', 0.1, function() {
            $.post(url, null, function(data) {
                updateMobrow(mobrow);
            }, 'json');
        });*/
        submitRSVP(mobrow, url);
    });
    $('a.attending').live('mouseover', function() {
        $(this).addClass('attending-hover');
        $("span", this).text("I'm out");
    });
    $('a.attending').live('mouseout', function() {
        $(this).removeClass('attending-hover');
        $("span", this).text("I'm in");
    });


    $("a.not-attending").live('click', function(e) {
        e.preventDefault();

        /* Clicking the mobrow button when it
             * is in the 'not-attending' state means that we switch
             * it to the 'attending' state, while also switching
             * out the text it displays. */
        var url = $(this).parent().siblings("form#attend_mob_form").attr('action');
        var mobrow = $(this).parent().parent('li');

        mpmetrics.track('not_attending_to_attending_mobrow_rsvp', {
            'user_public_name' : USER_PUBLIC_NAME
        });

        /*mobrow.fadeTo('slow', 0.1, function() {
            $.post(url, null, function(data) {
                updateMobrow(mobrow);
            }, 'json');
        });*/
        submitRSVP(mobrow, url);
    });
    $("a.not-attending").live('mouseover', function() {
        $(this).addClass('not-attending-hover')
        $("span", this).text("I'm in");
    });
    $("a.not-attending").live('mouseout', function() {
        $(this).removeClass('not-attending-hover');
        $("span", this).text("I'm out");
    });


    $("a.no-rsvp").live('click', function(e) {
        e.preventDefault();

        /* Clicking the mobrow button when it
             * is in the 'no-rsvp' state means that we switch
             * it to the 'attending' state, while also switching
             * out the text it displays. */
        var url = $(this).parent().siblings("form#attend_mob_form").attr('action');
        var mobrow = $(this).parent().parent('li');
        mpmetrics.track('no_rsvp_to_attending_mobrow_rsvp', {
            'user_public_name' : USER_PUBLIC_NAME
        });

        /*mobrow.fadeTo('slow', 0.1, function() {
            $.post(url, null, function(data) {
                updateMobrow(mobrow);
            }, 'json');
        });*/
        submitRSVP(mobrow, url);

    });

    $("a.no-rsvp").live('mouseover', function() {
        $("span", this).text("I'm in");
        $(this).addClass('no-rsvp-hover');
    });
    $("a.no-rsvp").live('mouseout', function() {
        $("span", this).text('Join');
        $(this).removeClass('no-rsvp-hover');
    });

    mobstreamSharingButtons();

}





/**
 * Update the given mobrow (jQuery object) by calling the mobstream mobrow endpoint and
 * replacing its HTML by the returned data (if the mobrow URL is given). Otherwise, we just reload
 * the page.
 */
function updateMobrow(mobrow) {
    if (mobrow.find("form#mobrow_url_form").length == 0) {
        /* The mobrows are not AJAX-ified. Just reload the page. *sigh*... */
        window.location.replace($(location).attr('href'));
        return;
    }

    var update_url = mobrow.find("form#mobrow_url_form").attr('action') + '?format=html';
    var replacement_html = null;
    $.getJSON(update_url, null, function(data) {
        /* Replace the HTML */
        replacement_html = data.html;
        mobrow.replaceWith(replacement_html);
        mobstreamSharingButtons();
        mobrow.fadeTo('slow', 1);
    });
}






/**
 * This script file provides functionality to buttons on the site that are implemented
 * in non-traditional HTML ways (i.e not form submit buttons, but as links or something else).
 */

$(document).ready( function() {

    /* Bind the mobstream buttons to their logic - we use the jQuery live() mechanism so only make this call once per page load */
    mobstreamButtons();

    /* Bind the social sharing buttons to their logic - we use the jQuery live() mechanism so only make this call once per page load */
    socialSharingButtons();



    /* Bind to the social invite with facebook button if we're using the facebook SDK to open the app requests dialog */
    if ($("a#invite_friends_facebook_button").length && $("a#invite_friends_facebook_button").hasClass('use-facebook-sdk')) {

        $("a#invite_friends_facebook_button").live('click', function(e) {
            e.preventDefault();

            FB.login(function(response) {
                if (response.session) {
                    /* User logged in/was logged in - display the UI */
                    FB.api('/me/friends', function(response) {
                        alert(JSON.stringify(response));
                    });
                } else {
                    alert('cancelled login');
                }
            });
        });
    }


    /* Disable comment button submission on first click */
    $("form#add_comment").submit( function(e) {
        $(this).find('input[type="submit"]').attr('disabled', 'disabled');
        $(this).find('input[type="submit"]').css({
            'opacity' : '0.7'
        });
        return true;
    });

    /* Disable comment button submission until user types something */
    $('form#add_comment input[type="submit"]').attr('disabled', 'disabled');
    $('form#add_comment input[type="submit"]').css({
        'opacity' : '0.7'
    });
    $("form#add_comment textarea").keyup( function(e) {
        if ($(this).val() == '') {
            $(this).siblings('input[type="submit"]').attr('disabled', 'disabled');
            $(this).siblings('input[type="submit"]').css({
                'opacity' : '0.7'
            });
        } else {
            $(this).siblings('input[type="submit"]').removeAttr('disabled');
            $(this).siblings('input[type="submit"]').css({
                'opacity' : '1.0'
            });
        }
    } );




    /* provide display option functionality for the links on the search bar up top (just under the navigation bar). */
    $("div#main div.display-options ul.date-list form").each( function() {
        var action = $(this).attr('action');

        /* Attach the functionality as a click event to the link (which is a sibling of this form) */
        $(this).siblings('a').first().click( function(e) {
            e.preventDefault();
            
            /* Make the POST submission */
            var submit_data = $(this).siblings('form').first().serializeArray();
            $.post(action,
                submit_data,
                function(result) {
                    /* Reload the page we're told to reload - this can be updated later for only reloading
                     * specific segments of the page. */
                    window.location.replace(result.redirect);
                }, 'json');
        });

    });




    /* Provide functionality to the RSVP buttons on the Mob Page */

    /* If we have a 'not attending' form, we expect there to be a link we can attach
         * some behaviour to. Same with the 'attending' form.
         */
    if ($("#rsvp_panel form#not_attending_form").length != 0) {

        /* We don't attach hover effects if we have both buttons */
        if ($("#rsvp_panel a#attending_button").length == 0) {
            /* We switch the class on page load so the user sees the
                 * big green icon indicating that he/she is attending this mob.
                 * We also attach on hover events to allow the user to change RSVP status */
            $("#rsvp_panel a#not_attending_button").removeClass('btn-cant');
            $("#rsvp_panel a#not_attending_button").addClass('btn-in');
            $("#rsvp_panel a#not_attending_button").text("I'm in");
            $("#rsvp_panel a#not_attending_button").hover(function(e) {
                $(this).removeClass('btn-in');
                $(this).addClass('btn-cant');
                $(this).text("Can't make it");
            }, function(e){
                $(this).removeClass('btn-cant');
                $(this).addClass('btn-in');
                $(this).text("I'm in");
            });
        }


        $("#rsvp_panel a#not_attending_button").click( function(e) {
            e.preventDefault();

            $(this).css({
                opacity : 0.5
            });
            $(this).text('working...');

            var submit_data = $("#rsvp_panel form#not_attending_form").serializeArray();
            var action = $("#rsvp_panel form#not_attending_form").attr('action');

            mpmetrics.track('not_attending_mob_page', {
                'user_public_name' : USER_PUBLIC_NAME
            });

            $.post(action, submit_data, function(result) {
                window.location.replace(result.redirect);
            }, 'json');
        });
    }

    if ($("#rsvp_panel form#attending_form").length != 0) {


        if ($("#rsvp_panel a#not_attending_button").length == 0) {
            /* We switch the class on page load so the user sees the
                 * big red icon indicating that he/she is not attending this mob.
                 * We also attach on hover events to allow the user to change RSVP status */
            $("#rsvp_panel a#attending_button").removeClass('btn-in');
            $("#rsvp_panel a#attending_button").addClass('btn-cant');
            $("#rsvp_panel a#attending_button").text("Can't make it");
            $("#rsvp_panel a#attending_button").hover(function(e) {
                $(this).removeClass('btn-cant');
                $(this).addClass('btn-in');
                $(this).text("I'm in");
            }, function(e){
                $(this).removeClass('btn-in');
                $(this).addClass('btn-cant');
                $(this).text("Can't make it");
            });
        }

        


        $("#rsvp_panel a#attending_button").click( function(e) {
            e.preventDefault();

            $(this).css({
                opacity : 0.5
            });
            $(this).text('working...');

            var submit_data = $("#rsvp_panel form#attending_form").serializeArray();
            var action = $("#rsvp_panel form#attending_form").attr('action');

            mpmetrics.track('attending_mob_page', {
                'user_public_name' : USER_PUBLIC_NAME
            });

            $.post(action, submit_data, function(result) {
                window.location.replace(result.redirect);
            }, 'json');
        });
    }





    /* Provide functionality to the Follow/Unfollow buttons on the user profile */
    if ($(".info-section form#unfollow_form").length != 0) {
        $(".info-section a#unfollow_button").click( function(e) {
            e.preventDefault();
            var submit_data = $(".info-section form#unfollow_form").serializeArray();
            var action = $(".info-section form#unfollow_form").attr('action');

            mpmetrics.track('unfollow', {
                'unfollow_url' : action
            });

            $.post(action, submit_data, function(result) {
                window.location.replace(result.redirect);
            }, 'json');
        });
    }

    if ($(".info-section form#follow_form").length != 0) {
        $(".info-section form#follow_form").submit( function(e) {
            e.preventDefault();
            var submit_data = $(".info-section form#follow_form").serializeArray();
            var action = $(".info-section form#follow_form").attr('action');

            mpmetrics.track('follow', {
                'follow_url' : action
            });

            $.post(action, submit_data, function(result) {
                window.location.replace(result.redirect);
            }, 'json');
        });
    }



    /* Provide functionality to delete mob/user comments */
    if ($("ul.comment-list a.btn-close").length != 0) {
        $("ul.comment-list a.btn-close").each( function() {
            var delete_action = $("ul.comment-list form#" + $(this).attr('id')).attr('action');
            $(this).click( function(e) {
                e.preventDefault();

                mpmetrics.track('delete_comment', {
                    'user_public_name' : USER_PUBLIC_NAME
                });
              
                $.post(delete_action, null, function(result) {
                    window.location.replace(result.redirect);
                }, 'json');
            });
        });
    }


    /* Provide user settings submit button functionality */
    if ($("button#user_settings_submit").length) {
        $("button#user_settings_submit").click( function(e)
        {
            e.preventDefault();

            /* Clear any errors that might have been displayed */
            $("span#error-holder").html('');

            /* We have to submit to two seperate endpoints, since we may have
             * updated user settings as well as edited email address / password.
             */

            var user_settings_data = $("form#set_user_settings_form").serializeArray();
            var user_settings_action = $("form#set_user_settings_form").attr('action');
            $.post(user_settings_action, user_settings_data, function(user_settings_response)
            {
                var redirect_url = user_settings_response.redirect;
                if (user_settings_response.result == 'failure') {
                    /* Display the errors */
                    if (user_settings_response.errors != undefined && user_settings_response.errors.length != 0) {
                        /* Clear any errors that might have been displayed */
                        $("span#error-holder").html('');

                        /* Build the HTML to insert */
                        var html = '<div class="row"><div class="error-block"><ul>';
                        for (var key in user_settings_response.errors) {
                            html = html + '<li>' + user_settings_response.errors[key] + '</li>';
                        }
                        html = html + '</ul></div></div>';
                        $("span#error-holder").html(html);
                    }

                    /* Scroll to the top of the page so the user is aware
                    * of the validation errors.
                    */
                    $('body').scrollTop(0);
                } else if (user_settings_response.result == 'success') {
                    /* Successful submission of the user settings - submit the user profile data
                     * changes too.
                     */
                    var user_data_data = $("form#set_user_data_form").serializeArray();
                    var user_data_action = $("form#set_user_data_form").attr('action');
                    $.post(user_data_action, user_data_data, function(user_data_response)
                    {
                        if (user_data_response.result == 'failure') {
                            /* Display the errors */
                            if (user_data_response.errors != undefined && user_data_response.errors.length != 0) {
                                /* Clear any errors that might have been displayed */
                                $("span#error-holder").html('');

                                /* Build the HTML to insert */
                                var html = '<div class="row"><div class="error-block"><ul>';
                                for (var key in user_data_response.errors) {
                                    html = html + '<li>' + user_data_response.errors[key] + '</li>';
                                }
                                html = html + '</ul></div></div>';
                                $("span#error-holder").html(html);
                            }

                            /* Scroll to the top of the page so the user is aware
                            * of the validation errors.
                            */
                            $('body').scrollTop(0);
                        } else if (user_data_response.result == 'success') {
                            window.location.replace(redirect_url);
                        }
                    });
                }
            });
        });
    }
});




/* Initialise the tooltips on the mob pages */
function initTooltips() {

    /* Attach the PoshyTip (http://vadikom.com/tools/poshy-tip-jquery-plugin-for-stylish-tooltips) good
     * mob guide tooltips to the input fields that need them.
     */
    var show_in = 500;
    
    if ($("form.create-mob-form textarea#description").length) {
        $("form.create-mob-form textarea#description").poshytip({
            className: 'tip-yellowsimple',
            showOn: 'focus',
            alignTo: 'target',
            showTimeout: show_in,
            offsetX: 10,
            alignX: 'right',
            alignY: 'center',
            content: "Be descriptive! What are we doing, what should we bring, etc."
        });
    }
    if ($("form.create-mob-form input#name").length) {
        $("form.create-mob-form input#name").poshytip({
            className: 'tip-yellowsimple',
            showOn: 'focus',
            alignTo: 'target',
            showTimeout: show_in,
            alignX: 'center',
            offsetY: 8,
            alignY: 'top',
            content: "Don't be boring - pick a fun and interesting name!"
        });
    }
    if ($("form.create-mob-form input#tags").length) {
        $("form.create-mob-form input#tags").poshytip({
            className: 'tip-yellowsimple',
            showOn: 'focus',
            alignTo: 'target',
            showTimeout: show_in,
            offsetX: 10,
            alignX: 'right',
            alignY: 'center',
            content: "Tags help us show your mob to people who care about this kind of workout - so go nuts"
        });
    }
    if ($("form.create-mob-form input#city").length) {
        $("form.create-mob-form input#city").poshytip({
            className: 'tip-yellowsimple',
            showOn: 'focus',
            alignTo: 'target',
            showTimeout: show_in,
            offsetY: 8,
            alignX: 'center',
            alignY: 'top',
            content: "Give us the (single) town/city that your mob is in. Don't worry - people that live nearby will see it!"
        });
    }

    if ($("form.create-mob-form input#start_date").length) {
        $("form.create-mob-form input#start_date").poshytip({
            className: 'tip-yellowsimple',
            showOn: 'focus',
            alignTo: 'target',
            showTimeout: show_in,
            offsetY: 8,
            alignX: 'right',
            alignY: 'top',
            content: "Click the day your mob is happening. You can click more than one day to set up recurring mobs"
        });
    }

    if ($("form.create-mob-form input#meeting_point").length) {
        $("form.create-mob-form input#meeting_point").poshytip({
            className: 'tip-yellowsimple',
            showOn: 'focus',
            alignTo: 'target',
            showTimeout: show_in,
            offsetX: 10,
            alignX: 'right',
            alignY: 'center',
            content: "Where should attendees meet? This makes it super easy for people to find your mob"
        });
    }
}


/* Called to attach the enhanced jQuery UI date pickers on the create a mob and edit mob pages */
function attachDatePickers() {

    var datepicker_options = {
        showAnim: "fadeIn",
        minDate: "0",
        maxDate: "+40D",
        dateFormat: "dd/mm/yy",
        onSelect: function() {
            $(this).removeClass('placeholder');
        }
    }

    if ($("input#start_date").length) {
        if ($("form#create_mob_form").length) {
            /* The create a mob page has a multi-date selector */
            $("input#start_date").multiDatesPicker(datepicker_options);
        } else if ($("form#edit_mob_form").length) {
            $("input#start_date").datepicker(datepicker_options);
        }
    }
    
}


/* Attach the functionality to create a new mob */
function initCreateMobFunctionality() {

    /* Attach enhanced date picker functionality if required by
     * elements on the page
     */
    attachDatePickers();


    if ($("input#create_mob_submit").length != 0 ) {
        var create_mob_url = $("form#create_mob_form").attr('action');
        $("input#create_mob_submit").click(function(e) {
            e.preventDefault();

            /* Disable the submit button until the result returns, and change its
             * text to indicate something's happening. */
            var old_text = $("input#create_mob_submit").attr('value');
            $("input#create_mob_submit").attr('disabled', 'true');
            $("input#create_mob_submit").css({
                opacity : 0.7
            });
            $("input#create_mob_submit").attr('value', 'Adding...');

            var input_map = {
                name : $("input#name").val(),
                type : $("input#type").val(),
                price : $("input#price") ? $("input#price").val() : 0,
                start_date : $("input#start_date").val(),
                start_time : $("input#start_time").val(),
                /*start_block : $("select#start_block option:selected").val(), */
                duration : $("input#duration").val(),
                description : $("textarea#description").val(),
                street_address : $("input#street_address").val(),
                city : $("input#city").val(),
                country : $("input#country").val(),
                meeting_point : $("input#meeting_point").val(),
                tags : $("input#tags").val(),
                credits: $("#stamp-amount").val()
            };

            /* Submit the mob fields */
            $.post(create_mob_url, input_map,
                function(data) {
                    if (data.result == 'failure') {

                        mpmetrics.track("create_mob_validation_failure", {
                            'input' : JSON.stringify(input_map),
                            'errors' : JSON.stringify(data.errors)
                        });

                        /* Display the errors */
                        if (data.errors != undefined && data.errors.length != 0) {
                            /* Build the HTML to insert */
                            var html = '<div class="row"><div class="error-block"><ul>';
                            for (var key in data.errors) {
                                html = html + '<li>' + data.errors[key] + '</li>';
                            }
                            html = html + '</ul></div></div>';
                            $("span#error-holder").html(html);
                        }

                        /* Scroll to the top of the page so the user is aware
                         * of the validation errors.
                         */
                        $('body').scrollTo(0, 700, {
                            axis : 'y',
                            easing: 'swing'
                        });

                        /* Re-enable the button */
                        $("input#create_mob_submit").removeAttr('disabled');
                        $("input#create_mob_submit").css({
                            opacity : 1.0
                        });
                        $("input#create_mob_submit").attr('value', old_text);

                    } else if (data.result == 'success') {

                        /* Log the create mob event */
                        mpmetrics.track("create_mob_success", {
                            'name' : $("input#name").val(),
                            'type' : $("input#type").val(),
                            'city' : $("input#city").val(),
                            'country' : $("input#country").val()
                        });

                        var toRedirect = data.redirect;

                        /* The URL to POST to to invite people to the recently created mob */
                        var mob_invite_url = data.mob.invite_url;

                        /* Should we be inviting all followers? */
                        var invite_followers = $("input#invite_all_followers").attr('checked');

                        var invite_message_text = $("textarea#invite_message").val();

                        /* Build the users arrays to submit from the email addresses and/or the public names
                         * given.
                         */
                        var usersToInvite = Array();

                        /* Check if the user has selected any of his/her followers to invite */
                        if ($("input.follower_invite_input:checked").length > 0) {
                            var invited_followers = $("input.follower_invite_input:checked");
                            for (var j = 0; j < invited_followers.length; j++) {
                                usersToInvite.push({
                                    "public_name" : invited_followers[j].name
                                });
                            }
                        }

                        var pieces = $("textarea#invite_by_email").val().split(',');
                        for (var i = 0; i < pieces.length; i++) {
                            /* When you tokenise by ',' if there isn't any input we still
                             * get one element in the array thats empty */
                            if (pieces[i] != "") {
                                usersToInvite.push({
                                    "email_address" : pieces[i]
                                });
                            }

                        }

                        var usersJSON = JSON.stringify(usersToInvite);

                        /* Log this invitation operation */
                        mpmetrics.track("create_mob_invite", {
                            'users' : usersJSON,
                            'invite_all_followers' : invite_followers,
                            'invite_message' : invite_message_text
                        });

                        /* POST the mob invitations request */
                        $.post(mob_invite_url, {
                            users: usersJSON,
                            invite_all_followers: invite_followers,
                            invite_message: invite_message_text
                        },
                        function(data) {

                            if (data.result == false) {
                                /* Show the notification message */
                                alert(data.notification_message);
                            } else {
                                /* Finally, we redirect to the URL provided in response to the mob creation operation */
                                window.location.replace(toRedirect);
                            }
                        },'json');


                    }
                },'json');
        });
    }


    /* Implement the dynamic behaviour to populate the form based on
     * previous mob selection */
    if ($("select#previous_mobs").length != 0) {
        $('select#previous_mobs').change( function() {
            var link = $('select#previous_mobs option:selected').attr('value');

            $.getJSON(link, null, function(data) {
                $("input#name").removeClass('placeholder').val(data.name);
                /* Little hack to strip HTML tags that might exist in the mob description. We surround the description in
                 * a new element, and then get the element's HTML */
                $("textarea#description").removeClass('placeholder').text($('<div>' + data.description + '</div>').text());
                $("input#type").removeClass('placeholder').val(data.type.name);
                $("input#duration").removeClass('placeholder').val(parseInt(data.duration));
                $("input#price").removeClass('placeholder').val(parseInt(data.price));
                $("input#street_address").removeClass('placeholder').val(data.street_address);
                $("input#city").removeClass('placeholder').val(data.city);
                $("input#country").removeClass('placeholder').val(data.country);
                $("input#meeting_point").removeClass('placeholder').val(data.meeting_point);
                $("input#tags").removeClass('placeholder').val(data.tags_string);
                $("input#start_time").removeClass('placeholder').val(data.input_start.time + data.input_start.block);

                /* Fire the paid/free mob label logic */
                $("input#price").trigger('keyup');

                /* Scroll to the bottom of the page so
                 * the pop-up date input selector doesn't get pushed above the field
	         	*/
                $('body').scrollTo($("input#meeting_point"), 400, {
                    axis : 'y',
                    easing: 'swing'
                });

                /* Slow this down a little so it isn't so jarring. */
                setTimeout(function() {
                    $("input#start_date").focus();
                }, 700);
            });

            mpmetrics.track("create_from_previous_mob_dropdown_used");

        });
    }



}


/* Attach the functionality to invite people to a mob */
function initMobInviteFunctionality() {

    /* Attach the send invite logic to the invite button */
    if ($("a#mob_invites_submit").length) {
        $("a#mob_invites_submit").click( function(e) {

            e.preventDefault();

            /* The invite URL */
            var mob_invite_url = $("form#invite_form").attr('action');

            /* Should we be inviting all followers? */
            var invite_followers = $("input#invite_all_followers").attr('checked');

            var invite_message_text = $("textarea#invite_message").val();

            /* Build the users arrays to submit from the email addresses and/or the public names
             * given.
             */
            var usersToInvite = Array();

            /* Check if the user has selected any of his/her followers to invite */
            if ($("input.follower_invite_input:checked").length > 0) {
                var invited_followers = $("input.follower_invite_input:checked");
                for (var j = 0; j < invited_followers.length; j++) {
                    usersToInvite.push({
                        "public_name" : invited_followers[j].name
                    });
                }
            }

            var pieces = $("textarea#invite_by_email").val().split(',');
            for (var i = 0; i < pieces.length; i++) {
                /* When you tokenise by ',' if there isn't any input we still
                     * get one element in the array thats empty */
                if (pieces[i] != "") {
                    usersToInvite.push({
                        "email_address" : pieces[i]
                    });
                }

            }

            var usersJSON = JSON.stringify(usersToInvite);

            /* Log this invitation operation */
            mpmetrics.track("mob_invite", {
                'users' : usersJSON,
                'invite_all_followes' : invite_followers,
                'invite_message' : invite_message_text
            });

            /* POST the mob invitations request */
            $.post(mob_invite_url, {
                users: usersJSON,
                invite_all_followers: invite_followers,
                invite_message: invite_message_text
            },
            function(data) {
                /* Finally, we redirect to the URL provided */
                window.location.replace(data.redirect);
            },'json');
        });
    }

    /*
     * Hide the invites panel on page load, only to be shown when the user clicks the
     * panel seperator. Also, attach the show effect onto the panel seperator
     * span.
     */
    if ($("span#mob_invitations_panel").length != 0) {
        $("a.expand_mob_invitations_panel").click( function() {
            $("span#mob_invitations_panel").slideDown('slow', null);
            mpmetrics.track('mob_page_invite_panel_shown', {
                'user_public_name' : USER_PUBLIC_NAME
            });
        });
    }

    /* Attach the invite all followers check/uncheck functionality to check/uncheck
     * all the followers invited list checkboxes, respectively.
     *
     * Due to the fancy JS gymnastics we do to show styled input checkboxes,
     * we need to attach to both the input checkbox and its sibling div.
     */
    $("input#invite_all_followers").click( function(e) {
        if($("input#invite_all_followers").is(':checked')) {
            $("input.follower_invite_input").each( function(){
                $(this).attr('checked', true);
                $(this).siblings("div.checkboxArea").addClass('checkboxAreaChecked');
                $(this).siblings("div.checkboxArea").removeClass('checkboxArea');
            } );
        } else {
            $("input.follower_invite_input").each( function(){
                $(this).attr('checked', false);
                $(this).siblings("div.checkboxAreaChecked").addClass('checkboxArea');
                $(this).siblings("div.checkboxAreaChecked").removeClass('checkboxAreaChecked');
            } );
        }
    });
    $("input#invite_all_followers").siblings("div.checkboxArea").click(function(e) {
        if($("input#invite_all_followers").is(':checked')) {
            $("input.follower_invite_input").each( function(){
                $(this).attr('checked', true);
                $(this).siblings("div.checkboxArea").addClass('checkboxAreaChecked');
                $(this).siblings("div.checkboxArea").removeClass('checkboxArea');
            } );
        } else {
            $("input.follower_invite_input").each( function(){
                $(this).attr('checked', false);
                $(this).siblings("div.checkboxAreaChecked").addClass('checkboxArea');
                $(this).siblings("div.checkboxAreaChecked").removeClass('checkboxAreaChecked');
            } );
        }
    });
    
}

function initRSVPFunctionality() {

    /* Check that the data-ajax attribute is 'true' on the RSVP panel before
     * we attach the logic - this indicates that it has requested that it be AJAX-ified
     */
    if ($("#rsvp_panel[data-ajax='true']").length == 0) {
        return;
    }

    function attendingMobFormCallback(data) {
        /* Using the retrieved data, this function needs to rebuild the
         * RSVP panel from the jQuery template provided */
        mpmetrics.track('attending_mob_page', {
            'user_public_name' : USER_PUBLIC_NAME
        });
        var replaceable_element = $("#rsvp_panel_html_template").tmpl(data);
        replaceable_element.css({
            'opacity' : '0.0'
        });
        $("#rsvp_panel").replaceWith(replaceable_element);
        $("#rsvp_panel").fadeTo('slow', 1);
        notificationAndExperimentResponse(data);

        /* Need to re-bind to the forms */
        bindToRSVPForms();
    }

    function notAttendingMobFormCallback(data) {
        /* Using the retrieved data, this function needs to rebuild the
         * RSVP panel from the jQuery template provided */
        mpmetrics.track('not_attending_mob_page', {
            'user_public_name' : USER_PUBLIC_NAME
        });
        var replaceable_element = $("#rsvp_panel_html_template").tmpl(data);
        replaceable_element.css({
            'opacity' : '0.0'
        });
        $("#rsvp_panel").replaceWith(replaceable_element);
        $("#rsvp_panel").fadeTo('slow', 1);
        notificationAndExperimentResponse(data);

        /* Need to re-bind to the forms */
        bindToRSVPForms();
    }

    function bindToRSVPForms() {
        $("#rsvp_panel[data-ajax='true'] #attending_form").ajaxForm({
            dataType: 'json',
            clearForm : true,
            resetForm : true,
            beforeSubmit : function() {
                /* Fade out the panel */
                $("#rsvp_panel").fadeTo('slow', 0.1);
            },
            success : attendingMobFormCallback
        });
        $("#rsvp_panel[data-ajax='true'] #not_attending_form").ajaxForm({
            dataType: 'json',
            clearForm : true,
            resetForm : true,
            beforeSubmit : function() {
                /* Fade out the panel */
                $("#rsvp_panel").fadeTo('slow', 0.1);
            },
            success : notAttendingMobFormCallback
        });

        /* Implement the switching effect on the buttons. That is, if a user is attending a mob, the button should say 'I'm in', but change to 'Can't make it'
         * on hover. And vice versa. */
        $("#rsvp_panel[data-ajax='true'] #attending_button.swap-on-hover").hover( function(e){
            $(this).removeClass('red-submit').addClass('green-submit');
            $(this).text("I'm in");
        }, function(e) {
            $(this).removeClass('green-submit').addClass('red-submit');
            $(this).text("Can't make it");
        });
        $("#rsvp_panel[data-ajax='true'] #not_attending_button.swap-on-hover").hover( function(e){
            $(this).removeClass('green-submit').addClass('red-submit');
            $(this).text("Can't make it");
        }, function(e) {
            $(this).removeClass('red-submit').addClass('green-submit');
            $(this).text("I'm in");
        });


    }

    /* Bind to the attend and unattend form submissions */
    bindToRSVPForms();

}

function initEditMobFunctionality() {

    /* Attach behaviour to the 'delete this mob' link on the mob edit page */
    $("a#delete_mob_link").fancybox({});
    /* Attach behaviour to each of the links shown when the 'delete this mob' link is clicked - a
     * confirmation link and a cancel one
     */
    if ($("a#delete_mob_confirm").length) {
        $("a#delete_mob_confirm").click( function(e) {
            e.preventDefault();
            var delete_mob_url = $("form#delete_mob_form").attr('action');

            /* Change the status of the 'delete' link so it is clear that
             * something is happening - also get rid of the 'cancel' link.
             */
            $("a#cancel").remove();
            $(this).replaceWith('<p id="delete_mob_confirm">deleting...</p>');

            $.post(delete_mob_url, {}, function(data){

                /* If the operation was successful */
                if (data.result == 'success') {
                    $.fancybox.close();
                    /* We just redirect to the given URL */
                    window.location.replace(data.redirect);
                } else {
                    $.fancybox.close();
                /* Not really much we can do here... */
                }
            }, 'json');

        });
    }
    if ($("a#cancel").length) {
        $("a#cancel").click( function(e) {
            e.preventDefault();
            /* Just remove the lightbox */
            $.fancybox.close();
        });
    }

}


function initMobPageFunctionality() {

    /* Attach the logic to the invite panel */
    initMobInviteFunctionality();

    /* Attach the logic to the RSVP panel */
    initRSVPFunctionality();

    /* Attach the lightbox providing functionality to report a mob as inappropriate */
    if ($("a#flag_mob_link").length) {
        $("form#flag_mob_form").ajaxForm(
        {
            dataType: 'json',
            clearForm : true,
            resetForm : true,
            success: function(data) {
                var replace_element_id = null;
                if (data.result == "failure") {
                    replace_element_id = "flag_mob_failure_text";
                } else {
                    replace_element_id = "flag_mob_success_text";
                }
                $("div#flag_mob_form_container").hide();
                $("#" + replace_element_id).show();
                setTimeout(function() {
                    $.fancybox.close();
                }, 2500);
            }
        } );

        $('a#flag_mob_link').fancybox(
        {
            onComplete : function() {
                /* Send a MixPanel event about the user clicking this link*/
                mpmetrics.track('flag_mob_clicked', {
                    'user_public_name' : USER_PUBLIC_NAME,
                    'flag_mob_url' : $("form#flag_mob_form").attr('action')
                });
            }
        });
    }
    
}



/* JS-enabled functionality for the Create Mob, Edit Mob and Mob pages */
$(document).ready( function() {
    initTooltips();
    initCreateMobFunctionality();
    initEditMobFunctionality();
    initMobPageFunctionality();    
});



/**
 * Binds the switching/loading content functionality of the regular (not pro) user profile tabs (comment wall and attended mobs).
 */
function userProfileTabs() {
    /* Enable the tabbed views of the comments and attended mobs panels */
    if ($("a#comments_tab_button").length != 0) {
        $("a#comments_tab_button").click( function(e) {
            e.preventDefault();

            /* Change the active tab */
            $("a#attended_mobs_tab_button").parent().removeClass('active');
            $("a#comments_tab_button").parent().addClass('active');

            /* Until we get the jQuery-enabled switching working, just reload this page (which shall
             * default to the comments view). */
            window.location.replace($(location).attr('href'));
        });
    }
    if ($("a#attended_mobs_tab_button").length != 0) {
        $("a#attended_mobs_tab_button").click( function(e) {
            e.preventDefault();

            /* Change the active tab */
            $("a#comments_tab_button").parent().removeClass('active');
            $("a#attended_mobs_tab_button").parent().addClass('active');

            /* Remove the comment textarea, and replace the comment list with a loading animation */
            $("div.txt-section div.area-section").remove();
            displayLoadingSpinner($("ul.comment-list"));


            /* Get the recently attended mobs from the server, then build the HTML using the JSON we get. */
            $.getJSON($("form#attended_mobs_form").attr('action'), null, function(data)
            {
                /* Template the HTML, returned as jQuery element */
                var attended_mobs_json = data.attended_mobs;
                var mobrow_list = $("#attended_mobs_html_template").tmpl(attended_mobs_json);

                /* We replace the spot where the comment list was with a list of mob rows, with a nice little fade-in
                 * animation. */
                mobrow_list.hide();
                $("ul.comment-list").replaceWith(mobrow_list);
                $("ul.attended-mobs-list").fadeIn('slow');

            });
        });
    }
}


/**
 * JS-enabled functionality and presentation for the user profile / edit user profile
 * pages.
 */

$(document).ready( function() {

    /* Bind switching logic to the regular user profile tabs */
    userProfileTabs();

    /* Attach the logic onto the all_followers and all_following links. This may be AJAX-ified */
    if ($('a#all_following_link').length) {
        if ($("form#load_all_following_form").length) {
            /* We're AJAX-ifying this display. This means that the contents of the lightbox to be shown (all the
             * users that this user is following) are to be asynchronously loaded. */
            var all_following_link_text = $("a#all_following_link").text();
            $("a#all_following_link").click( function(e) {
               e.preventDefault();
               $.fancybox.showActivity();
               $(this).attr('disabled', 'disabled');
               $(this).text('loading...');

               var action = $("form#load_all_following_form").attr('action');
               $.ajax({
                    url: action,
                    cache : true,
                    data : 'format=html',
                    success: function(html) {
                        /* Launch a fancybox with the html returned from the request */
                        $.fancybox(html);
                        $("a#all_following_link").removeAttr('disabled');
                        $("a#all_following_link").text(all_following_link_text);
                        $.fancybox.hideActivity();
                    },
                    dataType : 'html'
               });  
            } );
        } else {
            /* Regular, non-AJAX display of the all following box */
            $('a#all_following_link').fancybox();
        }
        
    }
    
    if ($('a#all_followers_link').length) {
        if ($("form#load_all_followers_form").length) {
            /* We're AJAX-ifying this display. This means that the contents of the lightbox to be shown (all the
             * users that are following this user) are to be asynchronously loaded. */
            var all_followers_link_text = $("a#all_followers_link").text();
            $("a#all_followers_link").click( function(e) {
               e.preventDefault();
               $.fancybox.showActivity();
               $(this).attr('disabled', 'disabled');
               $(this).text('loading...');

               var action = $("form#load_all_followers_form").attr('action');
               $.ajax({
                    url: action,
                    cache : true,
                    data : 'format=html',
                    success: function(html) {
                        /* Launch a fancybox with the html returned from the request */
                        $.fancybox(html);
                        $("a#all_followers_link").removeAttr('disabled');
                        $("a#all_followers_link").text(all_followers_link_text);
                        $.fancybox.hideActivity();
                    },
                    dataType : 'html'
               });
            } );
        } else {
            $('a#all_followers_link').fancybox();
        }
    }


    
});


function displayLoginWindow( url, windowName ) 
{
	var width = 900;
	var height = 500;
	var left = (screen.width / 2) - (width / 2);
	var top = (screen.height / 2) - (height / 2);
	var loginWnd = window.open( url, windowName, "menubar=1,resizable=1,scrollbars=yes," + "width=" + width + ",height=" + height + ",left=" + left + ",top=" + top);
	loginWnd.focus();
}


function runRPX( originForm )
{
	var loginForm = $( originForm );
	var loginWindowName = 'TrainingMobsEngageBridge';
	loginForm.attr( 'target', loginWindowName ); 
	displayLoginWindow( 'about:blank', loginWindowName );
	loginForm.submit();
}

/**
 * Contains specific client-side logic for experiments that we're currently running. This file
 * can be thought of as the client-side version of the Experiments library class on the server side.
 */


function isExperimentRunning(experiment_name) {
    /* The experiment is running if the expected HTML structure is present */
    if ($("div.experiment").length == 0) {
        return false;
    }

    /* If we do have the .experiment div, we expect the 'name' p.experiment-attribute element */
    if ($("div.experiment #name").length == 0) {
        return false;
    }

    /* Make sure that the name is the experiment that we're expecting */
    if ($("div.experiment #name").text() == experiment_name) {
        return true;
    } else {
        return false;
    }
}


function runExperiment(experiment_name, params) {

    if (params == undefined || params == null) {
        params = {};
    }

    if (experiment_name == 'share_on_mob_rsvp') {
        return share_on_mob_rsvp(params);
    } else if (experiment_name == 'invite_users_on_mob_add') {
        return invite_users_on_mob_add(params);
    }
}


/**
 * Displays a lightbox asking the user (who just created a mob) if he/she would like to invite the users
 * we randomly selected to the mob, with some clever copy.
 *
 * @param object params A parameters object containing whatever information this method needs. All params are optional.
 */
function invite_users_on_mob_add(params) {

    /* The experiment HTML should provide the URLs to query to get the users' information to display */
    var inviteUsers = [];
    var inviteUsersURLs = [];
    $("div.experiment ul#users_to_invite").children("li").each( function(index) {
    	inviteUsersURLs.push($(this).text());
    });

    /* If we don't have any users to invite, skip this experiment */
    if (inviteUsersURLs.length == 0) {
        return;
    }

    /* Get the URL to invite the users to the mob, returning and aborting the experiment
     * if we don't have it. */
    var mob_invite_url = $('div.experiment #mob_invite_url').text();
    if (mob_invite_url == '' || mob_invite_url == null) {
        return;
    }


    /* Now, we need to query each of the URLs, appending the returned JSON to the array of users.
     * We also take this opportunity to build the JSON string of the public names of the users we're
     * inviting, so we can POST to the mob invite endpoint */
    var publicNames = [];
    var requests_completed = 0;
    for (var index in inviteUsersURLs) {
        $.getJSON(inviteUsersURLs[index], null,
            function(data) {
                inviteUsers.push(data);
                publicNames.push({"public_name" : data.public_name});
                requests_completed++;
            });
    }
    var publicNamesJSON = '';

    /* First, we need insert some HTML to open a lightbox on */
    var super_div = $('<div style="display: none;">');
    var invite_users_link = $('<a id="invite_users_prompt_link" style="display: none;">link</a>');
    invite_users_link.attr('href', "#invite_users_prompt");
    var invite_users_prompt = $('<div id="invite_users_prompt" class="lightbox-prompt">');
    invite_users_prompt.append('<h3 class="lightbox-prompt-header">Feel like making someone\'s day? Invite these newbies and get them out to their first mob!</h3>');

    var button_row = $('<div class="lightbox-prompt-button-row">');

    /* The invite button on the lightbox */
    var invite_yes = function() {
        $.fancybox.showActivity();
        
        /* POST the mob invitations request */
        $.post(mob_invite_url, {
               users: publicNamesJSON,
               invite_all_followers: false,
               context : "invite_users_on_mob_add"
        },
        function(data) {
            if (data.result == 'failure') {
                /* Close the lightbox */
                $.fancybox.hideActivity();
                $.fancybox.close();
                 alert('Something went wrong - could not send invites');
            } else {
                /* Log this invitation operation, then reload the page */
                mpmetrics.track("invite_users_on_mob_add_experiment", {
                   'users' : publicNamesJSON
                }, function() {
                    /* Close the lightbox */
                    $.fancybox.hideActivity();
                    $.fancybox.close();
                    window.location.replace($(location).attr('href'));
                });
                setTimeout(function() {
                    /* Close the lightbox */
                    $.fancybox.hideActivity();
                    $.fancybox.close();
                    window.location.replace($(location).attr('href'));
                }, 1000);
            }
        },'json');
    }

    var invite_button = $('<button id="invite_users_prompt_yes" class="lightbox-button button">Invite</button>');
    invite_button.click(invite_yes);

    button_row.append(invite_button);

    var intervals_waited = 0;
    var interval_id = setInterval(
        function() {

            /* If we've waited too long, assume the requests timed out and abort this experiment */
            if (intervals_waited > 20) {
                clearInterval(interval_id);
                return;
            }

            if (requests_completed < inviteUsersURLs.length) {
                /* Not all the user data requests have returned yet - return
                 * from this function and wait for the next interval. */
                intervals_waited = intervals_waited + 1;
                return;

            }

            /* All the user data requests have finished - clear the interval and
             * continue execution */
            clearInterval(interval_id);

            /* All the requests have returned - we can build the public names JSON string now */
            publicNamesJSON = JSON.stringify(publicNames);

            /* Build the invitees HTML */
            var invitees_box = $('<div id="users_to_invite" class="font-80">');
            invitees_box.append('<ul class="conn-list highlight-on-hover">');
            var user_list = invitees_box.find("ul.conn-list");
            for (var user_index in inviteUsers) {
                var currUser = inviteUsers[user_index];
                var user_list_item = $('<li><img class="bordered-1pixel" height="37" width="37" src="' + currUser.social_mobstream_image_url + '" alt="' + currUser.name + '"/></li>');
                var user_list_item_name = $('<div class="conn-item"><span class="conn-text">' + currUser.name + '</span></div>');
                user_list_item.append(user_list_item_name);
                user_list.append(user_list_item);
            }

            invite_users_prompt.append(invitees_box);
            invite_users_prompt.append(button_row);
            super_div.append(invite_users_prompt);

            $('body').append(invite_users_link);
            $('body').append(super_div);

            /* Now, we can attach a fancybox to the link we built. */
            $("a#invite_users_prompt_link").fancybox();

            /* Finally, click the link to fire the fancybox */
            $("a#invite_users_prompt_link").click();

            return;

        }, 300);

}


/**
 * Displays a lightbox asking the user if he/she wants to share the mob that he/she just
 * RSVPed to to twitter or facebook.
 *
 * @param object params A parameters object containing whatever information this method needs.
 *               we recognise the params 'twitter' and 'facebook', to contain the twitter and facebook <a> elements we need to show
 *               in the lightbox for this experiment. All params are optional.
 */
function share_on_mob_rsvp(params) {

    /* First, we need insert some HTML to open a lightbox on. Before we go any further, though, we need to check
     * if the HTML structure we're about to insert already exists in the DOM. If so, this experiment is already
     * being run by some other logic. */
    if ($("div#share_mob_prompt").length || $("a#share_mob_prompt_link").length) {
        /* Abort this experiment - already under way */
        return;
    }


    /* Callback functions for sharing buttons */
    function fireFacebookShare() {
        mpmetrics.track('share_mob_facebook_experiment', {
            'experiment_name' : 'share_on_mob_rsvp',
            'shared_mob_public_name' : mob_public_name,
            'user_public_name' : USER_PUBLIC_NAME
        });
        $.fancybox.close();
    }
    function fireTwitterShare() {
        mpmetrics.track('share_mob_twitter_experiment', {
            'experiment_name' : 'share_on_mob_rsvp',
            'shared_mob_public_name' : mob_public_name
        });
        $.fancybox.close();
    }

    

    var mob_public_name = $('div.experiment #attending_mob_public_name').text();
    
    var super_div = $('<div style="display: none;">');
    var share_mob_link = $('<a id="share_mob_prompt_link" style="display: none;">link</a>');
    share_mob_link.attr('href', "#share_mob_prompt");

    /* If we've got the mob share lightbox HTML attached to the params, we can short-circuit this process
     * at this point
     */
    if (params.share_mob_lightbox_html != undefined) {
        
        var share_mob_prompt = $(params.share_mob_lightbox_html);
        var close_link = share_mob_prompt.find("a#close_share_mob_prompt").first();
        close_link.click( function(e) {
            e.preventDefault();
            $.fancybox.close();
        });
        share_mob_prompt.find("a.facebook").first().click( function(e) {
            e.preventDefault();
            fireFacebookShare();
        });
        share_mob_prompt.find("a.twitter").first().click( function(e) {
            e.preventDefault();
            fireTwitterShare();
        });

    } else {

        /* Otherwise, we have to build everything from the given experiment HTML. This is the old
         * way of doing things, and is left in for compatibility. We will eventually move to providing
         * the share mob lightbox HTML with the AJAX response
         */

        var share_mob_prompt = $('<div id="share_mob_prompt" class="lightbox-prompt">');
        share_mob_prompt.append('<h3 class="lightbox-prompt-header">Glad you can make it! Share your mob with friends and help Training Mobs grow</h3>');
        var button_row = $('<div class="lightbox-prompt-button-row">');

        var no_thanks = $('<div class="lightbox-prompt-button-row">');
        var close_link = $('<a id="close_share_mob_prompt" href="#">No thanks</a>');
        close_link.click( function(e) {
            e.preventDefault();
            $.fancybox.close();
        });
        no_thanks.append(close_link);

        /* Build the new button images for these sharing buttons */
        var facebook_img_src = $('div.experiment #facebook_button_image').text();
        var twitter_img_src = $('div.experiment #twitter_button_image').text();
        var facebook_img = $('<img src="' + facebook_img_src + '" />');
        var twitter_img = $('<img src="' + twitter_img_src + '" />');

        /* Check if we've been given the twitter button with the params or we have to create it from scratch */
         var cloned_twitter_button = null;
        if (params.twitter != undefined) {
            cloned_twitter_button = params.twitter;
        } else {
            cloned_twitter_button = $("li#" + mob_public_name).find('div.mobrow-social a.twitter').clone(true);
        }
        /* Replace its contents with the img tag we have */
        cloned_twitter_button.html(twitter_img);

        /* The facebook case is a little different - we have a <span> in there containing the data we may need to invoke
         * the facebook dialog API, so we want to preserve this span in the HTML replacement */
        var cloned_facebook_button = null;
        if (params.facebook != undefined) {
            cloned_facebook_button = params.facebook;
        } else {
            cloned_facebook_button = $("li#" + mob_public_name).find('div.mobrow-social a.facebook').clone(true);
        }
        /* Grab a copy of this info element, so we can blow away the contents of the facebook share button and
         * replace it with this info span as well as our facebook button image */
        var share_info_span = cloned_facebook_button.find(".facebook-share-info").clone();
        cloned_facebook_button.html(share_info_span);
        cloned_facebook_button.append(facebook_img);


        cloned_facebook_button.click(function(e) {
            fireFacebookShare();
        });
        cloned_twitter_button.click(function(e) {
            fireTwitterShare();
        });

        button_row.append(cloned_facebook_button);
        button_row.append(cloned_twitter_button);

        share_mob_prompt.append(button_row);
        share_mob_prompt.append(no_thanks);
    }



    super_div.append(share_mob_prompt);

    $('body').append(share_mob_link);
    $('body').append(super_div);

    /* Now, we can attach a fancybox to the link we built. */
    $("a#share_mob_prompt_link").fancybox({
        centerOnScroll : true,
        onClosed : function() {
            /* Delete the fancybox HTML from the DOM */
            $("a#share_mob_prompt_link").remove();
            $('div#share_mob_prompt').parent().remove();
        }
    });

    /* Finally, click the link to fire the fancybox */
    $("a#share_mob_prompt_link").trigger('click');

    return;
}













/* Short delay to allow time for everything else to run on page load before the experiments kick in */
var experiment_delay = 1500;

/* ....And away we go! */
$(document).ready( function() {



    /* Check if we're running the share on mob RSVP experiment. This check here is for
     * RSVPs that are made through the mob rows instead of the mob page,
     * hence we make sure that a div found only on the mob page isn't present. */
    if ($('div#about_the_mob').length == 0 && isExperimentRunning('share_on_mob_rsvp')) {
        runExperiment('share_on_mob_rsvp');
    }


    /* If we're on the mob page, and we're running the share mob on RSVP experiment, run the experiment
     * with the specific twitter and facebook buttons on this page. */
    if ($('div#about_the_mob').length && isExperimentRunning('share_on_mob_rsvp')) {
        /* There should only by one facebook and twitter button one the page - clone them (making
         * sure that the attached event handlers are cloned too using the 'true' parameter). */
        var twitter_button = $('a.twitter').clone(true);
        var facebook_button = $('a.facebook').clone(true);
        setTimeout(function() {
           runExperiment('share_on_mob_rsvp', {
            'twitter' : twitter_button,
            'facebook' : facebook_button
           });
           return;
        }, experiment_delay);
        
    }

    /* Check if we're on the mob page (and the experiment to invite new users on mob creation is running) */
    if ($('div#about_the_mob').length && isExperimentRunning('invite_users_on_mob_add')) {
        setTimeout(function() {runExperiment('invite_users_on_mob_add')}, experiment_delay);
    }


});/**
 * This file contains client-side functionality that powers the payments engine. That is,
 * the feature set that allows mobsters to open mobster accounts, top them up with money from
 * their credit card and then pay for mobs using their mobster account balance.
 */

/* Retrieve the user's mob credits accounts information from the server,
 * and attach it to the jQuery element (using the data() method) to the element
 * matching the given element_selector.
 */
function getAndAttachCreditsInfo(element_selector) {
    if (PAYMENTS_ENGINE_ENABLED == false || typeof USER_CREDITS_INFO_URL === 'undefined') {
        return;
    }
    $.getJSON(USER_CREDITS_INFO_URL, null, function(data) {
        $("" + element_selector).data('user_credits_info', data);
    });
}




function bindPaidMobsRSVPFunctionality() {

    $("a.no-rsvp").live('click', function(e) {
        e.preventDefault();

        /* Clicking the mobrow button when it
         * is in the 'no-rsvp' state means that we switch
         * it to the 'attending' state, while also switching
         * out the text it displays. */
        var url = $(this).parent().siblings("form#attend_mob_form").attr('action');
        var mobrow = $(this).parent().parent('li');
        mpmetrics.track('no_rsvp_to_attending_mobrow_rsvp', {
            'user_public_name' : USER_PUBLIC_NAME
        });

        mobrow.fadeTo('slow', 0.1, function() {
            $.post(url, null, function(data) {
                updateMobrow(mobrow);
            }, 'json');
        });

    });
}



$(document).ready( function() {

    /* Upon page load, grab the user's mobster credits info (if we can) */
    getAndAttachCreditsInfo('body');

    /* Bind the logic to all RSVP buttons to paid mobs on the current page (could be mob page or mobrows).
     * This method hijacks all other logic previously attached to these RSVP buttons, assuming its the only
     * source of truth for what should happen when a user clicks to RSVP to a PAID mob. For unpaid mobs,
     * this method does nothing.
     */
    bindPaidMobsRSVPFunctionality();
});

/**
 * ------------------------------------------------------------------------------------------------------------------------------
 *
 * Contains behaviour and logic that powers the mobstream filtering functionality
 *
 * ------------------------------------------------------------------------------------------------------------------------------
 */



/* Copies everything from the canonical mobstream (the one retrieved from the server)
 * into a new JSON structure it creates, except it attaches an empty mobs_by_day field to the object.
 * It then returns the skeleton mobstream object it built.
 */
function getFilteredMobstreamSkeleton() {
    var server_mobstream = $('body').data('mobstream_data_response');
    var skeleton_mobstream = {};
    skeleton_mobstream.current_user = server_mobstream.current_user;
    skeleton_mobstream.day_identifiers_to_labels = server_mobstream.day_identifiers_to_labels;
    skeleton_mobstream.day_labels_to_identifiers = server_mobstream.day_labels_to_identifiers;
    skeleton_mobstream.is_filtered = true;
    return skeleton_mobstream;
}


function startFilteringAnimation() {
    $("div#mobstream").fadeOut('slow');
}
function stopFilteringAnimation() {

}

/**
 * Applies all the filters, returning the filtered mobstream that satisfies all the filter
 * criteria.
 */
function getFilteredMobstream() {


    function satisfiesTimeRange(mob) {

        var raw_time_values = [ $("#time_filter_slider").slider('values', 0),
                                $("#time_filter_slider").slider('values', 1) ];

        /* If the max range is selected, all mobs are allowed */
        if (raw_time_values[0] == 0 && raw_time_values[1] == 23) {
            return true;
        }

        var time_values = [ humanizeSliderTime(raw_time_values[0]),
                            humanizeSliderTime(raw_time_values[1]) ];

        /* Time is the time in 'g:i' format */
        var mob_input_time = mob.input_start.time;
        /* Block is the am/pm in 'a' format */
        var mob_input_block = mob.input_start.block;

        var lower_bound = Date.today().at(time_values[0]);
        var upper_bound = Date.today().at(time_values[1]);
        var start_time = Date.today().at("" + mob_input_time + mob_input_block);
        if (lower_bound <= start_time && start_time <= upper_bound) {
            return true;
        }
        return false;
    }

    function satisfiesPriceRange(mob) {
        var price_values = [$("#price_filter_slider").slider('values', 0), $("#price_filter_slider").slider('values', 1)];
        var price_bounds = [parseFloat(price_values[0]), parseFloat(price_values[1])];

        /* If the max range is selected, let any mob be included */
        if (price_bounds[0] == 0 && price_bounds[1] == 30) {
            return true;
        }

        var mob_price = parseFloat(mob.price);

        if (price_bounds[0] <= mob_price && mob_price <= price_bounds[1]) {
            return true;
        }
        return false;
    }



    /* Get the skeleton filtered mobstream JSON structure */
    var filtered_mobstream = getFilteredMobstreamSkeleton();

    var server_mobstream = $('body').data('mobstream_data_response');

    /* Get the visible map markers */
    var map = $("#location_filter_map").data('map');
    var bounds = map.getBounds();
    var visible_markers = [];
    var markers = map.get('markers');
    for (var i in markers) {
        var marker = map.markers[i];
        if (bounds.contains(marker.getPosition())) {
            visible_markers.push(marker);
        }
    }


    /* For a mob to appear in the filtered mobstream, this means that it passes
     * all the filtering criteria. Since we've already build the map markers breadcrumbs
     * structure into each of the markers, thats probably a good place to start (since it
     * will cut down on our processing time).

    /* For each visible marker, traverse its breadcrumbs to find
     * the path through the mobs_by_day structure to the mob it represents
     */
    for (var j in visible_markers) {
        var curr_marker = visible_markers[j];
        var day_string = curr_marker.get('day_string');
        var day_array_index = curr_marker.get('day_array_index');
        var mob_public_name = curr_marker.get('mob_public_name');

        /* Sanity check */
        var mob = server_mobstream.mobs_by_day[day_string][day_array_index];
        if (mob.public_name != mob_public_name) {
            throw new Error("mismatch in expected mob public name between server mobstream and visible mob markers. "
                + "This is a problem with the implementation of initializeLocationFilterMap()");
            continue;
        }

        /* Make sure this mob satisfies both the time range and the price range filters */
        if (!satisfiesTimeRange(mob) || !satisfiesPriceRange(mob)) {
            continue;
        }

        /* We only create the mobs_by_day property when we know that we'll be populating
         * it with something. This is so our HTML templating logic that builds the
         * mobstream HTML can determine whether or not to show an empty mobstream message
         * or to render a mobstream - it relies on the existence check of the mobs_by_day
         * property.
         */
        if (filtered_mobstream.mobs_by_day == undefined) {
            filtered_mobstream.mobs_by_day = {};
        }

        if (filtered_mobstream.mobs_by_day[day_string] == undefined) {
            filtered_mobstream.mobs_by_day[day_string] = [];
        }

        filtered_mobstream.mobs_by_day[day_string].push(mob);
    }

    return filtered_mobstream;

}


/**
 * Top-level function to display the filtering animation,
 * get the filtered mobstream, replace the current mobstream with the
 * filtered one and stop the filtering animation.
 */
function filterMobstream() {
    startFilteringAnimation();
    var filtered_mobstream = getFilteredMobstream();
    replaceMobstream(filtered_mobstream);
    stopFilteringAnimation();
}


/* Initialize the location filtering map. We call this independently of page load
 * since it depends upon the mobstream loading first */
function initializeLocationFilterMap() {

    /* Adds map markers for the mobs present in the given mobstream_response object
     * to the given map.
     */
    function addMobMarkers(mobstream_response, map) {

        var markers = [];

        if (mobstream_response.mobs_by_day) {
            for (var day_string in mobstream_response.mobs_by_day) {
                var day_mobs = mobstream_response.mobs_by_day[day_string];
                for (var i in day_mobs) {
                    var curr_mob = day_mobs[i];
                    if (curr_mob.location_geocode) {
                        /* Build our marker for this mob. We set some breadcrumbs to speed up the process of
                         * finding the mob this marker refers to when it comes time to filter the mobstream
                         * based on the markers visible in the map viewport
                         */
                        var marker = new google.maps.Marker({
                            'position' : new google.maps.LatLng(curr_mob.location_geocode.lat, curr_mob.location_geocode.lon),
                            'map' : map
                        });
                        marker.set('day_string', day_string);
                        marker.set('day_array_index', i);
                        marker.set('mob_public_name', curr_mob.public_name);
                        marker.set('mob_url', curr_mob.link);

                        markers.push(marker);
                    }
                }
            }
        }

        map.set('markers', markers);
    }


    if ($("#location_filter_map").length) {
        $("#location_filter_map").gmap({
            'center' : new google.maps.LatLng(USER_LOCATION_GEO.lat, USER_LOCATION_GEO.lon),
            'streetViewControl' : false,
            'zoom' : 9,
            'mapTypeControl' : false
        }).bind('init', function(ev, map) {

            /* Bind a reference to the map to the div that it exists on. This way we can
             * grab it without needing it passed in as a param
             */
            $("#location_filter_map").data('map', map);

            /* Add map markers */
            mobstream_response = $('body').data('mobstream_data_response');
            addMobMarkers(mobstream_response, map);

            /* Bind to the 'idle' event - this event is fired when the user is done
             * panning or zooming the map.
             */
            google.maps.event.addListener(map, 'idle', function(e){

                /* On map initialisation, this listener will fire before
                 * the user has panned or zoomed the map. We want to stop
                 * this firing off a filtering request, so we check for the existence
                 * of a marker that we add the first time this listener is called.
                 */
                if ($("#location_filter_map").data('listener_attached')) {
                    filterMobstream();
                    mpmetrics.track('filter_mobstream', { 'user_public_name' : USER_PUBLIC_NAME,
                                                          'filter_by' : 'location' });
                } else {
                    $("#location_filter_map").data('listener_attached', true);
                }
                
            });

        });
    }

}

/* Called when the user changes the selected range on the time filter slider */
function timeFilterCallback(event, ui) {
    filterMobstream();
    mpmetrics.track('filter_mobstream', { 'user_public_name' : USER_PUBLIC_NAME,
                                          'filter_by' : 'time',
                                          'lower_bound' : ui.values[0],
                                          'upper_bound' : ui.values[1] });
}

/* Called when the user changes the selected range on the price filter slider */
function priceFilterCallback(event, ui) {
    filterMobstream();
    mpmetrics.track('filter_mobstream', { 'user_public_name' : USER_PUBLIC_NAME,
                                          'filter_by' : 'price',
                                          'lower_bound' : ui.values[0],
                                          'upper_bound' : ui.values[1] });
}


/* Update the displayed value for the time range */
function updateTimeRangeDisplay(event, ui) {

    if (ui.values[0] == 0 && ui.values[1] == 23) {
        /* any time */
        $("#time_filter .filter-range-display").text('any time');
    } else if (ui.values[0] == ui.values[1]) {
        $("#time_filter .filter-range-display").text(humanizeSliderTime(ui.values[0]));
    } else {
        $("#time_filter .filter-range-display").text(humanizeSliderTime(ui.values[0]) + " - " + humanizeSliderTime(ui.values[1]));
    }
}

/* Update the displayed value for the price range */
function updatePriceRangeDisplay(event, ui) {
    if (ui.values[0] == 0 && ui.values[1] == 30) {
        $("#price_filter .filter-range-display").text('any price');
    } else if (ui.values[0] == ui.values[1]) {
        $("#price_filter .filter-range-display").text("$" + ui.values[0]);
    } else {
        $("#price_filter .filter-range-display").text("$" + ui.values[0] + " - $" + ui.values[1]);
    }

}


function humanizeSliderTime(time_on_slider) {
    if (time_on_slider == 0) {
        return '12am';
    } else if (time_on_slider >= 1 && time_on_slider < 12) {
        return time_on_slider + 'am';
    } else if (time_on_slider == 12) {
        return time_on_slider + 'pm';
    } else if (time_on_slider > 12 && time_on_slider <= 23) {
        return (time_on_slider - 12) + 'pm';
    } else {
        throw new Error('dont know how to deal with the given slider time ' + time_on_slider);
    }
}



$(document).ready( function() {

    $("#time_filter_slider").slider({
        range : true,
        min : 0,
        values : [0, 23],
        max : 23,
        step : 1,
        stop : timeFilterCallback,
        slide : updateTimeRangeDisplay
    });
    $("#time_filter .filter-range-display").text('any time');


    $("#price_filter_slider").slider({
        range : true,
        min : 0,
        values : [0, 30],
        max : 30,
        step : 5,
        stop : priceFilterCallback,
        slide : updatePriceRangeDisplay
    });
    $("#price_filter .filter-range-display").text('any price');

});
