
/**
 * Baseurl
 *
 * @type {string}
 */
var baseurl;

/**
 * Powermail main JavaScript for form validation
 */
jQuery(document).ready(function($) {

	// Read baseURL
	baseurl = getBaseUrl();

	// Form validation
	if ($.fn.validationEngine) {
		$('.powermail_form').validationEngine();
	}

	// Tabs
	if ($.fn.powermailTabs) {
		$('.powermail_morestep').powermailTabs();
	}

	// Datepicker field
	if ($.fn.datepicker) {
		$('.powermail_date').datepicker({
			dateFormat: $('.container_datepicker_dateformat:first').val(),
			dayNamesMin: [
				$('.container_datepicker_day_so:first').val(),
				$('.container_datepicker_day_mo:first').val(),
				$('.container_datepicker_day_tu:first').val(),
				$('.container_datepicker_day_we:first').val(),
				$('.container_datepicker_day_th:first').val(),
				$('.container_datepicker_day_fr:first').val(),
				$('.container_datepicker_day_sa:first').val()
			],
			monthNames: [
				$('.container_datepicker_month_jan:first').val(),
				$('.container_datepicker_month_feb:first').val(),
				$('.container_datepicker_month_mar:first').val(),
				$('.container_datepicker_month_apr:first').val(),
				$('.container_datepicker_month_may:first').val(),
				$('.container_datepicker_month_jun:first').val(),
				$('.container_datepicker_month_jul:first').val(),
				$('.container_datepicker_month_aug:first').val(),
				$('.container_datepicker_month_sep:first').val(),
				$('.container_datepicker_month_oct:first').val(),
				$('.container_datepicker_month_nov:first').val(),
				$('.container_datepicker_month_dec:first').val()
			],
			nextText: '&gt;',
			prevText: '&lt;',
			firstDay: 1
		});
	}

	// Location field
	if ($('.powermail_fieldwrap_location input').length > 0) {
		getLocationAndWrite();
	}
});

/**
 * Custom Validation of checkboxes for powermail
 *
 * @param	object		Current Field
 * @param	object		Given Rules
 * @param	int			Index
 * @param	object		Options
 * @return	string		Error Message
 */
function checkCheckboxes(field, rules, i, options) {
	var checked = 0; // no checkbox checked at the beginning
	var classes = field.attr('class').split(' ');
	jQuery('.' + classes[1]).each(function() {
		if (jQuery(this).attr('checked')) {
			checked = 1;
		}
	});

	if (!checked) {
		return options.allrules.checkCheckboxes.alertText;
	}
}

/**
 * Getting the Location by the browser and write to inputform as address
 *
 * @return void
 */
function getLocationAndWrite() {
	if (navigator.geolocation) { // Read location from Browser
		navigator.geolocation.getCurrentPosition(function(position) {
			var lat = position.coords.latitude;
			var lng = position.coords.longitude;
			var url = baseurl + '/index.php' + '?eID=' + 'powermailEidGetLocation';
			jQuery.ajax({
				url: url,
				data: 'lat=' + lat + '&lng=' + lng,
				cache: false,
				beforeSend: function(jqXHR, settings) {
					jQuery('body').css('cursor', 'wait');
				},
				complete: function(jqXHR, textStatus) {
					jQuery('body').css('cursor', 'default');
				},
				success: function(data) { // return values
					if (data) {
						jQuery('.powermail_fieldwrap_location input').val(data);
					}
				}
			});
		});
	}
}

/**
 * Return BaseUrl as prefix
 *
 * @return	string	Base Url
 */
function getBaseUrl() {
	var baseurl;
	if (jQuery('base').length > 0) {
		baseurl = jQuery('base').attr('href');
	} else {
		if (window.location.protocol != "https:") {
			baseurl = 'http://' + window.location.hostname;
		} else {
			baseurl = 'https://' + window.location.hostname;
		}
	}
	return baseurl;
}
/**
 * Powermail_Frontend main JavaScript
 */
jQuery(document).ready(function($) {

});
/*
 * jQuery UI Datepicker 1.8.18
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Datepicker
 *
 * Depends:
 *	jquery.ui.core.js
 */(function($,undefined){function isArray(a){return a&&($.browser.safari&&typeof a=="object"&&a.length||a.constructor&&a.constructor.toString().match(/\Array\(\)/))}function extendRemove(a,b){$.extend(a,b);for(var c in b)if(b[c]==null||b[c]==undefined)a[c]=b[c];return a}function bindHover(a){var b="button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";return a.bind("mouseout",function(a){var c=$(a.target).closest(b);!c.length||c.removeClass("ui-state-hover ui-datepicker-prev-hover ui-datepicker-next-hover")}).bind("mouseover",function(c){var d=$(c.target).closest(b);!$.datepicker._isDisabledDatepicker(instActive.inline?a.parent()[0]:instActive.input[0])&&!!d.length&&(d.parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"),d.addClass("ui-state-hover"),d.hasClass("ui-datepicker-prev")&&d.addClass("ui-datepicker-prev-hover"),d.hasClass("ui-datepicker-next")&&d.addClass("ui-datepicker-next-hover"))})}function Datepicker(){this.debug=!1,this._curInst=null,this._keyEvent=!1,this._disabledInputs=[],this._datepickerShowing=!1,this._inDialog=!1,this._mainDivId="ui-datepicker-div",this._inlineClass="ui-datepicker-inline",this._appendClass="ui-datepicker-append",this._triggerClass="ui-datepicker-trigger",this._dialogClass="ui-datepicker-dialog",this._disableClass="ui-datepicker-disabled",this._unselectableClass="ui-datepicker-unselectable",this._currentClass="ui-datepicker-current-day",this._dayOverClass="ui-datepicker-days-cell-over",this.regional=[],this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su","Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:!1,hideIfNoPrevNext:!1,navigationAsDateFormat:!1,gotoCurrent:!1,changeMonth:!1,changeYear:!1,yearRange:"c-10:c+10",showOtherMonths:!1,selectOtherMonths:!1,showWeek:!1,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:!0,showButtonPanel:!1,autoSize:!1,disabled:!1},$.extend(this._defaults,this.regional[""]),this.dpDiv=bindHover($('<div id="'+this._mainDivId+'" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>'))}$.extend($.ui,{datepicker:{version:"1.8.18"}});var PROP_NAME="datepicker",dpuuid=(new Date).getTime(),instActive;$.extend(Datepicker.prototype,{markerClassName:"hasDatepicker",maxRows:4,log:function(){this.debug&&console.log.apply("",arguments)},_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(a){extendRemove(this._defaults,a||{});return this},_attachDatepicker:function(target,settings){var inlineSettings=null;for(var attrName in this._defaults){var attrValue=target.getAttribute("date:"+attrName);if(attrValue){inlineSettings=inlineSettings||{};try{inlineSettings[attrName]=eval(attrValue)}catch(err){inlineSettings[attrName]=attrValue}}}var nodeName=target.nodeName.toLowerCase(),inline=nodeName=="div"||nodeName=="span";target.id||(this.uuid+=1,target.id="dp"+this.uuid);var inst=this._newInst($(target),inline);inst.settings=$.extend({},settings||{},inlineSettings||{}),nodeName=="input"?this._connectDatepicker(target,inst):inline&&this._inlineDatepicker(target,inst)},_newInst:function(a,b){var c=a[0].id.replace(/([^A-Za-z0-9_-])/g,"\\\\$1");return{id:c,input:a,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:b,dpDiv:b?bindHover($('<div class="'+this._inlineClass+' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>')):this.dpDiv}},_connectDatepicker:function(a,b){var c=$(a);b.append=$([]),b.trigger=$([]);c.hasClass(this.markerClassName)||(this._attachments(c,b),c.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp).bind("setData.datepicker",function(a,c,d){b.settings[c]=d}).bind("getData.datepicker",function(a,c){return this._get(b,c)}),this._autoSize(b),$.data(a,PROP_NAME,b),b.settings.disabled&&this._disableDatepicker(a))},_attachments:function(a,b){var c=this._get(b,"appendText"),d=this._get(b,"isRTL");b.append&&b.append.remove(),c&&(b.append=$('<span class="'+this._appendClass+'">'+c+"</span>"),a[d?"before":"after"](b.append)),a.unbind("focus",this._showDatepicker),b.trigger&&b.trigger.remove();var e=this._get(b,"showOn");(e=="focus"||e=="both")&&a.focus(this._showDatepicker);if(e=="button"||e=="both"){var f=this._get(b,"buttonText"),g=this._get(b,"buttonImage");b.trigger=$(this._get(b,"buttonImageOnly")?$("<img/>").addClass(this._triggerClass).attr({src:g,alt:f,title:f}):$('<button type="button"></button>').addClass(this._triggerClass).html(g==""?f:$("<img/>").attr({src:g,alt:f,title:f}))),a[d?"before":"after"](b.trigger),b.trigger.click(function(){$.datepicker._datepickerShowing&&$.datepicker._lastInput==a[0]?$.datepicker._hideDatepicker():$.datepicker._datepickerShowing&&$.datepicker._lastInput!=a[0]?($.datepicker._hideDatepicker(),$.datepicker._showDatepicker(a[0])):$.datepicker._showDatepicker(a[0]);return!1})}},_autoSize:function(a){if(this._get(a,"autoSize")&&!a.inline){var b=new Date(2009,11,20),c=this._get(a,"dateFormat");if(c.match(/[DM]/)){var d=function(a){var b=0,c=0;for(var d=0;d<a.length;d++)a[d].length>b&&(b=a[d].length,c=d);return c};b.setMonth(d(this._get(a,c.match(/MM/)?"monthNames":"monthNamesShort"))),b.setDate(d(this._get(a,c.match(/DD/)?"dayNames":"dayNamesShort"))+20-b.getDay())}a.input.attr("size",this._formatDate(a,b).length)}},_inlineDatepicker:function(a,b){var c=$(a);c.hasClass(this.markerClassName)||(c.addClass(this.markerClassName).append(b.dpDiv).bind("setData.datepicker",function(a,c,d){b.settings[c]=d}).bind("getData.datepicker",function(a,c){return this._get(b,c)}),$.data(a,PROP_NAME,b),this._setDate(b,this._getDefaultDate(b),!0),this._updateDatepicker(b),this._updateAlternate(b),b.settings.disabled&&this._disableDatepicker(a),b.dpDiv.css("display","block"))},_dialogDatepicker:function(a,b,c,d,e){var f=this._dialogInst;if(!f){this.uuid+=1;var g="dp"+this.uuid;this._dialogInput=$('<input type="text" id="'+g+'" style="position: absolute; top: -100px; width: 0px; z-index: -10;"/>'),this._dialogInput.keydown(this._doKeyDown),$("body").append(this._dialogInput),f=this._dialogInst=this._newInst(this._dialogInput,!1),f.settings={},$.data(this._dialogInput[0],PROP_NAME,f)}extendRemove(f.settings,d||{}),b=b&&b.constructor==Date?this._formatDate(f,b):b,this._dialogInput.val(b),this._pos=e?e.length?e:[e.pageX,e.pageY]:null;if(!this._pos){var h=document.documentElement.clientWidth,i=document.documentElement.clientHeight,j=document.documentElement.scrollLeft||document.body.scrollLeft,k=document.documentElement.scrollTop||document.body.scrollTop;this._pos=[h/2-100+j,i/2-150+k]}this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px"),f.settings.onSelect=c,this._inDialog=!0,this.dpDiv.addClass(this._dialogClass),this._showDatepicker(this._dialogInput[0]),$.blockUI&&$.blockUI(this.dpDiv),$.data(this._dialogInput[0],PROP_NAME,f);return this},_destroyDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!!b.hasClass(this.markerClassName)){var d=a.nodeName.toLowerCase();$.removeData(a,PROP_NAME),d=="input"?(c.append.remove(),c.trigger.remove(),b.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)):(d=="div"||d=="span")&&b.removeClass(this.markerClassName).empty()}},_enableDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!!b.hasClass(this.markerClassName)){var d=a.nodeName.toLowerCase();if(d=="input")a.disabled=!1,c.trigger.filter("button").each(function(){this.disabled=!1}).end().filter("img").css({opacity:"1.0",cursor:""});else if(d=="div"||d=="span"){var e=b.children("."+this._inlineClass);e.children().removeClass("ui-state-disabled"),e.find("select.ui-datepicker-month, select.ui-datepicker-year").removeAttr("disabled")}this._disabledInputs=$.map(this._disabledInputs,function(b){return b==a?null:b})}},_disableDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!!b.hasClass(this.markerClassName)){var d=a.nodeName.toLowerCase();if(d=="input")a.disabled=!0,c.trigger.filter("button").each(function(){this.disabled=!0}).end().filter("img").css({opacity:"0.5",cursor:"default"});else if(d=="div"||d=="span"){var e=b.children("."+this._inlineClass);e.children().addClass("ui-state-disabled"),e.find("select.ui-datepicker-month, select.ui-datepicker-year").attr("disabled","disabled")}this._disabledInputs=$.map(this._disabledInputs,function(b){return b==a?null:b}),this._disabledInputs[this._disabledInputs.length]=a}},_isDisabledDatepicker:function(a){if(!a)return!1;for(var b=0;b<this._disabledInputs.length;b++)if(this._disabledInputs[b]==a)return!0;return!1},_getInst:function(a){try{return $.data(a,PROP_NAME)}catch(b){throw"Missing instance data for this datepicker"}},_optionDatepicker:function(a,b,c){var d=this._getInst(a);if(arguments.length==2&&typeof b=="string")return b=="defaults"?$.extend({},$.datepicker._defaults):d?b=="all"?$.extend({},d.settings):this._get(d,b):null;var e=b||{};typeof b=="string"&&(e={},e[b]=c);if(d){this._curInst==d&&this._hideDatepicker();var f=this._getDateDatepicker(a,!0),g=this._getMinMaxDate(d,"min"),h=this._getMinMaxDate(d,"max");extendRemove(d.settings,e),g!==null&&e.dateFormat!==undefined&&e.minDate===undefined&&(d.settings.minDate=this._formatDate(d,g)),h!==null&&e.dateFormat!==undefined&&e.maxDate===undefined&&(d.settings.maxDate=this._formatDate(d,h)),this._attachments($(a),d),this._autoSize(d),this._setDate(d,f),this._updateAlternate(d),this._updateDatepicker(d)}},_changeDatepicker:function(a,b,c){this._optionDatepicker(a,b,c)},_refreshDatepicker:function(a){var b=this._getInst(a);b&&this._updateDatepicker(b)},_setDateDatepicker:function(a,b){var c=this._getInst(a);c&&(this._setDate(c,b),this._updateDatepicker(c),this._updateAlternate(c))},_getDateDatepicker:function(a,b){var c=this._getInst(a);c&&!c.inline&&this._setDateFromField(c,b);return c?this._getDate(c):null},_doKeyDown:function(a){var b=$.datepicker._getInst(a.target),c=!0,d=b.dpDiv.is(".ui-datepicker-rtl");b._keyEvent=!0;if($.datepicker._datepickerShowing)switch(a.keyCode){case 9:$.datepicker._hideDatepicker(),c=!1;break;case 13:var e=$("td."+$.datepicker._dayOverClass+":not(."+$.datepicker._currentClass+")",b.dpDiv);e[0]&&$.datepicker._selectDay(a.target,b.selectedMonth,b.selectedYear,e[0]);var f=$.datepicker._get(b,"onSelect");if(f){var g=$.datepicker._formatDate(b);f.apply(b.input?b.input[0]:null,[g,b])}else $.datepicker._hideDatepicker();return!1;case 27:$.datepicker._hideDatepicker();break;case 33:$.datepicker._adjustDate(a.target,a.ctrlKey?-$.datepicker._get(b,"stepBigMonths"):-$.datepicker._get(b,"stepMonths"),"M");break;case 34:$.datepicker._adjustDate(a.target,a.ctrlKey?+$.datepicker._get(b,"stepBigMonths"):+$.datepicker._get(b,"stepMonths"),"M");break;case 35:(a.ctrlKey||a.metaKey)&&$.datepicker._clearDate(a.target),c=a.ctrlKey||a.metaKey;break;case 36:(a.ctrlKey||a.metaKey)&&$.datepicker._gotoToday(a.target),c=a.ctrlKey||a.metaKey;break;case 37:(a.ctrlKey||a.metaKey)&&$.datepicker._adjustDate(a.target,d?1:-1,"D"),c=a.ctrlKey||a.metaKey,a.originalEvent.altKey&&$.datepicker._adjustDate(a.target,a.ctrlKey?-$.datepicker._get(b,"stepBigMonths"):-$.datepicker._get(b,"stepMonths"),"M");break;case 38:(a.ctrlKey||a.metaKey)&&$.datepicker._adjustDate(a.target,-7,"D"),c=a.ctrlKey||a.metaKey;break;case 39:(a.ctrlKey||a.metaKey)&&$.datepicker._adjustDate(a.target,d?-1:1,"D"),c=a.ctrlKey||a.metaKey,a.originalEvent.altKey&&$.datepicker._adjustDate(a.target,a.ctrlKey?+$.datepicker._get(b,"stepBigMonths"):+$.datepicker._get(b,"stepMonths"),"M");break;case 40:(a.ctrlKey||a.metaKey)&&$.datepicker._adjustDate(a.target,7,"D"),c=a.ctrlKey||a.metaKey;break;default:c=!1}else a.keyCode==36&&a.ctrlKey?$.datepicker._showDatepicker(this):c=!1;c&&(a.preventDefault(),a.stopPropagation())},_doKeyPress:function(a){var b=$.datepicker._getInst(a.target);if($.datepicker._get(b,"constrainInput")){var c=$.datepicker._possibleChars($.datepicker._get(b,"dateFormat")),d=String.fromCharCode(a.charCode==undefined?a.keyCode:a.charCode);return a.ctrlKey||a.metaKey||d<" "||!c||c.indexOf(d)>-1}},_doKeyUp:function(a){var b=$.datepicker._getInst(a.target);if(b.input.val()!=b.lastVal)try{var c=$.datepicker.parseDate($.datepicker._get(b,"dateFormat"),b.input?b.input.val():null,$.datepicker._getFormatConfig(b));c&&($.datepicker._setDateFromField(b),$.datepicker._updateAlternate(b),$.datepicker._updateDatepicker(b))}catch(a){$.datepicker.log(a)}return!0},_showDatepicker:function(a){a=a.target||a,a.nodeName.toLowerCase()!="input"&&(a=$("input",a.parentNode)[0]);if(!$.datepicker._isDisabledDatepicker(a)&&$.datepicker._lastInput!=a){var b=$.datepicker._getInst(a);$.datepicker._curInst&&$.datepicker._curInst!=b&&($.datepicker._curInst.dpDiv.stop(!0,!0),b&&$.datepicker._datepickerShowing&&$.datepicker._hideDatepicker($.datepicker._curInst.input[0]));var c=$.datepicker._get(b,"beforeShow"),d=c?c.apply(a,[a,b]):{};if(d===!1)return;extendRemove(b.settings,d),b.lastVal=null,$.datepicker._lastInput=a,$.datepicker._setDateFromField(b),$.datepicker._inDialog&&(a.value=""),$.datepicker._pos||($.datepicker._pos=$.datepicker._findPos(a),$.datepicker._pos[1]+=a.offsetHeight);var e=!1;$(a).parents().each(function(){e|=$(this).css("position")=="fixed";return!e}),e&&$.browser.opera&&($.datepicker._pos[0]-=document.documentElement.scrollLeft,$.datepicker._pos[1]-=document.documentElement.scrollTop);var f={left:$.datepicker._pos[0],top:$.datepicker._pos[1]};$.datepicker._pos=null,b.dpDiv.empty(),b.dpDiv.css({position:"absolute",display:"block",top:"-1000px"}),$.datepicker._updateDatepicker(b),f=$.datepicker._checkOffset(b,f,e),b.dpDiv.css({position:$.datepicker._inDialog&&$.blockUI?"static":e?"fixed":"absolute",display:"none",left:f.left+"px",top:f.top+"px"});if(!b.inline){var g=$.datepicker._get(b,"showAnim"),h=$.datepicker._get(b,"duration"),i=function(){var a=b.dpDiv.find("iframe.ui-datepicker-cover");if(!!a.length){var c=$.datepicker._getBorders(b.dpDiv);a.css({left:-c[0],top:-c[1],width:b.dpDiv.outerWidth(),height:b.dpDiv.outerHeight()})}};b.dpDiv.zIndex($(a).zIndex()+1),$.datepicker._datepickerShowing=!0,$.effects&&$.effects[g]?b.dpDiv.show(g,$.datepicker._get(b,"showOptions"),h,i):b.dpDiv[g||"show"](g?h:null,i),(!g||!h)&&i(),b.input.is(":visible")&&!b.input.is(":disabled")&&b.input.focus(),$.datepicker._curInst=b}}},_updateDatepicker:function(a){var b=this;b.maxRows=4;var c=$.datepicker._getBorders(a.dpDiv);instActive=a,a.dpDiv.empty().append(this._generateHTML(a));var d=a.dpDiv.find("iframe.ui-datepicker-cover");!d.length||d.css({left:-c[0],top:-c[1],width:a.dpDiv.outerWidth(),height:a.dpDiv.outerHeight()}),a.dpDiv.find("."+this._dayOverClass+" a").mouseover();var e=this._getNumberOfMonths(a),f=e[1],g=17;a.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""),f>1&&a.dpDiv.addClass("ui-datepicker-multi-"+f).css("width",g*f+"em"),a.dpDiv[(e[0]!=1||e[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi"),a.dpDiv[(this._get(a,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl"),a==$.datepicker._curInst&&$.datepicker._datepickerShowing&&a.input&&a.input.is(":visible")&&!a.input.is(":disabled")&&a.input[0]!=document.activeElement&&a.input.focus();if(a.yearshtml){var h=a.yearshtml;setTimeout(function(){h===a.yearshtml&&a.yearshtml&&a.dpDiv.find("select.ui-datepicker-year:first").replaceWith(a.yearshtml),h=a.yearshtml=null},0)}},_getBorders:function(a){var b=function(a){return{thin:1,medium:2,thick:3}[a]||a};return[parseFloat(b(a.css("border-left-width"))),parseFloat(b(a.css("border-top-width")))]},_checkOffset:function(a,b,c){var d=a.dpDiv.outerWidth(),e=a.dpDiv.outerHeight(),f=a.input?a.input.outerWidth():0,g=a.input?a.input.outerHeight():0,h=document.documentElement.clientWidth+$(document).scrollLeft(),i=document.documentElement.clientHeight+$(document).scrollTop();b.left-=this._get(a,"isRTL")?d-f:0,b.left-=c&&b.left==a.input.offset().left?$(document).scrollLeft():0,b.top-=c&&b.top==a.input.offset().top+g?$(document).scrollTop():0,b.left-=Math.min(b.left,b.left+d>h&&h>d?Math.abs(b.left+d-h):0),b.top-=Math.min(b.top,b.top+e>i&&i>e?Math.abs(e+g):0);return b},_findPos:function(a){var b=this._getInst(a),c=this._get(b,"isRTL");while(a&&(a.type=="hidden"||a.nodeType!=1||$.expr.filters.hidden(a)))a=a[c?"previousSibling":"nextSibling"];var d=$(a).offset();return[d.left,d.top]},_hideDatepicker:function(a){var b=this._curInst;if(!(!b||a&&b!=$.data(a,PROP_NAME))&&this._datepickerShowing){var c=this._get(b,"showAnim"),d=this._get(b,"duration"),e=this,f=function(){$.datepicker._tidyDialog(b),e._curInst=null};$.effects&&$.effects[c]?b.dpDiv.hide(c,$.datepicker._get(b,"showOptions"),d,f):b.dpDiv[c=="slideDown"?"slideUp":c=="fadeIn"?"fadeOut":"hide"](c?d:null,f),c||f(),this._datepickerShowing=!1;var g=this._get(b,"onClose");g&&g.apply(b.input?b.input[0]:null,[b.input?b.input.val():"",b]),this._lastInput=null,this._inDialog&&(this._dialogInput.css({position:"absolute",left:"0",top:"-100px"}),$.blockUI&&($.unblockUI(),$("body").append(this.dpDiv))),this._inDialog=!1}},_tidyDialog:function(a){a.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(a){if(!!$.datepicker._curInst){var b=$(a.target),c=$.datepicker._getInst(b[0]);(b[0].id!=$.datepicker._mainDivId&&b.parents("#"+$.datepicker._mainDivId).length==0&&!b.hasClass($.datepicker.markerClassName)&&!b.closest("."+$.datepicker._triggerClass).length&&$.datepicker._datepickerShowing&&(!$.datepicker._inDialog||!$.blockUI)||b.hasClass($.datepicker.markerClassName)&&$.datepicker._curInst!=c)&&$.datepicker._hideDatepicker()}},_adjustDate:function(a,b,c){var d=$(a),e=this._getInst(d[0]);this._isDisabledDatepicker(d[0])||(this._adjustInstDate(e,b+(c=="M"?this._get(e,"showCurrentAtPos"):0),c),this._updateDatepicker(e))},_gotoToday:function(a){var b=$(a),c=this._getInst(b[0]);if(this._get(c,"gotoCurrent")&&c.currentDay)c.selectedDay=c.currentDay,c.drawMonth=c.selectedMonth=c.currentMonth,c.drawYear=c.selectedYear=c.currentYear;else{var d=new Date;c.selectedDay=d.getDate(),c.drawMonth=c.selectedMonth=d.getMonth(),c.drawYear=c.selectedYear=d.getFullYear()}this._notifyChange(c),this._adjustDate(b)},_selectMonthYear:function(a,b,c){var d=$(a),e=this._getInst(d[0]);e["selected"+(c=="M"?"Month":"Year")]=e["draw"+(c=="M"?"Month":"Year")]=parseInt(b.options[b.selectedIndex].value,10),this._notifyChange(e),this._adjustDate(d)},_selectDay:function(a,b,c,d){var e=$(a);if(!$(d).hasClass(this._unselectableClass)&&!this._isDisabledDatepicker(e[0])){var f=this._getInst(e[0]);f.selectedDay=f.currentDay=$("a",d).html(),f.selectedMonth=f.currentMonth=b,f.selectedYear=f.currentYear=c,this._selectDate(a,this._formatDate(f,f.currentDay,f.currentMonth,f.currentYear))}},_clearDate:function(a){var b=$(a),c=this._getInst(b[0]);this._selectDate(b,"")},_selectDate:function(a,b){var c=$(a),d=this._getInst(c[0]);b=b!=null?b:this._formatDate(d),d.input&&d.input.val(b),this._updateAlternate(d);var e=this._get(d,"onSelect");e?e.apply(d.input?d.input[0]:null,[b,d]):d.input&&d.input.trigger("change"),d.inline?this._updateDatepicker(d):(this._hideDatepicker(),this._lastInput=d.input[0],typeof d.input[0]!="object"&&d.input.focus(),this._lastInput=null)},_updateAlternate:function(a){var b=this._get(a,"altField");if(b){var c=this._get(a,"altFormat")||this._get(a,"dateFormat"),d=this._getDate(a),e=this.formatDate(c,d,this._getFormatConfig(a));$(b).each(function(){$(this).val(e)})}},noWeekends:function(a){var b=a.getDay();return[b>0&&b<6,""]},iso8601Week:function(a){var b=new Date(a.getTime());b.setDate(b.getDate()+4-(b.getDay()||7));var c=b.getTime();b.setMonth(0),b.setDate(1);return Math.floor(Math.round((c-b)/864e5)/7)+1},parseDate:function(a,b,c){if(a==null||b==null)throw"Invalid arguments";b=typeof b=="object"?b.toString():b+"";if(b=="")return null;var d=(c?c.shortYearCutoff:null)||this._defaults.shortYearCutoff;d=typeof d!="string"?d:(new Date).getFullYear()%100+parseInt(d,10);var e=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,f=(c?c.dayNames:null)||this._defaults.dayNames,g=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,h=(c?c.monthNames:null)||this._defaults.monthNames,i=-1,j=-1,k=-1,l=-1,m=!1,n=function(b){var c=s+1<a.length&&a.charAt(s+1)==b;c&&s++;return c},o=function(a){var c=n(a),d=a=="@"?14:a=="!"?20:a=="y"&&c?4:a=="o"?3:2,e=new RegExp("^\\d{1,"+d+"}"),f=b.substring(r).match(e);if(!f)throw"Missing number at position "+r;r+=f[0].length;return parseInt(f[0],10)},p=function(a,c,d){var e=$.map(n(a)?d:c,function(a,b){return[[b,a]]}).sort(function(a,b){return-(a[1].length-b[1].length)}),f=-1;$.each(e,function(a,c){var d=c[1];if(b.substr(r,d.length).toLowerCase()==d.toLowerCase()){f=c[0],r+=d.length;return!1}});if(f!=-1)return f+1;throw"Unknown name at position "+r},q=function(){if(b.charAt(r)!=a.charAt(s))throw"Unexpected literal at position "+r;r++},r=0;for(var s=0;s<a.length;s++)if(m)a.charAt(s)=="'"&&!n("'")?m=!1:q();else switch(a.charAt(s)){case"d":k=o("d");break;case"D":p("D",e,f);break;case"o":l=o("o");break;case"m":j=o("m");break;case"M":j=p("M",g,h);break;case"y":i=o("y");break;case"@":var t=new Date(o("@"));i=t.getFullYear(),j=t.getMonth()+1,k=t.getDate();break;case"!":var t=new Date((o("!")-this._ticksTo1970)/1e4);i=t.getFullYear(),j=t.getMonth()+1,k=t.getDate();break;case"'":n("'")?q():m=!0;break;default:q()}if(r<b.length)throw"Extra/unparsed characters found in date: "+b.substring(r);i==-1?i=(new Date).getFullYear():i<100&&(i+=(new Date).getFullYear()-(new Date).getFullYear()%100+(i<=d?0:-100));if(l>-1){j=1,k=l;for(;;){var u=this._getDaysInMonth(i,j-1);if(k<=u)break;j++,k-=u}}var t=this._daylightSavingAdjust(new Date(i,j-1,k));if(t.getFullYear()!=i||t.getMonth()+1!=j||t.getDate()!=k)throw"Invalid date";return t},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925))*24*60*60*1e7,formatDate:function(a,b,c){if(!b)return"";var d=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,e=(c?c.dayNames:null)||this._defaults.dayNames,f=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,g=(c?c.monthNames:null)||this._defaults.monthNames,h=function(b){var c=m+1<a.length&&a.charAt(m+1)==b;c&&m++;return c},i=function(a,b,c){var d=""+b;if(h(a))while(d.length<c)d="0"+d;return d},j=function(a,b,c,d){return h(a)?d[b]:c[b]},k="",l=!1;if(b)for(var m=0;m<a.length;m++)if(l)a.charAt(m)=="'"&&!h("'")?l=!1:k+=a.charAt(m);else switch(a.charAt(m)){case"d":k+=i("d",b.getDate(),2);break;case"D":k+=j("D",b.getDay(),d,e);break;case"o":k+=i("o",Math.round(((new Date(b.getFullYear(),b.getMonth(),b.getDate())).getTime()-(new Date(b.getFullYear(),0,0)).getTime())/864e5),3);break;case"m":k+=i("m",b.getMonth()+1,2);break;case"M":k+=j("M",b.getMonth(),f,g);break;case"y":k+=h("y")?b.getFullYear():(b.getYear()%100<10?"0":"")+b.getYear()%100;break;case"@":k+=b.getTime();break;case"!":k+=b.getTime()*1e4+this._ticksTo1970;break;case"'":h("'")?k+="'":l=!0;break;default:k+=a.charAt(m)}return k},_possibleChars:function(a){var b="",c=!1,d=function(b){var c=e+1<a.length&&a.charAt(e+1)==b;c&&e++;return c};for(var e=0;e<a.length;e++)if(c)a.charAt(e)=="'"&&!d("'")?c=!1:b+=a.charAt(e);else switch(a.charAt(e)){case"d":case"m":case"y":case"@":b+="0123456789";break;case"D":case"M":return null;case"'":d("'")?b+="'":c=!0;break;default:b+=a.charAt(e)}return b},_get:function(a,b){return a.settings[b]!==undefined?a.settings[b]:this._defaults[b]},_setDateFromField:function(a,b){if(a.input.val()!=a.lastVal){var c=this._get(a,"dateFormat"),d=a.lastVal=a.input?a.input.val():null,e,f;e=f=this._getDefaultDate(a);var g=this._getFormatConfig(a);try{e=this.parseDate(c,d,g)||f}catch(h){this.log(h),d=b?"":d}a.selectedDay=e.getDate(),a.drawMonth=a.selectedMonth=e.getMonth(),a.drawYear=a.selectedYear=e.getFullYear(),a.currentDay=d?e.getDate():0,a.currentMonth=d?e.getMonth():0,a.currentYear=d?e.getFullYear():0,this._adjustInstDate(a)}},_getDefaultDate:function(a){return this._restrictMinMax(a,this._determineDate(a,this._get(a,"defaultDate"),new Date))},_determineDate:function(a,b,c){var d=function(a){var b=new Date;b.setDate(b.getDate()+a);return b},e=function(b){try{return $.datepicker.parseDate($.datepicker._get(a,"dateFormat"),b,$.datepicker._getFormatConfig(a))}catch(c){}var d=(b.toLowerCase().match(/^c/)?$.datepicker._getDate(a):null)||new Date,e=d.getFullYear(),f=d.getMonth(),g=d.getDate(),h=/([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,i=h.exec(b);while(i){switch(i[2]||"d"){case"d":case"D":g+=parseInt(i[1],10);break;case"w":case"W":g+=parseInt(i[1],10)*7;break;case"m":case"M":f+=parseInt(i[1],10),g=Math.min(g,$.datepicker._getDaysInMonth(e,f));break;case"y":case"Y":e+=parseInt(i[1],10),g=Math.min(g,$.datepicker._getDaysInMonth(e,f))}i=h.exec(b)}return new Date(e,f,g)},f=b==null||b===""?c:typeof b=="string"?e(b):typeof b=="number"?isNaN(b)?c:d(b):new Date(b.getTime());f=f&&f.toString()=="Invalid Date"?c:f,f&&(f.setHours(0),f.setMinutes(0),f.setSeconds(0),f.setMilliseconds(0));return this._daylightSavingAdjust(f)},_daylightSavingAdjust:function(a){if(!a)return null;a.setHours(a.getHours()>12?a.getHours()+2:0);return a},_setDate:function(a,b,c){var d=!b,e=a.selectedMonth,f=a.selectedYear,g=this._restrictMinMax(a,this._determineDate(a,b,new Date));a.selectedDay=a.currentDay=g.getDate(),a.drawMonth=a.selectedMonth=a.currentMonth=g.getMonth(),a.drawYear=a.selectedYear=a.currentYear=g.getFullYear(),(e!=a.selectedMonth||f!=a.selectedYear)&&!c&&this._notifyChange(a),this._adjustInstDate(a),a.input&&a.input.val(d?"":this._formatDate(a))},_getDate:function(a){var b=!a.currentYear||a.input&&a.input.val()==""?null:this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return b},_generateHTML:function(a){var b=new Date;b=this._daylightSavingAdjust(new Date(b.getFullYear(),b.getMonth(),b.getDate()));var c=this._get(a,"isRTL"),d=this._get(a,"showButtonPanel"),e=this._get(a,"hideIfNoPrevNext"),f=this._get(a,"navigationAsDateFormat"),g=this._getNumberOfMonths(a),h=this._get(a,"showCurrentAtPos"),i=this._get(a,"stepMonths"),j=g[0]!=1||g[1]!=1,k=this._daylightSavingAdjust(a.currentDay?new Date(a.currentYear,a.currentMonth,a.currentDay):new Date(9999,9,9)),l=this._getMinMaxDate(a,"min"),m=this._getMinMaxDate(a,"max"),n=a.drawMonth-h,o=a.drawYear;n<0&&(n+=12,o--);if(m){var p=this._daylightSavingAdjust(new Date(m.getFullYear(),m.getMonth()-g[0]*g[1]+1,m.getDate()));p=l&&p<l?l:p;while(this._daylightSavingAdjust(new Date(o,n,1))>p)n--,n<0&&(n=11,o--)}a.drawMonth=n,a.drawYear=o;var q=this._get(a,"prevText");q=f?this.formatDate(q,this._daylightSavingAdjust(new Date(o,n-i,1)),this._getFormatConfig(a)):q;var r=this._canAdjustMonth(a,-1,o,n)?'<a class="ui-datepicker-prev ui-corner-all" onclick="DP_jQuery_'+dpuuid+".datepicker._adjustDate('#"+a.id+"', -"+i+", 'M');\""+' title="'+q+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"e":"w")+'">'+q+"</span></a>":e?"":'<a class="ui-datepicker-prev ui-corner-all ui-state-disabled" title="'+q+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"e":"w")+'">'+q+"</span></a>",s=this._get(a,"nextText");s=f?this.formatDate(s,this._daylightSavingAdjust(new Date(o,n+i,1)),this._getFormatConfig(a)):s;var t=this._canAdjustMonth(a,1,o,n)?'<a class="ui-datepicker-next ui-corner-all" onclick="DP_jQuery_'+dpuuid+".datepicker._adjustDate('#"+a.id+"', +"+i+", 'M');\""+' title="'+s+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"w":"e")+'">'+s+"</span></a>":e?"":'<a class="ui-datepicker-next ui-corner-all ui-state-disabled" title="'+s+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"w":"e")+'">'+s+"</span></a>",u=this._get(a,"currentText"),v=this._get(a,"gotoCurrent")&&a.currentDay?k:b;u=f?this.formatDate(u,v,this._getFormatConfig(a)):u;var w=a.inline?"":'<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" onclick="DP_jQuery_'+dpuuid+'.datepicker._hideDatepicker();">'+this._get(a,"closeText")+"</button>",x=d?'<div class="ui-datepicker-buttonpane ui-widget-content">'+(c?w:"")+(this._isInRange(a,v)?'<button type="button" class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all" onclick="DP_jQuery_'+dpuuid+".datepicker._gotoToday('#"+a.id+"');\""+">"+u+"</button>":"")+(c?"":w)+"</div>":"",y=parseInt(this._get(a,"firstDay"),10);y=isNaN(y)?0:y;var z=this._get(a,"showWeek"),A=this._get(a,"dayNames"),B=this._get(a,"dayNamesShort"),C=this._get(a,"dayNamesMin"),D=this._get(a,"monthNames"),E=this._get(a,"monthNamesShort"),F=this._get(a,"beforeShowDay"),G=this._get(a,"showOtherMonths"),H=this._get(a,"selectOtherMonths"),I=this._get(a,"calculateWeek")||this.iso8601Week,J=this._getDefaultDate(a),K="";for(var L=0;L<g[0];L++){var M="";this.maxRows=4;for(var N=0;N<g[1];N++){var O=this._daylightSavingAdjust(new Date(o,n,a.selectedDay)),P=" ui-corner-all",Q="";if(j){Q+='<div class="ui-datepicker-group';if(g[1]>1)switch(N){case 0:Q+=" ui-datepicker-group-first",P=" ui-corner-"+(c?"right":"left");break;case g[1]-1:Q+=" ui-datepicker-group-last",P=" ui-corner-"+(c?"left":"right");break;default:Q+=" ui-datepicker-group-middle",P=""}Q+='">'}Q+='<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix'+P+'">'+(/all|left/.test(P)&&L==0?c?t:r:"")+(/all|right/.test(P)&&L==0?c?r:t:"")+this._generateMonthYearHeader(a,n,o,l,m,L>0||N>0,D,E)+'</div><table class="ui-datepicker-calendar"><thead>'+"<tr>";var R=z?'<th class="ui-datepicker-week-col">'+this._get(a,"weekHeader")+"</th>":"";for(var S=0;S<7;S++){var T=(S+y)%7;R+="<th"+((S+y+6)%7>=5?' class="ui-datepicker-week-end"':"")+">"+'<span title="'+A[T]+'">'+C[T]+"</span></th>"}Q+=R+"</tr></thead><tbody>";var U=this._getDaysInMonth(o,n);o==a.selectedYear&&n==a.selectedMonth&&(a.selectedDay=Math.min(a.selectedDay,U));var V=(this._getFirstDayOfMonth(o,n)-y+7)%7,W=Math.ceil((V+U)/7),X=j?this.maxRows>W?this.maxRows:W:W;this.maxRows=X;var Y=this._daylightSavingAdjust(new Date(o,n,1-V));for(var Z=0;Z<X;Z++){Q+="<tr>";var _=z?'<td class="ui-datepicker-week-col">'+this._get(a,"calculateWeek")(Y)+"</td>":"";for(var S=0;S<7;S++){var ba=F?F.apply(a.input?a.input[0]:null,[Y]):[!0,""],bb=Y.getMonth()!=n,bc=bb&&!H||!ba[0]||l&&Y<l||m&&Y>m;_+='<td class="'+((S+y+6)%7>=5?" ui-datepicker-week-end":"")+(bb?" ui-datepicker-other-month":"")+(Y.getTime()==O.getTime()&&n==a.selectedMonth&&a._keyEvent||J.getTime()==Y.getTime()&&J.getTime()==O.getTime()?" "+this._dayOverClass:"")+(bc?" "+this._unselectableClass+" ui-state-disabled":"")+(bb&&!G?"":" "+ba[1]+(Y.getTime()==k.getTime()?" "+this._currentClass:"")+(Y.getTime()==b.getTime()?" ui-datepicker-today":""))+'"'+((!bb||G)&&ba[2]?' title="'+ba[2]+'"':"")+(bc?"":' onclick="DP_jQuery_'+dpuuid+".datepicker._selectDay('#"+a.id+"',"+Y.getMonth()+","+Y.getFullYear()+', this);return false;"')+">"+(bb&&!G?"&#xa0;":bc?'<span class="ui-state-default">'+Y.getDate()+"</span>":'<a class="ui-state-default'+(Y.getTime()==b.getTime()?" ui-state-highlight":"")+(Y.getTime()==k.getTime()?" ui-state-active":"")+(bb?" ui-priority-secondary":"")+'" href="#">'+Y.getDate()+"</a>")+"</td>",Y.setDate(Y.getDate()+1),Y=this._daylightSavingAdjust(Y)}Q+=_+"</tr>"}n++,n>11&&(n=0,o++),Q+="</tbody></table>"+(j?"</div>"+(g[0]>0&&N==g[1]-1?'<div class="ui-datepicker-row-break"></div>':""):""),M+=Q}K+=M}K+=x+($.browser.msie&&parseInt($.browser.version,10)<7&&!a.inline?'<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>':""),
a._keyEvent=!1;return K},_generateMonthYearHeader:function(a,b,c,d,e,f,g,h){var i=this._get(a,"changeMonth"),j=this._get(a,"changeYear"),k=this._get(a,"showMonthAfterYear"),l='<div class="ui-datepicker-title">',m="";if(f||!i)m+='<span class="ui-datepicker-month">'+g[b]+"</span>";else{var n=d&&d.getFullYear()==c,o=e&&e.getFullYear()==c;m+='<select class="ui-datepicker-month" onchange="DP_jQuery_'+dpuuid+".datepicker._selectMonthYear('#"+a.id+"', this, 'M');\" "+">";for(var p=0;p<12;p++)(!n||p>=d.getMonth())&&(!o||p<=e.getMonth())&&(m+='<option value="'+p+'"'+(p==b?' selected="selected"':"")+">"+h[p]+"</option>");m+="</select>"}k||(l+=m+(f||!i||!j?"&#xa0;":""));if(!a.yearshtml){a.yearshtml="";if(f||!j)l+='<span class="ui-datepicker-year">'+c+"</span>";else{var q=this._get(a,"yearRange").split(":"),r=(new Date).getFullYear(),s=function(a){var b=a.match(/c[+-].*/)?c+parseInt(a.substring(1),10):a.match(/[+-].*/)?r+parseInt(a,10):parseInt(a,10);return isNaN(b)?r:b},t=s(q[0]),u=Math.max(t,s(q[1]||""));t=d?Math.max(t,d.getFullYear()):t,u=e?Math.min(u,e.getFullYear()):u,a.yearshtml+='<select class="ui-datepicker-year" onchange="DP_jQuery_'+dpuuid+".datepicker._selectMonthYear('#"+a.id+"', this, 'Y');\" "+">";for(;t<=u;t++)a.yearshtml+='<option value="'+t+'"'+(t==c?' selected="selected"':"")+">"+t+"</option>";a.yearshtml+="</select>",l+=a.yearshtml,a.yearshtml=null}}l+=this._get(a,"yearSuffix"),k&&(l+=(f||!i||!j?"&#xa0;":"")+m),l+="</div>";return l},_adjustInstDate:function(a,b,c){var d=a.drawYear+(c=="Y"?b:0),e=a.drawMonth+(c=="M"?b:0),f=Math.min(a.selectedDay,this._getDaysInMonth(d,e))+(c=="D"?b:0),g=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(d,e,f)));a.selectedDay=g.getDate(),a.drawMonth=a.selectedMonth=g.getMonth(),a.drawYear=a.selectedYear=g.getFullYear(),(c=="M"||c=="Y")&&this._notifyChange(a)},_restrictMinMax:function(a,b){var c=this._getMinMaxDate(a,"min"),d=this._getMinMaxDate(a,"max"),e=c&&b<c?c:b;e=d&&e>d?d:e;return e},_notifyChange:function(a){var b=this._get(a,"onChangeMonthYear");b&&b.apply(a.input?a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){var b=this._get(a,"numberOfMonths");return b==null?[1,1]:typeof b=="number"?[1,b]:b},_getMinMaxDate:function(a,b){return this._determineDate(a,this._get(a,b+"Date"),null)},_getDaysInMonth:function(a,b){return 32-this._daylightSavingAdjust(new Date(a,b,32)).getDate()},_getFirstDayOfMonth:function(a,b){return(new Date(a,b,1)).getDay()},_canAdjustMonth:function(a,b,c,d){var e=this._getNumberOfMonths(a),f=this._daylightSavingAdjust(new Date(c,d+(b<0?b:e[0]*e[1]),1));b<0&&f.setDate(this._getDaysInMonth(f.getFullYear(),f.getMonth()));return this._isInRange(a,f)},_isInRange:function(a,b){var c=this._getMinMaxDate(a,"min"),d=this._getMinMaxDate(a,"max");return(!c||b.getTime()>=c.getTime())&&(!d||b.getTime()<=d.getTime())},_getFormatConfig:function(a){var b=this._get(a,"shortYearCutoff");b=typeof b!="string"?b:(new Date).getFullYear()%100+parseInt(b,10);return{shortYearCutoff:b,dayNamesShort:this._get(a,"dayNamesShort"),dayNames:this._get(a,"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,b,c,d){b||(a.currentDay=a.selectedDay,a.currentMonth=a.selectedMonth,a.currentYear=a.selectedYear);var e=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(d,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),e,this._getFormatConfig(a))}}),$.fn.datepicker=function(a){if(!this.length)return this;$.datepicker.initialized||($(document).mousedown($.datepicker._checkExternalClick).find("body").append($.datepicker.dpDiv),$.datepicker.initialized=!0);var b=Array.prototype.slice.call(arguments,1);if(typeof a=="string"&&(a=="isDisabled"||a=="getDate"||a=="widget"))return $.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this[0]].concat(b));if(a=="option"&&arguments.length==2&&typeof arguments[1]=="string")return $.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this[0]].concat(b));return this.each(function(){typeof a=="string"?$.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this].concat(b)):$.datepicker._attachDatepicker(this,a)})},$.datepicker=new Datepicker,$.datepicker.initialized=!1,$.datepicker.uuid=(new Date).getTime(),$.datepicker.version="1.8.18",window["DP_jQuery_"+dpuuid]=$})(jQuery);
/**
 * This file is modified for powermail localization
 */
(function($){
    $.fn.validationEngineLanguage = function(){
    };
    $.validationEngineLanguage = {
        newLang: function(){
            $.validationEngineLanguage.allRules = {
                "required": { // Add your regex rules here, you can take telephone as an example
                    "regex": "none",
//                    "alertText": "* This field is required",
					"alertText": JsValidationCheckRequired,
//                    "alertTextCheckboxMultiple": "* Please select an option",
                    "alertTextCheckboxMultiple": JsValidationCheckRequiredOption,
                    "alertTextCheckboxe": "* This checkbox is required",
                    "alertTextDateRange": "* Both date range fields are required"
                },
                "dateRange": {
                    "regex": "none",
                    "alertText": "* Invalid ",
                    "alertText2": "Date Range"
                },
                "dateTimeRange": {
                    "regex": "none",
                    "alertText": "* Invalid ",
                    "alertText2": "Date Time Range"
                },
                "minSize": {
                    "regex": "none",
                    "alertText": "* Minimum ",
                    "alertText2": " characters allowed"
                },
                "maxSize": {
                    "regex": "none",
                    "alertText": "* Maximum ",
                    "alertText2": " characters allowed"
                },
				"groupRequired": {
                    "regex": "none",
                    "alertText": "* You must fill one of the following fields"
                },
                "min": {
                    "regex": "none",
                    "alertText": "* Minimum value is "
                },
                "max": {
                    "regex": "none",
                    "alertText": "* Maximum value is "
                },
                "past": {
                    "regex": "none",
                    "alertText": "* Date prior to "
                },
                "future": {
                    "regex": "none",
                    "alertText": "* Date past "
                },	
                "maxCheckbox": {
                    "regex": "none",
                    "alertText": "* Maximum ",
                    "alertText2": " options allowed"
                },
                "minCheckbox": {
                    "regex": "none",
                    "alertText": "* Please select ",
                    "alertText2": " options"
                },
                "equals": {
                    "regex": "none",
                    "alertText": "* Fields do not match"
                },
                "creditCard": {
                    "regex": "none",
                    "alertText": "* Invalid credit card number"
                },
                "phone": {
                    // credit: jquery.h5validate.js / orefalo
                    "regex": /^([\+][0-9]{1,3}[ \.\-])?([\(]{1}[0-9]{2,6}[\)])?([0-9 \.\-\/]{3,20})((x|ext|extension)[ ]?[0-9]{1,4})?$/,
//                    "alertText": "* Invalid phone number"
					"alertText": JsValidationCheckPhone
                },
                "email": {
                    // Shamelessly lifted from Scott Gonzalez via the Bassistance Validation plugin http://projects.scottsplayground.com/email_address_validation/
                    "regex": /^((([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,
//                    "alertText": "* Invalid email address"
                    "alertText": JsValidationCheckEmail
                },
                "integer": {
                    "regex": /^[\-\+]?\d+$/,
//                    "alertText": "* Not a valid integer"
                    "alertText": JsValidationCheckInteger
                },
                "number": {
                    // Number, including positive, negative, and floating decimal. credit: orefalo
                    "regex": /^[\-\+]?(([0-9]+)([\.,]([0-9]+))?|([\.,]([0-9]+))?)$/,
                    "alertText": "* Invalid floating decimal number"
                },
                "date": {
                    "regex": /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/,
                    "alertText": "* Invalid date, must be in YYYY-MM-DD format"
                },
                "ipv4": {
                    "regex": /^((([01]?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5]))[.]){3}(([0-1]?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5]))$/,
                    "alertText": "* Invalid IP address"
                },
                "url": {
                    "regex": /^(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,
//                    "alertText": "* Invalid URL"
                    "alertText": JsValidationCheckUrl
                },
                "onlyNumberSp": {
                    "regex": /^[0-9\ ]+$/,
                    "alertText": "* Numbers only"
                },
                "onlyLetterSp": {
                    "regex": /^[a-zA-Z\ \']+$/,
//                    "alertText": "* Letters only"
					"alertText": JsValidationCheckLetters
                },
                "onlyLetterNumber": {
                    "regex": /^[0-9a-zA-Z]+$/,
                    "alertText": "* No special characters allowed"
                },
                // --- CUSTOM RULES -- Those are specific to the demos, they can be removed or changed to your likings
                "ajaxUserCall": {
                    "url": "ajaxValidateFieldUser",
                    // you may want to pass extra data on the ajax call
                    "extraData": "name=eric",
                    "alertText": "* This user is already taken",
                    "alertTextLoad": "* Validating, please wait"
                },
				"ajaxUserCallPhp": {
                    "url": "phpajax/ajaxValidateFieldUser.php",
                    // you may want to pass extra data on the ajax call
                    "extraData": "name=eric",
                    // if you provide an "alertTextOk", it will show as a green prompt when the field validates
                    "alertTextOk": "* This username is available",
                    "alertText": "* This user is already taken",
                    "alertTextLoad": "* Validating, please wait"
                },
                "ajaxNameCall": {
                    // remote json service location
                    "url": "ajaxValidateFieldName",
                    // error
                    "alertText": "* This name is already taken",
                    // if you provide an "alertTextOk", it will show as a green prompt when the field validates
                    "alertTextOk": "* This name is available",
                    // speaks by itself
                    "alertTextLoad": "* Validating, please wait"
                },
				 "ajaxNameCallPhp": {
	                    // remote json service location
	                    "url": "phpajax/ajaxValidateFieldName.php",
	                    // error
	                    "alertText": "* This name is already taken",
	                    // speaks by itself
	                    "alertTextLoad": "* Validating, please wait"
	                },
                "validate2fields": {
                    "alertText": "* Please input HELLO"
                },
	            //tls warning:homegrown not fielded 
                "dateFormat":{
                    "regex": /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$|^(?:(?:(?:0?[13578]|1[02])(\/|-)31)|(?:(?:0?[1,3-9]|1[0-2])(\/|-)(?:29|30)))(\/|-)(?:[1-9]\d\d\d|\d[1-9]\d\d|\d\d[1-9]\d|\d\d\d[1-9])$|^(?:(?:0?[1-9]|1[0-2])(\/|-)(?:0?[1-9]|1\d|2[0-8]))(\/|-)(?:[1-9]\d\d\d|\d[1-9]\d\d|\d\d[1-9]\d|\d\d\d[1-9])$|^(0?2(\/|-)29)(\/|-)(?:(?:0[48]00|[13579][26]00|[2468][048]00)|(?:\d\d)?(?:0[48]|[2468][048]|[13579][26]))$/,
                    "alertText": "* Invalid Date"
                },
                //tls warning:homegrown not fielded 
				"dateTimeFormat": {
	                "regex": /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])\s+(1[012]|0?[1-9]){1}:(0?[1-5]|[0-6][0-9]){1}:(0?[0-6]|[0-6][0-9]){1}\s+(am|pm|AM|PM){1}$|^(?:(?:(?:0?[13578]|1[02])(\/|-)31)|(?:(?:0?[1,3-9]|1[0-2])(\/|-)(?:29|30)))(\/|-)(?:[1-9]\d\d\d|\d[1-9]\d\d|\d\d[1-9]\d|\d\d\d[1-9])$|^((1[012]|0?[1-9]){1}\/(0?[1-9]|[12][0-9]|3[01]){1}\/\d{2,4}\s+(1[012]|0?[1-9]){1}:(0?[1-5]|[0-6][0-9]){1}:(0?[0-6]|[0-6][0-9]){1}\s+(am|pm|AM|PM){1})$/,
                    "alertText": "* Invalid Date or Date Format",
                    "alertText2": "Expected Format: ",
                    "alertText3": "mm/dd/yyyy hh:mm:ss AM|PM or ", 
                    "alertText4": "yyyy-mm-dd hh:mm:ss AM|PM"
	            },
				/* powermail new */
				"checkCheckboxes": {
					"alertText": JsValidationCheckCheckboxes
				}
				/* powermail new end */
            };
            
        }
    };

    $.validationEngineLanguage.newLang();
    
})(jQuery);
/*
 * Inline Form Validation Engine 2.6, jQuery plugin
 *
 * Copyright(c) 2010, Cedric Dugas
 * http://www.position-absolute.com
 *
 * 2.0 Rewrite by Olivier Refalo
 * http://www.crionics.com
 *
 * Form validation engine allowing custom regex rules to be added.
 * Licensed under the MIT License
 */
(function($) {

	"use strict";

	var methods = {

		/**
		 * Kind of the constructor, called before any action
		 * @param {Map} user options
		 */
		init: function(options) {
			var form = this;
			if (!form.data('jqv') || form.data('jqv') == null ) {
				options = methods._saveOptions(form, options);
				// bind all formError elements to close on click
				$(".formError").live("click", function() {
					$(this).fadeOut(150, function() {
						// remove prompt once invisible
						$(this).parent('.formErrorOuter').remove();
						$(this).remove();
					});
				});
			}
			return this;
		},
		/**
		 * Attachs jQuery.validationEngine to form.submit and field.blur events
		 * Takes an optional params: a list of options
		 * ie. jQuery("#formID1").validationEngine('attach', {promptPosition : "centerRight"});
		 */
		attach: function(userOptions) {

			if(!$(this).is("form")) {
				alert("Sorry, jqv.attach() only applies to a form");
				return this;
			}

			var form = this;
			var options;

			if(userOptions)
				options = methods._saveOptions(form, userOptions);
			else
				options = form.data('jqv');

			options.validateAttribute = (form.find("[data-validation-engine*=validate]").length) ? "data-validation-engine" : "class";
			if (options.binded) {

				// bind fields
				form.find("["+options.validateAttribute+"*=validate]").not("[type=checkbox]").not("[type=radio]").not(".datepicker").bind(options.validationEventTrigger, methods._onFieldEvent);
				form.find("["+options.validateAttribute+"*=validate][type=checkbox],["+options.validateAttribute+"*=validate][type=radio]").bind("click", methods._onFieldEvent);
				form.find("["+options.validateAttribute+"*=validate][class*=datepicker]").bind(options.validationEventTrigger,{"delay": 300}, methods._onFieldEvent);
			}
			if (options.autoPositionUpdate) {
				$(window).bind("resize", {
					"noAnimation": true,
					"formElem": form
				}, methods.updatePromptsPosition);
			}
			// bind form.submit
			form.bind("submit", methods._onSubmitEvent);
			return this;
		},
		/**
		 * Unregisters any bindings that may point to jQuery.validaitonEngine
		 */
		detach: function() {

			if(!$(this).is("form")) {
				alert("Sorry, jqv.detach() only applies to a form");
				return this;
			}

			var form = this;
			var options = form.data('jqv');

			// unbind fields
			form.find("["+options.validateAttribute+"*=validate]").not("[type=checkbox]").unbind(options.validationEventTrigger, methods._onFieldEvent);
			form.find("["+options.validateAttribute+"*=validate][type=checkbox],[class*=validate][type=radio]").unbind("click", methods._onFieldEvent);

			// unbind form.submit
			form.unbind("submit", methods.onAjaxFormComplete);

			// unbind live fields (kill)
			form.find("["+options.validateAttribute+"*=validate]").not("[type=checkbox]").die(options.validationEventTrigger, methods._onFieldEvent);
			form.find("["+options.validateAttribute+"*=validate][type=checkbox]").die("click", methods._onFieldEvent);

			// unbind form.submit
			form.die("submit", methods.onAjaxFormComplete);
			form.removeData('jqv');

			if (options.autoPositionUpdate)
				$(window).unbind("resize", methods.updatePromptsPosition);

			return this;
		},
		/**
		 * Validates either a form or a list of fields, shows prompts accordingly.
		 * Note: There is no ajax form validation with this method, only field ajax validation are evaluated
		 *
		 * @return true if the form validates, false if it fails
		 */
		validate: function() {
			if($(this).is("form"))
				return methods._validateFields(this);
			else {
				// field validation
				var form = $(this).closest('form');
				var options = form.data('jqv');
				var r = methods._validateField($(this), options);

				if (options.onSuccess && options.InvalidFields.length == 0)
					options.onSuccess();
				else if (options.onFailure && options.InvalidFields.length > 0)
					options.onFailure();

				return r;
			}
		},
		/**
		 *  Redraw prompts position, useful when you change the DOM state when validating
		 */
		updatePromptsPosition: function(event) {

			if (event && this == window) {
				var form = event.data.formElem;
				var noAnimation = event.data.noAnimation;
			}
			else
				var form = $(this.closest('form'));

			var options = form.data('jqv');
			// No option, take default one
			form.find('['+options.validateAttribute+'*=validate]').not(":disabled").each(function(){
				var field = $(this);
				var prompt = methods._getPrompt(field);
				var promptText = $(prompt).find(".formErrorContent").html();

				if(prompt)
					methods._updatePrompt(field, $(prompt), promptText, undefined, false, options, noAnimation);
			});
			return this;
		},
		/**
		 * Displays a prompt on a element.
		 * Note that the element needs an id!
		 *
		 * @param {String} promptText html text to display type
		 * @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red)
		 * @param {String} possible values topLeft, topRight, bottomLeft, centerRight, bottomRight
		 */
		showPrompt: function(promptText, type, promptPosition, showArrow) {

			var form = this.closest('form');
			var options = form.data('jqv');
			// No option, take default one
			if(!options)
				options = methods._saveOptions(this, options);
			if(promptPosition)
				options.promptPosition=promptPosition;
			options.showArrow = showArrow==true;

			methods._showPrompt(this, promptText, type, false, options);
			return this;
		},
		/**
		 * Closes form error prompts, CAN be invidual
		 */
		hide: function() {
			var form = $(this).closest('form');
			if(form.length == 0)
				return this;
			var options = form.data('jqv');
			var closingtag;
			if($(this).is("form")) {
				closingtag = "parentForm"+methods._getClassName($(this).attr("id"));
			} else {
				closingtag = methods._getClassName($(this).attr("id")) +"formError";
			}
			$('.'+closingtag).fadeTo(options.fadeDuration, 0.3, function() {
				$(this).parent('.formErrorOuter').remove();
				$(this).remove();
			});
			return this;
		},
		/**
		 * Closes all error prompts on the page
		 */
		hideAll: function() {

			var form = this;
			var options = form.data('jqv');
			var duration = options ? options.fadeDuration:0.3;
			$('.formError').fadeTo(duration, 0.3, function() {
				$(this).parent('.formErrorOuter').remove();
				$(this).remove();
			});
			return this;
		},
		/**
		 * Typically called when user exists a field using tab or a mouse click, triggers a field
		 * validation
		 */
		_onFieldEvent: function(event) {
			var field = $(this);
			var form = field.closest('form');
			var options = form.data('jqv');
			options.eventTrigger = "field";
			// validate the current field
			window.setTimeout(function() {
				methods._validateField(field, options);
				if (options.InvalidFields.length == 0 && options.onSuccess) {
					options.onSuccess();
				} else if (options.InvalidFields.length > 0 && options.onFailure) {
					options.onFailure();
				}
			}, (event.data) ? event.data.delay : 0);

		},
		/**
		 * Called when the form is submited, shows prompts accordingly
		 *
		 * @param {jqObject}
			*            form
		 * @return false if form submission needs to be cancelled
		 */
		_onSubmitEvent: function() {
			var form = $(this);
			var options = form.data('jqv');
			options.eventTrigger = "submit";

			// validate each field 
			// (- skip field ajax validation, not necessary IF we will perform an ajax form validation)
			var r=methods._validateFields(form);

			if (r && options.ajaxFormValidation) {
				methods._validateFormWithAjax(form, options);
				// cancel form auto-submission - process with async call onAjaxFormComplete
				return false;
			}

			if(options.onValidationComplete) {
				// !! ensures that an undefined return is interpreted as return false but allows a onValidationComplete() to possibly return true and have form continue processing
				return !!options.onValidationComplete(form, r);
			}
			return r;
		},
		/**
		 * Return true if the ajax field validations passed so far
		 * @param {Object} options
		 * @return true, is all ajax validation passed so far (remember ajax is async)
		 */
		_checkAjaxStatus: function(options) {
			var status = true;
			$.each(options.ajaxValidCache, function(key, value) {
				if (!value) {
					status = false;
					// break the each
					return false;
				}
			});
			return status;
		},

		/**
		 * Return true if the ajax field is validated
		 * @param {String} fieldid
		 * @param {Object} options
		 * @return true, if validation passed, false if false or doesn't exist
		 */
		_checkAjaxFieldStatus: function(fieldid, options) {
			return options.ajaxValidCache[fieldid] == true;
		},
		/**
		 * Validates form fields, shows prompts accordingly
		 *
		 * @param {jqObject}
			*            form
		 * @param {skipAjaxFieldValidation}
			*            boolean - when set to true, ajax field validation is skipped, typically used when the submit button is clicked
		 *
		 * @return true if form is valid, false if not, undefined if ajax form validation is done
		 */
		_validateFields: function(form) {
			var options = form.data('jqv');

			// this variable is set to true if an error is found
			var errorFound = false;

			// Trigger hook, start validation
			form.trigger("jqv.form.validating");
			// first, evaluate status of non ajax fields
			var first_err=null;
			form.find('['+options.validateAttribute+'*=validate]').not(":disabled").each( function() {
				var field = $(this);
				var names = [];
				if ($.inArray(field.attr('name'), names) < 0) {
					errorFound |= methods._validateField(field, options);
					if (errorFound && first_err==null)
						if (field.is(":hidden") && options.prettySelect)
							first_err = field = form.find("#" + options.usePrefix + field.attr('id') + options.useSuffix);
						else
							first_err=field;
					if (options.doNotShowAllErrosOnSubmit)
						return false;
					names.push(field.attr('name'));
				}
			});

			// second, check to see if all ajax calls completed ok
			// errorFound |= !methods._checkAjaxStatus(options);

			// third, check status and scroll the container accordingly
			form.trigger("jqv.form.result", [errorFound]);

			if (errorFound) {
				if (options.scroll) {
					var destination=first_err.offset().top;
					var fixleft = first_err.offset().left;

					//prompt positioning adjustment support. Usage: positionType:Xshift,Yshift (for ex.: bottomLeft:+20 or bottomLeft:-20,+10)
					var positionType=options.promptPosition;
					if (typeof(positionType)=='string' && positionType.indexOf(":")!=-1)
						positionType=positionType.substring(0,positionType.indexOf(":"));

					if (positionType!="bottomRight" && positionType!="bottomLeft") {
						var prompt_err= methods._getPrompt(first_err);
						destination=prompt_err.offset().top;
					}

					// get the position of the first error, there should be at least one, no need to check this
					//var destination = form.find(".formError:not('.greenPopup'):first").offset().top;
					if (options.isOverflown) {
						var overflowDIV = $(options.overflownDIV);
						if(!overflowDIV.length) return false;
						var scrollContainerScroll = overflowDIV.scrollTop();
						var scrollContainerPos = -parseInt(overflowDIV.offset().top);

						destination += scrollContainerScroll + scrollContainerPos - 5;
						var scrollContainer = $(options.overflownDIV + ":not(:animated)");

						scrollContainer.animate({ scrollTop: destination }, 1100, function(){
							if(options.focusFirstField) first_err.focus();
						});
					} else {
						$("html:not(:animated),body:not(:animated)").animate({
							scrollTop: destination,
							scrollLeft: fixleft
						}, 1100, function(){
							if(options.focusFirstField) first_err.focus();
						});
					}

				} else if(options.focusFirstField)
					first_err.focus();
				return false;
			}
			return true;
		},
		/**
		 * This method is called to perform an ajax form validation.
		 * During this process all the (field, value) pairs are sent to the server which returns a list of invalid fields or true
		 *
		 * @param {jqObject} form
		 * @param {Map} options
		 */
		_validateFormWithAjax: function(form, options) {

			var data = form.serialize();
			var type = (options.ajaxmethod) ? options.ajaxmethod : "GET";
			var url = (options.ajaxFormValidationURL) ? options.ajaxFormValidationURL : form.attr("action");
			var dataType = (options.dataType) ? options.dataType : "json";
			$.ajax({
				type: type,
				url: url,
				cache: false,
				dataType: dataType,
				data: data,
				form: form,
				methods: methods,
				options: options,
				beforeSend: function() {
					return options.onBeforeAjaxFormValidation(form, options);
				},
				error: function(data, transport) {
					methods._ajaxError(data, transport);
				},
				success: function(json) {
					if (json !== true) {
						// getting to this case doesn't necessary means that the form is invalid
						// the server may return green or closing prompt actions
						// this flag helps figuring it out
						var errorInForm=false;
						for (var i = 0; i < json.length; i++) {
							var value = json[i];

							var errorFieldId = value[0];
							var errorField = $($("#" + errorFieldId)[0]);

							// make sure we found the element
							if (errorField.length == 1) {

								// promptText or selector
								var msg = value[2];
								// if the field is valid
								if (value[1] == true) {

									if (msg == ""  || !msg){
										// if for some reason, status==true and error="", just close the prompt
										methods._closePrompt(errorField);
									} else {
										// the field is valid, but we are displaying a green prompt
										if (options.allrules[msg]) {
											var txt = options.allrules[msg].alertTextOk;
											if (txt)
												msg = txt;
										}
										methods._showPrompt(errorField, msg, "pass", false, options, true);
									}
								} else {
									// the field is invalid, show the red error prompt
									errorInForm|=true;
									if (options.allrules[msg]) {
										var txt = options.allrules[msg].alertText;
										if (txt)
											msg = txt;
									}
									methods._showPrompt(errorField, msg, "", false, options, true);
								}
							}
						}
						options.onAjaxFormComplete(!errorInForm, form, json, options);
					} else
						options.onAjaxFormComplete(true, form, "", options);
				}
			});

		},
		/**
		 * Validates field, shows prompts accordingly
		 *
		 * @param {jqObject}
			*            field
		 * @param {Array[String]}
			*            field's validation rules
		 * @param {Map}
			*            user options
		 * @return false if field is valid (It is inversed for *fields*, it return false on validate and true on errors.)
		 */
		_validateField: function(field, options, skipAjaxValidation) {
			if (!field.attr("id")) {
				field.attr("id", "form-validation-field-" + $.validationEngine.fieldIdCounter);
				++$.validationEngine.fieldIdCounter;
			}

			if (field.is(":hidden") && !options.prettySelect || field.parent().is(":hidden"))
				return false;

			var rulesParsing = field.attr(options.validateAttribute);
			var getRules = /validate\[(.*)\]/.exec(rulesParsing);

			if (!getRules)
				return false;
			var str = getRules[1];
			var rules = str.split(/\[|,|\]/);

			// true if we ran the ajax validation, tells the logic to stop messing with prompts
			var isAjaxValidator = false;
			var fieldName = field.attr("name");
			var promptText = "";
			var promptType = "";
			var required = false;
			options.isError = false;
			options.showArrow = true;

			var form = $(field.closest("form"));

			for (var i = 0; i < rules.length; i++) {
				// Fix for adding spaces in the rules
				rules[i] = rules[i].replace(" ", "");
				var errorMsg = undefined;
				switch (rules[i]) {

					case "required":
						required = true;
						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._required);
						break;
					case "custom":
						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._custom);
						break;
					case "groupRequired":
						// Check is its the first of group, if not, reload validation with first field
						// AND continue normal validation on present field
						var classGroup = "["+options.validateAttribute+"*=" +rules[i + 1] +"]";
						var firstOfGroup = form.find(classGroup).eq(0);
						if(firstOfGroup[0] != field[0]){
							methods._validateField(firstOfGroup, options, skipAjaxValidation);
							options.showArrow = true;
							continue;
						}
						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._groupRequired);
						if(errorMsg)  required = true;
						options.showArrow = false;
						break;
					case "ajax":
						// AJAX defaults to returning it's loading message
						errorMsg = methods._ajax(field, rules, i, options);
						if (errorMsg) {
							promptType = "load";
						}
						break;
					case "minSize":
						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._minSize);
						break;
					case "maxSize":
						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._maxSize);
						break;
					case "min":
						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._min);
						break;
					case "max":
						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._max);
						break;
					case "past":
						errorMsg = methods._getErrorMessage(form, field,rules[i], rules, i, options, methods._past);
						break;
					case "future":
						errorMsg = methods._getErrorMessage(form, field,rules[i], rules, i, options, methods._future);
						break;
					case "dateRange":
						var classGroup = "["+options.validateAttribute+"*=" + rules[i + 1] + "]";
						options.firstOfGroup = form.find(classGroup).eq(0);
						options.secondOfGroup = form.find(classGroup).eq(1);

						//if one entry out of the pair has value then proceed to run through validation
						if (options.firstOfGroup[0].value || options.secondOfGroup[0].value) {
							errorMsg = methods._getErrorMessage(form, field,rules[i], rules, i, options, methods._dateRange);
						}
						if (errorMsg) required = true;
						options.showArrow = false;
						break;

					case "dateTimeRange":
						var classGroup = "["+options.validateAttribute+"*=" + rules[i + 1] + "]";
						options.firstOfGroup = form.find(classGroup).eq(0);
						options.secondOfGroup = form.find(classGroup).eq(1);

						//if one entry out of the pair has value then proceed to run through validation
						if (options.firstOfGroup[0].value || options.secondOfGroup[0].value) {
							errorMsg = methods._getErrorMessage(form, field,rules[i], rules, i, options, methods._dateTimeRange);
						}
						if (errorMsg) required = true;
						options.showArrow = false;
						break;
					case "maxCheckbox":
						field = $(form.find("input[name='" + fieldName + "']"));
						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._maxCheckbox);
						break;
					case "minCheckbox":
						field = $(form.find("input[name='" + fieldName + "']"));
						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._minCheckbox);
						break;
					case "equals":
						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._equals);
						break;
					case "funcCall":
						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._funcCall);
						break;
					case "creditCard":
						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._creditCard);
						break;
					case "condRequired":
						errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._condRequired);
						if (errorMsg !== undefined) {
							required = true;
						}
						break;

					default:
				}
				if (errorMsg !== undefined) {
					promptText += errorMsg + "<br/>";
					options.isError = true;
				}

				//if option set, stop checking validation rules after one error is found
				if(options.showOneMessage === true && options.isError === true)
					break;
			}
			// If the rules required is not added, an empty field is not validated
			if(!required && field.val().length < 1) options.isError = false;

			// Hack for radio/checkbox group button, the validation go into the
			// first radio/checkbox of the group
			var fieldType = field.prop("type");

			if ((fieldType == "radio" || fieldType == "checkbox") && form.find("input[name='" + fieldName + "']").size() > 1) {
				field = $(form.find("input[name='" + fieldName + "'][type!=hidden]:first"));
				options.showArrow = false;
			}

			if(field.is(":hidden") && options.prettySelect) {
				field = form.find("#" + options.usePrefix + field.attr('id') + options.useSuffix);
			}

			if (options.isError){
				methods._showPrompt(field, promptText, promptType, false, options);
			}else{
				if (!isAjaxValidator) methods._closePrompt(field);
			}

			if (!isAjaxValidator) {
				field.trigger("jqv.field.result", [field, options.isError, promptText]);
			}

			/* Record error */
			var errindex = $.inArray(field[0], options.InvalidFields);
			if (errindex == -1) {
				if (options.isError)
					options.InvalidFields.push(field[0]);
			} else if (!options.isError) {
				options.InvalidFields.splice(errindex, 1);
			}

			return options.isError;
		},
		/********************
		 * _getErrorMessage
		 *
		 * @param form
		 * @param field
		 * @param rule
		 * @param rules
		 * @param i
		 * @param options
		 * @param originalValidationMethod
		 * @return {*}
		 * @private
		 */
		_getErrorMessage:function (form, field, rule, rules, i, options, originalValidationMethod) {
			// If we are using the custon validation type, build the index for the rule.
			// Otherwise if we are doing a function call, make the call and return the object
			// that is passed back.
			var beforeChangeRule = rule;
			if (rule == "custom") {
				var custom_validation_type_index = jQuery.inArray(rule, rules)+ 1;
				var custom_validation_type = rules[custom_validation_type_index];
				rule = "custom[" + custom_validation_type + "]";
			}
			var element_classes = (field.attr("data-validation-engine")) ? field.attr("data-validation-engine") : field.attr("class");
			var element_classes_array = element_classes.split(" ");

			// Call the original validation method. If we are dealing with dates, also pass the form
			var errorMsg;
			if (rule == "future" || rule == "past"  || rule == "maxCheckbox" || rule == "minCheckbox") {
				errorMsg = originalValidationMethod(form, field, rules, i, options);
			} else {
				errorMsg = originalValidationMethod(field, rules, i, options);
			}

			// If the original validation method returned an error and we have a custom error message,
			// return the custom message instead. Otherwise return the original error message.
			if (errorMsg != undefined) {
				var custom_message = methods._getCustomErrorMessage($(field), element_classes_array, beforeChangeRule, options);
				if (custom_message) return custom_message;
			}
			return errorMsg;

		},
		_getCustomErrorMessage:function (field, classes, rule, options) {
			var custom_message = false;
			var validityProp = methods._validityProp[rule];
			if (validityProp != undefined) {
				custom_message = field.attr("data-errormessage-"+validityProp);
				if (custom_message != undefined)
					return custom_message;
			}
			custom_message = field.attr("data-errormessage");
			if (custom_message != undefined)
				return custom_message;
			var id = '#' + field.attr("id");
			// If we have custom messages for the element's id, get the message for the rule from the id.
			// Otherwise, if we have custom messages for the element's classes, use the first class message we find instead.
			if (typeof options.custom_error_messages[id] != "undefined" &&
				typeof options.custom_error_messages[id][rule] != "undefined" ) {
				custom_message = options.custom_error_messages[id][rule]['message'];
			} else if (classes.length > 0) {
				for (var i = 0; i < classes.length && classes.length > 0; i++) {
					var element_class = "." + classes[i];
					if (typeof options.custom_error_messages[element_class] != "undefined" &&
						typeof options.custom_error_messages[element_class][rule] != "undefined") {
						custom_message = options.custom_error_messages[element_class][rule]['message'];
						break;
					}
				}
			}
			if (!custom_message &&
				typeof options.custom_error_messages[rule] != "undefined" &&
				typeof options.custom_error_messages[rule]['message'] != "undefined"){
				custom_message = options.custom_error_messages[rule]['message'];
			}
			return custom_message;
		},
		_validityProp: {
			"required": "value-missing",
			"custom": "custom-error",
			"groupRequired": "value-missing",
			"ajax": "custom-error",
			"minSize": "range-underflow",
			"maxSize": "range-overflow",
			"min": "range-underflow",
			"max": "range-overflow",
			"past": "type-mismatch",
			"future": "type-mismatch",
			"dateRange": "type-mismatch",
			"dateTimeRange": "type-mismatch",
			"maxCheckbox": "range-overflow",
			"minCheckbox": "range-underflow",
			"equals": "pattern-mismatch",
			"funcCall": "custom-error",
			"creditCard": "pattern-mismatch",
			"condRequired": "value-missing"
		},
		/**
		 * Required validation
		 *
		 * @param {jqObject} field
		 * @param {Array[String]} rules
		 * @param {int} i rules index
		 * @param {Map}
			*            user options
		 * @return an error string if validation failed
		 */
		_required: function(field, rules, i, options) {
			switch (field.prop("type")) {
				case "text":
				case "password":
				case "textarea":
				case "file":
				case "select-one":
				case "select-multiple":
				default:

					if (! $.trim(field.val()) || field.val() == field.attr("data-validation-placeholder") || field.val() == field.attr("placeholder"))
						return options.allrules[rules[i]].alertText;
					break;
				case "radio":
				case "checkbox":
					var form = field.closest("form");
					var name = field.attr("name");
					if (form.find("input[name='" + name + "']:checked").size() == 0) {
						if (form.find("input[name='" + name + "']:visible").size() == 1)
							return options.allrules[rules[i]].alertTextCheckboxe;
						else
							return options.allrules[rules[i]].alertTextCheckboxMultiple;
					}
					break;
			}
		},
		/**
		 * Validate that 1 from the group field is required
		 *
		 * @param {jqObject} field
		 * @param {Array[String]} rules
		 * @param {int} i rules index
		 * @param {Map}
			*            user options
		 * @return an error string if validation failed
		 */
		_groupRequired: function(field, rules, i, options) {
			var classGroup = "["+options.validateAttribute+"*=" +rules[i + 1] +"]";
			var isValid = false;
			// Check all fields from the group
			field.closest("form").find(classGroup).each(function(){
				if(!methods._required($(this), rules, i, options)){
					isValid = true;
					return false;
				}
			});

			if(!isValid) {
				return options.allrules[rules[i]].alertText;
			}
		},
		/**
		 * Validate rules
		 *
		 * @param {jqObject} field
		 * @param {Array[String]} rules
		 * @param {int} i rules index
		 * @param {Map}
			*            user options
		 * @return an error string if validation failed
		 */
		_custom: function(field, rules, i, options) {
			var customRule = rules[i + 1];
			var rule = options.allrules[customRule];
			var fn;
			if(!rule) {
				alert("jqv:custom rule not found - "+customRule);
				return;
			}

			if(rule["regex"]) {
				var ex=rule.regex;
				if(!ex) {
					alert("jqv:custom regex not found - "+customRule);
					return;
				}
				var pattern = new RegExp(ex);

				if (!pattern.test(field.val())) return options.allrules[customRule].alertText;

			} else if(rule["func"]) {
				fn = rule["func"];

				if (typeof(fn) !== "function") {
					alert("jqv:custom parameter 'function' is no function - "+customRule);
					return;
				}

				if (!fn(field, rules, i, options))
					return options.allrules[customRule].alertText;
			} else {
				alert("jqv:custom type not allowed "+customRule);
				return;
			}
		},
		/**
		 * Validate custom function outside of the engine scope
		 *
		 * @param {jqObject} field
		 * @param {Array[String]} rules
		 * @param {int} i rules index
		 * @param {Map}
			*            user options
		 * @return an error string if validation failed
		 */
		_funcCall: function(field, rules, i, options) {
			var functionName = rules[i + 1];
			var fn;
			if(functionName.indexOf('.') >-1)
			{
				var namespaces = functionName.split('.');
				var scope = window;
				while(namespaces.length)
				{
					scope = scope[namespaces.shift()];
				}
				fn = scope;
			}
			else
				fn = window[functionName] || options.customFunctions[functionName];
			if (typeof(fn) == 'function')
				return fn(field, rules, i, options);

		},
		/**
		 * Field match
		 *
		 * @param {jqObject} field
		 * @param {Array[String]} rules
		 * @param {int} i rules index
		 * @param {Map}
			*            user options
		 * @return an error string if validation failed
		 */
		_equals: function(field, rules, i, options) {
			var equalsField = rules[i + 1];

			if (field.val() != $("#" + equalsField).val())
				return options.allrules.equals.alertText;
		},
		/**
		 * Check the maximum size (in characters)
		 *
		 * @param {jqObject} field
		 * @param {Array[String]} rules
		 * @param {int} i rules index
		 * @param {Map}
			*            user options
		 * @return an error string if validation failed
		 */
		_maxSize: function(field, rules, i, options) {
			var max = rules[i + 1];
			var len = field.val().length;

			if (len > max) {
				var rule = options.allrules.maxSize;
				return rule.alertText + max + rule.alertText2;
			}
		},
		/**
		 * Check the minimum size (in characters)
		 *
		 * @param {jqObject} field
		 * @param {Array[String]} rules
		 * @param {int} i rules index
		 * @param {Map}
			*            user options
		 * @return an error string if validation failed
		 */
		_minSize: function(field, rules, i, options) {
			var min = rules[i + 1];
			var len = field.val().length;

			if (len < min) {
				var rule = options.allrules.minSize;
				return rule.alertText + min + rule.alertText2;
			}
		},
		/**
		 * Check number minimum value
		 *
		 * @param {jqObject} field
		 * @param {Array[String]} rules
		 * @param {int} i rules index
		 * @param {Map}
			*            user options
		 * @return an error string if validation failed
		 */
		_min: function(field, rules, i, options) {
			var min = parseFloat(rules[i + 1]);
			var len = parseFloat(field.val());

			if (len < min) {
				var rule = options.allrules.min;
				if (rule.alertText2) return rule.alertText + min + rule.alertText2;
				return rule.alertText + min;
			}
		},
		/**
		 * Check number maximum value
		 *
		 * @param {jqObject} field
		 * @param {Array[String]} rules
		 * @param {int} i rules index
		 * @param {Map}
			*            user options
		 * @return an error string if validation failed
		 */
		_max: function(field, rules, i, options) {
			var max = parseFloat(rules[i + 1]);
			var len = parseFloat(field.val());

			if (len >max ) {
				var rule = options.allrules.max;
				if (rule.alertText2) return rule.alertText + max + rule.alertText2;
				//orefalo: to review, also do the translations
				return rule.alertText + max;
			}
		},
		/**
		 * Checks date is in the past
		 *
		 * @param {jqObject} field
		 * @param {Array[String]} rules
		 * @param {int} i rules index
		 * @param {Map}
			*            user options
		 * @return an error string if validation failed
		 */
		_past: function(form, field, rules, i, options) {

			var p=rules[i + 1];
			var fieldAlt = $(form.find("input[name='" + p.replace(/^#+/, '') + "']"));
			var pdate;

			if (p.toLowerCase() == "now") {
				pdate = new Date();
			} else if (undefined != fieldAlt.val()) {
				if (fieldAlt.is(":disabled"))
					return;
				pdate = methods._parseDate(fieldAlt.val());
			} else {
				pdate = methods._parseDate(p);
			}
			var vdate = methods._parseDate(field.val());

			if (vdate > pdate ) {
				var rule = options.allrules.past;
				if (rule.alertText2) return rule.alertText + methods._dateToString(pdate) + rule.alertText2;
				return rule.alertText + methods._dateToString(pdate);
			}
		},
		/**
		 * Checks date is in the future
		 *
		 * @param {jqObject} field
		 * @param {Array[String]} rules
		 * @param {int} i rules index
		 * @param {Map}
			*            user options
		 * @return an error string if validation failed
		 */
		_future: function(form, field, rules, i, options) {

			var p=rules[i + 1];
			var fieldAlt = $(form.find("input[name='" + p.replace(/^#+/, '') + "']"));
			var pdate;

			if (p.toLowerCase() == "now") {
				pdate = new Date();
			} else if (undefined != fieldAlt.val()) {
				if (fieldAlt.is(":disabled"))
					return;
				pdate = methods._parseDate(fieldAlt.val());
			} else {
				pdate = methods._parseDate(p);
			}
			var vdate = methods._parseDate(field.val());

			if (vdate < pdate ) {
				var rule = options.allrules.future;
				if (rule.alertText2)
					return rule.alertText + methods._dateToString(pdate) + rule.alertText2;
				return rule.alertText + methods._dateToString(pdate);
			}
		},
		/**
		 * Checks if valid date
		 *
		 * @param {string} date string
		 * @return a bool based on determination of valid date
		 */
		_isDate: function (value) {
			var dateRegEx = new RegExp(/^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$|^(?:(?:(?:0?[13578]|1[02])(\/|-)31)|(?:(?:0?[1,3-9]|1[0-2])(\/|-)(?:29|30)))(\/|-)(?:[1-9]\d\d\d|\d[1-9]\d\d|\d\d[1-9]\d|\d\d\d[1-9])$|^(?:(?:0?[1-9]|1[0-2])(\/|-)(?:0?[1-9]|1\d|2[0-8]))(\/|-)(?:[1-9]\d\d\d|\d[1-9]\d\d|\d\d[1-9]\d|\d\d\d[1-9])$|^(0?2(\/|-)29)(\/|-)(?:(?:0[48]00|[13579][26]00|[2468][048]00)|(?:\d\d)?(?:0[48]|[2468][048]|[13579][26]))$/);
			return dateRegEx.test(value);
		},
		/**
		 * Checks if valid date time
		 *
		 * @param {string} date string
		 * @return a bool based on determination of valid date time
		 */
		_isDateTime: function (value){
			var dateTimeRegEx = new RegExp(/^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])\s+(1[012]|0?[1-9]){1}:(0?[1-5]|[0-6][0-9]){1}:(0?[0-6]|[0-6][0-9]){1}\s+(am|pm|AM|PM){1}$|^(?:(?:(?:0?[13578]|1[02])(\/|-)31)|(?:(?:0?[1,3-9]|1[0-2])(\/|-)(?:29|30)))(\/|-)(?:[1-9]\d\d\d|\d[1-9]\d\d|\d\d[1-9]\d|\d\d\d[1-9])$|^((1[012]|0?[1-9]){1}\/(0?[1-9]|[12][0-9]|3[01]){1}\/\d{2,4}\s+(1[012]|0?[1-9]){1}:(0?[1-5]|[0-6][0-9]){1}:(0?[0-6]|[0-6][0-9]){1}\s+(am|pm|AM|PM){1})$/);
			return dateTimeRegEx.test(value);
		},
		//Checks if the start date is before the end date
		//returns true if end is later than start
		_dateCompare: function (start, end) {
			return (new Date(start.toString()) < new Date(end.toString()));
		},
		/**
		 * Checks date range
		 *
		 * @param {jqObject} first field name
		 * @param {jqObject} second field name
		 * @return an error string if validation failed
		 */
		_dateRange: function (field, rules, i, options) {
			//are not both populated
			if ((!options.firstOfGroup[0].value && options.secondOfGroup[0].value) || (options.firstOfGroup[0].value && !options.secondOfGroup[0].value)) {
				return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2;
			}

			//are not both dates
			if (!methods._isDate(options.firstOfGroup[0].value) || !methods._isDate(options.secondOfGroup[0].value)) {
				return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2;
			}

			//are both dates but range is off
			if (!methods._dateCompare(options.firstOfGroup[0].value, options.secondOfGroup[0].value)) {
				return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2;
			}
		},
		/**
		 * Checks date time range
		 *
		 * @param {jqObject} first field name
		 * @param {jqObject} second field name
		 * @return an error string if validation failed
		 */
		_dateTimeRange: function (field, rules, i, options) {
			//are not both populated
			if ((!options.firstOfGroup[0].value && options.secondOfGroup[0].value) || (options.firstOfGroup[0].value && !options.secondOfGroup[0].value)) {
				return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2;
			}
			//are not both dates
			if (!methods._isDateTime(options.firstOfGroup[0].value) || !methods._isDateTime(options.secondOfGroup[0].value)) {
				return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2;
			}
			//are both dates but range is off
			if (!methods._dateCompare(options.firstOfGroup[0].value, options.secondOfGroup[0].value)) {
				return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2;
			}
		},
		/**
		 * Max number of checkbox selected
		 *
		 * @param {jqObject} field
		 * @param {Array[String]} rules
		 * @param {int} i rules index
		 * @param {Map}
			*            user options
		 * @return an error string if validation failed
		 */
		_maxCheckbox: function(form, field, rules, i, options) {

			var nbCheck = rules[i + 1];
			var groupname = field.attr("name");
			var groupSize = form.find("input[name='" + groupname + "']:checked").size();
			if (groupSize > nbCheck) {
				options.showArrow = false;
				if (options.allrules.maxCheckbox.alertText2)
					return options.allrules.maxCheckbox.alertText + " " + nbCheck + " " + options.allrules.maxCheckbox.alertText2;
				return options.allrules.maxCheckbox.alertText;
			}
		},
		/**
		 * Min number of checkbox selected
		 *
		 * @param {jqObject} field
		 * @param {Array[String]} rules
		 * @param {int} i rules index
		 * @param {Map}
			*            user options
		 * @return an error string if validation failed
		 */
		_minCheckbox: function(form, field, rules, i, options) {

			var nbCheck = rules[i + 1];
			var groupname = field.attr("name");
			var groupSize = form.find("input[name='" + groupname + "']:checked").size();
			if (groupSize < nbCheck) {
				options.showArrow = false;
				return options.allrules.minCheckbox.alertText + " " + nbCheck + " " + options.allrules.minCheckbox.alertText2;
			}
		},
		/**
		 * Checks that it is a valid credit card number according to the
		 * Luhn checksum algorithm.
		 *
		 * @param {jqObject} field
		 * @param {Array[String]} rules
		 * @param {int} i rules index
		 * @param {Map}
			*            user options
		 * @return an error string if validation failed
		 */
		_creditCard: function(field, rules, i, options) {
			//spaces and dashes may be valid characters, but must be stripped to calculate the checksum.
			var valid = false, cardNumber = field.val().replace(/ +/g, '').replace(/-+/g, '');

			var numDigits = cardNumber.length;
			if (numDigits >= 14 && numDigits <= 16 && parseInt(cardNumber) > 0) {

				var sum = 0, i = numDigits - 1, pos = 1, digit, luhn = new String();
				do {
					digit = parseInt(cardNumber.charAt(i));
					luhn += (pos++ % 2 == 0) ? digit * 2 : digit;
				} while (--i >= 0)

				for (i = 0; i < luhn.length; i++) {
					sum += parseInt(luhn.charAt(i));
				}
				valid = sum % 10 == 0;
			}
			if (!valid) return options.allrules.creditCard.alertText;
		},
		/**
		 * Ajax field validation
		 *
		 * @param {jqObject} field
		 * @param {Array[String]} rules
		 * @param {int} i rules index
		 * @param {Map}
			*            user options
		 * @return nothing! the ajax validator handles the prompts itself
		 */
		_ajax: function(field, rules, i, options) {

			var errorSelector = rules[i + 1];
			var rule = options.allrules[errorSelector];
			var extraData = rule.extraData;
			var extraDataDynamic = rule.extraDataDynamic;
			var data = {
				"fieldId" : field.attr("id"),
				"fieldValue" : field.val()
			};

			if (typeof extraData === "object") {
				$.extend(data, extraData);
			} else if (typeof extraData === "string") {
				var tempData = extraData.split("&");
				for(var i = 0; i < tempData.length; i++) {
					var values = tempData[i].split("=");
					if (values[0] && values[0]) {
						data[values[0]] = values[1];
					}
				}
			}

			if (extraDataDynamic) {
				var tmpData = [];
				var domIds = String(extraDataDynamic).split(",");
				for (var i = 0; i < domIds.length; i++) {
					var id = domIds[i];
					if ($(id).length) {
						var inputValue = field.closest("form").find(id).val();
						var keyValue = id.replace('#', '') + '=' + escape(inputValue);
						data[id.replace('#', '')] = inputValue;
					}
				}
			}

			// If a field change event triggered this we want to clear the cache for this ID
			if (options.eventTrigger == "field") {
				delete(options.ajaxValidCache[field.attr("id")]);
			}

			// If there is an error or if the the field is already validated, do not re-execute AJAX
			if (!options.isError && !methods._checkAjaxFieldStatus(field.attr("id"), options)) {
				$.ajax({
					type: options.ajaxFormValidationMethod,
					url: rule.url,
					cache: false,
					dataType: "json",
					data: data,
					field: field,
					rule: rule,
					methods: methods,
					options: options,
					beforeSend: function() {},
					error: function(data, transport) {
						methods._ajaxError(data, transport);
					},
					success: function(json) {

						// asynchronously called on success, data is the json answer from the server
						var errorFieldId = json[0];
						//var errorField = $($("#" + errorFieldId)[0]);
						var errorField = $($("input[id='" + errorFieldId +"']")[0]);

						// make sure we found the element
						if (errorField.length == 1) {
							var status = json[1];
							// read the optional msg from the server
							var msg = json[2];
							if (!status) {
								// Houston we got a problem - display an red prompt
								options.ajaxValidCache[errorFieldId] = false;
								options.isError = true;

								// resolve the msg prompt
								if(msg) {
									if (options.allrules[msg]) {
										var txt = options.allrules[msg].alertText;
										if (txt) {
											msg = txt;
										}
									}
								}
								else
									msg = rule.alertText;

								methods._showPrompt(errorField, msg, "", true, options);
							} else {
								options.ajaxValidCache[errorFieldId] = true;

								// resolves the msg prompt
								if(msg) {
									if (options.allrules[msg]) {
										var txt = options.allrules[msg].alertTextOk;
										if (txt) {
											msg = txt;
										}
									}
								}
								else
									msg = rule.alertTextOk;

								// see if we should display a green prompt
								if (msg)
									methods._showPrompt(errorField, msg, "pass", true, options);
								else
									methods._closePrompt(errorField);

								// If a submit form triggered this, we want to re-submit the form
								if (options.eventTrigger == "submit")
									field.closest("form").submit();
							}
						}
						errorField.trigger("jqv.field.result", [errorField, options.isError, msg]);
					}
				});

				return rule.alertTextLoad;
			}
		},
		/**
		 * Common method to handle ajax errors
		 *
		 * @param {Object} data
		 * @param {Object} transport
		 */
		_ajaxError: function(data, transport) {
			if(data.status == 0 && transport == null)
				alert("The page is not served from a server! ajax call failed");
			else if(typeof console != "undefined")
				console.log("Ajax error: " + data.status + " " + transport);
		},
		/**
		 * date -> string
		 *
		 * @param {Object} date
		 */
		_dateToString: function(date) {
			return date.getFullYear()+"-"+(date.getMonth()+1)+"-"+date.getDate();
		},
		/**
		 * Parses an ISO date
		 * @param {String} d
		 */
		_parseDate: function(d) {

			var dateParts = d.split("-");
			if(dateParts==d)
				dateParts = d.split("/");
			return new Date(dateParts[0], (dateParts[1] - 1) ,dateParts[2]);
		},
		/**
		 * Builds or updates a prompt with the given information
		 *
		 * @param {jqObject} field
		 * @param {String} promptText html text to display type
		 * @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red)
		 * @param {boolean} ajaxed - use to mark fields than being validated with ajax
		 * @param {Map} options user options
		 */
		_showPrompt: function(field, promptText, type, ajaxed, options, ajaxform) {
			var prompt = methods._getPrompt(field);
			// The ajax submit errors are not see has an error in the form,
			// When the form errors are returned, the engine see 2 bubbles, but those are ebing closed by the engine at the same time
			// Because no error was found befor submitting
			if(ajaxform) prompt = false;
			if (prompt)
				methods._updatePrompt(field, prompt, promptText, type, ajaxed, options);
			else
				methods._buildPrompt(field, promptText, type, ajaxed, options);
		},
		/**
		 * Builds and shades a prompt for the given field.
		 *
		 * @param {jqObject} field
		 * @param {String} promptText html text to display type
		 * @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red)
		 * @param {boolean} ajaxed - use to mark fields than being validated with ajax
		 * @param {Map} options user options
		 */
		_buildPrompt: function(field, promptText, type, ajaxed, options) {

			// create the prompt
			var prompt = $('<div>');
			prompt.addClass(methods._getClassName(field.attr("id")) + "formError");
			// add a class name to identify the parent form of the prompt
			prompt.addClass("parentForm"+methods._getClassName(field.parents('form').attr("id")));
			prompt.addClass("formError");

			switch (type) {
				case "pass":
					prompt.addClass("greenPopup");
					break;
				case "load":
					prompt.addClass("blackPopup");
					break;
				default:
				/* it has error  */
				//alert("unknown popup type:"+type);
			}
			if (ajaxed)
				prompt.addClass("ajaxed");

			// create the prompt content
			var promptContent = $('<div>').addClass("formErrorContent").html(promptText).appendTo(prompt);
			// create the css arrow pointing at the field
			// note that there is no triangle on max-checkbox and radio
			if (options.showArrow) {
				var arrow = $('<div>').addClass("formErrorArrow");

				//prompt positioning adjustment support. Usage: positionType:Xshift,Yshift (for ex.: bottomLeft:+20 or bottomLeft:-20,+10)
				var positionType=field.data("promptPosition") || options.promptPosition;
				if (typeof(positionType)=='string')
				{
					var pos=positionType.indexOf(":");
					if(pos!=-1)
						positionType=positionType.substring(0,pos);
				}

				switch (positionType) {
					case "bottomLeft":
					case "bottomRight":
						prompt.find(".formErrorContent").before(arrow);
						arrow.addClass("formErrorArrowBottom").html('<div class="line1"><!-- --></div><div class="line2"><!-- --></div><div class="line3"><!-- --></div><div class="line4"><!-- --></div><div class="line5"><!-- --></div><div class="line6"><!-- --></div><div class="line7"><!-- --></div><div class="line8"><!-- --></div><div class="line9"><!-- --></div><div class="line10"><!-- --></div>');
						break;
					case "topLeft":
					case "topRight":
						arrow.html('<div class="line10"><!-- --></div><div class="line9"><!-- --></div><div class="line8"><!-- --></div><div class="line7"><!-- --></div><div class="line6"><!-- --></div><div class="line5"><!-- --></div><div class="line4"><!-- --></div><div class="line3"><!-- --></div><div class="line2"><!-- --></div><div class="line1"><!-- --></div>');
						prompt.append(arrow);
						break;
				}
			}
			// Modify z-indexes  for jquery ui
			if (field.closest('.ui-dialog').length)
				prompt.addClass('formErrorInsideDialog');

			prompt.css({
				"opacity": 0,
				'position':'absolute'
			});
			field.before(prompt);

			var pos = methods._calculatePosition(field, prompt, options);
			prompt.css({
				"top": pos.callerTopPosition,
				"left": pos.callerleftPosition,
				"marginTop": pos.marginTopSize,
				"opacity": 0
			}).data("callerField", field);

			if (options.autoHidePrompt) {
				setTimeout(function(){
					prompt.animate({
						"opacity": 0
					},function(){
						prompt.closest('.formErrorOuter').remove();
						prompt.remove();
					});
				}, options.autoHideDelay);
			}
			return prompt.animate({
				"opacity": 0.87
			});
		},
		/**
		 * Updates the prompt text field - the field for which the prompt
		 * @param {jqObject} field
		 * @param {String} promptText html text to display type
		 * @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red)
		 * @param {boolean} ajaxed - use to mark fields than being validated with ajax
		 * @param {Map} options user options
		 */
		_updatePrompt: function(field, prompt, promptText, type, ajaxed, options, noAnimation) {

			if (prompt) {
				if (typeof type !== "undefined") {
					if (type == "pass")
						prompt.addClass("greenPopup");
					else
						prompt.removeClass("greenPopup");

					if (type == "load")
						prompt.addClass("blackPopup");
					else
						prompt.removeClass("blackPopup");
				}
				if (ajaxed)
					prompt.addClass("ajaxed");
				else
					prompt.removeClass("ajaxed");

				prompt.find(".formErrorContent").html(promptText);

				var pos = methods._calculatePosition(field, prompt, options);
				var css = {"top": pos.callerTopPosition,
					"left": pos.callerleftPosition,
					"marginTop": pos.marginTopSize};

				if (noAnimation)
					prompt.css(css);
				else
					prompt.animate(css);
			}
		},
		/**
		 * Closes the prompt associated with the given field
		 *
		 * @param {jqObject}
			*            field
		 */
		_closePrompt: function(field) {
			var prompt = methods._getPrompt(field);
			if (prompt)
				prompt.fadeTo("fast", 0, function() {
					prompt.parent('.formErrorOuter').remove();
					prompt.remove();
				});
		},
		closePrompt: function(field) {
			return methods._closePrompt(field);
		},
		/**
		 * Returns the error prompt matching the field if any
		 *
		 * @param {jqObject}
			*            field
		 * @return undefined or the error prompt (jqObject)
		 */
		_getPrompt: function(field) {
			var formId = $(field).closest('form').attr('id');
			var className = methods._getClassName(field.attr("id")) + "formError";
			var match = $("." + methods._escapeExpression(className) + '.parentForm' + formId)[0];
			if (match)
				return $(match);
		},
		/**
		 * Returns the escapade classname
		 *
		 * @param {selector}
			*            className
		 */
		_escapeExpression: function (selector) {
			return selector.replace(/([#;&,\.\+\*\~':"\!\^$\[\]\(\)=>\|])/g, "\\$1");
		},
		/**
		 * returns true if we are in a RTLed document
		 *
		 * @param {jqObject} field
		 */
		isRTL: function(field)
		{
			var $document = $(document);
			var $body = $('body');
			var rtl =
				(field && field.hasClass('rtl')) ||
					(field && (field.attr('dir') || '').toLowerCase()==='rtl') ||
					$document.hasClass('rtl') ||
					($document.attr('dir') || '').toLowerCase()==='rtl' ||
					$body.hasClass('rtl') ||
					($body.attr('dir') || '').toLowerCase()==='rtl';
			return Boolean(rtl);
		},
		/**
		 * Calculates prompt position
		 *
		 * @param {jqObject}
			*            field
		 * @param {jqObject}
			*            the prompt
		 * @param {Map}
			*            options
		 * @return positions
		 */
		_calculatePosition: function (field, promptElmt, options) {

			var promptTopPosition, promptleftPosition, marginTopSize;
			var fieldWidth 	= field.width();
			var fieldLeft 	= field.position().left;
			var fieldTop 	=  field.position().top;
			var fieldHeight 	=  field.height();
			var promptHeight = promptElmt.height();


			// is the form contained in an overflown container?
			promptTopPosition = promptleftPosition = 0;
			// compensation for the arrow
			marginTopSize = -promptHeight;


			//prompt positioning adjustment support
			//now you can adjust prompt position
			//usage: positionType:Xshift,Yshift
			//for example:
			//   bottomLeft:+20 means bottomLeft position shifted by 20 pixels right horizontally
			//   topRight:20, -15 means topRight position shifted by 20 pixels to right and 15 pixels to top
			//You can use +pixels, - pixels. If no sign is provided than + is default.
			var positionType=field.data("promptPosition") || options.promptPosition;
			var shift1="";
			var shift2="";
			var shiftX=0;
			var shiftY=0;
			if (typeof(positionType)=='string') {
				//do we have any position adjustments ?
				if (positionType.indexOf(":")!=-1) {
					shift1=positionType.substring(positionType.indexOf(":")+1);
					positionType=positionType.substring(0,positionType.indexOf(":"));

					//if any advanced positioning will be needed (percents or something else) - parser should be added here
					//for now we use simple parseInt()

					//do we have second parameter?
					if (shift1.indexOf(",") !=-1) {
						shift2=shift1.substring(shift1.indexOf(",") +1);
						shift1=shift1.substring(0,shift1.indexOf(","));
						shiftY=parseInt(shift2);
						if (isNaN(shiftY)) shiftY=0;
					};

					shiftX=parseInt(shift1);
					if (isNaN(shift1)) shift1=0;

				};
			};


			switch (positionType) {
				default:
				case "topRight":
					promptleftPosition +=  fieldLeft + fieldWidth - 30;
					promptTopPosition +=  fieldTop;
					break;

				case "topLeft":
					promptTopPosition +=  fieldTop;
					promptleftPosition += fieldLeft;
					break;

				case "centerRight":
					promptTopPosition = fieldTop+4;
					marginTopSize = 0;
					promptleftPosition= fieldLeft + field.outerWidth(true)+5;
					break;
				case "centerLeft":
					promptleftPosition = fieldLeft - (promptElmt.width() + 2);
					promptTopPosition = fieldTop+4;
					marginTopSize = 0;

					break;

				case "bottomLeft":
					promptTopPosition = fieldTop + field.height() + 5;
					marginTopSize = 0;
					promptleftPosition = fieldLeft;
					break;
				case "bottomRight":
					promptleftPosition = fieldLeft + fieldWidth - 30;
					promptTopPosition =  fieldTop +  field.height() + 5;
					marginTopSize = 0;
			};



			//apply adjusments if any
			promptleftPosition += shiftX;
			promptTopPosition  += shiftY;

			return {
				"callerTopPosition": promptTopPosition + "px",
				"callerleftPosition": promptleftPosition + "px",
				"marginTopSize": marginTopSize + "px"
			};
		},
		/**
		 * Saves the user options and variables in the form.data
		 *
		 * @param {jqObject}
			*            form - the form where the user option should be saved
		 * @param {Map}
			*            options - the user options
		 * @return the user options (extended from the defaults)
		 */
		_saveOptions: function(form, options) {

			// is there a language localisation ?
			if ($.validationEngineLanguage)
				var allRules = $.validationEngineLanguage.allRules;
			else
				$.error("jQuery.validationEngine rules are not loaded, plz add localization files to the page");
			// --- Internals DO NOT TOUCH or OVERLOAD ---
			// validation rules and i18
			$.validationEngine.defaults.allrules = allRules;

			var userOptions = $.extend(true,{},$.validationEngine.defaults,options);

			form.data('jqv', userOptions);
			return userOptions;
		},

		/**
		 * Removes forbidden characters from class name
		 * @param {String} className
		 */
		_getClassName: function(className) {
			if(className)
				return className.replace(/:/g, "_").replace(/\./g, "_");
		},

		/**
		 * Conditionally required field
		 *
		 * @param {jqObject} field
		 * @param {Array[String]} rules
		 * @param {int} i rules index
		 * @param {Map}
			* user options
		 * @return an error string if validation failed
		 */
		_condRequired: function(field, rules, i, options) {
			var idx, dependingField;

			for(idx = (i + 1); idx < rules.length; idx++) {
				dependingField = jQuery("#" + rules[idx]).first();

				/* Use _required for determining wether dependingField has a value.
				 * There is logic there for handling all field types, and default value; so we won't replicate that here
				 */
				if (dependingField.length && methods._required(dependingField, ["required"], 0, options) == undefined) {
					/* We now know any of the depending fields has a value,
					 * so we can validate this field as per normal required code
					 */
					return methods._required(field, ["required"], 0, options);
				}
			}
		}
	};

	/**
	 * Plugin entry point.
	 * You may pass an action as a parameter or a list of options.
	 * if none, the init and attach methods are being called.
	 * Remember: if you pass options, the attached method is NOT called automatically
	 *
	 * @param {String}
		*            method (optional) action
	 */
	$.fn.validationEngine = function(method) {

		var form = $(this);
		if(!form[0]) return form;  // stop here if the form does not exist

		if (typeof(method) == 'string' && method.charAt(0) != '_' && methods[method]) {

			// make sure init is called once
			if(method != "showPrompt" && method != "hide" && method != "hideAll")
				methods.init.apply(form);

			return methods[method].apply(form, Array.prototype.slice.call(arguments, 1));
		} else if (typeof method == 'object' || !method) {

			// default constructor with or without arguments
			methods.init.apply(form, arguments);
			return methods.attach.apply(form);
		} else {
			$.error('Method ' + method + ' does not exist in jQuery.validationEngine');
		}
	};



	// LEAK GLOBAL OPTIONS
	$.validationEngine= {fieldIdCounter: 0,defaults:{

		// Name of the event triggering field validation
		validationEventTrigger: "blur",
		// Automatically scroll viewport to the first error
		scroll: true,
		// Focus on the first input
		focusFirstField:true,
		// Opening box position, possible locations are: topLeft,
		// topRight, bottomLeft, centerRight, bottomRight
		promptPosition: "topRight",
		bindMethod:"bind",
		// internal, automatically set to true when it parse a _ajax rule
		inlineAjax: false,
		// if set to true, the form data is sent asynchronously via ajax to the form.action url (get)
		ajaxFormValidation: false,
		// The url to send the submit ajax validation (default to action)
		ajaxFormValidationURL: false,
		// HTTP method used for ajax validation
		ajaxFormValidationMethod: 'get',
		// Ajax form validation callback method: boolean onComplete(form, status, errors, options)
		// retuns false if the form.submit event needs to be canceled.
		onAjaxFormComplete: $.noop,
		// called right before the ajax call, may return false to cancel
		onBeforeAjaxFormValidation: $.noop,
		// Stops form from submitting and execute function assiciated with it
		onValidationComplete: false,

		// Used when you have a form fields too close and the errors messages are on top of other disturbing viewing messages
		doNotShowAllErrosOnSubmit: false,
		// Object where you store custom messages to override the default error messages
		custom_error_messages:{},
		// true if you want to vind the input fields
		binded: true,
		// set to true, when the prompt arrow needs to be displayed
		showArrow: true,
		// did one of the validation fail ? kept global to stop further ajax validations
		isError: false,
		// Caches field validation status, typically only bad status are created.
		// the array is used during ajax form validation to detect issues early and prevent an expensive submit
		ajaxValidCache: {},
		// Auto update prompt position after window resize
		autoPositionUpdate: false,

		InvalidFields: [],
		onSuccess: false,
		onFailure: false,
		// Auto-hide prompt
		autoHidePrompt: false,
		// Delay before auto-hide
		autoHideDelay: 10000,
		// Fade out duration while hiding the validations
		fadeDuration: 0.3,
		// Use Prettify select library
		prettySelect: false,
		// Custom ID uses prefix
		usePrefix: "",
		// Custom ID uses suffix
		useSuffix: "",
		// Only show one message per error prompt
		showOneMessage: false
	}};
	$(function(){$.validationEngine.defaults.promptPosition = methods.isRTL()?'topLeft':"topRight"});
})(jQuery);
/***************************************************************
 *  Copyright notice
 *
 *  (c) 2012 Alexander Kellner <alexander.kellner@in2code.de>, in2code
 *
 *  All rights reserved
 *
 *  This script is part of the TYPO3 project. The TYPO3 project is
 *  free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  The GNU General Public License can be found at
 *  http://www.gnu.org/copyleft/gpl.html.
 *
 *  This script is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  This copyright notice MUST APPEAR in all copies of the script!
 ***************************************************************/

jQuery(document).ready(function($) {
	jQuery.fn.powermailTabs = function(options) {
		'use strict';
		var $this = jQuery(this);
		options = jQuery.extend({
			container: 'fieldset',
			header: 'legend'
		},options);

		// generate menu
		var $ul = jQuery('<ul />', {
			'id': 'powermail_tabmenu',
			'class': 'powermail_tabmenu'
		}).insertBefore($this.children(options.container).filter(':first'));

		//all containers
		$this.children(options.container).each(function(i, $fieldset){
			//tab_menu
			$ul.append(
				jQuery('<li/>')
				.html($(this).children(options.header).html())
				.addClass((i==0) ? 'act' : '')
				.click({
					container: $this.children(options.container),
					fieldset: $($fieldset)
				}, function(e){
					jQuery('.powermail_tabmenu li', $this).removeClass('act');
					jQuery(this).addClass('act');
					e.data.container.hide();
					e.data.fieldset.show()
				})
			)
		});

		// initial show first fieldset
		$this.children(options.container).hide();
		$this.find(options.container).first().show();

		// Stop submit
		$this.submit(function(e) {
			//e.preventDefault();
		});
	};
});
;
(function($) {
    var xhr = null;
    var lastLink = null;
    var loadNext = false;

    function mehrNews(href) {

        mehr(href, "#news_top > .spalte:last-child");
        //var frei = $("#news_top > .spalte:last-child .tiles").position().left - 143;
        //alert(frei);

    }
    function mehrReferenzen(href) {
        var temp = href.split("start=");
        var start;
        if (typeof temp[1] !== "undefined") {
            start = parseInt(temp[1]);
            if (start % 4 !== 0) {
                start -= 1;
            }
            start = start / 4 + 1;
        } else {
            start = 1;
        }
        var index = start;

        var length = $('.ui-page-active #referenz_middle .pb').length;
        if (index > length || length === 0) {
            if (index < 0){
                index = 1;
            }
            mehr(href, "#referenz_middle");
            length = $('.ui-page-active #referenz_middle .pb').length;
        }
        if ($('.ui-page-active #referenz_middle .apbs.aktiv').length === 0) {
            index = 1;
        }
        //aktEl.removeClass("aktiv");
        if (index <= length) {
            $('.ui-page-active #referenz_middle .next').html('<a href="/referenzen/auswahl/pagebrowser.html?start=' + (index * 4 + 1) + '">&gt;</a>');
        } else {
            $('.ui-page-active #referenz_middle .next').html('');
            index -= 1;
            $('.ui-page-active #referenz_middle').find('.apbs').eq((index - 1)).addClass("last");
        }
        if (index > 1) {
            $('.ui-page-active #referenz_middle .prev').html('<a href="/referenzen/auswahl/pagebrowser.html?start=' + ((index - 2) * 4) + '">&lt;</a>');
        } else {
            $('.ui-page-active #referenz_middle .prev').html('');
        }

        $('.ui-page-active #referenz_middle .apbs.aktiv').removeClass("aktiv");
        $('.ui-page-active #referenz_middle').find('.apbs').eq((index - 1)).addClass("aktiv");

        if ($('.ui-page-active #referenz_middle').find('.apbs').eq((index - 1)).find('.tiles').length < 4) {
            $('.ui-page-active #referenz_middle .next').html('');
        }

		    $(document).trigger('apb::readynext');
    }
    function mehr(href, container) {
        $.ajax({
            url: href,
            beforeSend: function() {
                $('.content > #more').fadeOut().remove();
                $('body').addClass('ui-loading');
            },
            async: false,
            dataType: "text",
            cache: true,
            complete: function(response) {
                if ($('.ui-page-active ' + container + ' > div').length === 0) {
                    var initial = true;
                } else {
                    var initial = false;
                }
                if (response.responseText.indexOf('div') !== -1) {
                    var el = $('.ui-page-active ' + container);
                    if ($(container).attr('id') === "referenz_middle") {
                        el.append('<div class="apbs">' + response.responseText + '</div>');
                        if (el.find(".apbs.aktiv").length > 1) {
                            el.find(".apbs:first").addClass("aktiv");
                        } else {
                            var aktEl = el.find(".apbs.aktiv");
                            aktEl.next('.apbs').addClass("aktiv");
                            aktEl.removeClass("aktiv");
                        }
                    } else {
                        el.append(response.responseText);
                        $('.ui-page-active #more').remove();
                    }

                    $('.more').remove();
//                    if (initial === false) {
//                        //el.masonry('reload');
//                    }
                    el.parents("#content_area").find('#more').delay(1000).fadeIn();
                    el.find('.tiles').each(function() {
                        var href = $(this).find('a').attr('href');
                        var url = window.location.toString();
                        if (url.indexOf(href) !== -1) {
                            $(this).addClass('aktiv');
                        }
                    });
                }
            }
        });
    }
    $(document).on("click", ".ui-page-active #wrapper.news #more a", function(e) {
        e.preventDefault();
	e.stopPropagation();
        mehrNews(this.href);
        $('body').removeClass('ui-loading');
    });
    $(document).on("click", ".ui-page-active #wrapper.referenz .next a", function(e) {
        e.preventDefault();
	e.stopPropagation();
        mehrReferenzen(this.href);

        $('body').removeClass('ui-loading');
    });
    $(document).on("click", ".ui-page-active #wrapper.referenz .prev a", function(e) {
        e.preventDefault();
	e.stopPropagation();
        mehrReferenzen(this.href);
        $('body').removeClass('ui-loading');
    });
//    $(document).on("pagehide", function() {
//        //$('.ui-page-active #wrapper.news .pb').remove();
//    });
    $(document).on("pageshow::pb", function() {
	var location = window.location.href;
        if ($('.ui-page-active #news_top > .spalte:last-child > div').length === 0) {
            if ($('.ui-page-active #news_top > .spalte:last-child > a').length !== 0) {
                var href = $('.ui-page-active #news_top > .spalte:last-child > a').attr('href');
                //var href = window.location.toString().split('.html').join('/pagebrowser.html');
                mehrNews(href);
                $('.ui-page-active #news_top > .spalte:last-child > a').remove();
            }
            if (window.location.href.match(/\/news\/$/gi)) {
                $('.ui-page-active #wrapper.news .bg .tiles:first-child').addClass('aktiv');
            }
        }
        if ($('.ui-page-active #wrapper.referenz').length > 0) {
            var findAktiv = false;
            var url = location;
		$(document).on('apb::readynext',function(){
			
        	$('body').addClass('ui-loading');
                    $('.ui-page-active #referenz_middle .apbs .tiles').each(function() {
                        var href = $(this).find('a').attr('href');
			var url  = window.location.href;
                        if (url.indexOf(href) !== -1) {
                            $(this).addClass('aktiv');
                            loadNext = false;
                        }
                    });
                    if (loadNext !== false) {
                        if ($(".ui-page-active #wrapper.referenz .next a").length > 0){
			var next = $(".ui-page-active #wrapper.referenz .next a").attr('href');
//console.log(loadNext);
        			mehrReferenzen(next);
			}
                    }

		    $('body').removeClass('ui-loading');
		})
            if (url.indexOf("auswahl.html") === -1) {
		loadNext = true;
            }
	    if ($('.ui-page-active #wrapper.referenz .next').length === 0) {
                $('.ui-page-active #referenz_middle ').prepend('<div class="tiles apbc prev"></div>');
                $('.ui-page-active #referenz_middle ').append('<div class="tiles apbc next"></div>');
                mehrReferenzen("/referenzen/auswahl/pagebrowser.html");
            }
        }

    });
})(jQuery);

function initialize() {
    var myLatlng = new google.maps.LatLng(51.99314, 6.92201)
    var mapOptions = {
        zoom: 13,
        center: myLatlng,
        mapTypeId: google.maps.MapTypeId.ROADMAP
    }
    var map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
  
    var contentString = '<div id="gmc">'+
    '<span style="color:#005192;">w+</span><br> \
			Werbe- und Internetagentur GmbH<br>\
			Dufkampstr. 40<br> \
			D-48703 Stadtlohn<br><br> \
			T +49 (0) 25 63 - 40 90 00<br> \
			F +49 (0) 25 63 - 40 90 10<br> '+
//			<div class="gmc_social">\
//				<a target="_blank" href="https://www.xing.com/companies/w%252Bwerbe-undinternetagenturgmbh"><img src="http://www.w-plus.de/core/cms/upload/Bildnavigation/xing.png" border="0"></a>&nbsp;\
//				<a target="_blank" href="http://twitter.com/#!/UlliUhle"><img src="http://www.w-plus.de/core/cms/upload/Bildnavigation/twitter.png" border="0"></a>&nbsp; \
//				<a target="_blank" href="http://blog.w-plus.de"><img src="http://www.w-plus.de/core/cms/upload/Bildnavigation/blog.png" border="0"></a>&nbsp; \
//				<a target="_blank" href="http://www.linkedin.com/company/1475598?trk=null"><img src="http://www.w-plus.de/core/cms/upload/Bildnavigation/linkedin.png" border="0"></a>&nbsp; \
//				<a target="_blank" href="http://www.facebook.com/wplus.de"><img src="http://www.w-plus.de/core/cms/upload/Bildnavigation/facebook.png" border="0"></a>&nbsp; \
//			</div>'+
    '</div>';

    var infowindow = new google.maps.InfoWindow({
        content: contentString
    });
    // var image = '/fileadmin/system/images/gmaps_marker.png';
    var image = new google.maps.MarkerImage('/fileadmin/system/images/favicon.ico',
        new google.maps.Size(32, 32),
        new google.maps.Point(0, 0),
        new google.maps.Point(0, 0)
        );

    var marker = new google.maps.Marker({
        position: myLatlng,
        map: map,
        icon: image,
        title:"die MARKENpfalnzer"
    });

    google.maps.event.addListener(marker, 'click', function() {
        infowindow.open(map,marker);
    });
}


/**
 * jQuery Masonry v2.1.08
 * A dynamic layout plugin for jQuery
 * The flip-side of CSS Floats
 * http://masonry.desandro.com
 *
 * Licensed under the MIT license.
 * Copyright 2012 David DeSandro
 */
(function(e,t,n){"use strict";var r=t.event,i;r.special.smartresize={setup:function(){t(this).bind("resize",r.special.smartresize.handler)},teardown:function(){t(this).unbind("resize",r.special.smartresize.handler)},handler:function(e,t){var n=this,s=arguments;e.type="smartresize",i&&clearTimeout(i),i=setTimeout(function(){r.dispatch.apply(n,s)},t==="execAsap"?0:100)}},t.fn.smartresize=function(e){return e?this.bind("smartresize",e):this.trigger("smartresize",["execAsap"])},t.Mason=function(e,n){this.element=t(n),this._create(e),this._init()},t.Mason.settings={isResizable:!0,isAnimated:!1,animationOptions:{queue:!1,duration:500},gutterWidth:0,isRTL:!1,isFitWidth:!1,containerStyle:{position:"relative"}},t.Mason.prototype={_filterFindBricks:function(e){var t=this.options.itemSelector;return t?e.filter(t).add(e.find(t)):e},_getBricks:function(e){var t=this._filterFindBricks(e).css({position:"absolute"}).addClass("masonry-brick");return t},_create:function(n){this.options=t.extend(!0,{},t.Mason.settings,n),this.styleQueue=[];var r=this.element[0].style;this.originalStyle={height:r.height||""};var i=this.options.containerStyle;for(var s in i)this.originalStyle[s]=r[s]||"";this.element.css(i),this.horizontalDirection=this.options.isRTL?"right":"left";var o=this.element.css("padding-"+this.horizontalDirection),u=this.element.css("padding-top");this.offset={x:o?parseInt(o,10):0,y:u?parseInt(u,10):0},this.isFluid=this.options.columnWidth&&typeof this.options.columnWidth=="function";var a=this;setTimeout(function(){a.element.addClass("masonry")},0),this.options.isResizable&&t(e).bind("smartresize.masonry",function(){a.resize()}),this.reloadItems()},_init:function(e){this._getColumns(),this._reLayout(e)},option:function(e,n){t.isPlainObject(e)&&(this.options=t.extend(!0,this.options,e))},layout:function(e,t){for(var n=0,r=e.length;n<r;n++)this._placeBrick(e[n]);var i={};i.height=Math.max.apply(Math,this.colYs);if(this.options.isFitWidth){var s=0;n=this.cols;while(--n){if(this.colYs[n]!==0)break;s++}i.width=(this.cols-s)*this.columnWidth-this.options.gutterWidth}this.styleQueue.push({$el:this.element,style:i});var o=this.isLaidOut?this.options.isAnimated?"animate":"css":"css",u=this.options.animationOptions,a;for(n=0,r=this.styleQueue.length;n<r;n++)a=this.styleQueue[n],a.$el[o](a.style,u);this.styleQueue=[],t&&t.call(e),this.isLaidOut=!0},_getColumns:function(){var e=this.options.isFitWidth?this.element.parent():this.element,t=e.width();this.columnWidth=this.isFluid?this.options.columnWidth(t):this.options.columnWidth||this.$bricks.outerWidth(!0)||t,this.columnWidth+=this.options.gutterWidth,this.cols=Math.floor((t+this.options.gutterWidth)/this.columnWidth),this.cols=Math.max(this.cols,1)},_placeBrick:function(e){var n=t(e),r,i,s,o,u;r=Math.ceil(n.outerWidth(!0)/this.columnWidth),r=Math.min(r,this.cols);if(r===1)s=this.colYs;else{i=this.cols+1-r,s=[];for(u=0;u<i;u++)o=this.colYs.slice(u,u+r),s[u]=Math.max.apply(Math,o)}var a=Math.min.apply(Math,s),f=0;for(var l=0,c=s.length;l<c;l++)if(s[l]===a){f=l;break}var h={top:a+this.offset.y};h[this.horizontalDirection]=this.columnWidth*f+this.offset.x,this.styleQueue.push({$el:n,style:h});var p=a+n.outerHeight(!0),d=this.cols+1-c;for(l=0;l<d;l++)this.colYs[f+l]=p},resize:function(){var e=this.cols;this._getColumns(),(this.isFluid||this.cols!==e)&&this._reLayout()},_reLayout:function(e){var t=this.cols;this.colYs=[];while(t--)this.colYs.push(0);this.layout(this.$bricks,e)},reloadItems:function(){this.$bricks=this._getBricks(this.element.children())},reload:function(e){this.reloadItems(),this._init(e)},appended:function(e,t,n){if(t){this._filterFindBricks(e).css({top:this.element.height()});var r=this;setTimeout(function(){r._appended(e,n)},1)}else this._appended(e,n)},_appended:function(e,t){var n=this._getBricks(e);this.$bricks=this.$bricks.add(n),this.layout(n,t)},remove:function(e){this.$bricks=this.$bricks.not(e),e.remove()},destroy:function(){this.$bricks.removeClass("masonry-brick").each(function(){this.style.position="",this.style.top="",this.style.left=""});var n=this.element[0].style;for(var r in this.originalStyle)n[r]=this.originalStyle[r];this.element.unbind(".masonry").removeClass("masonry").removeData("masonry"),t(e).unbind(".masonry")}},t.fn.imagesLoaded=function(e){function u(){e.call(n,r)}function a(e){var n=e.target;n.src!==s&&t.inArray(n,o)===-1&&(o.push(n),--i<=0&&(setTimeout(u),r.unbind(".imagesLoaded",a)))}var n=this,r=n.find("img").add(n.filter("img")),i=r.length,s="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==",o=[];return i||u(),r.bind("load.imagesLoaded error.imagesLoaded",a).each(function(){var e=this.src;this.src=s,this.src=e}),n};var s=function(t){e.console&&e.console.error(t)};t.fn.masonry=function(e){if(typeof e=="string"){var n=Array.prototype.slice.call(arguments,1);this.each(function(){var r=t.data(this,"masonry");if(!r){s("cannot call methods on masonry prior to initialization; attempted to call method '"+e+"'");return}if(!t.isFunction(r[e])||e.charAt(0)==="_"){s("no such method '"+e+"' for masonry instance");return}r[e].apply(r,n)})}else this.each(function(){var n=t.data(this,"masonry");n?(n.option(e||{}),n._init()):t.data(this,"masonry",new t.Mason(e,this))});return this}})(window,jQuery);
///#source 1 1 /Scripts/MetroJs/src/js/init.js
/*!
* Metro JS for jQuery
* http://drewgreenwell.com/ 
* For details and usage info see: http://drewgreenwell.com/projects/metrojs

Copyright (C) 2012, Drew Greenwell

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), 
to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
;(function ($) {
    // the metrojs object contains helper methods and theme settings
    $.fn.metrojs = {
        capabilities: null,
        checkCapabilities: function(stgs, recheck){
            if($.fn.metrojs.capabilities == null || (typeof(recheck) != "undefined" && recheck == true))
                $.fn.metrojs.capabilities = new $.fn.metrojs.MetroModernizr(stgs);
            return  $.fn.metrojs.capabilities;
        }
    };
    var metrojs = $.fn.metrojs;
///#source 1 1 /Scripts/MetroJs/src/js/liveTile.js
var MAX_LOOP_COUNT = 99000;
// .liveTile
$.fn.liveTile = function (method) {
    if (pubMethods[method]) {
        var args = [];
        for (var i = 1; i <= arguments.length; i++) {
            args[i - 1] = arguments[i];
        }
        return pubMethods[method].apply(this, args);
    } else if (typeof method === 'object' || !method) {
        return pubMethods.init.apply(this, arguments);
    } else {
        $.error('Method ' + method + ' does not exist on jQuery.liveTile');
        return null;
    }
};


$.fn.liveTile.contentModules = {
    modules: {},
    /* the default module layout
    {
        image: defaultModules.imageSwap,
        html: defaultModules.htmlSwap
    },*/
    addContentModule: function (moduleName, module) {
        if (typeof (this.modules) !== "object")
            this.modules = {};
        this.modules[moduleName] = module;
    },
    hasContentModule: function(moduleName){
        if (typeof (moduleName) === "undefined" || typeof (this.modules) !== "object")
            return false;
        return (typeof (this.modules[moduleName]) !== "undefined");
    }
};

// default option values for .liveTile
$.fn.liveTile.defaults = {
    mode: 'slide',                          // 'slide', 'flip', 'flip-list', carousel
    speed: 500,                             // how fast should animations be performed, in milliseconds
    initDelay: -1,                          // how long to wait before the initial animation
    delay: 5000,                            // how long to wait between animations 
    stops: "100%",                          // how much of the back tile should 'slide' reveal before starting a delay
    stack: false,                           // should tiles in slide mode appear stacked (e.g Me tile) 
    direction: 'vertical',                  // which direction should animations be performed(horizontal | vertical)
    animationDirection: 'forward',          // the direction that carousel mode uses to determine which way to slide in tiles
    tileSelector: '>div,>li,>p,>img,>a',    // the selector used by carousel mode and flip-list to choose tile containers
    tileFaceSelector: '>div,>li,>p,>img,>a',// the selector used to choose the front and back containers
    ignoreDataAttributes: false,            // should data attributes be ignored
    click: null,                            // function ($tile, tdata) { return true; }
    link: '',                               // a url to go to when clicked
    newWindow: false,                       // should the link be opened in a new window
    bounce: false,                          // should the tile shrink when tapped
    pauseOnHover: false,                    // should tile animations be paused on hover in and restarted on hover out
    playOnHover: false,                     // should "play" be called on hover
    onHoverDelay: 0,                        // the amount of time to wait before the onHover event is fired
    repeatCount: -1,                        // number of times to repeat the animation        
    appendBack: true,                       // appends the .last tile if one doesnt exist (slide and flip only)        
    alwaysTrigger: false,                   // should every item in a flip list trigger every time a delay passes 
    flipListOnHover: false,                 // should items in flip-list flip and stop when hovered
    flipListOnHoverEvent: 'mouseout',       // which event should be used to trigger the flip-list faces
    noHAflipOpacity: '1',                   // the opacity level set for the backside of the flip animation on unaccelerated browsers
    haTransFunc: 'ease',                    // the tranisiton-timing function to use in hardware accelerated mode
    noHaTransFunc: 'linear',                // the tranisiton-timing function to use in non hardware accelerated mode
    currentIndex: 0,                        // what is the current stop index for slide mode or slide index for carousel mode
    startNow: true,                         // should the tile immediately start or wait util play or restart has been called
    useModernizr: (typeof (window.Modernizr) !== "undefined"), // checks to see if modernizer is already in use
    useHardwareAccel: true,                 // should css animations, transitions and transforms be used when available
    faces: {
        $front: null,                        // the jQuery element to use as the front face of the tile; this will bypass tileCssSelector
        $back: null                          // the jQuery element to use as the back face of the tile; this will bypass tileCssSelector
    },
    animationComplete: function (tileData, $front, $back) {
    },
    triggerDelay: function (idx) {          // used by flip-list to decide how random the tile flipping should be
        return Math.random() * 3000;
    },
    swap: '',                               // which swap modules are active for this tile (image, html) 
    swapFront: '-',                         // override the available swap modules for the front face
    swapBack: '-',                          // override the available swap modules for the back face
    contentModules: []
};
// public methods that can be called via .liveTile(method name)
var pubMethods = {
    init: function (options) {
        // Setup the public options for the livetile
        var stgs = {};
        $.extend(stgs, $.fn.liveTile.defaults, options);
        // checks for browser feature support to enable hardware acceleration                        
        metrojs.checkCapabilities(stgs);        
        // setup the default content modules
        if (!$.fn.liveTile.contentModules.hasContentModule("image"))
            $.fn.liveTile.contentModules.addContentModule("image", defaultModules.imageSwap);
        if (!$.fn.liveTile.contentModules.hasContentModule("html"))
            $.fn.liveTile.contentModules.addContentModule("html", defaultModules.htmlSwap);
        // this is where the magic happens
        return $(this).each(function (tileIndex, ele) {
            var $this = $(ele),
                data = privMethods.initTileData($this, stgs);
            // append back tiles and add appropriate classes to prepare tiles
            data.faces = privMethods.prepTile($this, data);
            // action methods
            data.slide = function (count) { privMethods.slide($this, count); };
            data.carousel = function (count) { privMethods.carousel($this, count); };
            data.flip = function (count) { privMethods.flip($this, count); };
            data.flipList = function (count) { privMethods.flipList($this, count); };

            data.doAction = function (count) {
                var actions = {
                    slide: data.slide,
                    carousel: data.carousel,
                    flip: data.flip,
                    'flip-list': data.flipList
                },
                // get the action for the current mode
                action = actions[data.mode];
                if (typeof (action) === "function") {
                    data.loopCount = count;
                    action(count);
                    data.hasRun = true;
                }
                // prevent pauseOnHover from resuming a tile that has finished
                if (count == data.timer.repeatCount)
                    data.runEvents = false;
            };
            
            // create a new tile timer
            data.timer = new $.fn.metrojs.TileTimer(data.delay, data.doAction, data.repeatCount);
            // apply the data
            $this.data("LiveTile", data);
            // handle events
            // only bind pause / play on hover if we are not using a fliplist or flipListOnHover isn't set set
            if (data.mode !== "flip-list" || data.flipListOnHover == false) {
                if (data.pauseOnHover) {
                    privMethods.bindPauseOnHover($this);
                } else if (data.playOnHover) {
                    privMethods.bindPlayOnHover($this);
                }
            }
            // add a click / link to the tile
            if (data.link.length > 0 || typeof(data.click) === "function") {
                $this.css({ cursor: 'pointer' }).bind("click.liveTile", function () {
                    var proceed = true;
                    if (typeof (data.click) === "function") {
                        proceed = data.click($this, data) || false;
                    }
                    if (proceed && data.link.length > 0) {
                        if (data.newWindow)
                            window.open(data.link);
                        else
                            window.location = data.link;
                    }
                });
            }
            // add bounce if set
            if (data.useHardwareAccel && metrojs.capabilities.canTransition)
                privMethods.bindBounce($this, data);            
            // start timer
            if (data.startNow && data.mode != "none") {
                data.runEvents = true;
                data.timer.start(data.initDelay);
            }
        });
    },
    // goto is a future reserved word
    'goto': function (options) {
        var opts, t = typeof (options);
        if(t === "undefined"){
            opts = {
                index: -99, //  same as next
                delay: 0,
                autoAniDirection: false
            };
        }if (t === "number" || !isNaN(options)) {
            opts = {
                index: parseInt(options, 10),
                delay: 0
            };
        } else if(t === "string"){
            if (options == "next") {
                opts = {
                    index: -99,
                    delay: 0
                }                
            } else if (options.indexOf("prev") === 0) {
                opts = {
                    index: -100,
                    delay: 0
                }                
            } else {
                $.error(options + " is not a recognized action for .liveTile(\"goto\")");
                return;
            }
        }else if (t === "object") {
            if (typeof (options.delay) === "undefined") {
                options.delay = 0;
            }
            var ti = typeof (options.index);
            if (ti === "undefined") {
                options.index = 0;
            } else if (ti === "string") {
                if (options.index === "next")
                    options.index = -99;
                else if (options.index.indexOf("prev") === 0)
                    options.index = -100;
            }
            opts = options;
        }       
        return $(this).each(function (tileIndex, ele) {
            var $tile = $(ele),
                data = $tile.data("LiveTile"),
                aniData = $tile.data("metrojs.tile"),
                goTo = opts.index;
            if (aniData.animating === true)
                return;
            if (data.mode === "carousel") {
                // get the index based off of the active carousel slide
                var $cur = data.faces.$listTiles.filter(".active");
                var curIdx = data.faces.$listTiles.index($cur);
                // carousel will look for these values as triggers
                if (goTo === -100) { // prev
                    // autoAniDirection determines if a forward or backward animation should be used based on the goTo index
                    if(typeof(opts.autoAniDirection) === "undefined" || opts.autoAniDirection)
                        data.tempValues.animationDirection = typeof(opts.animationDirection) === "undefined" ? "backward" : opts.animationDirection;
                    goTo = curIdx === 0 ? data.faces.$listTiles.length -1 : curIdx - 1;
                } else if (goTo === -99) { // next
                    if (typeof (opts.autoAniDirection) === "undefined" || opts.autoAniDirection)
                        data.tempValues.animationDirection = typeof (opts.animationDirection) === "undefined" ? "forward" : opts.animationDirection;
                    goTo = curIdx + 1;
                }
                if (curIdx == goTo) {
                    return;
                }
                if (typeof (opts.direction) !== "undefined") {
                    data.tempValues.direction = opts.direction;
                }
                if (typeof (opts.animationDirection) !== "undefined") {
                    data.tempValues.animationDirection = opts.animationDirection;
                }
                // the index is offset by 1 and incremented on animate
                if (goTo == 0)
                    data.currentIndex = data.faces.$listTiles.length;
                else
                    data.currentIndex = goTo - 1;
            } else // slide mode will use the index directly
                data.currentIndex = goTo;
            // start the timer
            data.runEvents = true;
            data.timer.start(opts.delay >= 0 ? opts.delay : data.delay);
        });  
    },
    play: function (options) {
        var opts, t = typeof (options);
        if (t === "undefined") {
            opts = {
                delay: -1
            };
        } else if (t === "number") {
            opts = {
                delay: options
            };
        } else if (t === "object") {
            if(typeof(options.delay) === "undefined"){
                options.delay = -1;                
            }
            opts = options;
        }
        return $(this).each(function (tileIndex, ele) {
            var $tile = $(ele),
                data = $tile.data("LiveTile");
            data.runEvents = true;
            if (opts.delay < 0 && !data.hasRun)
                opts.delay = data.initDelay;            
            data.timer.start(opts.delay >= 0 ? opts.delay : data.delay);
        });
    },
    animate: function () { // this is really only useful for slide mode
        return $(this).each(function (tileIndex, ele) {
            var $tile = $(ele),
                data = $tile.data("LiveTile");
            data.doAction();
        });
    },
    stop: function () {
        return $(this).each(function (tileIndex, ele) {
            var $tile = $(ele),
                data = $tile.data("LiveTile");
            data.hasRun = false;
            data.runEvents = false;
            data.timer.stop();
            window.clearTimeout(data.eventTimeout);
            window.clearTimeout(data.flCompleteTimeout);
            window.clearTimeout(data.completeTimeout);
            if (data.mode === "flip-list") {
                window.clearTimeout(data.completeTimeout);
                data.faces.$listTiles.each(function (idx, li) {
                    var ldata = $(li).data("metrojs.tile");
                    window.clearTimeout(ldata.eventTimeout);
                    window.clearTimeout(ldata.flCompleteTimeout);
                    window.clearTimeout(ldata.completeTimeout);
                });
            }
        });
    },
    pause: function () {
        return $(this).each(function (tileIndex, ele) {
            var $tile = $(ele),
                data = $tile.data("LiveTile");
            data.timer.pause();
            data.runEvents = false;
            window.clearTimeout(data.eventTimeout);
            window.clearTimeout(data.flCompleteTimeout);
            window.clearTimeout(data.completeTimeout);
            if (data.mode === "flip-list") {
                data.faces.$listTiles.each(function (idx, li) {
                    var ldata = $(li).data("metrojs.tile");
                    window.clearTimeout(ldata.eventTimeout);
                    window.clearTimeout(ldata.flCompleteTimeout);
                    window.clearTimeout(ldata.completeTimeout);
                });
            }
        });
    },
    restart: function (options) {
        var opts, t = typeof (options);
        if (t === "undefined") {
            opts = {
                delay: -1
            };
        } else if (t === "number") {
            opts = {
                delay: options
            };
        } else if (t === "object") {
            if (typeof (options.delay) === "undefined") {
                options.delay = -1;
            }
            opts = options;
        }
        return $(this).each(function (tileIndex, ele) {
            var $tile = $(ele),
                data = $tile.data("LiveTile");
            if (opts.delay < 0 && !data.hasRun)
                opts.delay = data.initDelay;
            data.hasRun = false;
            data.runEvents = true;
            data.timer.restart(opts.delay >= 0 ? opts.delay : data.delay);
        });
    },
    rebind: function (options) {
        return $(this).each(function (tileIndex, ele) {
            var $tile = $(ele);
            if (typeof (options) !== "undefined") {
                if (typeof (options.timer) !== "undefined" && options.timer != null) {
                    options.timer.stop();
                }                
                options.hasRun = false;
                pubMethods["init"].apply(ele, options);
            } else {
                pubMethods["init"].apply(ele, {});
            }
        });
    },
    destroy: function (options) {
        var t = typeof (options), opts;
        if (t === "undefined") {
            opts = {
                removeCss: false
            };
        } else if (t === "boolean") {
            opts = {
                removeCss: options
            };
        } else if (t === "object") {
            if (typeof (options.removeCss) === "undefined") {
                options.removeCss = false;
            }
            opts = options;
        }
        return $(this).each(function (tileIndex, ele) {
            var $tile = $(ele);
            var data = $tile.data("LiveTile");
            if (typeof (data) === "undefined")
                return;
            $tile.unbind(".liveTile");
            var resetCss = helperMethods.appendStyleProperties({ margin: '', cursor: '' }, ['transform', 'transition'], ['', '']);
            data.timer.stop();
            window.clearTimeout(data.eventTimeout);
            window.clearTimeout(data.flCompleteTimeout);
            window.clearTimeout(data.completeTimeout);
            if (data.faces.$listTiles != null) {
                data.faces.$listTiles.each(function (idx, li) {
                    var $li = $(li);
                    if (data.mode === "flip-list") {
                        var ldata = $li.data("metrojs.tile");
                        window.clearTimeout(ldata.eventTimeout);
                        window.clearTimeout(ldata.flCompleteTimeout);
                        window.clearTimeout(ldata.completeTimeout);
                    } else if (data.mode === "carousel") {
                        var sdata = data.listData[idx];
                        if (sdata.bounce) {
                            privMethods.unbindMsBounce($li, sdata);
                        }
                    }
                    if (opts.removeCss) {
                        $li.removeClass("ha");
                        $li.find(data.tileFaceSelector)
                            .unbind(".liveTile")
                            .removeClass("bounce flip-front flip-back ha slide slide-front slide-back")
                            .css(resetCss);
                    } else {
                        $li.find(data.tileFaceSelector).unbind(".liveTile");
                    }
                    $li.removeData("metrojs.tile");
                }).unbind(".liveTile");
            }
            if (data.faces.$front != null && opts.removeCss) {
                data.faces.$front.removeClass("flip-front flip-back ha slide slide-front slide-back")
                    .css(resetCss);
            }
            if (data.faces.$back != null && opts.removeCss) {
                data.faces.$back.removeClass("flip-front flip-back ha slide slide-front slide-back")
                    .css(resetCss);
            }
            // remove the bounce and hover methods
            // todo: combine all mouse/touch events (down, move, up)
            if (data.bounce) {
                privMethods.unbindMsBounce($tile, data);
            }
            if (data.playOnHover) {
                privMethods.unbindMsPlayOnHover($tile, data);
            }
            if (data.pauseOnhover) {
                privMethods.unbindMsPauseOnHover($tile, data);
            }
            $tile.removeClass("ha");
            $tile.removeData("LiveTile");
            $tile.removeData("metrojs.tile");
            data = null;
        });
    }
};

// private methods that are called by .liveTile
var privMethods = {
    //getDataOrDefault for older versions of jQuery that dont look for 'data-' properties
    dataAtr: function ($ele, name, def) {
        return typeof ($ele.attr('data-' + name)) !== "undefined" ? $ele.attr('data-' + name) : def;
    },
    dataMethod: function ($ele, name, def) {
        return typeof ($ele.data(name)) !== "undefined" ? $ele.data(name) : def;
    },
    getDataOrDefault: null,
    initTileData: function ($tile, stgs) {
        var useData = !stgs.ignoreDataAttributes,
            tdata;
        if (this.getDataOrDefault == null)
            this.getDataOrDefault = metrojs.capabilities.isOldJQuery ? this.dataAtr : this.dataMethod;
        if (useData) {
            tdata = { //an object to store settings for later access                
                speed: this.getDataOrDefault($tile, "speed", stgs.speed),
                delay: this.getDataOrDefault($tile, "delay", stgs.delay),
                stops: this.getDataOrDefault($tile, "stops", stgs.stops),
                stack: this.getDataOrDefault($tile, "stack", stgs.stack),
                mode: this.getDataOrDefault($tile, "mode", stgs.mode),
                direction: this.getDataOrDefault($tile, "direction", stgs.direction),
                useHardwareAccel: this.getDataOrDefault($tile, "ha", stgs.useHardwareAccel),
                repeatCount: this.getDataOrDefault($tile, "repeat", stgs.repeatCount),
                swap: this.getDataOrDefault($tile, "swap", stgs.swap),
                appendBack: this.getDataOrDefault($tile, "appendback", stgs.appendBack),
                currentIndex: this.getDataOrDefault($tile, "start-index", stgs.currentIndex),
                animationDirection: this.getDataOrDefault($tile, "slide-direction", stgs.animationDirection),
                startNow: this.getDataOrDefault($tile, "start-now", stgs.startNow),
                tileSelector: this.getDataOrDefault($tile, "tile-selector", stgs.tileSelector),
                tileFaceSelector: this.getDataOrDefault($tile, "face-selector", stgs.tileFaceSelector),
                bounce: this.getDataOrDefault($tile, "bounce", stgs.bounce),
                link: this.getDataOrDefault($tile, "link", stgs.link),
                newWindow: this.getDataOrDefault($tile, "new-window", stgs.newWindow),
                alwaysTrigger: this.getDataOrDefault($tile, "always-trigger", stgs.alwaysTrigger),
                flipListOnHover: this.getDataOrDefault($tile, "flip-onhover", stgs.flipListOnHover),
                pauseOnHover: this.getDataOrDefault($tile, "pause-onhover", stgs.pauseOnHover),
                playOnHover: this.getDataOrDefault($tile, "play-onhover", stgs.playOnHover),
                onHoverDelay: this.getDataOrDefault($tile, "hover-delay", stgs.onHoverDelay),
                noHAflipOpacity: this.getDataOrDefault($tile, "flip-opacity", stgs.noHAflipOpacity),
                runEvents: false,
                isReversed: false,
                loopCount: 0,
                contentModules: {},
                listData: [],
                height: $tile.height(),
                width: $tile.width(),
                tempValues: {}
            };
        } else {
            tdata = $.extend({
                runEvents: false,
                isReversed: false,
                loopCount: 0,
                contentModules: {},
                listData: [],
                height: $tile.height(),
                width: $tile.width(),
                tempValues: {}
            }, stgs);
        }
        // set the margin to half of the height or width based on the direction
        tdata.margin = (tdata.direction === "vertical") ? tdata.height / 2 : tdata.width / 2;
        // convert stops if needed
        tdata.stops = (typeof (stgs.stops) === "object" && (stgs.stops instanceof Array)) ? stgs.stops : ("" + tdata.stops).split(",");
        // add a return stop
        if (tdata.stops.length === 1)
            tdata.stops.push("0px");
        // add content modules, start with global swaps            
        var swaps = tdata.swap.replace(' ', '').split(",");
        // get the front and back swap data
        var sf = useData ? this.getDataOrDefault($tile, "swap-front", stgs.swapFront) : stgs.swapFront;
        var sb = useData ? this.getDataOrDefault($tile, "swap-back", stgs.swapBack) : stgs.swapBack;
        // set the data to the global value if its still the default
        tdata.swapFront = sf === '-' ? swaps : sf.replace(' ', '').split(",");
        tdata.swapBack = sb === '-' ? swaps : sb.replace(' ', '').split(",");
        // make sure the swaps includes all front and back swaps
        var i;
        for (i = 0; i < tdata.swapFront.length; i++) {
            if (tdata.swapFront[i].length > 0 && $.inArray(tdata.swapFront[i], swaps) === -1)
                swaps.push(tdata.swapFront[i]);
        }
        for (i = 0; i < tdata.swapBack.length; i++) {
            if (tdata.swapBack[i].length > 0 && $.inArray(tdata.swapBack[i], swaps) === -1)
                swaps.push(tdata.swapBack[i]);
        }
        tdata.swap = swaps;
        // add all required content modules for the swaps
        for (i = 0; i < swaps.length; i++) {
            if (swaps[i].length > 0 && typeof ($.fn.liveTile.contentModules.modules[swaps[i]]) !== "undefined") {
                tdata.contentModules[swaps[i]] = $.fn.liveTile.contentModules.modules[swaps[i]];
            }
        }        
        // set the initDelay value to the delay if it's not set
        tdata.initDelay = useData ? this.getDataOrDefault($tile, "initdelay", stgs.initDelay) : stgs.initDelay;
        // if the delay is -1 call the triggerDelay function to get a value
        if (tdata.delay < -1)
            tdata.delay = stgs.triggerDelay(1);
        else if (tdata.delay < 0)
            tdata.delay = 3500 + (Math.random() * 4501);
        // match the delay value if less than 0
        if (tdata.initDelay < 0)
            tdata.initDelay = tdata.delay;
        // merge the objects
        var mergedData = {},
            module;
        for (module in tdata.contentModules)
            $.extend(mergedData, tdata.contentModules[module].data);
        $.extend(mergedData, stgs, tdata);
        // add flip-list / carousel data
        var $tiles;
        if (mergedData.mode === "flip-list") {
            $tiles = $tile.find(mergedData.tileSelector).not(".tile-title");
            $tiles.each(function (idx, ele) {
                var $li = $(ele);
                var ldata = {
                    direction: useData ? privMethods.getDataOrDefault($li, "direction", mergedData.direction) : mergedData.direction,
                    newWindow: useData ? privMethods.getDataOrDefault($li, "new-window", false) : false,
                    link: useData ? privMethods.getDataOrDefault($li, "link", "") : "",
                    faces: { $front: null, $back: null },
                    height: $li.height(),
                    width: $li.width(),
                    isReversed: false
                };
                ldata.margin = ldata.direction === "vertical" ? ldata.height / 2 : ldata.width / 2;
                mergedData.listData.push(ldata);
            });
        } else if (mergedData.mode === "carousel") {
            mergedData.stack = true;
            $tiles = $tile.find(mergedData.tileSelector).not(".tile-title");
            $tiles.each(function (idx, ele) {
                var $slide = $(ele);
                var sdata = {
                    bounce: useData ? privMethods.getDataOrDefault($slide, "bounce", false) : false,
                    link: useData ? privMethods.getDataOrDefault($slide, "link", "") : "",
                    newWindow: useData ? privMethods.getDataOrDefault($slide, "new-window", false) : false,
                    animationDirection: useData ? privMethods.getDataOrDefault($slide, "ani-direction", "") : "",
                    direction: useData ? privMethods.getDataOrDefault($slide, "direction", "") : ""
                };
                mergedData.listData.push(sdata);
            });
        }
        // get any additional options from the modules
        for (module in mergedData.contentModules) {
            if (typeof (mergedData.contentModules[module].initData) === "function")
                mergedData.contentModules[module].initData(mergedData, $tile);
        }
        tdata = null;
        return mergedData;
    },
    prepTile: function ($tile, tdata) {
        //add the mode to the tile if it's not already there.
        $tile.addClass(tdata.mode);
        var ret = {
            $tileFaces: null,     // all possible tile faces in a liveTile in a non list mode
            $listTiles: null,     // all possible tiles in a liveTile in a list mode
            $front: null,         // the front face of a tile in a non list mode
            $back: null          // the back face of a tile in a non list mode
        };
        var rotateDir, backFaceCss, frontCss, backCss;
        // prepare the tile based on the current mode
        switch (tdata.mode) {
            case "slide":
                // front and back tile faces
                ret.$tileFaces = $tile.find(tdata.tileFaceSelector).not(".tile-title");
                // get front face from settings or via selector
                ret.$front = (tdata.faces.$front != null && tdata.faces.$front.length > 0) ?
                                tdata.faces.$front.addClass('slide-front') :
                                ret.$tileFaces.filter(":first").addClass('slide-front'); // using :first for pre jQuery 1.4
                // get back face from settings, via selector, or append it if necessary
                if (tdata.faces.$back != null && tdata.faces.$back.length > 0)    // use $back option
                    ret.$back = tdata.faces.$back.addClass('slide-back');
                else if (ret.$tileFaces.length > 1)                             // get the last tile face
                    ret.$back = ret.$tileFaces.filter(":last").addClass('slide-back');
                else if (tdata.appendBack)                                       // append the back tile
                    ret.$back = $('<div class="slide-back"></div>').appendTo($tile);
                else                                                            // just keep an empty placeholder
                    ret.$back = $('<div></div>');
                // stack mode
                if (tdata.stack == true) {
                    if (tdata.direction === "vertical") {
                        ret.$back.css({ top: -tdata.height + 'px' });
                    } else {
                        ret.$back.css({ left: '-100%' });
                        ret.$back.css({ left: '-100%' });
                    }
                }
                $tile.data("metrojs.tile", { animating: false });
                if (metrojs.capabilities.canTransition && tdata.useHardwareAccel) {   // hardware accelerated :)                        
                    $tile.addClass("ha");
                    ret.$front.addClass("ha");
                    ret.$back.addClass("ha");
                }                
                break;
            case "carousel":
                ret.$listTiles = $tile.find(tdata.tileSelector).not(".tile-title");
                var numberOfSlides = ret.$listTiles.length;
                $tile.data("metrojs.tile", { animating: false });
                tdata.currentIndex = Math.min(tdata.currentIndex, numberOfSlides - 1);
                ret.$listTiles.each(function (idx, ele) {
                    var $slide = $(ele).addClass("slide");
                    var sdata = tdata.listData[idx],
                        aniDir = typeof (sdata.animationDirection) === "string" && sdata.animationDirection.length > 0 ? sdata.animationDirection : tdata.animationDirection,
                        dir = typeof (sdata.direction) === "string" && sdata.direction.length > 0 ? sdata.direction : tdata.direction;
                    if (idx == tdata.currentIndex) {
                        $slide.addClass("active");
                    } else if (aniDir === "forward") {
                        if (dir === "vertical") {
                            $slide.css({ top: tdata.height + 'px', left:'0%' });
                        } else {
                            $slide.css({ left: tdata.width + 'px', top: '0%' });
                        }
                    } else if (aniDir === "backward") {
                        if (dir === "vertical") {
                            $slide.css({ top: -tdata.height + 'px', left:'0%' });
                        } else {
                            $slide.css({ left: -tdata.width + 'px', top:'0%' });
                        }
                    }
                    // link and bounce can be bound per slide
                    // add the click handler and link property
                    privMethods.bindLink($slide, sdata);
                    // add the bounce effect
                    if (tdata.useHardwareAccel && metrojs.capabilities.canTransition)
                        privMethods.bindBounce($slide, sdata);                    
                    $slide = null;
                    sdata = null;
                });
                // hardware accelerated :)
                if (metrojs.capabilities.canFlip3d && tdata.useHardwareAccel) {
                    $tile.addClass("ha");
                    ret.$listTiles.addClass("ha");
                }
                break;
            case "flip-list":
                // the tile containers inside the list
                ret.$listTiles = $tile.find(tdata.tileSelector).not(".tile-title");
                ret.$listTiles.each(function (idx, ele) {
                    var $li = $(ele).addClass("tile-" + (idx + 1));
                    // add the flip class to the front face
                    var $lFront = $li.find(tdata.tileFaceSelector).filter(":first").addClass("flip-front").css({ margin: "0px" });
                    // append a back tile face if one isnt present
                    if ($li.find(tdata.tileFaceSelector).length === 1 && tdata.appendBack == true)
                        $li.append("<div></div>");
                    // add the flip class to the back face
                    var $lBack = $li.find(tdata.tileFaceSelector).filter(":last").addClass("flip-back").css({ margin: "0px" });
                    // update the tdata object with the faces
                    tdata.listData[idx].faces.$front = $lFront;
                    tdata.listData[idx].faces.$back = $lBack;
                    // set data for overrides and easy access
                    $li.data("metrojs.tile", {
                        animating: false,
                        count: 1,
                        completeTimeout: null,
                        flCompleteTimeout: null,
                        index: idx
                    });
                    var ldata = $li.data("metrojs.tile");
                    // add the hardware accelerated classes
                    if (metrojs.capabilities.canFlip3d && tdata.useHardwareAccel) {   // hardware accelerated :)
                        $li.addClass("ha");
                        $lFront.addClass("ha");
                        $lBack.addClass("ha");
                        rotateDir = tdata.listData[idx].direction === "vertical" ? "rotateX(180deg)" : "rotateY(180deg)";
                        backFaceCss = helperMethods.appendStyleProperties({}, ["transform"], [rotateDir]);
                        $lBack.css(backFaceCss);
                    } else { // not hardware accelerated :(
                        // the front tile face will take up the entire tile
                        frontCss = (tdata.listData[idx].direction === "vertical") ?
								        { height: '100%', width: '100%', marginTop: '0px', opacity: '1' } :
								        { height: '100%', width: '100%', marginLeft: '0px', opacity: '1' };
                        // the back tile face is hidden by default and expanded halfway through a flip
                        backCss = (tdata.listData[idx].direction === "vertical") ?
							            { height: '0%', width: '100%', marginTop: tdata.listData[idx].margin + 'px', opacity: tdata.noHAflipOpacity } :
							            { height: '100%', width: '0%', marginLeft: tdata.listData[idx].margin + 'px', opacity: tdata.noHAflipOpacity };
                        $lFront.css(frontCss);
                        $lBack.css(backCss);
                    }
                    var flipEnded = function() {
                        ldata.count++;
                        if (ldata.count >= MAX_LOOP_COUNT)
                            ldata.count = 1;
                    };
                    if (tdata.flipListOnHover) {
                        var event = tdata.flipListOnHoverEvent + ".liveTile";
                        $lFront.bind(event, function () {
                                privMethods.flip($li, ldata.count, tdata, flipEnded);
                        });
                        $lBack.bind(event, function () {
                                privMethods.flip($li, ldata.count, tdata, flipEnded);
                        });
                    }
                    if (tdata.listData[idx].link.length > 0) {
                        $li.css({ cursor: 'pointer' }).bind("click.liveTile", function () {
                            if (tdata.listData[idx].newWindow)
                                window.open(tdata.listData[idx].link)
                            else
                                window.location = tdata.listData[idx].link;
                        });
                    }
                });
                break;
            case "flip":
                // front and back tile faces
                ret.$tileFaces = $tile.find(tdata.tileFaceSelector).not(".tile-title");
                // get front face from settings or via selector
                ret.$front = (tdata.faces.$front != null && tdata.faces.$front.length > 0) ?
                                tdata.faces.$front.addClass('flip-front') :
                                ret.$tileFaces.filter(":first").addClass('flip-front');
                // get back face from settings, via selector, or append it if necessary
                if (tdata.faces.$back != null && tdata.faces.$back.length > 0) {
                    // use $back option
                    ret.$back = tdata.faces.$back.addClass('flip-back');
                } else if (ret.$tileFaces.length > 1) {
                    // get the last tile face
                    ret.$back = ret.$tileFaces.filter(":last").addClass('flip-back');
                } else if (tdata.appendBack) {
                    // append the back tile
                    ret.$back = $('<div class="flip-back"></div>').appendTo($tile);
                } else {
                    // just keep an empty placeholder
                    ret.$back = $('<div></div>');
                }
                $tile.data("metrojs.tile", { animating: false });
                if (metrojs.capabilities.canFlip3d && tdata.useHardwareAccel) {
                    // hardware accelerated :)
                    $tile.addClass("ha");
                    ret.$front.addClass("ha");
                    ret.$back.addClass("ha");
                    rotateDir = tdata.direction === "vertical" ? "rotateX(180deg)" : "rotateY(180deg)";
                    backFaceCss = helperMethods.appendStyleProperties({}, ["transform"], [rotateDir]);
                    ret.$back.css(backFaceCss);

                } else {
                    // not hardware accelerated :(
                    // the front tile face will take up the entire tile
                    frontCss = (tdata.direction === "vertical") ?
								        { height: '100%', width: '100%', marginTop: '0px', opacity: '1' } :
								        { height: '100%', width: '100%', marginLeft: '0px', opacity: '1' };
                    // the back tile face is hidden by default and expanded halfway through a flip
                    backCss = (tdata.direction === "vertical") ?
							            { height: '0px', width: tdata.width + 'px', marginTop: tdata.margin + 'px', opacity: '0' } :
							            { height: tdata.height + 'px', width: '0px', marginLeft: tdata.margin + 'px', opacity: '0' };
                    ret.$front.css(frontCss);
                    ret.$back.css(backCss);
                }
                break;
        }
        return ret;
    },
    bindPauseOnHover: function($tile){        
        // stop the tile when hovered and resume after a delay
        (function () {
            var data = $tile.data("LiveTile"),
                isOver = false,
                isPending = false;
            data.pOnHoverMethods = {
                over: function (e) {
                    if (isOver || isPending)
                        return;
                    if (data.runEvents) {
                        isPending = true;
                        data.eventTimeout = window.setTimeout(function () {
                            isPending = false;
                            isOver = true;
                            data.timer.pause();
                            if (data.mode === "flip-list") {
                                data.faces.$listTiles.each(function (idx, li) {
                                    window.clearTimeout($(li).data("metrojs.tile").completeTimeout);
                                });
                            }
                        }, data.onHoverDelay);
                    }
                },
                out: function (e) {
                    if (isPending) {
                        window.clearTimeout(data.eventTimeout);
                        isPending = false;
                        return;
                    }
                    if (!isOver && !isPending)
                        return;
                    if (data.runEvents)
                        data.timer.start(data.hasRun ? data.delay : data.initDelay);
                    isOver = false;
                }
            };
            if (!metrojs.capabilities.canTouch) {
                $tile.bind("mouseover.liveTile", data.pOnHoverMethods.over);
                $tile.bind("mouseout.liveTile", data.pOnHoverMethods.out);
            } else {
                if (window.navigator.msPointerEnabled) { // pointer
                    $tile[0].addEventListener('MSPointerOver', data.pOnHoverMethods.over, false);
                    $tile[0].addEventListener('MSPointerOut', data.pOnHoverMethods.out, false);
                } else { // touch events
                    $tile.bind("touchstart.liveTile", data.pOnHoverMethods.over);
                    $tile.bind("touchend.liveTile", data.pOnHoverMethods.out);
                }

            }
        })();
    },
    unbindMsPauseOnHover: function ($tile, data) {
        if (typeof (data.pOnHoverMethods) !== "undefined" && window.navigator.msPointerEnabled) {
            $tile[0].removeEventListener('MSPointerOver', data.pOnHoverMethods.over, false);
            $tile[0].removeEventListener('MSPointerOut', data.pOnHoverMethods.out, false);
        }
    },
    bindPlayOnHover: function ($tile) {
        // play the tile immediately when hovered
        (function () {
            var data = $tile.data("LiveTile"),
                isOver = false,
                isPending = false;
            data.onHoverMethods = {
                over: function(event) {
                    if (isOver || isPending)
                        return;
                    // if startNow is set use the opposite of isReversed so we're in sync            
                    var rev = data.startNow ? !data.isReversed : data.isReversed;
                    window.clearTimeout(data.eventTimeout);
                    if ((data.runEvents && rev) || !data.hasRun) {
                        isPending = true;
                        data.eventTimeout = window.setTimeout(function () {
                            isPending = false;
                            isOver = true;
                            pubMethods["play"].apply($tile[0], [0]);
                        }, data.onHoverDelay);
                    }            
                },
                out: function(event) {
                    if (isPending) {
                        window.clearTimeout(data.eventTimeout);
                        isPending = false;
                        return;
                    }
                    if (!isOver && !isPending)
                        return;
                    window.clearTimeout(data.eventTimeout);
                    data.eventTimeout = window.setTimeout(function () {
                        var rev = data.startNow ? data.isReversed : !data.isReversed;
                        if (data.runEvents && rev) {
                            pubMethods["play"].apply($tile[0], [0]);
                        }
                        isOver = false;
                    }, data.speed + 200);            
                }
            };
            $tile.addClass("noselect");
            if (!metrojs.capabilities.canTouch) {
                $tile.bind('mouseenter.liveTile', function (e) {                    
                    data.onHoverMethods.over(e);
                });
                $tile.bind('mouseleave.liveTile', function (e) {                    
                        data.onHoverMethods.out(e);
                });            
                //$tile.bind("mouseenter.liveTile", over);
                //$tile.bind("mouseleave.liveTile", out);
            } else {
                if (window.navigator.msPointerEnabled) { // pointer
                    $tile[0].addEventListener('MSPointerDown', data.onHoverMethods.over, false);
                    // mouseleave gives a more consistent effect than out when the children are transformed
                    $tile.bind("mouseleave.liveTile", data.onHoverMethods.out);
                } else { // touch events
                    $tile.bind("touchstart.liveTile", data.onHoverMethods.over);
                    $tile.bind("touchend.liveTile", data.onHoverMethods.out);
                }

            }
        })();
    },
    unbindMsPlayOnHover: function ($tile, data) {
        if (typeof (data.onHoverMethods) !== "undefined" && window.navigator.msPointerEnabled) {
            $tile[0].removeEventListener('MSPointerDown', data.onHoverMethods.over, false);
        }
    },
    bindBounce: function($tile, data){
        // add bounce
        if (data.bounce) {
            var bounceCss = helperMethods.appendStyleProperties({}, ['transition-property', 'transition-duration'], ['scale', '200ms']);
            $tile.addClass("bounce");
            (function () {                
                data.bounceMethods = {
                    down: false,
                    threshold: 10,
                    zeroPos: { x: 0, y: 0 },
                    prevPos: { x: 0, y: 0 },
                    bounceDown: function (e) {
                        this.prevPos = {
                            x: e.pageX, // todo: transform based on mouse pos? e.pageX - parentOffset.left,
                            y: e.pageY // e.pageY - parentOffset.top
                        };
                        $tile.addClass("bounce-dwn");
                        this.down = true;
                    },
                    bounceUp: function() {
                        if (this.down === true) {
                            data.bounceMethods.unBounce();
                        }
                    },
                    bounceMove: function(e) {
                        if (this.down === true) {
                            if (Math.abs(e.pageX - prevPos.x) > this.threshold || Math.abs(e.pageY - prevPos.y) > this.threshold) {
                                //data.bounceMethods.unBounce();
                            }
                        }
                    },
                    unBounce: function () {
                        $tile.removeClass("bounce-dwn");
                        this.down = false;
                        this.prevPos = this.zeroPos;
                    }
                };            
                // IE 10+
                if (window.navigator.msPointerEnabled) {// touch only -> // && window.navigator.msMaxTouchPoints) {
                    $tile[0].addEventListener('MSPointerDown', data.bounceMethods.bounceDown, false);
                    $tile[0].addEventListener('MSPointerCancel', data.bounceMethods.bounceUp, false);
                    $tile[0].addEventListener('MSPointerOut', data.bounceMethods.bounceUp, false);
                    $tile[0].addEventListener('MSPointerUp', data.bounceMethods.bounceUp, false);
                    //$tile[0].addEventListener('MSPointerMove', data.bounceMethods.bounceMove, false);
                } else {
                    // everybody else
                    $tile.bind("mousedown.liveTile touchstart.liveTile", data.bounceMethods.bounceDown);
                    $tile.bind("mouseup.liveTile touchend.liveTile, mouseout.liveTile touchcancel.liveTile", data.bounceMethods.bounceUp);
                    // $tile.bind("mousemove.liveTile touchmove.liveTile", data.bounceMethods.bounceMove);
                }
            })();
        }
    },
    unbindMsBounce: function($tile, data){
        if(data.bounce && window.navigator.msPointerEnabled) {// touch only -> // && window.navigator.msMaxTouchPoints) {
            $tile[0].removeEventListener('MSPointerDown', data.bounceMethods.bounceDown, false);
            $tile[0].removeEventListener('MSPointerCancel', data.bounceMethods.bounceUp, false);
            $tile[0].removeEventListener('MSPointerOut', data.bounceMethods.bounceUp, false);
            //$tile[0].removeEventListener('MSPointerMove', data.bounceMethods.bounceMove, false);
        }        
    },
    bindLink: function($tile, data){
        if (data.link.length > 0) {
            $tile.css({ cursor: 'pointer' }).bind("click.liveTile", function () {
                if (data.newWindow)
                    window.open(data.link);
                else
                    window.location = data.link;
            });
        }
    },
    slide: function ($tile, count, data, stopIndex, callback) {
        var tdata = typeof (data) === "undefined" ? $tile.data("LiveTile") : data;
        var aniData = $tile.data("metrojs.tile");
        if (aniData.animating == true || $tile.is(":animated")) {
            tdata = null;
            aniData = null;
            return;
        }
        if (tdata.mode !== "carousel") {
            tdata.isReversed = count % 2 === 0;  // the count starts at 1
        } else
            tdata.isReversed = true; // in carousel mode the face that just left the stage is always the $back
        tdata.timer.pause();
        // get temp values passed in from data methods            
        var direction;
        if (typeof (tdata.tempValues.direction) === "string" && tdata.tempValues.direction.length > 0)
            direction = tdata.tempValues.direction;
        else
            direction = tdata.direction;
        tdata.tempValues.direction = null;
        var css = {},
            cssback = {},
            // the stop index is overridden in carousel mode
            stopIdx = typeof (stopIndex) === "undefined" ? tdata.currentIndex : stopIndex,
            stop = $.trim(tdata.stops[Math.min(stopIdx, tdata.stops.length - 1)]),
            pxIdx = stop.indexOf('px'),
            offset = 0,
            amount = 0,
            metric = (direction === "vertical") ? tdata.height : tdata.width,
            tProp = (direction === "vertical") ? "top" : "left";        
        // when the slide is complete increment the index or call the callback
        var slideFinished = function () {
            if (typeof (callback) === "undefined") {
                tdata.currentIndex = tdata.currentIndex + 1;
                if (tdata.currentIndex > tdata.stops.length - 1) {
                    tdata.currentIndex = 0;
                }
            } else {
                callback();
            }
            // run content modules and animationComplete callback
            for (var module in tdata.contentModules)
                tdata.contentModules[module].action(tdata, tdata.faces.$front, tdata.faces.$back, tdata.currentIndex);
            tdata.animationComplete(tdata, tdata.faces.$front, tdata.faces.$back);
            // if the tile should run again start the timer back with the current delay
            if (tdata.timer.repeatCount > 0 || tdata.timer.repeatCount == -1) {
                if (tdata.timer.count != tdata.timer.repeatCount) {
                    tdata.timer.start(tdata.delay);                    
                }
            }
            tdata = null;
            aniData = null;
        };
//        if (pxIdx > 0) {
//            amount = parseInt(stop.substring(0, pxIdx), 10);
//            offset = (amount - metric) + 'px';
//        } else {
            //is a percentage
            amount = parseInt(stop.replace('%', ''), 10);
            offset = (amount - 100) + '%';
//        }
        // hardware accelerated :)
        if (metrojs.capabilities.canTransition && tdata.useHardwareAccel) {
            if (typeof (aniData.animating) !== "undefined" && aniData.animating == true)
                return;
            aniData.animating = true;
            css = helperMethods.appendStyleProperties(css, ['transition-property', 'transition-duration', 'transition-timing-function'], [tProp, tdata.speed + 'ms', tdata.haTransFunc]);
            if (direction === "vertical")
                css.top = stop;
            else
                css.left = stop;
            tdata.faces.$front.css(css);
            if (tdata.stack == true) {
                if (direction === "vertical")
                    css.top = offset;
                else
                    css.left = offset;
                tdata.faces.$back.css(css);
            }            
            window.clearTimeout(tdata.completeTimeout);
            tdata.completeTimeout = window.setTimeout(function () {
                aniData.animating = false;
                slideFinished();
            }, tdata.speed);
        } else {
            // not hardware accelerated :(
            css[tProp] = stop;
            cssback[tProp] = offset;
            aniData.animating = true;
            tdata.faces.$front.stop().animate(css, tdata.speed, tdata.noHaTransFunc, function () {
                aniData.animating = false;
                slideFinished();
            });
            if (tdata.stack == true) {
                // change the css value to the offset                
                tdata.faces.$back.stop().animate(cssback, tdata.speed, tdata.noHaTransFunc, function () { });
            }
        }
    },
    carousel: function ($tile, count) {
        var tdata = $tile.data("LiveTile");
        // dont update css or call slide if animated or if there's only one face
        var aniData = $tile.data("metrojs.tile");
        if (aniData.animating == true || tdata.faces.$listTiles.length <= 1) {
            aniData = null;
            return;
        }
        // pause the timer and use a per slide delay
        tdata.timer.pause();
        var $cur = tdata.faces.$listTiles.filter(".active"),
            idx = tdata.faces.$listTiles.index($cur),
            goTo = tdata.currentIndex,
            eq = goTo != idx ? goTo : idx,
            nxtIdx = eq + 1 >= tdata.faces.$listTiles.length ? 0 : eq + 1,
            sdata = tdata.listData[nxtIdx];
        if (idx == nxtIdx) {
            aniData = null;
            $cur = null;
            return;
        }
        // get temp values passed in from data methods
        var animationDirection;
        if (typeof (tdata.tempValues.animationDirection) === "string" && tdata.tempValues.animationDirection.length > 0)
            animationDirection = tdata.tempValues.animationDirection;
        else if (typeof (sdata.animationDirection) === "string" && sdata.animationDirection.length > 0) {
            animationDirection = sdata.animationDirection;
        }else
            animationDirection = tdata.animationDirection;
        // the temp value for animation direction is not used in slide: so i'm setting it to null
        tdata.tempValues.animationDirection = null;
        var direction;
        if (typeof (tdata.tempValues.direction) === "string" && tdata.tempValues.direction.length > 0){
            direction = tdata.tempValues.direction;
        } else if (typeof (sdata.direction) === "string" && sdata.direction.length > 0) {
            direction = sdata.direction;
            tdata.tempValues.direction = direction;
        } else {
            direction = tdata.direction;
        }
        var $nxt = tdata.faces.$listTiles.eq(nxtIdx);
        var nxtCss = helperMethods.appendStyleProperties({}, ['transition-duration'], ['0s']);        
        if (animationDirection === "backward") {
            if (direction === "vertical") {                
                nxtCss.top = "-100%";
                nxtCss.left = "0px";
            } else {
                nxtCss.top = "0px";
                nxtCss.left = "-100%";                
            }
            tdata.faces.$front = $cur;
            tdata.faces.$back = $nxt;
            tdata.stops = ['100%'];
        } else {
            if (direction === "vertical") {
                nxtCss.top = "100%";
                nxtCss.left = "0px";
            } else {
                nxtCss.top = "0px";
                nxtCss.left = "100%";                
            }
            tdata.faces.$front = $nxt;
            tdata.faces.$back = $cur;
            tdata.stops = ['0px'];
        }
        $nxt.css(nxtCss);
        // the timeout wrapper gives the css call above enough time to finish in case we dynamically set the direction
        window.setTimeout(function () {            
            
            privMethods.slide($tile, count, tdata, 0, function ()
            {   
                $cur.removeClass("active");
                $nxt.addClass("active");
                tdata.currentIndex = nxtIdx;
                aniData = null;
                $cur = null;
                $nxt = null;
                if (tdata.timer.repeatCount > 0 || tdata.timer.repeatCount == -1) {
                    if (tdata.timer.count != tdata.timer.repeatCount) {
                        tdata.timer.start(tdata.delay);
                    }
                }
            });
        }, 200);

    },
    flip: function ($tile, count, data, callback) {
        var aniData = $tile.data("metrojs.tile");
        if (aniData.animating == true) {
            anidata = null;
            return;
        }
        var tdata = typeof (data) === "object" ? data : $tile.data("LiveTile");
        var $front, $back, direction, deg, rotateDir, css,
            raiseEvt = typeof (callback) === "undefined",
            index = 0,
            isReversed = count % 2 === 0;  // the count starts at 1
        if (tdata.mode === "flip-list") {
            index = aniData.index;
            $front = tdata.listData[index].faces.$front;
            $back = tdata.listData[index].faces.$back;
            tdata.listData[index].isReversed = isReversed;
            direction = tdata.listData[index].direction;
            height = tdata.listData[index].height;
            width = tdata.listData[index].width;
            margin = tdata.listData[index].margin;
        } else {
            $front = tdata.faces.$front;
            $back = tdata.faces.$back;
            tdata.isReversed = isReversed;
            direction = tdata.direction;
            height = tdata.height;
            width = tdata.width;
            margin = tdata.margin;
        }
        if (metrojs.capabilities.canFlip3d && tdata.useHardwareAccel) { // Hardware accelerated :)
            deg = !isReversed ? "180deg" : "360deg";
            rotateDir = direction === "vertical" ? "rotateX(" + deg + ")" : "rotateY(" + deg + ")";
            css = helperMethods.appendStyleProperties({}, ["transform", "transition"], [rotateDir, "all " + tdata.speed + "ms " + tdata.haTransFunc + " 0s"]);
            var bDeg = !isReversed ? "360deg" : "540deg";
            var bRotateDir = direction === "vertical" ? "rotateX(" + bDeg + ")" : "rotateY(" + bDeg + ")";
            var bCss = helperMethods.appendStyleProperties({}, ["transform", "transition"], [bRotateDir, "all " + tdata.speed + "ms " + tdata.haTransFunc + " 0s"]);
            $front.css(css);
            $back.css(bCss);

            var action = function () {
                aniData.animating = false;
                var resetDir, newCss, module;
                if (!isReversed) {
                    for (module in tdata.contentModules)
                        tdata.contentModules[module].action(tdata, $back, $front, index);
                    if (raiseEvt)
                        tdata.animationComplete(tdata, $back, $front);
                    else
                        callback(tdata, $back, $front);
                } else {                    
                        resetDir = direction === "vertical" ? "rotateX(0deg)" : "rotateY(0deg)";
                        newCss = helperMethods.appendStyleProperties({}, ["transform", "transition"], [resetDir, "all 0s " + tdata.haTransFunc + " 0s"]);
                        //aggressively resetting the direction appears to cause some issues on IE10 on WinRT
                        //var bResetDir = direction === "vertical" ? "rotateX(180deg)" : "rotateY(180deg)";
                        //var bNewCss = helperMethods.appendStyleProperties({}, ["transition"], ["all 0s ease 0s"]);
                        $front.css(newCss);
                        //$back.css(bNewCss);
                        //window.setTimeout(function () {
                            //bNewCss = helperMethods.appendStyleProperties(bNewCss, ["transform"], [bResetDir]);
                            //$back.css(bNewCss);
                            //console.log('nil');
                        //}, 50);
                        //call content modules
                        for (module in tdata.contentModules)
                            tdata.contentModules[module].action(tdata, $front, $back, index);
                        if (raiseEvt)
                            tdata.animationComplete(tdata, $front, $back);
                        else
                            callback(tdata, $front, $back);
                        $front = null;
                        $back = null;
                        tdata = null;
                        aniData = null;
                   
                }
            };
            if (tdata.mode === "flip-list") {
                window.clearTimeout(tdata.listData[index].completeTimeout);
                tdata.listData[index].completeTimeout = window.setTimeout(action, tdata.speed);
            } else {
                window.clearTimeout(tdata.completeTimeout);
                tdata.completeTimeout = window.setTimeout(action, tdata.speed);
            }
        } else { // not Hardware accelerated :(
            var speed = tdata.speed / 2;
            var hideCss = (direction === "vertical") ?
							   { height: '0px', width: '100%', marginTop: margin + 'px', opacity: tdata.noHAflipOpacity } :
							   { height: '100%', width: '0px', marginLeft: margin + 'px', opacity: tdata.noHAflipOpacity };
            var showCss = (direction === "vertical") ?
								{ height: '100%', width: '100%', marginTop: '0px', opacity: '1' } :
								{ height: '100%', width: '100%', marginLeft: '0px', opacity: '1' };
            var noHaAction;
            if (!isReversed) {
                aniData.animating = true;
                $front.stop().animate(hideCss, { duration: speed });
                noHaAction = function () {                    
                    aniData.animating = false;
                    $back.stop().animate(showCss, {
                        duration: speed, complete: function () {
                            for (var module in tdata.contentModules)
                                tdata.contentModules[module].action(tdata, $back, $front, index);
                            if (raiseEvt)
                                tdata.animationComplete(tdata, $back, $front);
                            else
                                callback(tdata, $back, $front);
                            $front = null;
                            $back = null;
                            tdata = null;
                            aniData = null;
                        }
                    });
                };
                if (tdata.mode === "flip-list") {      
                    window.clearTimeout(tdata.listData[aniData.index].completeTimeout);
                    tdata.listData[aniData.index].completeTimeout = window.setTimeout(noHaAction, speed);
                } else {
                    window.clearTimeout(tdata.completeTimeout);
                    tdata.completeTimeout = window.setTimeout(noHaAction, speed);
                }
            } else {
                aniData.animating = true;
                $back.stop().animate(hideCss, { duration: speed });
                noHaAction = function () {
                    aniData.animating = false;
                    $front.stop().animate(showCss, {
                        duration: speed, complete: function () {
                            for (var module in tdata.contentModules)
                                tdata.contentModules[module].action(tdata, $front, $back, index);
                            if (raiseEvt)
                                tdata.animationComplete(tdata, $front, $back);
                            else
                                callback(tdata, $front, $back);
                            aniData = null;
                            $front = null;
                            $back = null;
                        }
                    });
                };
                if (tdata.mode === "flip-list") {
                    window.clearTimeout(tdata.listData[aniData.index].completeTimeout);
                    tdata.listData[aniData.index].completeTimeout = window.setTimeout(noHaAction, speed);
                } else {
                    window.clearTimeout(tdata.completeTimeout);
                    tdata.completeTimeout = window.setTimeout(noHaAction, speed);
                }
            }

        }
    },    
    flipList: function ($tile, count) {
        var tdata = $tile.data("LiveTile");
        var maxDelay = tdata.speed;
        var triggered = false;
        tdata.timer.pause();
        tdata.faces.$listTiles.each(function (idx, ele) {
            var $li = $(ele);
            var ldata = $li.data("metrojs.tile");            
            var tDelay = tdata.triggerDelay(idx);
            var triggerDelay = tdata.speed + Math.max(tDelay, 0);
            var trigger = tdata.alwaysTrigger;
            if (!trigger)
                trigger = (Math.random() * 351) > 150 ? true : false;
            if (trigger) {
                triggered = true;
                maxDelay = Math.max(triggerDelay + tdata.speed, maxDelay);                
                window.clearTimeout(ldata.flCompleteTimeout);
                ldata.flCompleteTimeout = window.setTimeout(function () {                    
                    // call the flip method with the merged data, but dont fire animationComplete
                    privMethods.flip($li, ldata.count, tdata, function (data) {                        
                        ldata.count++;                        
                        if (ldata.count >= MAX_LOOP_COUNT)
                            ldata.count = 1;
                        $li = null;
                        ldata = null;
                    });
                }, triggerDelay);
            }
        });
        if (triggered) {
            window.clearTimeout(tdata.flCompleteTimeout);
            tdata.flCompleteTimeout = window.setTimeout(function () {
                for (var module in tdata.contentModules)
                    tdata.contentModules[module].action(tdata, null, null, -1);
                tdata.animationComplete(tdata, null, null);
                if (tdata.timer.repeatCount > 0 || tdata.timer.repeatCount == -1) {
                    if (tdata.timer.count != tdata.timer.repeatCount) {
                        tdata.timer.start(tdata.delay);
                    }
                }
                //tdata = null;
            }, maxDelay + tdata.speed); // add some padding to make sure the final callback finished
            
        }
    }
};


// methods that can be called more universally
var helperMethods = {
    stylePrefixes: 'Webkit Moz O ms Khtml '.split(' '),
    domPrefixes: '-webkit- -moz- -o- -ms- -khtml- '.split(' '),
    // a method to append css3 properties for each browser
    // note: values are identical for each property
    appendStyleProperties: function (obj, names, values) {
        for (var i = 0; i <= names.length - 1; i++) {
            for (var j = 0; j <= this.domPrefixes.length - 1; j++)
                obj[$.trim(this.domPrefixes[j] + names[i])] = values[i];
        }
        return obj;
    },
    //a shuffle method to provide more randomness than sort
    //credit: http://javascript.about.com/library/blshuffle.htm
    //note: avoiding prototype for sharepoint compatability
    shuffleArray: function (array) {
        var s = [];
        while (array.length) s.push(array.splice(Math.random() * array.length, 1));
        while (s.length) array.push(s.pop());
        return array;
    }
};

var defaultModules = {
    customSwap: {
        data: {
            customDoSwapFront: function () { return false; },
            customDoSwapBack: function () { return false; },
            customGetContent: function(tdata, $front, $back, index) { return null; }
        },
        initData: function (tdata, $ele) {
            var swapData = {};
            swapData.doSwapFront = $.inArray('custom', tdata.swapFront) > -1 && tdata.customDoSwapFront();
            swapData.doSwapBack = $.inArray('custom', tdata.swapBack) > -1 && tdata.customDoSwapBack();
            if (typeof (tdata.customSwap) !== "undefined")
                tdata.customSwap = $.extend(swapData, tdata.customSwap);
            else
                tdata.customSwap = swapData;
        },
        action: function (tdata, $front, $back, index) {

        }
    },
    htmlSwap: {
        data: { // public data for the swap module                
            frontContent: [],                       // a list of html to use for the front
            frontIsRandom: true,                    // should html be chosen at random or in order                
            frontIsInGrid: false,                   // only chooses one item for each iteration in flip-list                
            backContent: [],                        // a list of html to use for the back
            backIsRandom: true,                     // should html be chosen at random or in order                
            backIsInGrid: false                     // only chooses one item for each iteration in flip-list                
        },
        initData: function (tdata, $ele) {
            var swapData = { // private data for the swap module
                backBag: [],
                backIndex: 0,
                backStaticIndex: 0,
                backStaticRndm: -1,
                prevBackIndex: -1,
                frontBag: [],
                frontIndex: 0,
                frontStaticIndex: 0,
                frontStaticRndm: -1,
                prevFrontIndex: -1
            };
            swapData.frontIsRandom = !tdata.ignoreDataAttributes ? privMethods.getDataOrDefault($ele, "front-israndom", tdata.frontIsRandom) : tdata.frontIsRandom;
            swapData.frontIsInGrid = !tdata.ignoreDataAttributes ? privMethods.getDataOrDefault($ele, "front-isingrid", tdata.frontIsInGrid) : tdata.frontIsInGrid;            
            swapData.backIsRandom = !tdata.ignoreDataAttributes ? privMethods.getDataOrDefault($ele, "back-israndom", tdata.backIsRandom) : tdata.backIsRandom;
            swapData.backIsInGrid = !tdata.ignoreDataAttributes ? privMethods.getDataOrDefault($ele, "back-isingrid", tdata.backIsInGrid) : tdata.backIsInGrid;            
            swapData.doSwapFront = $.inArray('html', tdata.swapFront) > -1 && (tdata.frontContent instanceof Array) && tdata.frontContent.length > 0;
            swapData.doSwapBack = $.inArray('html', tdata.swapBack) > -1 && (tdata.backContent instanceof Array) && tdata.backContent.length > 0;
            if (typeof (tdata.htmlSwap) !== "undefined")
                tdata.htmlSwap = $.extend(swapData, tdata.htmlSwap);
            else
                tdata.htmlSwap = swapData;
            if (tdata.htmlSwap.doSwapFront) {
                tdata.htmlSwap.frontBag = this.prepBag(tdata.htmlSwap.frontBag, tdata.frontContent, tdata.htmlSwap.prevFrontIndex);
                tdata.htmlSwap.frontStaticRndm = tdata.htmlSwap.frontBag.pop();
            }
            if (tdata.htmlSwap.doSwapBack) {
                tdata.htmlSwap.backBag = this.prepBag(tdata.htmlSwap.backBag, tdata.backContent, tdata.htmlSwap.prevBackIndex);
                tdata.htmlSwap.backStaticRndm = tdata.htmlSwap.backBag.pop();
            }
        },
        prepBag: function (bag, content, prevIdx) {
            bag = [];
            var bagCount = 0;
            for (var i = 0; i < content.length; i++) {
                //make sure there's not an immediate repeat
                if (i != prevIdx || bag.length === 1) {
                    bag[bagCount] = i;
                    bagCount++;
                }
            }
            return helperMethods.shuffleArray(bag);
        },
        getFrontSwapIndex: function (tdata) {
            var idx = 0;
            if (!tdata.htmlSwap.frontIsRandom) {
                idx = tdata.htmlSwap.frontIsInGrid ? tdata.htmlSwap.frontStaticIndex : tdata.htmlSwap.frontIndex;
            } else {
                if (tdata.htmlSwap.frontBag.length === 0) {
                    tdata.htmlSwap.frontBag = this.prepBag(tdata.htmlSwap.frontBag, tdata.frontContent, tdata.htmlSwap.prevFrontIndex);
                }
                if (tdata.htmlSwap.frontIsInGrid) {
                    idx = tdata.htmlSwap.frontStaticRndm;
                } else {
                    idx = tdata.htmlSwap.frontBag.pop();
                }
            }
            return idx;
        },
        getBackSwapIndex: function (tdata) {
            var idx = 0;
            if (!tdata.htmlSwap.backIsRandom) {
                idx = tdata.htmlSwap.backIsInGrid ? tdata.htmlSwap.backStaticIndex : tdata.htmlSwap.backIndex;
            } else {
                if (tdata.htmlSwap.backBag.length === 0) {
                    tdata.htmlSwap.backBag = this.prepBag(tdata.htmlSwap.backBag, tdata.backContent, tdata.htmlSwap.prevBackIndex);
                }
                if (tdata.htmlSwap.backIsInGrid) {
                    idx = tdata.htmlSwap.backStaticRndm;
                } else {
                    idx = tdata.htmlSwap.backBag.pop();
                }
            }
            return idx;
        },
        action: function (tdata, $front, $back, index) {
            if (!tdata.htmlSwap.doSwapFront && !tdata.htmlSwap.doSwapBack)
                return;
            var isList = tdata.mode === "flip-list";
            var swapIndex = 0;
            var isReversed = isList ? tdata.listData[Math.max(index, 0)].isReversed : tdata.isReversed;
            if (isList && index == -1) {
                // flip list completed
                if (!isReversed) {
                    if (tdata.htmlSwap.doSwapFront) {
                        // update the random value for grid mode
                        if (tdata.htmlSwap.frontBag.length === 0)
                            tdata.htmlSwap.frontBag = this.prepBag(tdata.htmlSwap.frontBag, tdata.frontContent, tdata.htmlSwap.frontStaticRndm);
                        tdata.htmlSwap.frontStaticRndm = tdata.htmlSwap.frontBag.pop();
                        // update the static index
                        tdata.htmlSwap.frontStaticIndex++;
                        if (tdata.htmlSwap.frontStaticIndex >= tdata.frontContent.length)
                            tdata.htmlSwap.frontStaticIndex = 0;
                    }
                } else {
                    if (tdata.htmlSwap.doSwapBack) {
                        // update the random value for grid mode
                        if (tdata.htmlSwap.backBag.length === 0)
                            tdata.htmlSwap.backBag = this.prepBag(tdata.htmlSwap.backBag, tdata.backContent, tdata.htmlSwap.backStaticRndm);
                        tdata.htmlSwap.backStaticRndm = tdata.htmlSwap.backBag.pop();
                        // update the static index
                        tdata.htmlSwap.backStaticIndex++;
                        if (tdata.htmlSwap.backStaticIndex >= tdata.backContent.length)
                            tdata.htmlSwap.backStaticIndex = 0;
                    }
                }
                return;
            }
            if (!isReversed) {
                if (!tdata.htmlSwap.doSwapFront)
                    return;
                swapIndex = this.getFrontSwapIndex(tdata);
                tdata.htmlSwap.prevFrontIndex = swapIndex;
                if (tdata.mode === "slide") {
                    if (!tdata.startNow)
                        $front.html(tdata.frontContent[swapIndex]);
                    else
                        $back.html(tdata.frontContent[swapIndex]);
                } else
                    $back.html(tdata.frontContent[swapIndex]);
                // increment the front index to get the next item from the list
                tdata.htmlSwap.frontIndex++;
                if (tdata.htmlSwap.frontIndex >= tdata.frontContent.length)
                    tdata.htmlSwap.frontIndex = 0;
                if (!isList) {
                    // increment the static index if we're not in list mode
                    tdata.htmlSwap.frontStaticIndex++;
                    if (tdata.htmlSwap.frontStaticIndex >= tdata.frontContent.length)
                        tdata.htmlSwap.frontStaticIndex = 0;
                } else {
                    // flip list
                }
            } else {
                if (!tdata.htmlSwap.doSwapBack)
                    return;
                swapIndex = this.getBackSwapIndex(tdata);
                tdata.htmlSwap.prevBackIndex = swapIndex;
                $back.html(tdata.backContent[tdata.htmlSwap.backIndex]);
                tdata.htmlSwap.backIndex++;
                if (tdata.htmlSwap.backIndex >= tdata.backContent.length)
                    tdata.htmlSwap.backIndex = 0;
                if (!isList) {
                    tdata.htmlSwap.backStaticIndex++;
                    if (tdata.htmlSwap.backStaticIndex >= tdata.backContent.length)
                        tdata.htmlSwap.backStaticIndex = 0;
                } else {
                    // flip list
                }
            }
        }
    },
    imageSwap: {
        data: {
            preloadImages: false,
            imageCssSelector: '>img,>a>img',        // the selector used to choose a an image to apply a src or background to
            frontImages: [],                        // a list of images to use for the front
            frontIsRandom: true,                    // should images be chosen at random or in order
            frontIsBackgroundImage: false,          // set the src attribute or css background-image property
            frontIsInGrid: false,                    // only chooses one item for each iteration in flip-list
            backImages: null,                       // a list of images to use for the back
            backIsRandom: true,                     // should images be chosen at random or in order
            backIsBackgroundImage: false,           // set the src attribute or css background-image property
            backIsInGrid: false                     // only chooses one item for each iteration in flip-list                
        },
        initData: function (tdata, $ele) {
            var swapData = {
                backBag: [],
                backIndex: 0,
                backStaticIndex: 0,
                backStaticRndm: -1,
                frontBag: [],
                frontIndex: 0,
                frontStaticIndex: 0,
                frontStaticRndm: -1,
                prevBackIndex: -1,
                prevFrontIndex: -1
            };
            swapData.imageCssSelector = !tdata.ignoreDataAttributes ? privMethods.getDataOrDefault($ele, "image-css", tdata.imageCssSelector) : tdata.imageCssSelector;
            swapData.frontIsRandom = !tdata.ignoreDataAttributes ? privMethods.getDataOrDefault($ele, "front-israndom", tdata.frontIsRandom) : tdata.frontIsRandom;
            swapData.frontIsInGrid = !tdata.ignoreDataAttributes ? privMethods.getDataOrDefault($ele, "front-isingrid", tdata.frontIsInGrid) : tdata.frontIsInGrid;
            swapData.frontIsBackgroundImage = !tdata.ignoreDataAttributes ? privMethods.getDataOrDefault($ele, "front-isbg", tdata.frontIsBackgroundImage) : tdata.frontIsBackgroundImage;
            swapData.backIsRandom = !tdata.ignoreDataAttributes ? privMethods.getDataOrDefault($ele, "back-israndom", tdata.backIsRandom) : tdata.backIsRandom;
            swapData.backIsInGrid = !tdata.ignoreDataAttributes ? privMethods.getDataOrDefault($ele, "back-isingrid", tdata.backIsInGrid) : tdata.backIsInGrid;
            swapData.backIsBackgroundImage = !tdata.ignoreDataAttributes ? privMethods.getDataOrDefault($ele, "back-isbg", tdata.backIsBackgroundImage) : tdata.backIsBackgroundImage;
            swapData.doSwapFront = $.inArray('image', tdata.swapFront) > -1 && (tdata.frontImages instanceof Array) && tdata.frontImages.length > 0;
            swapData.doSwapBack = $.inArray('image', tdata.swapBack) > -1 && (tdata.backImages instanceof Array) && tdata.backImages.length > 0;
            if(typeof(tdata.imgSwap) !== "undefined")
                tdata.imgSwap = $.extend(swapData, tdata.imgSwap);
            else
                tdata.imgSwap = swapData;
            if (tdata.imgSwap.doSwapFront) {
                tdata.imgSwap.frontBag = this.prepBag(tdata.imgSwap.frontBag, tdata.frontImages, tdata.imgSwap.prevFrontIndex);
                tdata.imgSwap.frontStaticRndm = tdata.imgSwap.frontBag.pop();
                if (tdata.preloadImages)
                    $(tdata.frontImages).metrojs.preloadImages(function () { });
            }
            if (tdata.imgSwap.doSwapBack) {
                tdata.imgSwap.backBag = this.prepBag(tdata.imgSwap.backBag, tdata.backImages, tdata.imgSwap.prevBackIndex);
                tdata.imgSwap.backStaticRndm = tdata.imgSwap.backBag.pop();
                if (tdata.preloadImages)
                    $(tdata.backImages).metrojs.preloadImages(function () { });
            }
        },
        prepBag: function (bag, content, prevIdx) {
            bag = [];
            var bagCount = 0;
            for (var i = 0; i < content.length; i++) {
                //make sure there's not an immediate repeat
                if (i != prevIdx || content.length === 1) {
                    bag[bagCount] = i;
                    bagCount++;
                }
            }
            return helperMethods.shuffleArray(bag);
        },
        getFrontSwapIndex: function (tdata) {
            var idx = 0;
            if (!tdata.imgSwap.frontIsRandom) {
                idx = tdata.imgSwap.frontIsInGrid ? tdata.imgSwap.frontStaticIndex : tdata.imgSwap.frontIndex;
            } else {
                if (tdata.imgSwap.frontBag.length === 0) {
                    tdata.imgSwap.frontBag = this.prepBag(tdata.imgSwap.frontBag, tdata.frontImages, tdata.imgSwap.prevFrontIndex);
                }
                if (tdata.imgSwap.frontIsInGrid) {
                    idx = tdata.imgSwap.frontStaticRndm;
                } else {
                    idx = tdata.imgSwap.frontBag.pop();
                }
            }
            return idx;
        },
        getBackSwapIndex: function (tdata) {
            var idx = 0;
            if (!tdata.imgSwap.backIsRandom) {
                idx = tdata.imgSwap.backIsInGrid ? tdata.imgSwap.backStaticIndex : tdata.imgSwap.backIndex;
            } else {
                if (tdata.imgSwap.backBag.length === 0) {
                    tdata.imgSwap.backBag = this.prepBag(tdata.imgSwap.backBag, tdata.backImages, tdata.imgSwap.prevBackIndex);
                }
                if (tdata.imgSwap.backIsInGrid) {
                    idx = tdata.imgSwap.backStaticRndm;
                } else {
                    idx = tdata.imgSwap.backBag.pop();
                }
            }
            return idx;
        },
        setImageProperties: function ($img, image, isBackground) {
            var css = {}, // css object to apply
                attr = {}; // attribute values to apply
            // get image source
            if (typeof (image.src) !== 'undefined') {
                if (!isBackground)
                    attr.src = image.src;
                else
                    css.backgroundImage = "url('" + image.src + "')";
            }
            // get alt text
            if (typeof (image.alt) !== 'undefined')
                attr.alt = image.alt;
            // set css
            if (typeof (image.css) === 'object')
                $img.css($.extend(css, image.css));
            else
                $img.css(css);
            // set attributes
            if (typeof (image.attr) === 'object')
                $img.attr($.extend(attr, image.attr));
            else
                $img.attr(attr);
        },
        action: function (tdata, $front, $back, index) {
            if (!tdata.imgSwap.doSwapFront && !tdata.imgSwap.doSwapBack)
                return;
            var isList = tdata.mode === "flip-list";
            var swapIndex = 0;
            var isReversed = isList ? tdata.listData[Math.max(index, 0)].isReversed : tdata.isReversed;
            if (isList && index == -1) {
                // flip list completed
                if (!isReversed) {
                    if (tdata.imgSwap.doSwapFront) {
                        // update the random value for grid mode
                        if (tdata.imgSwap.frontBag.length === 0)
                            tdata.imgSwap.frontBag = this.prepBag(tdata.imgSwap.frontBag, tdata.frontImages, tdata.imgSwap.frontStaticRndm);
                        tdata.imgSwap.frontStaticRndm = tdata.imgSwap.frontBag.pop();
                        // update the static index
                        tdata.imgSwap.frontStaticIndex++;
                        if (tdata.imgSwap.frontStaticIndex >= tdata.frontImages.length)
                            tdata.imgSwap.frontStaticIndex = 0;
                    }
                } else {
                    if (tdata.imgSwap.doSwapBack) {
                        // update the random value for grid mode
                        if (tdata.imgSwap.backBag.length === 0)
                            tdata.imgSwap.backBag = this.prepBag(tdata.imgSwap.backBag, tdata.backImages, tdata.imgSwap.backStaticRndm);
                        tdata.imgSwap.backStaticRndm = tdata.imgSwap.backBag.pop();
                        // update the static index
                        tdata.imgSwap.backStaticIndex++;
                        if (tdata.imgSwap.backStaticIndex >= tdata.backImages.length)
                            tdata.imgSwap.backStaticIndex = 0;
                    }
                }
                return;
            }
            var $face, // face being swapped
                $img, // image to apply values
                image; // image object to hold properties
            if (!isReversed) {
                if (!tdata.imgSwap.doSwapFront)
                    return;
                swapIndex = this.getFrontSwapIndex(tdata);
                tdata.imgSwap.prevFrontIndex = swapIndex;
                // slide mode has a static front and back face
                $face = (tdata.mode === "slide") ? $front : $back;
                $img = $face.find(tdata.imgSwap.imageCssSelector);
                image = typeof (tdata.frontImages[swapIndex]) === "object" ? tdata.frontImages[swapIndex] : { src: tdata.frontImages[swapIndex] };
                // set src, alt, css and attribute values
                this.setImageProperties($img, image, tdata.imgSwap.frontIsBackgroundImage);
                // increment indexes
                tdata.imgSwap.frontIndex++;
                if (tdata.imgSwap.frontIndex >= tdata.frontImages.length)
                    tdata.imgSwap.frontIndex = 0;
                if (!isList) {
                    tdata.imgSwap.frontStaticIndex++;
                    if (tdata.imgSwap.frontStaticIndex >= tdata.frontImages.length)
                        tdata.imgSwap.frontStaticIndex = 0;
                } else {

                }
            } else {
                if (!tdata.imgSwap.doSwapBack)
                    return;
                // get the new index
                swapIndex = this.getBackSwapIndex(tdata);
                tdata.imgSwap.prevBackIndex = swapIndex;
                // use the $face var for consistency
                $face = $back;
                $img = $face.find(tdata.imgSwap.imageCssSelector);
                image = typeof (tdata.backImages[swapIndex]) === "object" ? tdata.backImages[swapIndex] : { src: tdata.backImages[swapIndex] };
                // set src, alt, css and attribute values
                this.setImageProperties($img, image, tdata.imgSwap.backIsBackgroundImage);
                // increment indexes
                tdata.imgSwap.backIndex++;
                if (tdata.imgSwap.backIndex >= tdata.backImages.length)
                    tdata.imgSwap.backIndex = 0;
                if (!isList) {
                    tdata.imgSwap.backStaticIndex++;
                    if (tdata.imgSwap.backStaticIndex >= tdata.backImages.length)
                        tdata.imgSwap.backStaticIndex = 0;
                } else {

                }
            }
            $face = null;
            $img = null;

        }
    }
};

// object to maintain timer state
$.fn.metrojs.TileTimer = function (interval, callback, repeatCount) {
    this.timerId = null;                                                        // the id of the current timeout
    this.interval = interval;                                                   // the amount of time to wait between each action call
    this.action = callback;                                                     // the method that is fired on each tick
    this.count = 0;                                                             // the number of times the action has been fired
    this.repeatCount = typeof (repeatCount) === "undefined" ? 0 : repeatCount;   // the number of times the action will be fired        
    // call the action method after a delay and call start | stop based on repeat count
    this.start = function (delay) {
        window.clearTimeout(this.timerId);
        var t = this;
        this.timerId = window.setTimeout(function () {
            t.tick.call(t, interval);
        }, delay);
    };

    this.tick = function (interval) {
        this.action(this.count + 1);
        this.count++;
        // reset the loop count
        if (this.count >= MAX_LOOP_COUNT)
            this.count = 0;
        if (this.repeatCount > 0 || this.repeatCount == -1) {
            if (this.count != this.repeatCount) {
                this.start(interval);
            } else
                this.stop();
        }
    }
    // clear the timer and reset the count
    this.stop = function () {
        this.timerId = window.clearTimeout(this.timerId);
        this.reset();
    };

    this.resume = function () {
        if (this.repeatCount > 0 || this.repeatCount == -1) {
            if (this.count != this.repeatCount) {
                this.start(interval);                
            }
        }
    };

    // clear the timer but leave the count intact
    this.pause = function () {
        this.timerId = window.clearTimeout(this.timerId);
    };

    // reset count
    this.reset = function () {
        this.count = 0;
    };

    // reset count and timer
    this.restart = function (delay) {
        this.stop();
        this.start(delay);
    };
};
///#source 1 1 /Scripts/MetroJs/src/js/fin.js
/* Preload Images */
// Usage: jQuery(['img1.jpg','img2.jpg']).metrojs.preloadImages(function(){ ... });
// Callback function gets called after all images are preloaded
jQuery.fn.metrojs.preloadImages = function (callback) {
    var checklist = jQuery(this).toArray();
    var $img = jQuery("<img style='display:none;' />").appendTo("body");
    jQuery(this).each(function () {
        $img.attr({ src: this }).load(function () {
            var src = jQuery(this).attr('src');
            for (var i = 0; i < checklist.length; i++) {
                if (checklist[i] == element) { checklist.splice(i, 1); }
            }
            if (checklist.length == 0) { callback(); }
        });
    });
    $img.remove();
};
// object used for compatibility checks
$.fn.metrojs.MetroModernizr = function (stgs) {
    if(typeof(stgs) === "undefined"){
        stgs = { useHardwareAccel: true, useModernizr: typeof(window.Modernizr) !== "undefined"  }
    }
    this.isOldJQuery =  /^1\.[0123]/.test(jQuery.fn.jquery),
    this.canTransform = false;
    this.canTransition = false;
    this.canTransform3d = false;
    this.canAnimate = false;
    this.canTouch = false;
    this.canFlip3d = stgs.useHardwareAccel;
    if (stgs.useHardwareAccel == true) {
        if (stgs.useModernizr == false) {
            //determine if the browser supports the neccessary accelerated features
            if (typeof (window.MetroModernizr) !== "undefined") {
                this.canTransform = window.MetroModernizr.canTransform;
                this.canTransition = window.MetroModernizr.canTransition;
                this.canTransform3d = window.MetroModernizr.canTransform3d;
                this.canAnimate = window.MetroModernizr.canAnimate;
                this.canTouch = window.MetroModernizr.canTouch;
            } else {
                window.MetroModernizr = {};
                /***** check for browser capabilities credit: modernizr-1.7 http://modernizr.com/ *****/
                var mod = 'metromodernizr';
                var docElement = document.documentElement;
                var docHead = document.head || document.getElementsByTagName('head')[0];
                var modElem = document.createElement(mod);
                var m_style = modElem.style;
                var prefixes = ' -webkit- -moz- -o- -ms- '.split(' ');
                var domPrefixes = 'Webkit Moz O ms Khtml'.split(' ');
                var test_props = function (props, callback) {
                    for (var i in props) {
                        if (m_style[props[i]] !== undefined && (!callback || callback(props[i], modElem))) {
                            return true;
                        }
                    }
                };
                var test_props_all = function (prop, callback) {
                    var uc_prop = prop.charAt(0).toUpperCase() + prop.substr(1),
                    props = (prop + ' ' + domPrefixes.join(uc_prop + ' ') + uc_prop).split(' ');
                    return !!test_props(props, callback);
                };
                var test_3d = function () {
                    var ret = !!test_props(['perspectiveProperty', 'WebkitPerspective', 'MozPerspective', 'OPerspective', 'msPerspective']);
                    if (ret && 'webkitPerspective' in docElement.style) {
                        // Webkit allows this media query to succeed only if the feature is enabled.
                        // '@media (transform-3d),(-o-transform-3d),(-moz-transform-3d),(-ms-transform-3d),(-webkit-transform-3d),(modernizr){ ... }'
                        ret = testMediaQuery(['@media (',prefixes.join('transform-3d),('),mod,')','{#metromodernizr{left:9px;position:absolute;height:3px;}}'].join(''), function(div){
                            return div.offsetHeight === 3 && div.offsetLeft === 9;
                        });
                    }
                    return ret;
                };
                var testMediaQuery = function (mq, predicate) {
                    var st = document.createElement('style'),
                        div = document.createElement('div'),
                        ret;
                    st.textContent = mq;
                    docHead.appendChild(st);
                    div.id = mod;
                    docElement.appendChild(div);
                    ret = predicate(div);
                    st.parentNode.removeChild(st);
                    div.parentNode.removeChild(div);
                    return !!ret;
                };
                var test_touch = function() {
                    return canTouch = ('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch || 
                        (typeof(window.navigator.msMaxTouchPoints) !== "undefined" && window.navigator.msMaxTouchPoints > 0) || 
                        testMediaQuery(['@media (',prefixes.join('touch-enabled),('),mod,')','{#metromodernizr{top:9px;position:absolute}}'].join(''), function(div){
                            return div.offsetTop === 9;
                        }); 
                };
                this.canTransform = !!test_props(['transformProperty', 'WebkitTransform', 'MozTransform', 'OTransform', 'msTransform']);
                this.canTransition = test_props_all('transitionProperty');
                this.canTransform3d = test_3d();
                this.canAnimate = test_props_all('animationName');
                this.canTouch = test_touch();
                window.MetroModernizr.canTransform = this.canTransform;
                window.MetroModernizr.canTransition = this.canTransition;
                window.MetroModernizr.canTransform3d = this.canTransform3d;
                window.MetroModernizr.canAnimate = this.canAnimate;
                window.MetroModernizr.canTouch = this.canTouch;
                docElement = null;
                docHead = null;
                modElem = null;
                m_style = null;
            }
        } else {
            this.canTransform = $("html").hasClass("csstransforms");
            this.canTransition = $("html").hasClass("csstransitions");
            this.canTransform3d = $("html").hasClass("csstransforms3d");
            this.canAnimate = $("html").hasClass("cssanimations");
            this.canTouch = $("html").hasClass("touch") || (typeof(window.navigator.msMaxTouchPoints) !== "undefined" && window.navigator.msMaxTouchPoints > 0);
        }
    }
    this.canFlip3d = this.canFlip3d && this.canAnimate && this.canTransform && this.canTransform3d;
};

})(jQuery);

/*
  SlidesJS 3.0.3 http://slidesjs.com
  (c) 2013 by Nathan Searles http://nathansearles.com
  Updated: March 15th, 2013
  Apache License: http://www.apache.org/licenses/LICENSE-2.0
*/
(function(){(function(a,b,c){var d,e,f;return f="slidesjs",e={width:940,height:528,start:1,navigation:{active:!0,effect:"slide"},pagination:{active:!0,effect:"slide"},play:{active:!1,effect:"slide",interval:5e3,auto:!1,swap:!0,pauseOnHover:!1,restartDelay:2500},effect:{slide:{speed:500},fade:{speed:300,crossfade:!0}},callback:{loaded:function(){},start:function(){},complete:function(){}}},d=function(){function b(b,c){this.element=b,this.options=a.extend(!0,{},e,c),this._defaults=e,this._name=f,this.init()}return b}(),d.prototype.init=function(){var c,d,e,f,g,h,i=this;return c=a(this.element),this.data=a.data(this),a.data(this,"animating",!1),a.data(this,"total",c.children().not(".slidesjs-navigation",c).length),a.data(this,"current",this.options.start-1),a.data(this,"vendorPrefix",this._getVendorPrefix()),"undefined"!=typeof TouchEvent&&(a.data(this,"touch",!0),this.options.effect.slide.speed=this.options.effect.slide.speed/2),c.css({overflow:"hidden"}),c.slidesContainer=c.children().not(".slidesjs-navigation",c).wrapAll("<div class='slidesjs-container'>",c).parent().css({overflow:"hidden",position:"relative"}),a(".slidesjs-container",c).wrapInner("<div class='slidesjs-control'>",c).children(),a(".slidesjs-control",c).css({position:"relative",left:0}),a(".slidesjs-control",c).children().addClass("slidesjs-slide").css({position:"absolute",top:0,left:0,width:"100%",zIndex:0,display:"none",webkitBackfaceVisibility:"hidden"}),a.each(a(".slidesjs-control",c).children(),function(b){var c;return c=a(this),c.attr("slidesjs-index",b)}),this.data.touch&&(a(".slidesjs-control",c).on("touchstart",function(a){return i._touchstart(a)}),a(".slidesjs-control",c).on("touchmove",function(a){return i._touchmove(a)}),a(".slidesjs-control",c).on("touchend",function(a){return i._touchend(a)})),c.fadeIn(0),this.update(),this.data.touch&&this._setuptouch(),a(".slidesjs-control",c).children(":eq("+this.data.current+")").eq(0).fadeIn(0,function(){return a(this).css({zIndex:10})}),this.options.navigation.active&&(g=a("<a>",{"class":"slidesjs-previous slidesjs-navigation",href:"#",title:"Previous",text:"Previous"}).appendTo(c),d=a("<a>",{"class":"slidesjs-next slidesjs-navigation",href:"#",title:"Next",text:"Next"}).appendTo(c)),a(".slidesjs-next",c).click(function(a){return a.preventDefault(),i.stop(!0),i.next(i.options.navigation.effect)}),a(".slidesjs-previous",c).click(function(a){return a.preventDefault(),i.stop(!0),i.previous(i.options.navigation.effect)}),this.options.play.active&&(f=a("<a>",{"class":"slidesjs-play slidesjs-navigation",href:"#",title:"Play",text:"Play"}).appendTo(c),h=a("<a>",{"class":"slidesjs-stop slidesjs-navigation",href:"#",title:"Stop",text:"Stop"}).appendTo(c),f.click(function(a){return a.preventDefault(),i.play(!0)}),h.click(function(a){return a.preventDefault(),i.stop(!0)}),this.options.play.swap&&h.css({display:"none"})),this.options.pagination.active&&(e=a("<ul>",{"class":"slidesjs-pagination"}).appendTo(c),a.each(Array(this.data.total),function(b){var c,d;return c=a("<li>",{"class":"slidesjs-pagination-item"}).appendTo(e),d=a("<a>",{href:"#","data-slidesjs-item":b,html:b+1}).appendTo(c),d.click(function(b){return b.preventDefault(),i.stop(!0),i.goto(1*a(b.currentTarget).attr("data-slidesjs-item")+1)})})),a(b).bind("resize",function(){return i.update()}),this._setActive(),this.options.play.auto&&this.play(),this.options.callback.loaded(this.options.start)},d.prototype._setActive=function(b){var c,d;return c=a(this.element),this.data=a.data(this),d=b>-1?b:this.data.current,a(".active",c).removeClass("active"),a("li:eq("+d+") a",c).addClass("active")},d.prototype.update=function(){var b,c,d;return b=a(this.element),this.data=a.data(this),a(".slidesjs-control",b).children(":not(:eq("+this.data.current+"))").css({display:"none",left:0,zIndex:0}),d=b.width(),c=this.options.height/this.options.width*d,this.options.width=d,this.options.height=c,a(".slidesjs-control, .slidesjs-container",b).css({width:d,height:c})},d.prototype.next=function(b){var c;return c=a(this.element),this.data=a.data(this),a.data(this,"direction","next"),void 0===b&&(b=this.options.navigation.effect),"fade"===b?this._fade():this._slide()},d.prototype.previous=function(b){var c;return c=a(this.element),this.data=a.data(this),a.data(this,"direction","previous"),void 0===b&&(b=this.options.navigation.effect),"fade"===b?this._fade():this._slide()},d.prototype.goto=function(b){var c,d;if(c=a(this.element),this.data=a.data(this),void 0===d&&(d=this.options.pagination.effect),b>this.data.total?b=this.data.total:1>b&&(b=1),"number"==typeof b)return"fade"===d?this._fade(b):this._slide(b);if("string"==typeof b){if("first"===b)return"fade"===d?this._fade(0):this._slide(0);if("last"===b)return"fade"===d?this._fade(this.data.total):this._slide(this.data.total)}},d.prototype._setuptouch=function(){var b,c,d,e;return b=a(this.element),this.data=a.data(this),e=a(".slidesjs-control",b),c=this.data.current+1,d=this.data.current-1,0>d&&(d=this.data.total-1),c>this.data.total-1&&(c=0),e.children(":eq("+c+")").css({display:"block",left:this.options.width}),e.children(":eq("+d+")").css({display:"block",left:-this.options.width})},d.prototype._touchstart=function(b){var c,d;return c=a(this.element),this.data=a.data(this),d=b.originalEvent.touches[0],this._setuptouch(),a.data(this,"touchtimer",Number(new Date)),a.data(this,"touchstartx",d.pageX),a.data(this,"touchstarty",d.pageY),b.stopPropagation()},d.prototype._touchend=function(b){var c,d,e,f,g,h,i,j=this;return c=a(this.element),this.data=a.data(this),h=b.originalEvent.touches[0],f=a(".slidesjs-control",c),f.position().left>.5*this.options.width||f.position().left>.1*this.options.width&&250>Number(new Date)-this.data.touchtimer?(a.data(this,"direction","previous"),this._slide()):f.position().left<-(.5*this.options.width)||f.position().left<-(.1*this.options.width)&&250>Number(new Date)-this.data.touchtimer?(a.data(this,"direction","next"),this._slide()):(e=this.data.vendorPrefix,i=e+"Transform",d=e+"TransitionDuration",g=e+"TransitionTimingFunction",f[0].style[i]="translateX(0px)",f[0].style[d]=.85*this.options.effect.slide.speed+"ms"),f.on("transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd",function(){return e=j.data.vendorPrefix,i=e+"Transform",d=e+"TransitionDuration",g=e+"TransitionTimingFunction",f[0].style[i]="",f[0].style[d]="",f[0].style[g]=""}),b.stopPropagation()},d.prototype._touchmove=function(b){var c,d,e,f,g;return c=a(this.element),this.data=a.data(this),f=b.originalEvent.touches[0],d=this.data.vendorPrefix,e=a(".slidesjs-control",c),g=d+"Transform",a.data(this,"scrolling",Math.abs(f.pageX-this.data.touchstartx)<Math.abs(f.pageY-this.data.touchstarty)),this.data.animating||this.data.scrolling||(b.preventDefault(),this._setuptouch(),e[0].style[g]="translateX("+(f.pageX-this.data.touchstartx)+"px)"),b.stopPropagation()},d.prototype.play=function(b){var c,d,e,f=this;return c=a(this.element),this.data=a.data(this),!this.data.playInterval&&(b&&(d=this.data.current,this.data.direction="next","fade"===this.options.play.effect?this._fade():this._slide()),a.data(this,"playInterval",setInterval(function(){return d=f.data.current,f.data.direction="next","fade"===f.options.play.effect?f._fade():f._slide()},this.options.play.interval)),e=a(".slidesjs-container",c),this.options.play.pauseOnHover&&(e.unbind(),e.bind("mouseenter",function(){return f.stop()}),e.bind("mouseleave",function(){return f.options.play.restartDelay?a.data(f,"restartDelay",setTimeout(function(){return f.play(!0)},f.options.play.restartDelay)):f.play()})),a.data(this,"playing",!0),a(".slidesjs-play",c).addClass("slidesjs-playing"),this.options.play.swap)?(a(".slidesjs-play",c).hide(),a(".slidesjs-stop",c).show()):void 0},d.prototype.stop=function(b){var c;return c=a(this.element),this.data=a.data(this),clearInterval(this.data.playInterval),this.options.play.pauseOnHover&&b&&a(".slidesjs-container",c).unbind(),a.data(this,"playInterval",null),a.data(this,"playing",!1),a(".slidesjs-play",c).removeClass("slidesjs-playing"),this.options.play.swap?(a(".slidesjs-stop",c).hide(),a(".slidesjs-play",c).show()):void 0},d.prototype._slide=function(b){var c,d,e,f,g,h,i,j,k,l,m=this;return c=a(this.element),this.data=a.data(this),this.data.animating||b===this.data.current+1?void 0:(a.data(this,"animating",!0),d=this.data.current,b>-1?(b-=1,l=b>d?1:-1,e=b>d?-this.options.width:this.options.width,g=b):(l="next"===this.data.direction?1:-1,e="next"===this.data.direction?-this.options.width:this.options.width,g=d+l),-1===g&&(g=this.data.total-1),g===this.data.total&&(g=0),this._setActive(g),i=a(".slidesjs-control",c),b>-1&&i.children(":not(:eq("+d+"))").css({display:"none",left:0,zIndex:0}),i.children(":eq("+g+")").css({display:"block",left:l*this.options.width,zIndex:10}),this.options.callback.start(d+1),this.data.vendorPrefix?(h=this.data.vendorPrefix,k=h+"Transform",f=h+"TransitionDuration",j=h+"TransitionTimingFunction",i[0].style[k]="translateX("+e+"px)",i[0].style[f]=this.options.effect.slide.speed+"ms",i.on("transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd",function(){return i[0].style[k]="",i[0].style[f]="",i.children(":eq("+g+")").css({left:0}),i.children(":eq("+d+")").css({display:"none",left:0,zIndex:0}),a.data(m,"current",g),a.data(m,"animating",!1),i.unbind("transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd"),i.children(":not(:eq("+g+"))").css({display:"none",left:0,zIndex:0}),m.data.touch&&m._setuptouch(),m.options.callback.complete(g+1)})):i.stop().animate({left:e},this.options.effect.slide.speed,function(){return i.css({left:0}),i.children(":eq("+g+")").css({left:0}),i.children(":eq("+d+")").css({display:"none",left:0,zIndex:0},a.data(m,"current",g),a.data(m,"animating",!1),m.options.callback.complete(g+1))}))},d.prototype._fade=function(b){var c,d,e,f,g,h=this;return c=a(this.element),this.data=a.data(this),this.data.animating||b===this.data.current+1?void 0:(a.data(this,"animating",!0),d=this.data.current,b?(b-=1,g=b>d?1:-1,e=b):(g="next"===this.data.direction?1:-1,e=d+g),-1===e&&(e=this.data.total-1),e===this.data.total&&(e=0),this._setActive(e),f=a(".slidesjs-control",c),f.children(":eq("+e+")").css({display:"none",left:0,zIndex:10}),this.options.callback.start(d+1),this.options.effect.fade.crossfade?(f.children(":eq("+this.data.current+")").stop().fadeOut(this.options.effect.fade.speed),f.children(":eq("+e+")").stop().fadeIn(this.options.effect.fade.speed,function(){return f.children(":eq("+e+")").css({zIndex:0}),a.data(h,"animating",!1),a.data(h,"current",e),h.options.callback.complete(e+1)})):f.children(":eq("+d+")").stop().fadeOut(this.options.effect.fade.speed,function(){return f.children(":eq("+e+")").stop().fadeIn(h.options.effect.fade.speed,function(){return f.children(":eq("+e+")").css({zIndex:10})}),a.data(h,"animating",!1),a.data(h,"current",e),h.options.callback.complete(e+1)}))},d.prototype._getVendorPrefix=function(){var a,b,d,e,f;for(a=c.body||c.documentElement,d=a.style,e="transition",f=["Moz","Webkit","Khtml","O","ms"],e=e.charAt(0).toUpperCase()+e.substr(1),b=0;f.length>b;){if("string"==typeof d[f[b]+e])return f[b];b++}return!1},a.fn[f]=function(b){return this.each(function(){return a.data(this,"plugin_"+f)?void 0:a.data(this,"plugin_"+f,new d(this,b))})}})(jQuery,window,document)}).call(this);

/* 
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

;
"use strict";
var flipTimeoutx;
var flipTimeouty;
var autofillTimeout;
var masonryoptions;
alterIE = false;
(function($) {
    if ($.browser.msie) {
        if (parseInt($.browser.version, 10) < 9)
            alterIE = true;
        //        if( parseInt($.browser.version, 10) < 8 ){
        //            window.location = '/index.php?id=79';
        //        }else{
        //            if( parseInt($.browser.version, 10) == 8 ){
        //                alert("Um diese Seite in ihrem vollen Glanz zu genießen, benötigen sie einen halbwegs aktuellen Webbrowser. \
        // (IE 9 oder höher)");
        //                
        //            }
        //        }
    }
    // $('body').append('<div class="ui-loader ui-corner-all ui-body-a ui-loader-default"><span class="ui-icon ui-icon-loading"></span><h1>loading</h1></div>');
    //return;

    function initAni() {
        spaltenSort();

        flipTimeoutx = setTimeout(function() {
            //window.clearTimeout(flipTimeoutx);
            if (Modernizr.csstransitions) {
                $(".flipHori > .bg").not(":first-child").css("opacity", "0");
                flip($(".ui-page-active .flipHori").not(".init"), "horizontal", 3000);
                $(".ui-page-active .flipHori").addClass("init");
            } else {
                $(".flipHori > .bg").css("opacity", "1");
                $(".ui-page-active .flipHori").css('overflow', 'hidden');
                $(".ui-page-active .flipHori").liveTile({
                    direction: 'horizontal', // or swap:'html' or data-swap="html"
                    mode: 'carousel',
                    backIsRandom: false
                });
            }
        }, 490);
        flipTimeouty = setTimeout(function() {
            //window.clearTimeout(flipTimeouty);
            if (Modernizr.csstransitions) {
                $(".flipVert > .bg").not(":first-child").css("opacity", "0");
                flip($(".flipVert").not(".init"), "vertical", 3300);
                $(".ui-page-active .flipVert").addClass("init");
            } else {
                $(".flipVert > .bg").css("opacity", "1");
                $(".ui-page-active .flipHori").css('overflow', 'hidden');
                $(".ui-page-active .flipHori").liveTile({
                    direction: 'horizontal', // or swap:'html' or data-swap="html"
                    mode: 'carousel',
                    backIsRandom: false
                });
            }
        }, 0);

        $('.ui-page-active .slideHori .live-tile').liveTile({
            direction: 'horizontal',
            stack: true,
            bounce: true,
            playOnHover: true,
            repeatCount: 0,
            delay: 0,
            startNow: false
        });
        $('.ui-page-active .slideVert .live-tile').liveTile({
            stack: true,
            bounce: true,
            playOnHover: true,
            repeatCount: 0,
            delay: 0,
            startNow: false
        });
        $(".ui-page-active .carouselHori .live-tile").liveTile({
            direction: 'horizontal', // or swap:'html' or data-swap="html"
            mode: 'carousel',
            backIsRandom: false
        });
        $(".ui-page-active .carouselVert .live-tile").liveTile({
            direction: 'vertical', // or swap:'html' or data-swap="html"
            mode: 'carousel',
            backIsRandom: false
        });


        if ($('.ui-page-active .slideshow .alignment-center figure').length > 1) {
            $('.ui-page-active .slideshow > .alignment-center').slidesjs({
                play: {
                    active: false,
                    interval: 5000,
                    auto: true
                },
                navigation: {
                    active: false
                },
                pagination: {
                    active: false
                },
                width: 479,
                height: 431
            });

            $('.ui-page-active .slideshow figure').each(function() {
                var href = $(this).find("a").attr("href");
                if ($(this).find(".slideshow-caption a").length < 1) {
                    $(this).find(".slideshow-caption").html('<a href="' + href + '">' + $(this).find(".slideshow-caption").html() + '</a>');
                }
            });
            // $(".ui-page-active .slideshow > .alignment-center").addClass("init");
        }
        $('.ui-page-active .contentslider').removeClass('aktiv');
        $('.ui-page-active .contentslider:first-child').addClass('aktiv');
        var count = $('.ui-page-active .contentslider.aktiv .bg > .table').length;
        if ($('.ui-page-active .contentslider.aktiv img').length > 1) {
            $('.ui-page-active .contentslider.aktiv .bg > .table > div').slidesjs({
                width: 575,
                height: 383,
                pagination: {
                    active: false
                }
            });
            // $(".ui-page-active .contentslider.aktiv .bg > .table > div").addClass("init");
        }
        setTimeout(function() {
            $('.ui-page-active .sliderbutton').each(function(index, Element) {
                if (index === 0) {
                    $(Element).addClass('aktiv');
                }
                if ($(Element).find("a").length === 0) {
                    var html = $(Element).html();
                    $(Element).html('<a href="#' + (index + 1) + '">' + html + '</a>');
                }
            });
        }, 0);
    }
    function loadGMScript() {
        if ($('.ui-page-active #map_canvas').length !== 0) {
            if ($('#GM_API').length === 0) {
                var script1 = document.createElement("script");
                script1.type = "text/javascript";
                script1.id = "GM_API";
                script1.src = "/fileadmin/system/js/googlemaps.js";
                document.body.appendChild(script1);
                var script2 = document.createElement("script");
                script2.type = "text/javascript";
                script2.id = "GM_API";
                script2.src = "http://maps.googleapis.com/maps/api/js?v=3&sensor=true&callback=initialize";
                document.body.appendChild(script2);
            } else {
                initialize();
            }
        }

    }
    function flip(parent, direction, delay) {
        if (typeof direction === "undefined") {
            direction = "horizontal";
        }
        if (direction === "horizontal") {
            var aniClassIn = 'flipInX';
            var aniClassOut = 'flipOutX';
            $(parent).find('div.bg.flipInY').removeClass('flipInY');
        } else {
            var aniClassIn = 'flipInY';
            var aniClassOut = 'flipOutY';
            $(parent).find('div.bg.flipInX').removeClass('flipInX');
        }
        var elem = $(parent).find('div.bg.' + aniClassIn);
        if (elem.length === 0) {
            $(parent).find('div.bg').addClass("animated");
            elem = $(parent).find('div.bg:first-child');
            $(parent).find('div.bg').addClass(aniClassOut);
            elem.addClass(aniClassIn);
        }
        var curPos = elem.index();
        var max = $(parent).find("div.bg").length;

        if (curPos + 1 < max) {
            elem.next('.bg').removeClass(aniClassOut).addClass(aniClassIn);
            elem.removeClass(aniClassIn).addClass(aniClassOut);
        } else {
            $(parent).find('.bg:first-child').removeClass(aniClassOut).addClass(aniClassIn);
            elem.removeClass(aniClassIn).addClass(aniClassOut);
        }
        setTimeout(function() {
            flipTimeout = flip(parent, direction, delay);
        }, delay);
    }
    function backgroundPosition() {
        var aktindex = $('#hauptnavigation li.aktiv').index();
        var pos = (100 / 6) * aktindex;
        if (pos < 0) {
            pos = pos * -1;
        }
        $('html').css('background-position', pos + "% top");
    }
    function unhideElements() {
        setTimeout(function() {
            var width = window.innerWidth;
            $('.container.masonry .sort.hideable').each(function() {
                if ($(this).attr('data-unhide-width') < width) {
                    if ($(this).css('position') === 'relative') {
                        $('.ui-page-active .container').masonry('reload');
                    }
                }
            });
        }, 0);
    }

    function nextPage(href) {
        $.mobile.changePage(href, {
            transition: "none",
            reverse: false
        });
        updateNavi();
    }

    function prevPage(href) {
        $.mobile.changePage(href, {
            transition: "none",
            reverse: true
        });
        updateNavi();
    }

    function centerTablepic() {
        setTimeout(function() {
            $(".ui-page-active .bg > div").not(".slide").find('.alignment-center > figure').each(function() {
                var width = $(this).width();
                var divWidth = $(this).parents(".bg").width();
                var height = $(this).height();
                var divHeight = $(this).parents(".bg").height();
                if ((divWidth - 3) < width && divHeight * .7 < height) {
                    // var verhaeltnis = ( 960/$('.ui-page-active #content_area').width() );
                    var offsetLeft = Math.round((divWidth / width) * width);
                    $(this).css('position', "relative");
                    $(this).css('left', "-50%");
                    $(this).css('margin-left', "" + offsetLeft + "px");
                } else {
                    $(this).css('left', "-50%");
                    $(this).css('margin-left', "0px");
                }
            });
        }, 0);
    }
    function rightTablepic() {
        setTimeout(function() {
            $('.ui-page-active .alignment-right > figure').each(function() {
                var width = $(this).width();
                var divWidth = $(this).parents(".bg").width();
                if (divWidth <= width) {
                    // var verhaeltnis = ( 960/$('.ui-page-active #content_area').width() );
                    var offsetLeft = divWidth - width;
                    $(this).parents(".table").css("display", "block");
                    $(this).parent().css("display", "block");
                    $(this).css('position', "relative");
                    //$(this).css('right',"-50%");
                    $(this).css('margin-left', "" + offsetLeft + "px");
                }
            });
        }, 0);
    }
    function positionImages() {
        if (alterIE !== true && window.screen.width > 768) {
            centerTablepic();
            rightTablepic();
        }
    }
    function autofill(el) {
        if (alterIE === true)
            return;
        if (el.hasClass("container") && !el.hasClass("masonry")) {
            autofillTimeout = setTimeout(function() {
                autofill(el);
            }, 0);
        } else {
            var width = 0;
            var zeile = 1;
            var contentWidth = $('.ui-page-active #content_area').width();
            var append = true;
            var neueBreite = 0;

            el.find(".spalte:last-child").each(function() {
                var lastHeight = 0;
                if ($(this).find('.autofilled.z' + zeile).length > 0) {
                    append = false;
                }

                $(this).find('.sort').not('.autofilled').each(function() {
                    if ($(this).hasClass("masonry-brick")) {
                        width = $(this).width() + parseInt($(this).css("left").split("px").join()) + 1;
                        if (width === contentWidth) {
                            //alert(right);
                            el.find('.z' + zeile).remove();
                            if (el.find(".masonry-brick").length > 0) {
                                el.masonry('reload');
                            }
                        } else {
                            if (el.find('.autofilled.z' + zeile).length === 0) {
                                append = true;
                            }
                            lastHeight = $(this).height();
                            neueBreite = contentWidth - width - 1;
                            if ((neueBreite + 1) % 48 !== 0) {
                                neueBreite = (Math.floor((neueBreite + 1) / 48) * 48) + 1;
                            }
                            el.find('.z' + zeile).css({
                                height: lastHeight + 'px',
                                width: neueBreite + "px"
                            });
                            if (el.find(".masonry-brick").length > 0) {
                                el.masonry('reload');
                            }
                        }
                    } else {
                        width += $(this).width() + 1;
                        lastHeight = $(this).height();
                        if ((width + 144) > contentWidth) {
                            neueBreite = contentWidth - width - 1;
                            //var last = el.find(".tiles:last-child");
                            if (neueBreite > 0 && neueBreite < (contentWidth - 47)) {
                                if ((neueBreite + 1) % 48 !== 0) {
                                    neueBreite = (Math.floor((neueBreite + 1) / 48) * 48) + 1;
                                }
                                if (append === true) {
                                    var last = $(this).find(".tiles:last-child");
                                    last.after('<div class="tiles sort autofilled z' + zeile + '" style="height:' + lastHeight + 'px;width:' + neueBreite + 'px"><div class="bg dunkelBlau"></div></div>');

                                    if (el.find(".masonry-brick").length > 0) {
                                        el.masonry('reload');
                                    }
                                }
                                if (append === false) {
                                    if (el.find('.z' + zeile).length > 0) {
                                        el.find('.z' + zeile).css({
                                            height: lastHeight + 'px',
                                            width: neueBreite + "px"
                                        });
                                    }
                                }
                            }
                            // el.find('.z'+zeile).find(".bg").text(width+"px");
                            zeile += 1;
                            width = 0;
                        }
                    }
                });

                neueBreite = contentWidth - width - 1;
                if (neueBreite > 0 && neueBreite < (contentWidth - 47)) {
                    if ((neueBreite + 1) % 48 !== 0) {
                        neueBreite = (Math.floor((neueBreite + 1) / 48) * 48) + 1;
                    }
                    if (append === true) {
                        var last = $(this).find(".tiles:last-child");
                        last.after('<div class="tiles sort autofilled z' + zeile + '" style="height:' + lastHeight + 'px;width:' + neueBreite + 'px"><div class="bg dunkelBlau"></div></div>');

                        if (el.find(".masonry-brick").length > 0) {
                            el.masonry('reload');
                        }
                    }
                    if (append === false) {
                        if (el.find('.z' + zeile).length > 0) {
                            el.find('.z' + zeile).css({
                                height: lastHeight + 'px',
                                width: neueBreite + "px"
                            });
                        }
                    }
                }
                //el.find('.z'+zeile).find(".bg").text(width+"px");
                width = 0;
            });
        }
    }
    function updateNavi() {
        setTimeout(function() {
            var url = window.location.href.toString();
            var temp = url.split("http://").join("").split("/");
            var section = temp[1].split(".html").join("");
            var found = false;
            $('#hauptnavigation a').each(function() {
                var temp = $(this).attr("href").split("/");
                var href = temp[1].split(".html").join("");
                if (href === section) {
                    $('#hauptnavigation a,#hauptnavigation li').removeClass("aktiv");
                    $(this).addClass("aktiv");
                    $(this).parent().addClass("aktiv");
                    found = true;
                }
            });
            if (found === false) {
                $('#hauptnavigation a,#hauptnavigation li').removeClass("aktiv");
            }
        }, 0);
    }
    function spaltenSort() {
        //        setTimeout(function(){
        $('body').addClass("ui-loading");
        $('.ui-page-active .container').each(function() {
            if ($(this).find('.sort').length === 0) {
                $(this).find('.spalte').not(':last-child').addClass('sort');
                $(this).find('.spalte:last-child .tiles').addClass('sort');
            }
            $(this).find('.spalte').each(function() {
                var sameClass = $(this).children().not($(this).find(':first-child').attr("class")).length;
                if ($(this).children().length === 1 || sameClass === 0) {
                    $(this).css('width', $(this).find(':first-child').width() + 1);
                }
                if (!$(this).hasClass('.sort') && $(this).find('.sort').length === 0) {
                    $(this).addClass("sort");
                }
                var max = 0;
                var spalteWidth = $(this).width();
                $(this).children().each(function() {
                    if ($(this).width() > spalteWidth) {
                        max = $(this).width() + 1;
                    }
                });
                if (max > 0)
                    $(this).css("width", max);
            });
            //$(this).addClass("animated").addClass("fadeIn");
        });
        $('.sort .sort').parents('.sort').removeClass('sort');
        $('a p > a').each(function() {
            $(this).html($(this).text());
        });
        $('.ui-page-active .container').masonry(masonryoptions);
        $('body').removeClass("ui-loading");
        //        },0);
    }

    function initialLoad() {
        if (alterIE === true) {
            $("a").each(function() {
                $(this).attr("rel", "external");
            });
            $('body').addClass("alterIE");
            $('div[data-role="header"], div[data-role="page"]').css({
                visibility: 'visible'
            });
            //$('#logo img:first-child').hide();
            $('#head').css('margin-top', '60px');
            $('.ui-page-active').css('margin-top', '60px');
        } else {
            var delay = 0;
            if ($('body > .ui-loader').length > 1) {
                $('body > .ui-loader:first').remove();
            }
            $('body').removeClass('ui-loading');
            $('div[data-role="header"], div[data-role="page"]').css({
                visibility: 'visible'
            });

            setTimeout(function() {
                //$('#logo img:first-child').fadeOut(5000);
                $('.ui-page-active .container').css({
                    opacity: "1"
                });
            }, 0);

            $('#content_area .tiles').removeClass("hidden");

            /*          var aniclass = "bounceIn";
             $('#content_area .tiles').each(function(){
             var obj = $(this);
             setTimeout(function(){
             obj.removeClass("hidden").addClass(aniclass);
             },delay);
             
             delay += 100;
             });
             var obj = $('.'+aniclass);
             setTimeout(function(){
             $('#content_area .tiles').removeClass(aniclass);
             },delay);
             */
        }
        /*
         * var options = {
         // options
         itemSelector : '.sort:visible',
         columnWidth : 48,
         isAnimated: !Modernizr.csstransitions, 
         isFluid:true
         };
         $('.spalte').each(function(){
         if($(this).find('.sort').length === 0);
         $(this).addClass("sort");
         });
         $('.ui-page-active .container').masonry(options);
         
         */
    }
    function documentReady() {
        if ($.browser.mozilla) {
            if (parseInt($.browser.version, 10) < 2) {
                $("body").prepend('<a class="stoerer" href="https://getfirefox.com" target="_blank"><div style="background-color:orange;position:fixed;width:100%;z-index:100;color:black;text-align:center;">Schade, wir haben uns mit der neuen Seite so viel Mühe gegeben. Um die neue w+ Seite korrekt dargestellt zu bekommen, benötigen Sie den Firefox 4 oder höher.<br>Hier geht es zu den Downloadseiten von Mozilla.<br>Also dann – bis später. </div></a>');
            }
        }
        if (alterIE === true) {
            $("body").prepend('<a class="stoerer" href="https://www.google.de/search?q=download+internet+explorer" target="_blank"><div style="background-color:orange;position:fixed;width:100%;z-index:100;color:black;text-align:center;">Schade, wir haben uns mit der neuen Seite so viel Mühe gegeben. Um die neue w+ Seite korrekt dargestellt zu bekommen, benötigen Sie den Internet Explorer 9 oder höher.<br>Hier geht es zu den Downloadseiten von Microsoft.<br>Also dann – bis später. </div></a>');
            $('.layout_4_8_8 .spalte').eq(0).addClass("x4");
            $('.layout_4_8_8 .spalte').eq(1).addClass("x8");
            $('.layout_4_8_8 .spalte').eq(2).addClass("x8");
            $('.layout_6_10_4 .spalte').eq(0).addClass("x6");
            $('.layout_6_10_4 .spalte').eq(1).addClass("x10");
            $('.layout_6_10_4 .spalte').eq(2).addClass("x4");

            $('.layout_3_5_6_6 .spalte').eq(0).addClass("x3");
            $('.layout_3_5_6_6 .spalte').eq(1).addClass("x5");
            $('.layout_3_5_6_6 .spalte').eq(2).addClass("x6");
            $('.layout_3_5_6_6 .spalte').eq(3).addClass("x6");

            $('.layout_13_7 .spalte').eq(0).addClass("x13");
            $('.layout_13_7 .spalte').eq(1).addClass("x7");

            $('.layout_3_6_11 .spalte').eq(0).addClass("x3");
            $('.layout_3_6_11 .spalte').eq(1).addClass("x6");
            $('.layout_3_6_11 .spalte').eq(2).addClass("x11");

            $('.layout_12_8 .spalte').eq(0).addClass("x12");
            $('.layout_12_8 .spalte').eq(1).addClass("x8");

            $('.layout_6_6_8 .spalte').eq(0).addClass("x6");
            $('.layout_6_6_8 .spalte').eq(1).addClass("x6");
            $('.layout_6_6_8 .spalte').eq(2).addClass("x8");
            $('.tiles').css('visibility', 'visible');
        }

        masonryoptions = {
            // options
            itemSelector: '.sort:visible',
            columnWidth: 48,
            isAnimated: !Modernizr.csstransitions,
            isFluid: true
        };
        //$('#content_area .tiles').addClass("hidden").addClass('animated');
        $('body').addClass('ui-loading');

        unhideElements();
        backgroundPosition();
    }

    function jqmInit() {
        $.mobile.selectmenu.prototype.options.nativeMenu = true;
        $.mobile.page.prototype.options.keepNative = "select, input.powermail_field, textarea.bar";
        $.extend($.mobile, {
            defaultPageTransition: slide
        });
    }

    function pageChange() {
        //$('.ui-page-active .container.masonry').masonry('reload');
        setTimeout(function() {
            updateNavi();
        }, 0);
        setTimeout(function() {
            $.fancybox.close();
        }, 0);
        setTimeout(function() {
            $('.powermail_form').validationEngine();
        }, 0);
//        setTimeout(function() {
//        }, 0);
        //if( parseInt($.browser.version, 10) == 9 ){
        $('.ui-page-active .container').css({
            'opacity': "1"
        });
        setTimeout(function() {
            autofill($(".ui-page-active #news_top"));
            initAni();
            positionImages();
        }, 0);
        $('div[data-role="page"]').css({
            'visibility': 'visible'
        });
        //}
    }

    function tileOverflow(el) {
        setTimeout(function() {
            if (typeof el === 'undefined' || el.length === 0)
                el = '.ui-page-active #wrapper .tiles .text, .ui-page-active #news_top .landscape_extraLarge .bg,.ui-page-active #news_top .landscape_large .bg,.ui-page-active #news_top .landscape_big .bg';
            $(el).each(function() {
                var totalHeight = 0;
                var height = $(this).height();
                $(this).children().each(function() {
                    if ($(this).css('position') !== "absolute") {
                        totalHeight += $(this).outerHeight(true);
                        var unterkante = $(this).position().top + $(this).outerHeight(true) - parseInt($(this).css('margin-bottom'));
                        if (unterkante > height) {
                            $(this).addClass('hidden');
                        }
                    }
                });

                if (height < totalHeight && $(this).find('.hidden').length > 0) {

                    if ($(this).hasClass('tiles')) {
                        $(this).addClass("zoomable");
                    } else {
                        $(this).parent().addClass("zoomable");
                    }
                    if ($(this).find('.tileMore').length === 0) {

                        $(this).prepend('<div class="tileMore cube_tiny" data-height="' + totalHeight + '"><img src="/fileadmin/system/images/article_more.png" width="47" height="47"></div>');
                    }
                }
            });
        }, 0);
    }

    /* Sobald HTML geladen ist*/
//    $(document).ready(function() {
    documentReady();
//    });

    /* Sobald alles geladen ist */
//    $(window).load(function() {
    initialLoad();
//    });

    $(document).on("pagecreate", function(e) {
        $("input, textarea, select", e.target).attr("data-" + $.mobile.ns + "role", "none");
    });

    $(document).bind("mobileinit", function() {
        jqmInit();
    });

    $(document).on("pagechange", function() {
        pageChange();
    });
    $(document).on("pagehide", function() {
        $('.live-tile').liveTile("destroy");
    });
    $(document).on("pagebeforeshow", function() {
        backgroundPosition();
        spaltenSort();
    });
    $(document).on("pageshow", function() {
        $(document).trigger("pageshow::pb");
        $(document).find('a.lightbox').each(function(index, element) {
            $(element).attr('rel', 'lightboxgroup');
        });
        $('.powermail_form').attr('novalidate', 'novalidate');
        tileOverflow();
        loadGMScript();
        if (window.screen.width > 768) {
            $('a:contains("+49")').each(function() {
                if ($(this).attr("href").indexOf('tel://') !== -1) {
                    var text = $(this).text();
                    $(this).replaceWith(text);
                }
            });
        }
    });
    $(document).on("click", '.ui-page-active .sliderbutton', function() {
        if (!$(this).hasClass('aktiv')) {
            $('.sliderbutton').removeClass('aktiv');
            $(this).addClass('aktiv');
            var idx = $(this).find('a').attr('href').split('#').join('');
            $('.ui-page-active .contentslider.aktiv').hide().removeClass('aktiv');
            $('.ui-page-active .contentslider').eq(idx - 1).show().addClass('aktiv');
            if ($('.ui-page-active .contentslider.aktiv > .text').length > 0) {
                //                $('.contentslider.aktiv > .text').each(function(){
                tileOverflow('.ui-page-active .contentslider.aktiv > .text');
                //                });
            } else {
                if ($('.ui-page-active .contentslider.aktiv img').length > 1) {
                    $('.ui-page-active .contentslider.aktiv .bg > .table > div').not(".init").slidesjs({
                        width: 575,
                        height: 383,
                        pagination: {
                            active: false
                        }
                    });
                    $(".ui-page-active .contentslider.aktiv .bg > .table > div").addClass("init");
                }
            }
            //alert(idx);
        }
    });

    $(document).on('click', ".ui-page-active #wrapper .zoomable", function(e) {
        $('#content_area').css('overflow', 'hidden');

        if (!$(this).hasClass('zoom')) {
            $('#wrapper .close').click();
            e.preventDefault();
            e.stopPropagation();
            var height = $(this).height();
            $('.ui-page-active #wrapper').addClass('grayOut');
            if ($(this).parents(".spalte").length > 0) {
                var links = $(this).parents(".spalte").position().left;
                if (links > 0) {
                    $(this).css("margin-left", -links + "px");
                }
            }
            $(this).addClass("zoom");
            $('#content_area').css('overflow', 'visible');
            var totalHeight = 0;
            $(this).find('.bg').children().each(function() {
                if ($(this).css('position') !== "absolute") {
                    totalHeight += $(this).outerHeight(true);
                    if (($(this).position().top + $(this).outerHeight(true)) > height) {
                        $(this).addClass('hidden');
                    }
                }
            });
            //$(this).css({height:$(this).find('.tileMore').attr('data-height')+'px'});
            if (totalHeight > height) {
                $(this).css({
                    height: totalHeight + 'px'
                });
            }else{
                $(this).css({
                    padding: '0px'
                });
            }
            $(this).find('.tileMore').attr('data-height', height);
            //var offset = $(this).position();
            $(this).find('.tileMore').addClass('close');
            $(this).find('.tileMore').html('<img src="/fileadmin/system/images/article_minus.png" width="47" height="47">');
            //$(this).after('<div class="close cube_tiny" style="top:'+offset.top+'px;right:0px"><a href="#">close</a></div>');
        }
    });
    $(document).on('click', function(event) {
        if ($(event.target).parents('.zoomable').length === 0) {
            $(".zoomable").find('.close').click();
            //$('.ui-page-active #wrapper').removeClass("grayOut");
        }
    });
    $(document).on('click', ".ui-page-active #wrapper .close", function(e) {
        e.stopPropagation();
        $('.ui-page-active #wrapper').removeClass("grayOut");
        $('.zoom').css({
            height: $('.zoom').find('.tileMore').attr('data-height') + 'px'
        });
        $('.zoomable').removeClass('zoom');
        $('.zoomable').css("margin-left", "0");
        $(this).removeClass('close');
        $(this).html('<img src="/fileadmin/system/images/article_more.png" width="47" height="47">');
    });
    $(document).on("submit", ".powermail_form", function(e) {
        e.preventDefault();
    });
    $(window).on("orientationchange", function() {
        unhideElements();
        tileOverflow();
    });

    //    $(document).on("swiperight", function() {
    //        var el = $('#hauptnavigation li.aktiv');
    //        aktindex = el.index();
    //        var href = el.prev('li').find('a').attr("href");
    //        prevPage(href);
    //        el.removeClass('aktiv');
    //        el.prev('li').addClass('aktiv');
    //    });
    //    $(document).on("swipeleft", function() {
    //        aktindex = $('#hauptnavigation li.aktiv').index();
    //        var href = $('#hauptnavigation li.aktiv').next('li').find('a').attr("href");
    //        nextPage(href);
    //    });

    $(document).on("click", "#hauptnavigation a", function(e) {
        if (alterIE !== true) {
            e.preventDefault();
            e.stopPropagation();
            var href = $(this).attr("href");
            var myindex = $(this).parent().index();
            var aktindex = $('#hauptnavigation li.aktiv').index();

            $('#hauptnavigation li.aktiv').removeClass('aktiv');
            if (myindex < aktindex) {
                prevPage(href);
            } else {
                if (myindex === aktindex) {
                    $.mobile.changePage(href);
                } else {
                    nextPage(href);
                }
            }
            $(this).parent().addClass('aktiv');
        }

    });

    $(document).on("click", "#logo a", function(e) {
        //if(alterIE == true) window.location.href = $(this).attr("href");

        $('#hauptnavigation li.aktiv').removeClass('aktiv');
        $('#hauptnavigation li:first-child').addClass('aktiv');
    });

    $(document).on("hover", ".tiles.slideup", function(e) {
        if (e.type === "mouseenter") {
            var offset = $(this).find('.hover').height();
            $(this).find('.normal').stop().animate({
                "margin-top": "-" + offset + 'px'
            }, "fast", "linear");
        } else {
            $(this).find('.normal').stop().animate({
                "margin-top": '0px'
            }, "fast", "linear");
        }
    });
//    if(alterIE == true){
//        $(document).on("click", "body > div a", function(e){
//            if( $(this).hasClass(".stoerer") ){
//                e.stopPropagation();
//                e.preventDefault();
//            }else{
//                window.location.href = $(this).attr("href");
//            }
//        });
//    }
    $(window).on("resize", function() {
        unhideElements();
        tileOverflow();
        positionImages();
        spaltenSort();
        autofillTimeout = setTimeout(function() {
            autofill($(".ui-page-active #news_top"));
        }, 700);
    });
    $(document).on("change", ".menu_level2 select", function() {
        var href = $(this).val();
        if (alterIE !== true) {
            if (href.indexOf('pagebrowser') !== -1)
                return;
            $.mobile.changePage(href);
            autofill($(".ui-page-active #news_top"));
        }
    });
})(jQuery);
