/* Minification failed. Returning unminified contents.
(4259,11-12): run-time error JS1010: Expected identifier: .
(4259,11-12): run-time error JS1195: Expected expression: .
(6437,76-77): run-time error JS1010: Expected identifier: .
(6437,76-77): run-time error JS1195: Expected expression: .
(6437,89-93): run-time error JS1034: Unmatched 'else'; no 'if' defined: else
 */
/*! modernizr 3.0.0 (Custom Build) | MIT *
 * http://modernizr.com/download/?-touchevents !*/
!function(e,n,t){function o(e,n){return typeof e===n}function s(){var e,n,t,s,a,i,r;for(var l in c){if(e=[],n=c[l],n.name&&(e.push(n.name.toLowerCase()),n.options&&n.options.aliases&&n.options.aliases.length))for(t=0;t<n.options.aliases.length;t++)e.push(n.options.aliases[t].toLowerCase());for(s=o(n.fn,"function")?n.fn():n.fn,a=0;a<e.length;a++)i=e[a],r=i.split("."),1===r.length?Modernizr[r[0]]=s:(!Modernizr[r[0]]||Modernizr[r[0]]instanceof Boolean||(Modernizr[r[0]]=new Boolean(Modernizr[r[0]])),Modernizr[r[0]][r[1]]=s),f.push((s?"":"no-")+r.join("-"))}}function a(e){var n=u.className,t=Modernizr._config.classPrefix||"";if(h&&(n=n.baseVal),Modernizr._config.enableJSClass){var o=new RegExp("(^|\\s)"+t+"no-js(\\s|$)");n=n.replace(o,"$1"+t+"js$2")}Modernizr._config.enableClasses&&(n+=" "+t+e.join(" "+t),h?u.className.baseVal=n:u.className=n)}function i(){return"function"!=typeof n.createElement?n.createElement(arguments[0]):h?n.createElementNS.call(n,"http://www.w3.org/2000/svg",arguments[0]):n.createElement.apply(n,arguments)}function r(){var e=n.body;return e||(e=i(h?"svg":"body"),e.fake=!0),e}function l(e,t,o,s){var a,l,f,c,d="modernizr",p=i("div"),h=r();if(parseInt(o,10))for(;o--;)f=i("div"),f.id=s?s[o]:d+(o+1),p.appendChild(f);return a=i("style"),a.type="text/css",a.id="s"+d,(h.fake?h:p).appendChild(a),h.appendChild(p),a.styleSheet?a.styleSheet.cssText=e:a.appendChild(n.createTextNode(e)),p.id=d,h.fake&&(h.style.background="",h.style.overflow="hidden",c=u.style.overflow,u.style.overflow="hidden",u.appendChild(h)),l=t(p,e),h.fake?(h.parentNode.removeChild(h),u.style.overflow=c,u.offsetHeight):p.parentNode.removeChild(p),!!l}var f=[],c=[],d={_version:"3.0.0",_config:{classPrefix:"",enableClasses:!0,enableJSClass:!0,usePrefixes:!0},_q:[],on:function(e,n){var t=this;setTimeout(function(){n(t[e])},0)},addTest:function(e,n,t){c.push({name:e,fn:n,options:t})},addAsyncTest:function(e){c.push({name:null,fn:e})}},Modernizr=function(){};Modernizr.prototype=d,Modernizr=new Modernizr;var u=n.documentElement,p=d._config.usePrefixes?" -webkit- -moz- -o- -ms- ".split(" "):[];d._prefixes=p;var h="svg"===u.nodeName.toLowerCase(),m=d.testStyles=l;Modernizr.addTest("touchevents",function(){var t;if("ontouchstart"in e||e.DocumentTouch&&n instanceof DocumentTouch)t=!0;else{var o=["@media (",p.join("touch-enabled),("),"heartz",")","{#modernizr{top:9px;position:absolute}}"].join("");m(o,function(e){t=9===e.offsetTop})}return t}),s(),a(f),delete d.addTest,delete d.addAsyncTest;for(var v=0;v<Modernizr._q.length;v++)Modernizr._q[v]();e.Modernizr=Modernizr}(window,document);;

var Utils = (function () {
	return {
		setCookie: function (name, value, expires, path, domain, secure, sameSite) {
			var today = new Date();
			today.setTime(today.getTime());

			if (expires) {
				//calculate by day
				expires = expires * 86400000;
			}

			var expires_date = new Date(today.getTime() + (expires));

			document.cookie = name + "=" + escape(value) +
				((expires) ? ";expires=" + expires_date.toGMTString() : "") +
				((path) ? ";path=" + path : "") +
				((domain) ? ";domain=" + domain : "") +
				((secure) ? ";secure" : "") +
				((sameSite) ? ";SameSite=" + sameSite : ";SameSite=Lax");
		},
		insertCookie: function (name, value, expires, path, domain, secure) {
			var today = new Date();
			today.setTime(today.getTime());

			if (expires) {
				//calculate by day
				expires = expires * 86400000;
			}

			var expires_date = new Date(today.getTime() + (expires));

			value = Utils.getCookie(name) + "," + value;

			document.cookie = name + "=" + escape(value) +
				((expires) ? ";expires=" + expires_date.toGMTString() : "") +
				((path) ? ";path=" + path : "") +
				((domain) ? ";domain=" + domain : "") +
				((secure) ? ";secure" : "");
		},
		insertCookieHourly: function (name, value, expires, path, domain, secure) {
			var today = new Date();
			today.setTime(today.getTime());

			if (expires) {
				//calculate by hour
				expires = expires * 3600000;
			}

			var expires_date = new Date(today.getTime() + (expires));

			value = Utils.getCookie(name) + "," + value;

			document.cookie = name + "=" + escape(value) +
				((expires) ? ";expires=" + expires_date.toGMTString() : "") +
				((path) ? ";path=" + path : "") +
				((domain) ? ";domain=" + domain : "") +
				((secure) ? ";secure" : "");
		},
		getCookie: function (cookieName) {
			var theCookie = "" + document.cookie;
			var ind = theCookie.indexOf(cookieName);
			if (ind == -1 || cookieName == "") return "";
			var ind1 = theCookie.indexOf(';', ind);
			if (ind1 == -1) ind1 = theCookie.length;
			return unescape(theCookie.substring(ind + cookieName.length + 1, ind1));
		},
		deleteCookie: function(cookieName){
			if (Utils.getCookie(cookieName)) {
				document.cookie = cookieName + "=" +
					";path=/;expires=Thu, 01 Jan 1970 00:00:01 GMT";
			}
		},
		loader: function (obj) {
			$(obj).html("<img src='/content/images/loading.gif' width='40px' height='40px' />");
		},
		hideLoader: function (obj){
			$(obj).html("");
		},
		preLoadCarouselImages: function (obj) {
			for (var i = 0; i < obj.length; i++) {
				//$("<img />").attr("src", obj[i].url + ".axd?preset=leftlargesquare");
				//$("<img />").attr("src", obj[i].url + ".axd?preset=rightlargesquare");

				var img = new Image(); //new img obj
				img.src = obj[i].url + ".axd?preset=leftlargesquare"; //set src either absolute or rel to css dir
			}
		},
		getQueryStringParam: function (key) {
			key = key.replace(/[*+?^$.\[\]{}()|\\\/]/g, "\\$&"); // escape RegEx meta chars
			var match = location.search.match(new RegExp("[?&]" + key + "=([^&]+)(&|$)"));
			return match && decodeURIComponent(match[1].replace(/\+/g, " "));
		},
		escapeRegExp: function (str) {
			return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
		},
		replaceAll: function (str, find, replace) {
			return str.replace(new RegExp(Utils.escapeRegExp(find), 'g'), replace);
		}
	}
})();

var GeoLocation = (function () {
	var clientLatitude = Utils.getCookie("clientlat");
	var clientLongitude = Utils.getCookie("clientlng");

	return {
		init: function () {
			if (clientLatitude == "" && clientLongitude == "") {

				if (typeof (navigator.geolocation) !== 'undefined') {
					// One-shot position request.
					navigator.geolocation.getCurrentPosition(this.setLocation);
				} else {
					console.log("Unable to determine position");
				}
			}

			return this;
		},
		setLocation: function (position) {
			if (clientLatitude == "" && clientLongitude == "") {
				Utils.loader("#nearby-list");

				//save in cookie
				Utils.setCookie("clientlat", position.coords.latitude, 365, "/", null, false);
				Utils.setCookie("clientlng", position.coords.longitude, 365, "/", null, false);

				$("#nearby-list").nearbycampgrounds({ clientlat: position.coords.latitude, clientlng: position.coords.longitude });
			}
		}
	}
})();

var ChangeLocation = (function () {
	var onClick = function () {

		var form = $(this).data("changelocation").options.form

		$.ajax({
			url: "/nearby/NearbyForm/",
			context: $(form),
			success: function (html) {
				$(this).html(html);

				$("#nearby-form").findnearbycampgrounds({ container: form });
			}
		});

	};

	return {
		init: function (options, elem) {
			// Mix in the passed in options with the default options
			this.options = $.extend({}, this.options, options);

			// Save the element reference, both as a jQuery
			// reference and a normal reference
			this.elem = elem;
			this.$elem = $(elem);

			this.$elem.click(onClick);

			return this;
		},
		options: {
			form: null
		}
	}
})();

var FindNearbyCampgrounds = (function () {
	var onSubmit = function (event) {
		/* stop form from submitting normally */
		event.preventDefault();

		var container = $(this).data("findnearbycampgrounds").options.container;

		/* get some values from elements on the page: */
		var $form = $(this),
			formlocation = $form.find('input[name=location]').val(),
			formredirecturl = $form.find('input[name=redirecturl]').val(),
			action = $form.attr('action');

		$.ajax({
			url: action,
			type: "POST",
			data: { location: formlocation, redirecturl: formredirecturl },
			beforeSend: function () {
				//setup the loading image
				Utils.loader(container);
			},
			success: function (html) {
				$(container).html(html);

				$("#change-location").changelocation({ form: "#nearby-list" });
				$("#nearby-form").findnearbycampgrounds({ container: container });

				//Update the Find A Koa link in the nav
				FindAKOA.setLocationLink("#btn-nav-find-koa");

				//Update the hot deals for this new location
				$.ajax({
					url: "/hot-deals/hotdealsnearby",
					type: "POST",
					data: { location: formlocation, redirecturl: formredirecturl },
					success: function (html) {
						$("#hd-list").html(html);
					},
					error: function () {
						//console.log("error");
					}
				});
			},
			error: function () {
				//console.log("error");
			}
		});
	};

	return {
		init: function (options, elem) {
			// Mix in the passed in options with the default options
			this.options = $.extend({}, this.options, options);

			// Save the element reference, both as a jQuery
			// reference and a normal reference
			this.elem = elem;
			this.$elem = $(elem);

			this.$elem.submit(onSubmit);

			return this;
		},
		options: {
			container: null
		}
	}
})();

var NearbyCampgrounds = (function () {
	return {
		init: function (options, elem) {
			//console.log("nearbycampgrounds");
			// Mix in the passed in options with the default options
			this.options = $.extend({}, this.options, options);

			// Save the element reference, both as a jQuery
			// reference and a normal reference
			this.elem = elem;
			this.$elem = $(elem);

			if (this.options.clientlat != null && this.options.clientlng != null) {
				Utils.loader("#nearby-list");

				$.ajax({
					url: "/nearby/GetNearbyCampgrounds/",
					data: "dLatitude=" + this.options.clientlat + "dLongitude" + this.options.clientlng,
					context: this.$elem,
					success: function (html) {
						$(this).html(html);
						$("#change-location").changelocation({ form: "#nearby-list" });
					}
				});
			}

			return this;
		},
		options: {
			clientlat: null,
			clientlng: null
		}
	}
})();

var Vkr = (function () {
	var onSubmit = function (event) {
		/* stop form from submitting normally */
		event.preventDefault();

		var success = false;

		var formcontainer = $(this).data("vkr").options.container;
		var loadingcontainer = $(this).data("vkr").options.loading;

		/* get some values from elements on the page: */
		var $form = $(this),
			formlogin = $form.find("input[name=Login]").val(),
			formpassword = $form.find("input[name=Password]").val(),
			formreturnurl = $form.find("input[name=ReturnUrl]").val(),
			action = $form.attr('action');

		$.ajax({
			url: action,
			type: "POST",
			data: { Login: formlogin, Password: formpassword, ReturnUrl: formreturnurl },
			beforeSend: function () {
				$(loadingcontainer).css("text-align", "center");
				//setup the loading image
				Utils.loader(loadingcontainer);
			},
			success: function (html) {
				$(formcontainer).html(html);
				$("#" + $form.attr("id")).vkr({ container: formcontainer, loading: loadingcontainer });
			},
			error: function (data) {

			},
			complete: function (data) {
				LoadCof();
			}
		});
	}
	return {

		init: function (options, elem) {
			// Mix in the passed in options with the default options
			this.options = $.extend({}, this.options, options);

			// Save the element reference, both as a jQuery
			// reference and a normal reference
			this.elem = elem;
			this.$elem = $(elem);

			this.$elem.submit(onSubmit);

			return this;
		},
		options: {
			container: null,
			loading: null
		}
	}
})();

var FindAKOA = (function () {
	var onSubmit = function (event) {
		/* stop form from submitting normally */
		event.preventDefault();

		/* get some values from elements on the page: */
		var $form = $(this),
			formquery = $form.find("input[name=q]").val(),
			action = $form.attr('action');

		if (action == '/search/' && (formquery.indexOf('KOA') > 0 || formquery.indexOf('koa') > 0)) {
			window.location.href = action + '?txtLocation=' + formquery;
		} else {
			window.location.href = '/find-a-koa/?s=ext#' + encodeURIComponent('{"map":{"search":"' + formquery + '"}}');

			if ($('#results-map').length > 0) {
				// Reload the page if we are on the map page
				window.location.reload();
			}

			window.location.href = '/find-a-koa/?s=ext#' + encodeURIComponent('{"map":{"search":"' + formquery + '"}}');
		}
	}

	return {
		init: function (options, elem) {
			// Mix in the passed in options with the default options
			this.options = $.extend({}, this.options, options);

			// Save the element reference, both as a jQuery
			// reference and a normal reference
			this.elem = elem;
			this.$elem = $(elem);

			this.$elem.submit(onSubmit);

			return this;
		},
		setLocationLink: function (elem) {
			if (Utils.getCookie("clientlocation") != "") {
				$(elem).attr("href", '/find-a-koa/#' + encodeURIComponent('{"map":{"search":"' + Utils.getCookie("clientlocation") + '"}}'));
			}
		},
		options: null
	}
})();

var FindStatesProvinces = (function () {
	var onClick = function (event) {
		/* stop form from submitting normally */
		//event.preventDefault();

		var stateProvince = $(this).attr("class");

		if (stateProvince.indexOf("link-map-us") != -1) {
			//save in cookie
			Utils.setCookie("koamap", "us", 10, "/", null, false);
		}

		if (stateProvince.indexOf("link-map-ca") != -1) {
			//save in cookie
			Utils.setCookie("koamap", "ca", 10, "/", null, false);
		}
	}

	return {
		init: function (options, elem) {
			// Mix in the passed in options with the default options
			this.options = $.extend({}, this.options, options);

			// Save the element reference, both as a jQuery
			// reference and a normal reference
			this.elem = elem;
			this.$elem = $(elem);

			this.$elem.click(onClick);

			return this;
		},
		options: null
	}
})();

var Kompass = (function () {
	$(document).ready(function () {
		$('#KompassCountry').on("change", function () {
			var country = $(this).val();
			switch (country) {
				case 'United States':
				case 'Canada':
					$('#statesDiv').removeClass('d-none');
					break;
				default:
					$('#statesDiv').addClass('d-none');
					break;
			}
		});
		if ($('form#form-kompass').length > 0) {
			$('form#form-kompass').each(function (index, value) {
				KompassValidation(value, index);
			});
		}
		else if ($('form#form-kompass').length > 0) {
			KompassValidation($('form#form-kompass'));
		}
	});

	function KompassValidation(kompassForm, index) {
		if (!index) {
			index = 0;
		}
		$(kompassForm).validate({
			messages: {
				KompassEmailAddress: {
					required: "A valid Email Address is required",
					email: "A valid Email Address is required"
				},
				KompassFirstName: {
					required: "A valid First Name is required",
				},
				KompassLastName: {
					required: "A valid Last Name is required",
				},
				KompassCountry: {
					required: "A Country selection is required",
				},
				KompassStateProvince: {
					required: "A State/Province selection is required",
				}
			},
			errorLabelContainer: 'form#form-kompass:eq(' + index + ') .validation-summary-errors #error-list',
			errorClass: 'input-validation-error',
			wrapper: 'li',
			onkeyup: false,
			onfocusout: false,
			invalidHandler: function (event, validator) {
				$('form#form-kompass:eq(' + index + ') .validation-summary-errors').show();
			},
			submitHandler: function (form) {
				$('form#form-kompass:eq(' + index + ') .validation-summary-errors').hide();
				$('form#form-kompass:eq(' + index + ')').submit();
			}
		});
	}
})();

// Make sure Object.create is available in the browser (for our prototypal inheritance)
// Courtesy of Papa Crockford
// Note this is not entirely equal to native Object.create, but compatible with our use-case
if (typeof Object.create !== 'function') {
	Object.create = function (o) {
		function F() { } // optionally move this outside the declaration and into a closure if you need more speed.
		F.prototype = o;
		return new F();
	};
}
(function ($) {
	$.plugin = function (name, object) {
		$.fn[name] = function (options) {
			return this.each(function () {
				if (!$.data(this, name)) {
					$.data(this, name, Object.create(object).init(options, this));
				}
			});

		};
	};
})(jQuery);

$.fn.customCheckbox = function (settings) {
	// Add a click listener to the label
	$('label' + this.selector).click(function (e) {
		e.stopPropagation();
	});

	// Add change listener to the input
	$('input' + this.selector).change(function (e) {
		var $this = $(this);
		var $label = $('label[for="' + $this.attr('id') + '"] > span');

		if ($this.is(':checked')) {
			$label.addClass('checked');
		}
		else {
			$label.removeClass('checked');
		}
	});

	return this;
};

$(function () {
	//load the plugins
	$.plugin("changelocation", ChangeLocation);
	$.plugin("nearbycampgrounds", NearbyCampgrounds);
	$.plugin("findnearbycampgrounds", FindNearbyCampgrounds);
	$.plugin("findakoa", FindAKOA);
	$.plugin("findstatesprovinces", FindStatesProvinces);
	$.plugin("kompass", Kompass);

	$("#change-location").changelocation({ form: "#nearby-list" });
	$("#nearby-form").findnearbycampgrounds({ container: "#nearby-list" });
	$("#form-find-a-koa, #form-nav-find-a-koa").findakoa();
	$(".link-map-us, .link-map-ca").findstatesprovinces();
});

$(document).ready(function () {

	FindAKOA.setLocationLink("#btn-nav-find-koa");

	LoadReadMore();

	// Main Menu
	$('.mainMenu .dropdown-toggle').on('click mouseover mouseleave', function (e) {
		var position = $('.mainMenu .collapse').position();
		var width = $('.mainMenu .collapse').css("width");
		$(this).next('.main-menu-container').css("left", position.left + "px").css("width", width);

		var currentPosition = $(this).offset();
		var currentWidth = $(this).css("width").replace("px", "");
		$(this).next('.main-menu-container').find(".indicator").css("left", (currentPosition.left - position.left - 10) + parseInt(currentWidth) / 2 + "px");

		if (e.type == "click") {
			$('.mainMenu .dropdown-toggle .fa-caret-up').removeClass('fa-caret-up').addClass('fa-caret-down');
			if ($(this).attr("aria-expanded") != "true") {
				$(this).children('.main-menu-caret').removeClass('fa-caret-down').addClass('fa-caret-up');
				// TODO: Still need to adjust a little bit for using tab/enter on the home page of the site
				$(this).parent().on('hidden.bs.dropdown', function () {
					if ($(this).children('.dropdown-toggle').attr("aria-expanded") != "true") {
						if ($(this).children('.dropdown-toggle').children('.main-menu-caret').hasClass('fa-caret-up')) {
							$(this).children('.dropdown-toggle').children('.main-menu-caret').removeClass('fa-caret-up').addClass('fa-caret-down');
						}
						$(this).off('hidden.bs.dropdown');
					}
				});
			}
		}

		if (e.type == "mouseleave") {
			if ($(this).attr("aria-expanded") != "true") {
				if ($(this).children('.main-menu-caret').hasClass('fa-caret-up')) {
					$(this).children('.main-menu-caret').removeClass('fa-caret-up').addClass('fa-caret-down');
				}
			}
			else {
				// TODO: Still need to adjust a little bit for using tab/enter on the home page of the site
				$(this).parent().on('hidden.bs.dropdown', function () {
					if ($(this).children('.dropdown-toggle').attr("aria-expanded") != "true") {
						if ($(this).children('.dropdown-toggle').children('.main-menu-caret').hasClass('fa-caret-up')) {
							$(this).children('.dropdown-toggle').children('.main-menu-caret').removeClass('fa-caret-up').addClass('fa-caret-down');
						}
						$(this).off('hidden.bs.dropdown');
					}
				});
			}
		}
	});

	// Top Menu
	$(".sharedMenu .dropdown-toggle").on("click mouseover mouseleave", function (e) {
		var currentPosition = $(this).offset();
		var navbarPosition = $('.sharedMenu').offset();
		var left = navbarPosition.left - currentPosition.left;
		var width = $(".sharedMenu").css("width").replace("px", "");

		if ($(this).hasClass("last")) {
			$(this).next('.topMenuContainer').css("left", left + "px").css("width", parseInt(width) + 15);
		} else if ($(this).hasClass("app")) {
			$(this).next('.topMenuContainer').css("left", -190 + "px").css("width", parseInt(width) + 110);
		} else {
			$(this).next('.topMenuContainer').css("left", -150 + "px").css("width", parseInt(width) + 110);
		}

		$('.sharedMenu .dropdown-toggle .fa-caret-up').each(function (index, item) {
			if ($(item).parent('a').siblings('.dropdown-menu').css("display") == "none") {
				$(item).removeClass('fa-caret-up').addClass('fa-caret-down');
			}
		});
		if ($(this).siblings('.dropdown-menu').css("display") != "none") {
			$(this).children('.shared-menu-caret').removeClass('fa-caret-down').addClass('fa-caret-up');
		}

		if (e.type == "mouseleave") {
			if ($(this).siblings('.dropdown-menu').css("display") == "none") {
				if ($(this).children('.shared-menu-caret').hasClass('fa-caret-up')) {
					$(this).children('.shared-menu-caret').removeClass('fa-caret-up').addClass('fa-caret-down');
				}
			}
			else {
				$(this).parent().on('hide.bs.dropdown hidden.bs.dropdown', function () {
					if ($(this).children('.dropdown-menu').css("display") == "none") {
						if ($(this).children('.dropdown-toggle').children('.shared-menu-caret').hasClass('fa-caret-up')) {
							$(this).children('.dropdown-toggle').children('.shared-menu-caret').removeClass('fa-caret-up').addClass('fa-caret-down');
						}
						$(this).off('hide.bs.dropdown hidden.bs.dropdown');
					}
				});
			}
		}
	});

	$(document).keyup(function (e) {
		if (e.keyCode == 27) {
			var activeMenu = $(".sharedMenu .dropdown.open");
			if (activeMenu.length > 0) {
				$(activeMenu[0]).removeClass('open');
				$(activeMenu[0]).children('a').prop('aria-expanded', 'false');
				activeMenu = $(activeMenu[0]).children('.topMenuContainer');
			} else {
				activeMenu = $(".sharedMenu .dropdown:hover .topMenuContainer");
			}
			if (activeMenu.length > 0) {
				$(activeMenu[0]).css('display', 'none');
				$(activeMenu[0]).parent().on('mouseleave mouseenter', function () {
					$(this).children('.topMenuContainer').css('display', '');
					$(this).off('mouseleave mouseenter');
				});
			}
		}
	});

	$('#homeCarousel').on('slide.bs.carousel', function () {
		$('.caption').hide();
	});
	$('#homeCarousel').on('slid.bs.carousel', function () {
		$('.caption').show();
	});

	$('.prettySocial').prettySocial();

	$('.modal-iframe-fb').click(function (e) {
		e.preventDefault();

		var locationHref = $(this).attr('href'),

			//append popup=true if it's not already on the url, since this is a modal
			separator = (locationHref.indexOf("?") === -1) ? "?" : "&",
			newParam = separator + "popup=true";

		//deal with duplicate parameters
		newUrl = locationHref.replace(newParam, "");
		newUrl += newParam;
		locationHref = newUrl;

		$.fancybox.open({
			src: locationHref,
			type: 'iframe',

			toolbar: false,
			smallBtn: false,

			buttons: [],

			opts: {
				preload: false,
				afterShow: function (instance, current) {

					//add universal close button if it does not exist
					if ($(".fancybox-content [data-fancybox-close]").length === 0) {
						$(".fancybox-content").append("<div class='mr-1 mt-1'><button data-fancybox-close class='close' title='Close'><i class='fas fa-window-close'</i></button></div>");
					}

					if ($('.fancybox-content [data-fancybox-close]').attr("onClick") === undefined) {
						//wire up the custom close button
						$('.fancybox-content [data-fancybox-close]').on('click', function () {
							parent.jQuery.fancybox.getInstance().close();
						});
					}

					//hide the default button for now
					$(".fancybox-button--close").hide();
				}
			}
		});
	});

	var scrollTopPosition = 0;
	var lastKnownScrollTopPosition = 0;

	$('.modal-iframe-selectsite').click(function (e) {

		var isMobile = window.matchMedia("only screen and (max-width: 760px)");

		//if mobile - ignore - open full screen, otherwise open in a popup
		if (!isMobile.matches) {
			e.preventDefault();

			var title = $(this).attr('title');
			var locationHref = $(this).attr('href');

			//append popup=true
			locationHref += "&popup=true";

			$('#modal-window-iframe-extra-large').modal({ show: true });

			$('#modal-window-iframe-extra-large').on('shown.bs.modal', function () {
				var modal = $(this);
				modal.find('iframe').attr("src", locationHref);
			});
			$('#modal-window-iframe-extra-large').on('hidden.bs.modal', function (e) {
				//clear the iframe url, so it does not show on the next load
				var modal = $(this);
				modal.find('iframe').attr("src", '/content/images/1px_trans.png');
			});
		}
	});

	$('.modal-iframe-availability').click(function (e) {

		var isMobile = window.matchMedia("only screen and (max-width: 760px)");

		//if mobile - ignore - open full screen, otherwise open in a popup
		if (!isMobile.matches) {
			e.preventDefault();

			var title = $(this).attr('title');
			var locationHref = $(this).attr('href');

			//append popup=true
			locationHref += "&popup=true";

			if (typeof title !== typeof undefined && title !== false) {
				$('#modal-window-iframe-lg-title').text(title);
			}
			else {
				$('#modal-window-iframe-lg-title').text("");
			}

			$('#modal-window-iframe-lg').modal({ show: true });

			$('#modal-window-iframe-lg').on('shown.bs.modal', function () {
				var modal = $(this);
				modal.find('iframe').attr("src", locationHref);
			});
			$('#modal-window-iframe-lg').on('hidden.bs.modal', function (e) {
				//clear the iframe url, so it does not show on the next load
				var modal = $(this);
				modal.find('iframe').attr("src", '/content/images/1px_trans.png');
			});
		}
	});

	$('.modal-iframe').click(function (e) {
		e.preventDefault();

		var width = $(this).data('width');
		var scrolling = $(this).attr('data-scroll');
		var popup = $(this).attr('data-popup');
		var sitetypeHref = $(this).attr('href');
		var title = $(this).attr('title');

		if (typeof title !== typeof undefined && title !== false) {
			$('#modal-window-iframe-title').text(title);
		}
		else {
			$('#modal-window-iframe-title').text("");
		}
		// This locationHref is being used by trip planner to pass in the json string with the trip data
		var dataHref = $(this).attr('data-href');
		var locationHref = dataHref == "true" ? window.location.hash.replace(/^[^#]*#?(.*)$/, '$1') : "";
		var targetOffsetTop = $(this).offset().top;
		if (scrolling) {
			$('#modal-window-iframe-scroll').on('show.bs.modal', function () {
				var modal = $(this);
				if (popup == "true") {
					sitetypeHref = sitetypeHref + "?popup=true";
				}
				modal.find("iframe").attr("src", sitetypeHref);
				if (width) {
					modal.find(".modal-dialog").css("width", width + "px");
				}
				enquire.register("screen and (max-width:768px)", {
					match: function () {
						modal.find(".modal-dialog").css("margin-top", targetOffsetTop + "px");
					},
					unmatch: function () {
						modal.find(".modal-dialog").css("margin-top", "auto");
					}
				});
			});
			$("#modal-window-iframe-scroll").modal({ show: true });
		} else {

			$('#modal-window-iframe').on('show.bs.modal', function (event) {
				var modal = $(this);
				if (width) {
					modal.find(".modal-dialog").css("width", width + "px");
				}
			});
			$('#modal-window-iframe').on('shown.bs.modal', function () {
				var modal = $(this);
				if (locationHref != "") {
					sitetypeHref = sitetypeHref + "&sTripData=" + locationHref;
				}
				modal.find('iframe').attr("src", sitetypeHref);
			});
			$('#modal-window-iframe').on('hidden.bs.modal', function (e) {
				//clear the iframe url, so it does not show on the next load
				var modal = $(this);
				modal.find('iframe').attr("src", '/content/images/1px_trans.png');
			});

			$('#modal-window-iframe').modal({ show: true });
		}
		width = null;
	});

	$('.btn-sitetype-view-rates').on('click', function (e) {
		e.preventDefault();

		var title = $(this).attr('title');
		var locationHref = $(this).attr('href');

		//append popup=true
		locationHref += "&popup=true";

		$('#modal-window-iframe-extra-large').modal({ show: true });

		$('#modal-window-iframe-extra-large').on('shown.bs.modal', function () {
			var modal = $(this);
			modal.find('iframe').attr("src", locationHref);
		});
		$('#modal-window-iframe-extra-large').on('hidden.bs.modal', function (e) {
			//clear the iframe url, so it does not show on the next load
			var modal = $(this);
			modal.find('iframe').attr("src", '/content/images/1px_trans.png');
		});
	});

	$('.modal-iframe-lg').click(function (e) {
		e.preventDefault();
		var srcHref = $(this).attr('href');
		var title = $(this).attr('title');
		var popup = $(this).attr('data-popup');

		// This locationHref is being used by trip planner to pass in the json string with the trip data
		var dataHref = $(this).attr('data-href');
		var locationHref = dataHref == "true" ? window.location.hash.replace(/^[^#]*#?(.*)$/, '$1') : "";

		//display the title if it was included
		if (typeof title !== typeof undefined && title !== false) {
			$('#modal-window-iframe-lg-title').text(title);
		}
		else {
			$('#modal-window-iframe-lg-title').text("");
		}

		$('#modal-window-iframe-lg').on('shown.bs.modal', function () {
			var modal = $(this);
			if (popup == "true") {
				srcHref = srcHref + "?popup=true";
			}
			if (locationHref != "") {
				srcHref = srcHref + "&sTripData=" + locationHref;
			}
			modal.find('iframe').attr("src", srcHref);
		});

		$('#modal-window-iframe-lg').on('hidden.bs.modal', function (e) {
			//clear the iframe url, so it does not show on the next load
			var modal = $(this);
			modal.find('iframe').attr("src", '/content/images/1px_trans.png');
		});

		$('#modal-window-iframe-lg').modal({ show: true });

	});

	$('.modal-iframe-xl').click(function (e) {
		e.preventDefault();
		var srcHref = $(this).attr('href');
		var title = $(this).attr('title');
		var popup = $(this).attr('data-popup');

		// This locationHref is being used by trip planner to pass in the json string with the trip data
		var dataHref = $(this).attr('data-href');
		var locationHref = dataHref == "true" ? window.location.hash.replace(/^[^#]*#?(.*)$/, '$1') : "";

		//display the title if it was included
		if (typeof title !== typeof undefined && title !== false) {
			$('#modal-window-iframe-xl-title').text(title);
		}
		else {
			$('#modal-window-iframe-xl-title').text("");
		}

		$('#modal-window-iframe-xl').on('shown.bs.modal', function () {
			var modal = $(this);
			if (popup == "true") {
				srcHref = srcHref + "?popup=true";
			}
			if (locationHref != "") {
				srcHref = srcHref + "&sTripData=" + locationHref;
			}
			modal.find('iframe').attr("src", srcHref);
		});

		$('#modal-window-iframe-xl').on('hidden.bs.modal', function (e) {
			//clear the iframe url, so it does not show on the next load
			var modal = $(this);
			modal.find('iframe').attr("src", '/content/images/1px_trans.png');
		});

		$('#modal-window-iframe-xl').modal({ show: true });

	});

	$("#modal-window").on('hidden.bs.modal', function () {
		$("#modal-window .modal-content").empty();
	});
	$("#modal-window-iframe, #modal-window-iframe-scroll").on('hidden.bs.modal', function () {
		var iFrame = $(this).find("iframe");
		iFrame.attr("src", "");
	});

	$('.modal-iframe-youtube').click(function (e) {
		e.preventDefault();
		var sitetypeHref = $(this).attr('href');
		var sitetypeHrefAuto = sitetypeHref + "?autoplay=1&rel=0"
		$('#modal-window-iframe-youtube').on('shown.bs.modal', function () {
			var iFrame = $(this).find("iframe");
			iFrame.attr("src", sitetypeHrefAuto);
		});
		$("#modal-window-iframe-youtube").on('hidden.bs.modal', function () {
			var iFrame = $(this).find("iframe");
			iFrame.attr("src", sitetypeHref);
		});
		$('#modal-window-iframe-youtube').modal({ show: true });
	});

	// If this platform accepts touch events, don't fix the menu's at the top. Allow scrolling.
	if ((("ontouchstart" in document.documentElement) || $("html").hasClass("touchevents")) && $('#smartbanner').length) {
		$(".topMenu, .mainMenu, .background, .clpMainMenu").addClass("touch");
	}

	$.ajaxSetup({ cache: true });
	$.getScript('//connect.facebook.net/en_US/sdk.js', function () {
		FB.init({
			appId: '1685564315011866', //koa.com
			version: 'v3.3'
		});
	});

	$("a.fb-share").on("click", function (e) {
		e.preventDefault();
		$this = $(this);
		// gather link info
		var link = {
			url: $this.data('url') || '',
			title: $this.data('title') || '',
			description: $this.data('description') || '',
			media: $this.data('media') || ''
		};
		var ogObject = {};
		if (link.width != '' && link.height != '') {
			ogObject = {
				'og:url': link.url,
				'og:title': link.title,
				'og:description': link.description,
				'og:image': link.media
			};
		} else {
			ogObject = {
				'og:url': link.url,
				'og:title': link.title,
				'og:description': link.description,
				'og:image': link.media
			};
		}
		if (!$.isEmptyObject(FB)) {
			FB.ui({
				method: 'share_open_graph',
				action_type: 'og.shares',
				action_properties: JSON.stringify({
					object: ogObject
				})
			});
		}
	});

	$('#mainUserInfoButtonMobile').click(function () {
		if ($('#mainMobileLoginContainer').css('display') == 'none') {
			$('#mainMobileLoginContainer').html($('.login-box').parent().html());
			if ($('.search-wrapper').css('display') != 'none') {
				$('.search-wrapper').hide();
			}
			var navHeight = $('.mainMenu').css('height');
			$('#mainMobileLoginContainer').css('margin-top', navHeight).fadeIn(300);
			$(this).toggleClass('active').find('i').switchClass('fas fa-user-circle', 'fal fa-times', 0);
		} else {
			$('#mainMobileLoginContainer').fadeOut(300);
			$(this).toggleClass('active').find('i').switchClass('fal fa-times', 'fas fa-user-circle', 0);
			$('.search-wrapper').show();
		}
	});

	$('#mobileConnect').click(function () {
		if ($.trim($('#kompassMobileFormContainer').html()) == '') {
			$('#kompassMobileFormContainer').html($('#kompass').html());
		}
	});

	$('.mainMenu .navbar-toggler, .mainMenu .navbar-toggle').on('click', function (e) {
		if ($(this).find('i').hasClass('fa-times')) {
			$(this).find('i').switchClass('fal fa-times', 'fas fa-bars', 0);
			$(document).off('keyup', NavbarEscape);
		} else {
			$(this).find('i').switchClass('fas fa-bars', 'fal fa-times', 0);
			$(document).on('keyup', NavbarEscape);
			$('.mainCollapse a').on('focusout', function () {
				if ($(this)[0] == $('.mainCollapse a:visible').last()[0]) {
					var navbarDisplay = $('.mainCollapse').css("display");
					if (navbarDisplay && navbarDisplay != "none") {
						if ($('.navbar-toggle').length > 0) {
							$('.mainCollapse').removeClass('in');
							$('.navbar-toggle.active').removeClass('active').attr('aria-expanded', 'false');
							$('.navbar-toggle > .fa-times').removeClass('fa-times').addClass('fa-bars');
						}
						else {
							//Navbar-toggler logic
							$('.mainCollapse').removeClass('show');
							$('.navbar-toggler.active').removeClass('active').addClass('collapsed').attr('aria-expanded', 'false');
							$('.navbar-toggler.collapsed > .fa-times').removeClass('fa-times').addClass('fa-bars');
						}
					}
					$(document).off('keyup', NavbarEscape);
				}
			});
		}
		$(this).toggleClass('active');
	});

	$(document).on('click', '.upcoming-stays-slider .slider-navigation .slider-indicator', function () {
		var parent = $(this).parents('.login-box')[0];
		if (!$(this).hasClass('active')) {
			var sliderId = $(this).attr('id').replace('upcoming-stay', 'stay-info');
			removeActiveProfileSliders(parent);
			$(this).addClass('active');
			$(parent).find('#' + sliderId).addClass('active');
		}

	});
	$(document).on('click', '.upcoming-stays-slider .slider-container .upcoming-stays-slider-left', function () {
		var parent = $(this).parents('.login-box')[0];
		var currentId = $(parent).find('.upcoming-stays-slider .stay-info-container.active').attr('id').replace('stay-info-', '');
		var upcomingStays = $(parent).find('.upcoming-stays-slider .stay-info-container').length;
		if (upcomingStays > 1) {
			var nextId = currentId;
			if (currentId == 0) {
				nextId = upcomingStays - 1;
			}
			else {
				nextId--;
			}
			removeActiveProfileSliders(parent);
			$(parent).find('#upcoming-stay-' + nextId).addClass('active');
			$(parent).find('#stay-info-' + nextId).addClass('active');
		}
	});
	$(document).on('click', '.upcoming-stays-slider .slider-container .upcoming-stays-slider-right', function () {
		var parent = $(this).parents('.login-box')[0];
		var currentId = $(parent).find('.upcoming-stays-slider .stay-info-container.active').attr('id').replace('stay-info-', '');
		var upcomingStays = $(parent).find('.upcoming-stays-slider .stay-info-container').length;
		if (upcomingStays > 1) {
			var nextId = currentId;
			if (currentId == upcomingStays - 1) {
				nextId = 0;
			}
			else {
				nextId++;
			}
			removeActiveProfileSliders(parent);
			$(parent).find('#upcoming-stay-' + nextId).addClass('active');
			$(parent).find('#stay-info-' + nextId).addClass('active');
		}
	});
	function removeActiveProfileSliders(parent) {
		$(parent).find('.upcoming-stays-slider .stay-info-container.active').removeClass('active');
		$(parent).find('.upcoming-stays-slider .slider-navigation .slider-indicator.active').removeClass('active');
	}

	$('.faq-section').on('shown.bs.collapse', function (item) {
		$(item.target).siblings('.card-header').find('.fa-angle-down').removeClass('fa-angle-down').addClass('fa-angle-up');
	});
	$('.faq-section').on('hidden.bs.collapse', function (item) {
		$(item.target).siblings('.card-header').find('.fa-angle-up').removeClass('fa-angle-up').addClass('fa-angle-down');
	});



	//Sub-dropdown logic for wts pages
	$('.sub-dropdown .list-group-item').on('click', function () {
		$(".sub-dropdown .dropdown-menu").each(function () {
			$(this).hide();
		});
	});

	$('html').on('click', function () {
		$(".sub-dropdown .dropdown-menu").each(function () {
			$(this).hide();
		});
	});

	$('.sub-dropdown').on('click', function (e) {
		e.stopPropagation();
	});

	$('.sub-dropdown').on("click", function () {
		$(this).find('div.dropdown-menu').show();
	});

	$('#cpra_button').on('click', function (e) {
		if (window.airgap) {
			if (window.airgap.getRegimes().has('US_DNSS')) {
				transcend.showConsentManager({ viewState: 'CompleteOptions' });
			}
			else {
				transcend.showConsentManager();
			}
		}
	});

	//$("#sensible-weather-add").click(function () {
	//	$("#addon-d114726ba6079be95076ad4289962f8e").prop("checked", true);
	//});

	//$("#sensible-weather-remove").click(function () {
	//	$("#addon-d114726ba6079be95076ad4289962f8e").prop("checked", false);
	//});

	//$('.sensible-weather-add-checkout').on('click', function () {
	//	$(".addon-d114726ba6079be95076ad4289962f8e-" + $(this).data('id')).prop("checked", true);
	//});

	//$('.sensible-weather-remove-checkout').on('click', function () {
	//	$(".addon-d114726ba6079be95076ad4289962f8e-" + $(this).data('id')).prop("checked", false);
	//});
});

function NavbarEscape(e) {
	if (e.key == "Escape") {
		var navbarDisplay = $('.mainCollapse').css("display");
		if (navbarDisplay && navbarDisplay != "none") {
			if ($('.navbar-toggle').length > 0) {
				$('.mainCollapse').removeClass('in');
				$('.navbar-toggle.active').removeClass('active').attr('aria-expanded', 'false');
				$('.navbar-toggle > .fa-times').removeClass('fa-times').addClass('fa-bars');
			}
			else {
				//Navbar-toggler logic
				$('.mainCollapse').removeClass('show');
				$('.navbar-toggler.active').removeClass('active').addClass('collapsed').attr('aria-expanded', 'false');
				$('.navbar-toggler.collapsed > .fa-times').removeClass('fa-times').addClass('fa-bars');
			}
		}
		$(document).off('keyup', NavbarEscape);
	}
}

var LoadReadMore = function () {
	$('.description-div').each(function () {
		var descriptionDivHeightMax = 77;
		var descriptionDivHeightDefault = 65;
		var descriptionDivHeight = $(this).height();
		var diff = descriptionDivHeight - descriptionDivHeightDefault;
		var descriptionID = '#' + $(this).attr('id');
		var descriptionReadMoreID = '#description-read-more-' + $(this).attr('id');
		var descriptionDivExpanded = false;

		var readMoreLink = $(descriptionReadMoreID);

		if (descriptionDivHeight > descriptionDivHeightMax) {
			readMoreLink.show();
			$(this).height(descriptionDivHeightDefault);
			readMoreLink.click(function (e, obj) {
				e.preventDefault();
				if (this.descriptionDivExpanded) {
					$(descriptionID).animate({ height: descriptionDivHeightDefault }, 180);
					readMoreLink.removeClass().addClass('bold-blue-link-glyph').text('Read More');
				}
				else {
					$(descriptionID).height(descriptionDivHeight);
					readMoreLink.removeClass().addClass('link-close').text('Close').prepend('<span class="glyphicon glyphicon-remove koa-red-font" aria-hidden="true"></span> ');
				}
				this.descriptionDivExpanded = !this.descriptionDivExpanded;
			});
		}
		else {
			readMoreLink.hide();
		}
	});
}

// Used to animate objects. Using this currently to animate arrows on home page modules.
$.fn.animateRotate = function (angle, duration, easing, complete) {
	var args = $.speed(duration, easing, complete);
	var step = args.step;
	return this.each(function (i, e) {
		args.step = function (now) {
			$.style(e, 'transform', 'rotate(' + now + 'deg)');
			if (step) return step.apply(this, arguments);
		};

		$({ deg: 0 }).animate({ deg: angle }, args);
	});
};

function GetIEVer() {
	var iev = 0;
	var ieold = (/MSIE (\d+\.\d+);/.test(navigator.userAgent));
	var trident = !!navigator.userAgent.match(/Trident\/7.0/);
	var rv = navigator.userAgent.indexOf("rv:11.0");
	var edge = navigator.userAgent.indexOf("Edge");

	if (ieold) iev = new Number(RegExp.$1);
	if (navigator.appVersion.indexOf("MSIE 10") != -1) iev = 10;
	if (trident && rv != -1) iev = 11;
	if (edge != -1) iev = "Edge";

	return iev;
}
;
$(document).ready(function () {
	$('input.account-koa-btn-inverse[type="submit"]').click(function (e) {
		var thisButton = $(this);
		window.setTimeout(function () { thisButton.attr('disabled', 'disabled'); }, 0);
	});

	$('input.account-koa-btn-inverse[type="button"]').click(function (e) {
		var thisButton = $(this);
		window.setTimeout(function () { thisButton.attr('disabled', 'disabled'); }, 0);
	});
});
;
/**
 * jQuery prettySocial: Use custom social share buttons
 * Author: Sonny T. <hi@sonnyt.com>, sonnyt.com
 */(function(a){a.fn.prettySocial=function(){var b={pinterest:{url:"http://pinterest.com/pin/create/button/?url={{url}}&media={{media}}&description={{description}}",popup:{width:685,height:500}},facebook:{url:"https://www.facebook.com/sharer/sharer.php?s=100&p[title]={{title}}&p[summary]={{description}}&p[url]={{url}}&p[images][0]={{media}}",popup:{width:626,height:436}},twitter:{url:"https://twitter.com/share?url={{url}}&via={{via}}&text={{description}}",popup:{width:685,height:500}},googleplus:{url:"https://plus.google.com/share?url={{url}}",popup:{width:600,height:600}},linkedin:{url:"https://www.linkedin.com/shareArticle?mini=true&url={{url}}&title={{title}}&summary={{description}}+&source={{via}}",popup:{width:600,height:600}}},d=function(f,e){var h=(window.innerWidth/2)-(f.popup.width/2),g=(window.innerHeight/2)-(f.popup.height/2);return window.open(e,"","toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=no, copyhistory=no, width="+f.popup.width+", height="+f.popup.height+", top="+g+", left="+h)},c=function(f,g){var e=f.url.replace(/{{url}}/g,encodeURIComponent(g.url)).replace(/{{title}}/g,encodeURIComponent(g.title)).replace(/{{description}}/g,encodeURIComponent(g.description)).replace(/{{media}}/g,encodeURIComponent(g.media)).replace(/{{via}}/g,encodeURIComponent(g.via));return e};return this.each(function(){var i=a(this);var g=i.data("type"),f=b[g]||null;if(!f){a.error("Social site is not set.")}var h={url:i.data("url")||"",title:i.data("title")||"",description:i.data("description")||"",media:i.data("media")||"",via:i.data("via")||""};var e=c(f,h);if(navigator.userAgent.match(/Android|IEMobile|BlackBerry|iPhone|iPad|iPod|Opera Mini/i)){i.bind("touchstart",function(j){if(j.originalEvent.touches.length>1){return}i.data("touchWithoutScroll",true)}).bind("touchmove",function(){i.data("touchWithoutScroll",false);return}).bind("touchend",function(k){k.preventDefault();var j=i.data("touchWithoutScroll");if(k.originalEvent.touches.length>1||!j){return}d(f,e)})}else{i.bind("click",function(j){j.preventDefault();d(f,e)})}})}})(jQuery);
;
/*!
 * skrollr core
 *
 * Alexander Prinzhorn - https://github.com/Prinzhorn/skrollr
 *
 * Free to use under terms of MIT license
 */
(function(window, document, undefined) {
	'use strict';

	/*
	 * Global api.
	 */
	var skrollr = {
		get: function() {
			return _instance;
		},
		//Main entry point.
		init: function(options) {
			return _instance || new Skrollr(options);
		},
		VERSION: '0.6.29'
	};

	//Minify optimization.
	var hasProp = Object.prototype.hasOwnProperty;
	var Math = window.Math;
	var getStyle = window.getComputedStyle;

	//They will be filled when skrollr gets initialized.
	var documentElement;
	var body;

	var EVENT_TOUCHSTART = 'touchstart';
	var EVENT_TOUCHMOVE = 'touchmove';
	var EVENT_TOUCHCANCEL = 'touchcancel';
	var EVENT_TOUCHEND = 'touchend';

	var SKROLLABLE_CLASS = 'skrollable';
	var SKROLLABLE_BEFORE_CLASS = SKROLLABLE_CLASS + '-before';
	var SKROLLABLE_BETWEEN_CLASS = SKROLLABLE_CLASS + '-between';
	var SKROLLABLE_AFTER_CLASS = SKROLLABLE_CLASS + '-after';

	var SKROLLR_CLASS = 'skrollr';
	var NO_SKROLLR_CLASS = 'no-' + SKROLLR_CLASS;
	var SKROLLR_DESKTOP_CLASS = SKROLLR_CLASS + '-desktop';
	var SKROLLR_MOBILE_CLASS = SKROLLR_CLASS + '-mobile';

	var DEFAULT_EASING = 'linear';
	var DEFAULT_DURATION = 1000;//ms
	var DEFAULT_MOBILE_DECELERATION = 0.004;//pixel/ms²

	var DEFAULT_SKROLLRBODY = 'skrollr-body';

	var DEFAULT_SMOOTH_SCROLLING_DURATION = 200;//ms

	var ANCHOR_START = 'start';
	var ANCHOR_END = 'end';
	var ANCHOR_CENTER = 'center';
	var ANCHOR_BOTTOM = 'bottom';

	//The property which will be added to the DOM element to hold the ID of the skrollable.
	var SKROLLABLE_ID_DOM_PROPERTY = '___skrollable_id';

	var rxTouchIgnoreTags = /^(?:input|textarea|button|select)$/i;

	var rxTrim = /^\s+|\s+$/g;

	//Find all data-attributes. data-[_constant]-[offset]-[anchor]-[anchor].
	var rxKeyframeAttribute = /^data(?:-(_\w+))?(?:-?(-?\d*\.?\d+p?))?(?:-?(start|end|top|center|bottom))?(?:-?(top|center|bottom))?$/;

	var rxPropValue = /\s*(@?[\w\-\[\]]+)\s*:\s*(.+?)\s*(?:;|$)/gi;

	//Easing function names follow the property in square brackets.
	var rxPropEasing = /^(@?[a-z\-]+)\[(\w+)\]$/;

	var rxCamelCase = /-([a-z0-9_])/g;
	var rxCamelCaseFn = function(str, letter) {
		return letter.toUpperCase();
	};

	//Numeric values with optional sign.
	var rxNumericValue = /[\-+]?[\d]*\.?[\d]+/g;

	//Used to replace occurences of {?} with a number.
	var rxInterpolateString = /\{\?\}/g;

	//Finds rgb(a) colors, which don't use the percentage notation.
	var rxRGBAIntegerColor = /rgba?\(\s*-?\d+\s*,\s*-?\d+\s*,\s*-?\d+/g;

	//Finds all gradients.
	var rxGradient = /[a-z\-]+-gradient/g;

	//Vendor prefix. Will be set once skrollr gets initialized.
	var theCSSPrefix = '';
	var theDashedCSSPrefix = '';

	//Will be called once (when skrollr gets initialized).
	var detectCSSPrefix = function() {
		//Only relevant prefixes. May be extended.
		//Could be dangerous if there will ever be a CSS property which actually starts with "ms". Don't hope so.
		var rxPrefixes = /^(?:O|Moz|webkit|ms)|(?:-(?:o|moz|webkit|ms)-)/;

		//Detect prefix for current browser by finding the first property using a prefix.
		if(!getStyle) {
			return;
		}

		var style = getStyle(body, null);

		for(var k in style) {
			//We check the key and if the key is a number, we check the value as well, because safari's getComputedStyle returns some weird array-like thingy.
			theCSSPrefix = (k.match(rxPrefixes) || (+k == k && style[k].match(rxPrefixes)));

			if(theCSSPrefix) {
				break;
			}
		}

		//Did we even detect a prefix?
		if(!theCSSPrefix) {
			theCSSPrefix = theDashedCSSPrefix = '';

			return;
		}

		theCSSPrefix = theCSSPrefix[0];

		//We could have detected either a dashed prefix or this camelCaseish-inconsistent stuff.
		if(theCSSPrefix.slice(0,1) === '-') {
			theDashedCSSPrefix = theCSSPrefix;

			//There's no logic behind these. Need a look up.
			theCSSPrefix = ({
				'-webkit-': 'webkit',
				'-moz-': 'Moz',
				'-ms-': 'ms',
				'-o-': 'O'
			})[theCSSPrefix];
		} else {
			theDashedCSSPrefix = '-' + theCSSPrefix.toLowerCase() + '-';
		}
	};

	var polyfillRAF = function() {
		var requestAnimFrame = window.requestAnimationFrame || window[theCSSPrefix.toLowerCase() + 'RequestAnimationFrame'];

		var lastTime = _now();

		if(_isMobile || !requestAnimFrame) {
			requestAnimFrame = function(callback) {
				//How long did it take to render?
				var deltaTime = _now() - lastTime;
				var delay = Math.max(0, 1000 / 60 - deltaTime);

				return window.setTimeout(function() {
					lastTime = _now();
					callback();
				}, delay);
			};
		}

		return requestAnimFrame;
	};

	var polyfillCAF = function() {
		var cancelAnimFrame = window.cancelAnimationFrame || window[theCSSPrefix.toLowerCase() + 'CancelAnimationFrame'];

		if(_isMobile || !cancelAnimFrame) {
			cancelAnimFrame = function(timeout) {
				return window.clearTimeout(timeout);
			};
		}

		return cancelAnimFrame;
	};

	//Built-in easing functions.
	var easings = {
		begin: function() {
			return 0;
		},
		end: function() {
			return 1;
		},
		linear: function(p) {
			return p;
		},
		quadratic: function(p) {
			return p * p;
		},
		cubic: function(p) {
			return p * p * p;
		},
		swing: function(p) {
			return (-Math.cos(p * Math.PI) / 2) + 0.5;
		},
		sqrt: function(p) {
			return Math.sqrt(p);
		},
		outCubic: function(p) {
			return (Math.pow((p - 1), 3) + 1);
		},
		//see https://www.desmos.com/calculator/tbr20s8vd2 for how I did this
		bounce: function(p) {
			var a;

			if(p <= 0.5083) {
				a = 3;
			} else if(p <= 0.8489) {
				a = 9;
			} else if(p <= 0.96208) {
				a = 27;
			} else if(p <= 0.99981) {
				a = 91;
			} else {
				return 1;
			}

			return 1 - Math.abs(3 * Math.cos(p * a * 1.028) / a);
		}
	};

	/**
	 * Constructor.
	 */
	function Skrollr(options) {
		documentElement = document.documentElement;
		body = document.body;

		detectCSSPrefix();

		_instance = this;

		options = options || {};

		_constants = options.constants || {};

		//We allow defining custom easings or overwrite existing.
		if(options.easing) {
			for(var e in options.easing) {
				easings[e] = options.easing[e];
			}
		}

		_edgeStrategy = options.edgeStrategy || 'set';

		_listeners = {
			//Function to be called right before rendering.
			beforerender: options.beforerender,

			//Function to be called right after finishing rendering.
			render: options.render,

			//Function to be called whenever an element with the `data-emit-events` attribute passes a keyframe.
			keyframe: options.keyframe
		};

		//forceHeight is true by default
		_forceHeight = options.forceHeight !== false;

		if(_forceHeight) {
			_scale = options.scale || 1;
		}

		_mobileDeceleration = options.mobileDeceleration || DEFAULT_MOBILE_DECELERATION;

		_smoothScrollingEnabled = options.smoothScrolling !== false;
		_smoothScrollingDuration = options.smoothScrollingDuration || DEFAULT_SMOOTH_SCROLLING_DURATION;

		//Dummy object. Will be overwritten in the _render method when smooth scrolling is calculated.
		_smoothScrolling = {
			targetTop: _instance.getScrollTop()
		};

		//A custom check function may be passed.
		_isMobile = ((options.mobileCheck || function() {
			return (/Android|iPhone|iPad|iPod|BlackBerry/i).test(navigator.userAgent || navigator.vendor || window.opera);
		})());

		if(_isMobile) {
			_skrollrBody = document.getElementById(options.skrollrBody || DEFAULT_SKROLLRBODY);

			//Detect 3d transform if there's a skrollr-body (only needed for #skrollr-body).
			if(_skrollrBody) {
				_detect3DTransforms();
			}

			_initMobile();
			_updateClass(documentElement, [SKROLLR_CLASS, SKROLLR_MOBILE_CLASS], [NO_SKROLLR_CLASS]);
		} else {
			_updateClass(documentElement, [SKROLLR_CLASS, SKROLLR_DESKTOP_CLASS], [NO_SKROLLR_CLASS]);
		}

		//Triggers parsing of elements and a first reflow.
		_instance.refresh();

		_addEvent(window, 'resize orientationchange', function() {
			var width = documentElement.clientWidth;
			var height = documentElement.clientHeight;

			//Only reflow if the size actually changed (#271).
			if(height !== _lastViewportHeight || width !== _lastViewportWidth) {
				_lastViewportHeight = height;
				_lastViewportWidth = width;

				_requestReflow = true;
			}
		});

		var requestAnimFrame = polyfillRAF();

		//Let's go.
		(function animloop(){
			_render();
			_animFrame = requestAnimFrame(animloop);
		}());

		return _instance;
	}

	/**
	 * (Re)parses some or all elements.
	 */
	Skrollr.prototype.refresh = function(elements) {
		var elementIndex;
		var elementsLength;
		var ignoreID = false;

		//Completely reparse anything without argument.
		if(elements === undefined) {
			//Ignore that some elements may already have a skrollable ID.
			ignoreID = true;

			_skrollables = [];
			_skrollableIdCounter = 0;

			elements = document.getElementsByTagName('*');
		} else if(elements.length === undefined) {
			//We also accept a single element as parameter.
			elements = [elements];
		}

		elementIndex = 0;
		elementsLength = elements.length;

		for(; elementIndex < elementsLength; elementIndex++) {
			var el = elements[elementIndex];
			var anchorTarget = el;
			var keyFrames = [];

			//If this particular element should be smooth scrolled.
			var smoothScrollThis = _smoothScrollingEnabled;

			//The edge strategy for this particular element.
			var edgeStrategy = _edgeStrategy;

			//If this particular element should emit keyframe events.
			var emitEvents = false;

			//If we're reseting the counter, remove any old element ids that may be hanging around.
			if(ignoreID && SKROLLABLE_ID_DOM_PROPERTY in el) {
				delete el[SKROLLABLE_ID_DOM_PROPERTY];
			}

			if(!el.attributes) {
				continue;
			}

			//Iterate over all attributes and search for key frame attributes.
			var attributeIndex = 0;
			var attributesLength = el.attributes.length;

			for (; attributeIndex < attributesLength; attributeIndex++) {
				var attr = el.attributes[attributeIndex];

				if(attr.name === 'data-anchor-target') {
					anchorTarget = document.querySelector(attr.value);

					if(anchorTarget === null) {
						throw 'Unable to find anchor target "' + attr.value + '"';
					}

					continue;
				}

				//Global smooth scrolling can be overridden by the element attribute.
				if(attr.name === 'data-smooth-scrolling') {
					smoothScrollThis = attr.value !== 'off';

					continue;
				}

				//Global edge strategy can be overridden by the element attribute.
				if(attr.name === 'data-edge-strategy') {
					edgeStrategy = attr.value;

					continue;
				}

				//Is this element tagged with the `data-emit-events` attribute?
				if(attr.name === 'data-emit-events') {
					emitEvents = true;

					continue;
				}

				var match = attr.name.match(rxKeyframeAttribute);

				if(match === null) {
					continue;
				}

				var kf = {
					props: attr.value,
					//Point back to the element as well.
					element: el,
					//The name of the event which this keyframe will fire, if emitEvents is
					eventType: attr.name.replace(rxCamelCase, rxCamelCaseFn)
				};

				keyFrames.push(kf);

				var constant = match[1];

				if(constant) {
					//Strip the underscore prefix.
					kf.constant = constant.substr(1);
				}

				//Get the key frame offset.
				var offset = match[2];

				//Is it a percentage offset?
				if(/p$/.test(offset)) {
					kf.isPercentage = true;
					kf.offset = (offset.slice(0, -1) | 0) / 100;
				} else {
					kf.offset = (offset | 0);
				}

				var anchor1 = match[3];

				//If second anchor is not set, the first will be taken for both.
				var anchor2 = match[4] || anchor1;

				//"absolute" (or "classic") mode, where numbers mean absolute scroll offset.
				if(!anchor1 || anchor1 === ANCHOR_START || anchor1 === ANCHOR_END) {
					kf.mode = 'absolute';

					//data-end needs to be calculated after all key frames are known.
					if(anchor1 === ANCHOR_END) {
						kf.isEnd = true;
					} else if(!kf.isPercentage) {
						//For data-start we can already set the key frame w/o calculations.
						//#59: "scale" options should only affect absolute mode.
						kf.offset = kf.offset * _scale;
					}
				}
				//"relative" mode, where numbers are relative to anchors.
				else {
					kf.mode = 'relative';
					kf.anchors = [anchor1, anchor2];
				}
			}

			//Does this element have key frames?
			if(!keyFrames.length) {
				continue;
			}

			//Will hold the original style and class attributes before we controlled the element (see #80).
			var styleAttr, classAttr;

			var id;

			if(!ignoreID && SKROLLABLE_ID_DOM_PROPERTY in el) {
				//We already have this element under control. Grab the corresponding skrollable id.
				id = el[SKROLLABLE_ID_DOM_PROPERTY];
				styleAttr = _skrollables[id].styleAttr;
				classAttr = _skrollables[id].classAttr;
			} else {
				//It's an unknown element. Asign it a new skrollable id.
				id = (el[SKROLLABLE_ID_DOM_PROPERTY] = _skrollableIdCounter++);
				styleAttr = el.style.cssText;
				classAttr = _getClass(el);
			}

			_skrollables[id] = {
				element: el,
				styleAttr: styleAttr,
				classAttr: classAttr,
				anchorTarget: anchorTarget,
				keyFrames: keyFrames,
				smoothScrolling: smoothScrollThis,
				edgeStrategy: edgeStrategy,
				emitEvents: emitEvents,
				lastFrameIndex: -1
			};

			_updateClass(el, [SKROLLABLE_CLASS], []);
		}

		//Reflow for the first time.
		_reflow();

		//Now that we got all key frame numbers right, actually parse the properties.
		elementIndex = 0;
		elementsLength = elements.length;

		for(; elementIndex < elementsLength; elementIndex++) {
			var sk = _skrollables[elements[elementIndex][SKROLLABLE_ID_DOM_PROPERTY]];

			if(sk === undefined) {
				continue;
			}

			//Parse the property string to objects
			_parseProps(sk);

			//Fill key frames with missing properties from left and right
			_fillProps(sk);
		}

		return _instance;
	};

	/**
	 * Transform "relative" mode to "absolute" mode.
	 * That is, calculate anchor position and offset of element.
	 */
	Skrollr.prototype.relativeToAbsolute = function(element, viewportAnchor, elementAnchor) {
		var viewportHeight = documentElement.clientHeight;
		var box = element.getBoundingClientRect();
		var absolute = box.top;

		//#100: IE doesn't supply "height" with getBoundingClientRect.
		var boxHeight = box.bottom - box.top;

		if(viewportAnchor === ANCHOR_BOTTOM) {
			absolute -= viewportHeight;
		} else if(viewportAnchor === ANCHOR_CENTER) {
			absolute -= viewportHeight / 2;
		}

		if(elementAnchor === ANCHOR_BOTTOM) {
			absolute += boxHeight;
		} else if(elementAnchor === ANCHOR_CENTER) {
			absolute += boxHeight / 2;
		}

		//Compensate scrolling since getBoundingClientRect is relative to viewport.
		absolute += _instance.getScrollTop();

		return (absolute + 0.5) | 0;
	};

	/**
	 * Animates scroll top to new position.
	 */
	Skrollr.prototype.animateTo = function(top, options) {
		options = options || {};

		var now = _now();
		var scrollTop = _instance.getScrollTop();

		//Setting this to a new value will automatically cause the current animation to stop, if any.
		_scrollAnimation = {
			startTop: scrollTop,
			topDiff: top - scrollTop,
			targetTop: top,
			duration: options.duration || DEFAULT_DURATION,
			startTime: now,
			endTime: now + (options.duration || DEFAULT_DURATION),
			easing: easings[options.easing || DEFAULT_EASING],
			done: options.done
		};

		//Don't queue the animation if there's nothing to animate.
		if(!_scrollAnimation.topDiff) {
			if(_scrollAnimation.done) {
				_scrollAnimation.done.call(_instance, false);
			}

			_scrollAnimation = undefined;
		}

		return _instance;
	};

	/**
	 * Stops animateTo animation.
	 */
	Skrollr.prototype.stopAnimateTo = function() {
		if(_scrollAnimation && _scrollAnimation.done) {
			_scrollAnimation.done.call(_instance, true);
		}

		_scrollAnimation = undefined;
	};

	/**
	 * Returns if an animation caused by animateTo is currently running.
	 */
	Skrollr.prototype.isAnimatingTo = function() {
		return !!_scrollAnimation;
	};

	Skrollr.prototype.isMobile = function() {
		return _isMobile;
	};

	Skrollr.prototype.setScrollTop = function(top, force) {
		_forceRender = (force === true);

		if(_isMobile) {
			_mobileOffset = Math.min(Math.max(top, 0), _maxKeyFrame);
		} else {
			window.scrollTo(0, top);
		}

		return _instance;
	};

	Skrollr.prototype.getScrollTop = function() {
		if(_isMobile) {
			return _mobileOffset;
		} else {
			return window.pageYOffset || documentElement.scrollTop || body.scrollTop || 0;
		}
	};

	Skrollr.prototype.getMaxScrollTop = function() {
		return _maxKeyFrame;
	};

	Skrollr.prototype.on = function(name, fn) {
		_listeners[name] = fn;

		return _instance;
	};

	Skrollr.prototype.off = function(name) {
		delete _listeners[name];

		return _instance;
	};

	Skrollr.prototype.destroy = function() {
		var cancelAnimFrame = polyfillCAF();
		cancelAnimFrame(_animFrame);
		_removeAllEvents();

		_updateClass(documentElement, [NO_SKROLLR_CLASS], [SKROLLR_CLASS, SKROLLR_DESKTOP_CLASS, SKROLLR_MOBILE_CLASS]);

		var skrollableIndex = 0;
		var skrollablesLength = _skrollables.length;

		for(; skrollableIndex < skrollablesLength; skrollableIndex++) {
			_reset(_skrollables[skrollableIndex].element);
		}

		documentElement.style.overflow = body.style.overflow = '';
		documentElement.style.height = body.style.height = '';

		if(_skrollrBody) {
			skrollr.setStyle(_skrollrBody, 'transform', 'none');
		}

		_instance = undefined;
		_skrollrBody = undefined;
		_listeners = undefined;
		_forceHeight = undefined;
		_maxKeyFrame = 0;
		_scale = 1;
		_constants = undefined;
		_mobileDeceleration = undefined;
		_direction = 'down';
		_lastTop = -1;
		_lastViewportWidth = 0;
		_lastViewportHeight = 0;
		_requestReflow = false;
		_scrollAnimation = undefined;
		_smoothScrollingEnabled = undefined;
		_smoothScrollingDuration = undefined;
		_smoothScrolling = undefined;
		_forceRender = undefined;
		_skrollableIdCounter = 0;
		_edgeStrategy = undefined;
		_isMobile = false;
		_mobileOffset = 0;
		_translateZ = undefined;
	};

	/*
		Private methods.
	*/

	var _initMobile = function() {
		var initialElement;
		var initialTouchY;
		var initialTouchX;
		var currentElement;
		var currentTouchY;
		var currentTouchX;
		var lastTouchY;
		var deltaY;

		var initialTouchTime;
		var currentTouchTime;
		var lastTouchTime;
		var deltaTime;

		_addEvent(documentElement, [EVENT_TOUCHSTART, EVENT_TOUCHMOVE, EVENT_TOUCHCANCEL, EVENT_TOUCHEND].join(' '), function(e) {
			var touch = e.changedTouches[0];

			currentElement = e.target;

			//We don't want text nodes.
			while(currentElement.nodeType === 3) {
				currentElement = currentElement.parentNode;
			}

			currentTouchY = touch.clientY;
			currentTouchX = touch.clientX;
			currentTouchTime = e.timeStamp;

			if(!rxTouchIgnoreTags.test(currentElement.tagName)) {
				e.preventDefault();
			}

			switch(e.type) {
				case EVENT_TOUCHSTART:
					//The last element we tapped on.
					if(initialElement) {
						initialElement.blur();
					}

					_instance.stopAnimateTo();

					initialElement = currentElement;

					initialTouchY = lastTouchY = currentTouchY;
					initialTouchX = currentTouchX;
					initialTouchTime = currentTouchTime;

					break;
				case EVENT_TOUCHMOVE:
					//Prevent default event on touchIgnore elements in case they don't have focus yet.
					if(rxTouchIgnoreTags.test(currentElement.tagName) && document.activeElement !== currentElement) {
						e.preventDefault();
					}

					deltaY = currentTouchY - lastTouchY;
					deltaTime = currentTouchTime - lastTouchTime;

					_instance.setScrollTop(_mobileOffset - deltaY, true);

					lastTouchY = currentTouchY;
					lastTouchTime = currentTouchTime;
					break;
				default:
				case EVENT_TOUCHCANCEL:
				case EVENT_TOUCHEND:
					var distanceY = initialTouchY - currentTouchY;
					var distanceX = initialTouchX - currentTouchX;
					var distance2 = distanceX * distanceX + distanceY * distanceY;

					//Check if it was more like a tap (moved less than 7px).
					if(distance2 < 49) {
						if(!rxTouchIgnoreTags.test(initialElement.tagName)) {
							initialElement.focus();

							//It was a tap, click the element.
							var clickEvent = document.createEvent('MouseEvents');
							clickEvent.initMouseEvent('click', true, true, e.view, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, 0, null);
							initialElement.dispatchEvent(clickEvent);
						}

						return;
					}

					initialElement = undefined;

					var speed = deltaY / deltaTime;

					//Cap speed at 3 pixel/ms.
					speed = Math.max(Math.min(speed, 3), -3);

					var duration = Math.abs(speed / _mobileDeceleration);
					var targetOffset = speed * duration + 0.5 * _mobileDeceleration * duration * duration;
					var targetTop = _instance.getScrollTop() - targetOffset;

					//Relative duration change for when scrolling above bounds.
					var targetRatio = 0;

					//Change duration proportionally when scrolling would leave bounds.
					if(targetTop > _maxKeyFrame) {
						targetRatio = (_maxKeyFrame - targetTop) / targetOffset;

						targetTop = _maxKeyFrame;
					} else if(targetTop < 0) {
						targetRatio = -targetTop / targetOffset;

						targetTop = 0;
					}

					duration = duration * (1 - targetRatio);

					_instance.animateTo((targetTop + 0.5) | 0, {easing: 'outCubic', duration: duration});
					break;
			}
		});

		//Just in case there has already been some native scrolling, reset it.
		window.scrollTo(0, 0);
		documentElement.style.overflow = body.style.overflow = 'hidden';
	};

	/**
	 * Updates key frames which depend on others / need to be updated on resize.
	 * That is "end" in "absolute" mode and all key frames in "relative" mode.
	 * Also handles constants, because they may change on resize.
	 */
	var _updateDependentKeyFrames = function() {
		var viewportHeight = documentElement.clientHeight;
		var processedConstants = _processConstants();
		var skrollable;
		var element;
		var anchorTarget;
		var keyFrames;
		var keyFrameIndex;
		var keyFramesLength;
		var kf;
		var skrollableIndex;
		var skrollablesLength;
		var offset;
		var constantValue;

		//First process all relative-mode elements and find the max key frame.
		skrollableIndex = 0;
		skrollablesLength = _skrollables.length;

		for(; skrollableIndex < skrollablesLength; skrollableIndex++) {
			skrollable = _skrollables[skrollableIndex];
			element = skrollable.element;
			anchorTarget = skrollable.anchorTarget;
			keyFrames = skrollable.keyFrames;

			keyFrameIndex = 0;
			keyFramesLength = keyFrames.length;

			for(; keyFrameIndex < keyFramesLength; keyFrameIndex++) {
				kf = keyFrames[keyFrameIndex];

				offset = kf.offset;
				constantValue = processedConstants[kf.constant] || 0;

				kf.frame = offset;

				if(kf.isPercentage) {
					//Convert the offset to percentage of the viewport height.
					offset = offset * viewportHeight;

					//Absolute + percentage mode.
					kf.frame = offset;
				}

				if(kf.mode === 'relative') {
					_reset(element);

					kf.frame = _instance.relativeToAbsolute(anchorTarget, kf.anchors[0], kf.anchors[1]) - offset;

					_reset(element, true);
				}

				kf.frame += constantValue;

				//Only search for max key frame when forceHeight is enabled.
				if(_forceHeight) {
					//Find the max key frame, but don't use one of the data-end ones for comparison.
					if(!kf.isEnd && kf.frame > _maxKeyFrame) {
						_maxKeyFrame = kf.frame;
					}
				}
			}
		}

		//#133: The document can be larger than the maxKeyFrame we found.
		_maxKeyFrame = Math.max(_maxKeyFrame, _getDocumentHeight());

		//Now process all data-end keyframes.
		skrollableIndex = 0;
		skrollablesLength = _skrollables.length;

		for(; skrollableIndex < skrollablesLength; skrollableIndex++) {
			skrollable = _skrollables[skrollableIndex];
			keyFrames = skrollable.keyFrames;

			keyFrameIndex = 0;
			keyFramesLength = keyFrames.length;

			for(; keyFrameIndex < keyFramesLength; keyFrameIndex++) {
				kf = keyFrames[keyFrameIndex];

				constantValue = processedConstants[kf.constant] || 0;

				if(kf.isEnd) {
					kf.frame = _maxKeyFrame - kf.offset + constantValue;
				}
			}

			skrollable.keyFrames.sort(_keyFrameComparator);
		}
	};

	/**
	 * Calculates and sets the style properties for the element at the given frame.
	 * @param fakeFrame The frame to render at when smooth scrolling is enabled.
	 * @param actualFrame The actual frame we are at.
	 */
	var _calcSteps = function(fakeFrame, actualFrame) {
		//Iterate over all skrollables.
		var skrollableIndex = 0;
		var skrollablesLength = _skrollables.length;

		for(; skrollableIndex < skrollablesLength; skrollableIndex++) {
			var skrollable = _skrollables[skrollableIndex];
			var element = skrollable.element;
			var frame = skrollable.smoothScrolling ? fakeFrame : actualFrame;
			var frames = skrollable.keyFrames;
			var framesLength = frames.length;
			var firstFrame = frames[0];
			var lastFrame = frames[frames.length - 1];
			var beforeFirst = frame < firstFrame.frame;
			var afterLast = frame > lastFrame.frame;
			var firstOrLastFrame = beforeFirst ? firstFrame : lastFrame;
			var emitEvents = skrollable.emitEvents;
			var lastFrameIndex = skrollable.lastFrameIndex;
			var key;
			var value;

			//If we are before/after the first/last frame, set the styles according to the given edge strategy.
			if(beforeFirst || afterLast) {
				//Check if we already handled this edge case last time.
				//Note: using setScrollTop it's possible that we jumped from one edge to the other.
				if(beforeFirst && skrollable.edge === -1 || afterLast && skrollable.edge === 1) {
					continue;
				}

				//Add the skrollr-before or -after class.
				if(beforeFirst) {
					_updateClass(element, [SKROLLABLE_BEFORE_CLASS], [SKROLLABLE_AFTER_CLASS, SKROLLABLE_BETWEEN_CLASS]);

					//This handles the special case where we exit the first keyframe.
					if(emitEvents && lastFrameIndex > -1) {
						_emitEvent(element, firstFrame.eventType, _direction);
						skrollable.lastFrameIndex = -1;
					}
				} else {
					_updateClass(element, [SKROLLABLE_AFTER_CLASS], [SKROLLABLE_BEFORE_CLASS, SKROLLABLE_BETWEEN_CLASS]);

					//This handles the special case where we exit the last keyframe.
					if(emitEvents && lastFrameIndex < framesLength) {
						_emitEvent(element, lastFrame.eventType, _direction);
						skrollable.lastFrameIndex = framesLength;
					}
				}

				//Remember that we handled the edge case (before/after the first/last keyframe).
				skrollable.edge = beforeFirst ? -1 : 1;

				switch(skrollable.edgeStrategy) {
					case 'reset':
						_reset(element);
						continue;
					case 'ease':
						//Handle this case like it would be exactly at first/last keyframe and just pass it on.
						frame = firstOrLastFrame.frame;
						break;
					default:
					case 'set':
						var props = firstOrLastFrame.props;

						for(key in props) {
							if(hasProp.call(props, key)) {
								value = _interpolateString(props[key].value);

								//Set style or attribute.
								if(key.indexOf('@') === 0) {
									element.setAttribute(key.substr(1), value);
								} else {
									skrollr.setStyle(element, key, value);
								}
							}
						}

						continue;
				}
			} else {
				//Did we handle an edge last time?
				if(skrollable.edge !== 0) {
					_updateClass(element, [SKROLLABLE_CLASS, SKROLLABLE_BETWEEN_CLASS], [SKROLLABLE_BEFORE_CLASS, SKROLLABLE_AFTER_CLASS]);
					skrollable.edge = 0;
				}
			}

			//Find out between which two key frames we are right now.
			var keyFrameIndex = 0;

			for(; keyFrameIndex < framesLength - 1; keyFrameIndex++) {
				if(frame >= frames[keyFrameIndex].frame && frame <= frames[keyFrameIndex + 1].frame) {
					var left = frames[keyFrameIndex];
					var right = frames[keyFrameIndex + 1];

					for(key in left.props) {
						if(hasProp.call(left.props, key)) {
							var progress = (frame - left.frame) / (right.frame - left.frame);

							//Transform the current progress using the given easing function.
							progress = left.props[key].easing(progress);

							//Interpolate between the two values
							value = _calcInterpolation(left.props[key].value, right.props[key].value, progress);

							value = _interpolateString(value);

							//Set style or attribute.
							if(key.indexOf('@') === 0) {
								element.setAttribute(key.substr(1), value);
							} else {
								skrollr.setStyle(element, key, value);
							}
						}
					}

					//Are events enabled on this element?
					//This code handles the usual cases of scrolling through different keyframes.
					//The special cases of before first and after last keyframe are handled above.
					if(emitEvents) {
						//Did we pass a new keyframe?
						if(lastFrameIndex !== keyFrameIndex) {
							if(_direction === 'down') {
								_emitEvent(element, left.eventType, _direction);
							} else {
								_emitEvent(element, right.eventType, _direction);
							}

							skrollable.lastFrameIndex = keyFrameIndex;
						}
					}

					break;
				}
			}
		}
	};

	/**
	 * Renders all elements.
	 */
	var _render = function() {
		if(_requestReflow) {
			_requestReflow = false;
			_reflow();
		}

		//We may render something else than the actual scrollbar position.
		var renderTop = _instance.getScrollTop();

		//If there's an animation, which ends in current render call, call the callback after rendering.
		var afterAnimationCallback;
		var now = _now();
		var progress;

		//Before actually rendering handle the scroll animation, if any.
		if(_scrollAnimation) {
			//It's over
			if(now >= _scrollAnimation.endTime) {
				renderTop = _scrollAnimation.targetTop;
				afterAnimationCallback = _scrollAnimation.done;
				_scrollAnimation = undefined;
			} else {
				//Map the current progress to the new progress using given easing function.
				progress = _scrollAnimation.easing((now - _scrollAnimation.startTime) / _scrollAnimation.duration);

				renderTop = (_scrollAnimation.startTop + progress * _scrollAnimation.topDiff) | 0;
			}

			_instance.setScrollTop(renderTop, true);
		}
		//Smooth scrolling only if there's no animation running and if we're not forcing the rendering.
		else if(!_forceRender) {
			var smoothScrollingDiff = _smoothScrolling.targetTop - renderTop;

			//The user scrolled, start new smooth scrolling.
			if(smoothScrollingDiff) {
				_smoothScrolling = {
					startTop: _lastTop,
					topDiff: renderTop - _lastTop,
					targetTop: renderTop,
					startTime: _lastRenderCall,
					endTime: _lastRenderCall + _smoothScrollingDuration
				};
			}

			//Interpolate the internal scroll position (not the actual scrollbar).
			if(now <= _smoothScrolling.endTime) {
				//Map the current progress to the new progress using easing function.
				progress = easings.sqrt((now - _smoothScrolling.startTime) / _smoothScrollingDuration);

				renderTop = (_smoothScrolling.startTop + progress * _smoothScrolling.topDiff) | 0;
			}
		}

		//That's were we actually "scroll" on mobile.
		if(_isMobile && _skrollrBody) {
			//Set the transform ("scroll it").
			skrollr.setStyle(_skrollrBody, 'transform', 'translate(0, ' + -(_mobileOffset) + 'px) ' + _translateZ);
		}

		//Did the scroll position even change?
		if(_forceRender || _lastTop !== renderTop) {
			//Remember in which direction are we scrolling?
			_direction = (renderTop > _lastTop) ? 'down' : (renderTop < _lastTop ? 'up' : _direction);

			_forceRender = false;

			var listenerParams = {
				curTop: renderTop,
				lastTop: _lastTop,
				maxTop: _maxKeyFrame,
				direction: _direction
			};

			//Tell the listener we are about to render.
			var continueRendering = _listeners.beforerender && _listeners.beforerender.call(_instance, listenerParams);

			//The beforerender listener function is able the cancel rendering.
			if(continueRendering !== false) {
				//Now actually interpolate all the styles.
				_calcSteps(renderTop, _instance.getScrollTop());

				//Remember when we last rendered.
				_lastTop = renderTop;

				if(_listeners.render) {
					_listeners.render.call(_instance, listenerParams);
				}
			}

			if(afterAnimationCallback) {
				afterAnimationCallback.call(_instance, false);
			}
		}

		_lastRenderCall = now;
	};

	/**
	 * Parses the properties for each key frame of the given skrollable.
	 */
	var _parseProps = function(skrollable) {
		//Iterate over all key frames
		var keyFrameIndex = 0;
		var keyFramesLength = skrollable.keyFrames.length;

		for(; keyFrameIndex < keyFramesLength; keyFrameIndex++) {
			var frame = skrollable.keyFrames[keyFrameIndex];
			var easing;
			var value;
			var prop;
			var props = {};

			var match;

			while((match = rxPropValue.exec(frame.props)) !== null) {
				prop = match[1];
				value = match[2];

				easing = prop.match(rxPropEasing);

				//Is there an easing specified for this prop?
				if(easing !== null) {
					prop = easing[1];
					easing = easing[2];
				} else {
					easing = DEFAULT_EASING;
				}

				//Exclamation point at first position forces the value to be taken literal.
				value = value.indexOf('!') ? _parseProp(value) : [value.slice(1)];

				//Save the prop for this key frame with his value and easing function
				props[prop] = {
					value: value,
					easing: easings[easing]
				};
			}

			frame.props = props;
		}
	};

	/**
	 * Parses a value extracting numeric values and generating a format string
	 * for later interpolation of the new values in old string.
	 *
	 * @param val The CSS value to be parsed.
	 * @return Something like ["rgba(?%,?%, ?%,?)", 100, 50, 0, .7]
	 * where the first element is the format string later used
	 * and all following elements are the numeric value.
	 */
	var _parseProp = function(val) {
		var numbers = [];

		//One special case, where floats don't work.
		//We replace all occurences of rgba colors
		//which don't use percentage notation with the percentage notation.
		rxRGBAIntegerColor.lastIndex = 0;
		val = val.replace(rxRGBAIntegerColor, function(rgba) {
			return rgba.replace(rxNumericValue, function(n) {
				return n / 255 * 100 + '%';
			});
		});

		//Handle prefixing of "gradient" values.
		//For now only the prefixed value will be set. Unprefixed isn't supported anyway.
		if(theDashedCSSPrefix) {
			rxGradient.lastIndex = 0;
			val = val.replace(rxGradient, function(s) {
				return theDashedCSSPrefix + s;
			});
		}

		//Now parse ANY number inside this string and create a format string.
		val = val.replace(rxNumericValue, function(n) {
			numbers.push(+n);
			return '{?}';
		});

		//Add the formatstring as first value.
		numbers.unshift(val);

		return numbers;
	};

	/**
	 * Fills the key frames with missing left and right hand properties.
	 * If key frame 1 has property X and key frame 2 is missing X,
	 * but key frame 3 has X again, then we need to assign X to key frame 2 too.
	 *
	 * @param sk A skrollable.
	 */
	var _fillProps = function(sk) {
		//Will collect the properties key frame by key frame
		var propList = {};
		var keyFrameIndex;
		var keyFramesLength;

		//Iterate over all key frames from left to right
		keyFrameIndex = 0;
		keyFramesLength = sk.keyFrames.length;

		for(; keyFrameIndex < keyFramesLength; keyFrameIndex++) {
			_fillPropForFrame(sk.keyFrames[keyFrameIndex], propList);
		}

		//Now do the same from right to fill the last gaps

		propList = {};

		//Iterate over all key frames from right to left
		keyFrameIndex = sk.keyFrames.length - 1;

		for(; keyFrameIndex >= 0; keyFrameIndex--) {
			_fillPropForFrame(sk.keyFrames[keyFrameIndex], propList);
		}
	};

	var _fillPropForFrame = function(frame, propList) {
		var key;

		//For each key frame iterate over all right hand properties and assign them,
		//but only if the current key frame doesn't have the property by itself
		for(key in propList) {
			//The current frame misses this property, so assign it.
			if(!hasProp.call(frame.props, key)) {
				frame.props[key] = propList[key];
			}
		}

		//Iterate over all props of the current frame and collect them
		for(key in frame.props) {
			propList[key] = frame.props[key];
		}
	};

	/**
	 * Calculates the new values for two given values array.
	 */
	var _calcInterpolation = function(val1, val2, progress) {
		var valueIndex;
		var val1Length = val1.length;

		//They both need to have the same length
		if(val1Length !== val2.length) {
			throw 'Can\'t interpolate between "' + val1[0] + '" and "' + val2[0] + '"';
		}

		//Add the format string as first element.
		var interpolated = [val1[0]];

		valueIndex = 1;

		for(; valueIndex < val1Length; valueIndex++) {
			//That's the line where the two numbers are actually interpolated.
			interpolated[valueIndex] = val1[valueIndex] + ((val2[valueIndex] - val1[valueIndex]) * progress);
		}

		return interpolated;
	};

	/**
	 * Interpolates the numeric values into the format string.
	 */
	var _interpolateString = function(val) {
		var valueIndex = 1;

		rxInterpolateString.lastIndex = 0;

		return val[0].replace(rxInterpolateString, function() {
			return val[valueIndex++];
		});
	};

	/**
	 * Resets the class and style attribute to what it was before skrollr manipulated the element.
	 * Also remembers the values it had before reseting, in order to undo the reset.
	 */
	var _reset = function(elements, undo) {
		//We accept a single element or an array of elements.
		elements = [].concat(elements);

		var skrollable;
		var element;
		var elementsIndex = 0;
		var elementsLength = elements.length;

		for(; elementsIndex < elementsLength; elementsIndex++) {
			element = elements[elementsIndex];
			skrollable = _skrollables[element[SKROLLABLE_ID_DOM_PROPERTY]];

			//Couldn't find the skrollable for this DOM element.
			if(!skrollable) {
				continue;
			}

			if(undo) {
				//Reset class and style to the "dirty" (set by skrollr) values.
				element.style.cssText = skrollable.dirtyStyleAttr;
				_updateClass(element, skrollable.dirtyClassAttr);
			} else {
				//Remember the "dirty" (set by skrollr) class and style.
				skrollable.dirtyStyleAttr = element.style.cssText;
				skrollable.dirtyClassAttr = _getClass(element);

				//Reset class and style to what it originally was.
				element.style.cssText = skrollable.styleAttr;
				_updateClass(element, skrollable.classAttr);
			}
		}
	};

	/**
	 * Detects support for 3d transforms by applying it to the skrollr-body.
	 */
	var _detect3DTransforms = function() {
		_translateZ = 'translateZ(0)';
		skrollr.setStyle(_skrollrBody, 'transform', _translateZ);

		var computedStyle = getStyle(_skrollrBody);
		var computedTransform = computedStyle.getPropertyValue('transform');
		var computedTransformWithPrefix = computedStyle.getPropertyValue(theDashedCSSPrefix + 'transform');
		var has3D = (computedTransform && computedTransform !== 'none') || (computedTransformWithPrefix && computedTransformWithPrefix !== 'none');

		if(!has3D) {
			_translateZ = '';
		}
	};

	/**
	 * Set the CSS property on the given element. Sets prefixed properties as well.
	 */
	skrollr.setStyle = function(el, prop, val) {
		var style = el.style;

		//Camel case.
		prop = prop.replace(rxCamelCase, rxCamelCaseFn).replace('-', '');

		//Make sure z-index gets a <integer>.
		//This is the only <integer> case we need to handle.
		if(prop === 'zIndex') {
			if(isNaN(val)) {
				//If it's not a number, don't touch it.
				//It could for example be "auto" (#351).
				style[prop] = val;
			} else {
				//Floor the number.
				style[prop] = '' + (val | 0);
			}
		}
		//#64: "float" can't be set across browsers. Needs to use "cssFloat" for all except IE.
		else if(prop === 'float') {
			style.styleFloat = style.cssFloat = val;
		}
		else {
			//Need try-catch for old IE.
			try {
				//Set prefixed property if there's a prefix.
				if(theCSSPrefix) {
					style[theCSSPrefix + prop.slice(0,1).toUpperCase() + prop.slice(1)] = val;
				}

				//Set unprefixed.
				style[prop] = val;
			} catch(ignore) {}
		}
	};

	/**
	 * Cross browser event handling.
	 */
	var _addEvent = skrollr.addEvent = function(element, names, callback) {
		var intermediate = function(e) {
			//Normalize IE event stuff.
			e = e || window.event;

			if(!e.target) {
				e.target = e.srcElement;
			}

			if(!e.preventDefault) {
				e.preventDefault = function() {
					e.returnValue = false;
					e.defaultPrevented = true;
				};
			}

			return callback.call(this, e);
		};

		names = names.split(' ');

		var name;
		var nameCounter = 0;
		var namesLength = names.length;

		for(; nameCounter < namesLength; nameCounter++) {
			name = names[nameCounter];

			if(element.addEventListener) {
				element.addEventListener(name, callback, false);
			} else {
				element.attachEvent('on' + name, intermediate);
			}

			//Remember the events to be able to flush them later.
			_registeredEvents.push({
				element: element,
				name: name,
				listener: callback
			});
		}
	};

	var _removeEvent = skrollr.removeEvent = function(element, names, callback) {
		names = names.split(' ');

		var nameCounter = 0;
		var namesLength = names.length;

		for(; nameCounter < namesLength; nameCounter++) {
			if(element.removeEventListener) {
				element.removeEventListener(names[nameCounter], callback, false);
			} else {
				element.detachEvent('on' + names[nameCounter], callback);
			}
		}
	};

	var _removeAllEvents = function() {
		var eventData;
		var eventCounter = 0;
		var eventsLength = _registeredEvents.length;

		for(; eventCounter < eventsLength; eventCounter++) {
			eventData = _registeredEvents[eventCounter];

			_removeEvent(eventData.element, eventData.name, eventData.listener);
		}

		_registeredEvents = [];
	};

	var _emitEvent = function(element, name, direction) {
		if(_listeners.keyframe) {
			_listeners.keyframe.call(_instance, element, name, direction);
		}
	};

	var _reflow = function() {
		var pos = _instance.getScrollTop();

		//Will be recalculated by _updateDependentKeyFrames.
		_maxKeyFrame = 0;

		if(_forceHeight && !_isMobile) {
			//un-"force" the height to not mess with the calculations in _updateDependentKeyFrames (#216).
			body.style.height = '';
		}

		_updateDependentKeyFrames();

		if(_forceHeight && !_isMobile) {
			//"force" the height.
			body.style.height = (_maxKeyFrame + documentElement.clientHeight) + 'px';
		}

		//The scroll offset may now be larger than needed (on desktop the browser/os prevents scrolling farther than the bottom).
		if(_isMobile) {
			_instance.setScrollTop(Math.min(_instance.getScrollTop(), _maxKeyFrame));
		} else {
			//Remember and reset the scroll pos (#217).
			_instance.setScrollTop(pos, true);
		}

		_forceRender = true;
	};

	/*
	 * Returns a copy of the constants object where all functions and strings have been evaluated.
	 */
	var _processConstants = function() {
		var viewportHeight = documentElement.clientHeight;
		var copy = {};
		var prop;
		var value;

		for(prop in _constants) {
			value = _constants[prop];

			if(typeof value === 'function') {
				value = value.call(_instance);
			}
			//Percentage offset.
			else if((/p$/).test(value)) {
				value = (value.slice(0, -1) / 100) * viewportHeight;
			}

			copy[prop] = value;
		}

		return copy;
	};

	/*
	 * Returns the height of the document.
	 */
	var _getDocumentHeight = function() {
		var skrollrBodyHeight = 0;
		var bodyHeight;

		if(_skrollrBody) {
			skrollrBodyHeight = Math.max(_skrollrBody.offsetHeight, _skrollrBody.scrollHeight);
		}

		bodyHeight = Math.max(skrollrBodyHeight, body.scrollHeight, body.offsetHeight, documentElement.scrollHeight, documentElement.offsetHeight, documentElement.clientHeight);

		return bodyHeight - documentElement.clientHeight;
	};

	/**
	 * Returns a string of space separated classnames for the current element.
	 * Works with SVG as well.
	 */
	var _getClass = function(element) {
		var prop = 'className';

		//SVG support by using className.baseVal instead of just className.
		if(window.SVGElement && element instanceof window.SVGElement) {
			element = element[prop];
			prop = 'baseVal';
		}

		return element[prop];
	};

	/**
	 * Adds and removes a CSS classes.
	 * Works with SVG as well.
	 * add and remove are arrays of strings,
	 * or if remove is ommited add is a string and overwrites all classes.
	 */
	var _updateClass = function(element, add, remove) {
		var prop = 'className';

		//SVG support by using className.baseVal instead of just className.
		if(window.SVGElement && element instanceof window.SVGElement) {
			element = element[prop];
			prop = 'baseVal';
		}

		//When remove is ommited, we want to overwrite/set the classes.
		if(remove === undefined) {
			element[prop] = add;
			return;
		}

		//Cache current classes. We will work on a string before passing back to DOM.
		var val = element[prop];

		//All classes to be removed.
		var classRemoveIndex = 0;
		var removeLength = remove.length;

		for(; classRemoveIndex < removeLength; classRemoveIndex++) {
			val = _untrim(val).replace(_untrim(remove[classRemoveIndex]), ' ');
		}

		val = _trim(val);

		//All classes to be added.
		var classAddIndex = 0;
		var addLength = add.length;

		for(; classAddIndex < addLength; classAddIndex++) {
			//Only add if el not already has class.
			if(_untrim(val).indexOf(_untrim(add[classAddIndex])) === -1) {
				val += ' ' + add[classAddIndex];
			}
		}

		element[prop] = _trim(val);
	};

	var _trim = function(a) {
		return a.replace(rxTrim, '');
	};

	/**
	 * Adds a space before and after the string.
	 */
	var _untrim = function(a) {
		return ' ' + a + ' ';
	};

	var _now = Date.now || function() {
		return +new Date();
	};

	var _keyFrameComparator = function(a, b) {
		return a.frame - b.frame;
	};

	/*
	 * Private variables.
	 */

	//Singleton
	var _instance;

	/*
		A list of all elements which should be animated associated with their the metadata.
		Exmaple skrollable with two key frames animating from 100px width to 20px:

		skrollable = {
			element: <the DOM element>,
			styleAttr: <style attribute of the element before skrollr>,
			classAttr: <class attribute of the element before skrollr>,
			keyFrames: [
				{
					frame: 100,
					props: {
						width: {
							value: ['{?}px', 100],
							easing: <reference to easing function>
						}
					},
					mode: "absolute"
				},
				{
					frame: 200,
					props: {
						width: {
							value: ['{?}px', 20],
							easing: <reference to easing function>
						}
					},
					mode: "absolute"
				}
			]
		};
	*/
	var _skrollables;

	var _skrollrBody;

	var _listeners;
	var _forceHeight;
	var _maxKeyFrame = 0;

	var _scale = 1;
	var _constants;

	var _mobileDeceleration;

	//Current direction (up/down).
	var _direction = 'down';

	//The last top offset value. Needed to determine direction.
	var _lastTop = -1;

	//The last time we called the render method (doesn't mean we rendered!).
	var _lastRenderCall = _now();

	//For detecting if it actually resized (#271).
	var _lastViewportWidth = 0;
	var _lastViewportHeight = 0;

	var _requestReflow = false;

	//Will contain data about a running scrollbar animation, if any.
	var _scrollAnimation;

	var _smoothScrollingEnabled;

	var _smoothScrollingDuration;

	//Will contain settins for smooth scrolling if enabled.
	var _smoothScrolling;

	//Can be set by any operation/event to force rendering even if the scrollbar didn't move.
	var _forceRender;

	//Each skrollable gets an unique ID incremented for each skrollable.
	//The ID is the index in the _skrollables array.
	var _skrollableIdCounter = 0;

	var _edgeStrategy;


	//Mobile specific vars. Will be stripped by UglifyJS when not in use.
	var _isMobile = false;

	//The virtual scroll offset when using mobile scrolling.
	var _mobileOffset = 0;

	//If the browser supports 3d transforms, this will be filled with 'translateZ(0)' (empty string otherwise).
	var _translateZ;

	//Will contain data about registered events by skrollr.
	var _registeredEvents = [];

	//Animation frame id returned by RequestAnimationFrame (or timeout when RAF is not supported).
	var _animFrame;

	//Expose skrollr as either a global variable or a require.js module.
	if(typeof define === 'function' && define.amd) {
		define([], function () {
			return skrollr;
		});
	} else if (typeof module !== 'undefined' && module.exports) {
		module.exports = skrollr;
	} else {
		window.skrollr = skrollr;
	}

}(window, document));
;
// Constructor
var KOAAutoSuggest = (function () {
	return {
		init: function (options, elem) {
			// Mix in the passed in options with the default options
			this.options = $.extend({}, this.options, options);

			if (this.options.input == null || this.options.container == null) {
				return;
			}

			this.typeTimeout = null;
			this.xhr = null;
			this.camps = {};

			//disable native browser autocomplete
			$(this.options.input).attr('autocomplete', 'off');

			jQuery(this.options.input).bind("keyup", this, this.onInputKeyUp);
			jQuery(document).bind("mousedown", this, this.onDocumentMouseDown);
		},
		options: {
			container: null,
			input: null,
			truncateAt: null
		},
		// Prototype Members
		onInputKeyUp: function (e) {
			var $suggestList = jQuery(e.data.options.container + ' .find-results');

			var keyCode = e.keyCode || e.which;

			switch (keyCode) {
				case 27: // Escape
					$suggestList.hide();
				case 9:
				case 16:
					//case 17:
				case 18:
				case 19:
				case 33:
				case 34:
				case 35:
				case 36:
				case 37:
				case 38:
				case 39:
				case 40:
				case 44:
				case 46:
				case 91:
				case 92:
				case 145:
				case 13:
					//case 224:
					return;
				default:
			}

			e.data.clearTypeTimeout();

			e.data.abortAjax();

			var $this = jQuery(this);
			var query = $this.val();

			if (query.length >= 3) {
				e.data.typeTimeout = window.setTimeout(function () {
					e.data.xhr = jQuery.ajax(
					{
						url: '/handlers/autosuggest.ashx?q=' + encodeURIComponent(query),
						type: 'GET',
						success: function () {
							e.data.onAutoSuggestSuccess(e.data);
						},
						error: function (e, jqxhr, settings, exception) {
							console.log(exception);
						}
					});
				}, 100);
			}
			else {
				$suggestList.hide();
			}
		},
		clearTypeTimeout: function () {
			if (this.typeTimeout != null) {
				window.clearTimeout(this.typeTimeout);
				this.typeTimeout = null;
			}
		},
		abortAjax: function () {
			if (this.xhr != null) {
				try {
					if (typeof (this.xhr.abort) === 'function') {
						this.xhr.abort();
					}
					if (typeof (this.xhr.close) === 'function') {
						this.xhr.close();
					}
				}
				catch (e) { }
			}
		},
		onAutoSuggestSuccess: function (data) {
			var $suggestList = jQuery(data.options.container + ' .find-results');

			try {
				data = jQuery.parseJSON(data.xhr.responseText);
			}
			catch (e) {
				$suggestList.hide();
				return;
			}

			if (data.status == "success") {
				var ilen = data.list.length;

				if (ilen > 0) {
					var suggestHTML = [];
					for (var i = 0; i < ilen; i++) {
						// Store the camp data
						this.camps[data.list[i].id] = data.list[i];

						suggestHTML[suggestHTML.length] = '<li class="';
						if (i == 0) {
							//suggestHTML[suggestHTML.length] = 'first ';
							suggestHTML[suggestHTML.length] = 'first';
						}

						// Truncate camp name
						fullCampName = '';
						campName = data.list[i].name;
						if (this.options.truncateAt != null && !isNaN(this.options.truncateAt) && campName.length > this.options.truncateAt) {
							fullCampName = campName;
							campName = campName.substr(0, this.options.truncateAt - 3) + '...';
						}

						// Set country indicator
						var countryIndicator = '';
						switch (data.list[i].state) {
							case "AB":
							case "BC":
							case "SK":
							case "MB":
							case "ON":
							case "QC":
							case "NB":
							case "NS":
							case "NL":
							case "PE":
								countryIndicator = '<br />Canada';
								break;
							default:
								countryIndicator = '<br />USA';
								break;
						}

						suggestHTML[suggestHTML.length] = '"><div class="col-1"><a href="';
						suggestHTML[suggestHTML.length] = data.list[i].link;
						suggestHTML[suggestHTML.length] = '/" title="';
						suggestHTML[suggestHTML.length] = fullCampName;
						suggestHTML[suggestHTML.length] = '" class="link-arrow5 link-suggest-camp-name" rel="';
						suggestHTML[suggestHTML.length] = data.list[i].id;
						suggestHTML[suggestHTML.length] = '">';
						suggestHTML[suggestHTML.length] = campName;
						suggestHTML[suggestHTML.length] = countryIndicator + '</a></div><div class="col-2">';

						if (data.list[i].irez == 1) {
							suggestHTML[suggestHTML.length] = '<a class="link-book" href="';
							suggestHTML[suggestHTML.length] = data.list[i].link + "/reserve/";
							suggestHTML[suggestHTML.length] = '" rel="';
							suggestHTML[suggestHTML.length] = data.list[i].id;
							suggestHTML[suggestHTML.length] = '">Reserve</a>';
						}

						suggestHTML[suggestHTML.length] = '</div><div style="clear:both;"></div></li>';
					}
					$suggestList.find('ul').html(suggestHTML.join(''));
					$suggestList.animate({ height: 'show' }, 250);
				}
				else {
					$suggestList.hide();
				}
			}
			else {
				$suggestList.hide();
			}
		},
		onDocumentMouseDown: function (e) {
			var $container = jQuery(e.data.options.container);
			var $suggestList = jQuery(e.data.options.container + ' .find-results');
			if ($container.has(e.target).length <= 0 && $suggestList.is(':visible')) {
				$suggestList.hide();
			}
		}
	}
})();

$(function () {
	//load the plugins
	$.plugin("koaautosuggest", KOAAutoSuggest);

	$("#input-find").koaautosuggest({ container: '#find-koa', input: '#input-find', truncateAt: 29 });
	$("#find-a-koa-small-search").koaautosuggest({ container: '#find-koa-wrap-small', input: '#find-a-koa-small-search' });
});
;
$(document).ready(function () {
	$(document).click(function (e) {
		if (!$("#saved-reservations").is(e.target) && !$("#saved-reservations").has(e.target).length) {
			$('#saved-reservations').collapse('hide');
		}
	});

	$('.saved-reservations-toggler').click(function () {
		var $navbar = $('#mainMenu .navbar-toggler');
		if ($navbar.attr('aria-expanded') === 'true') {
			$navbar.click();
		}
	});

	$('.save-res-save-link').click(function (e) {
		e.preventDefault();

		var link = $(this);
		var status = link.attr("data-status");

		if (status == 'Auto') {

			$.ajax({
				type: "POST",
				url: "/api/saved-reservations/save/",
				async: true,
				data: { id: $(this).attr("data-id") },
				success: function (response) {
					link.attr("data-status", "Saved");
					link.addClass("save-res-action-link-saved");

					var icon = link.find('.fa-star')
					icon.removeClass("far");
					icon.addClass("fas");
				}
			});

		}
		else {
			$.ajax({
				type: "POST",
				url: "/api/saved-reservations/remove/",
				async: true,
				data: { id: $(this).attr("data-id") },
				success: function (response) {
					link.attr("data-status", "Auto");
					link.removeClass("save-res-action-link-saved");
					var icon = link.find('.fa-star')
					icon.removeClass("fas");
					icon.addClass("far");
				}
			});
		}


		return false;
	});

	$('.save-res-delete-link').click(function (e) {
		e.preventDefault();

		var parentContainer = $("#save-res-panel-" + $(this).attr("data-id"));

		$.ajax({
			type: "POST",
			url: "/api/saved-reservations/delete/",
			async: true,
			data: { id: $(this).attr("data-id") },
			success: function (response) {
				parentContainer.fadeOut("normal", function () {
					$(this).remove();
				});
			}
		});
		return false;
	});

	$('.save-res-clear-history').click(function (e) {
		e.preventDefault();

		$.ajax({
			type: "POST",
			url: "/api/saved-reservations/delete-all/",
			async: true,
			success: function (response) {
				$($(".save-res-auto-save-panel").get().reverse()).each(function (index) {
					$(this).delay(400 * index).fadeOut("normal", function () {
						$(this).remove();
					});
				});
			}
		});

		return false;
	});

	$('.account-save-res-delete-link').click(function (e) {
		e.preventDefault();

		var parentContainer = $("#save-res-panel-" + $(this).attr("data-id"));

		$.ajax({
			type: "POST",
			url: "/api/saved-reservations/delete/",
			async: true,
			data: { id: $(this).attr("data-id") },
			success: function (response) {
				location.reload();
			}
		});
		return false;
	});

	$('.account-save-res-clear-history').click(function (e) {
		e.preventDefault();

		$.ajax({
			type: "POST",
			url: "/api/saved-reservations/delete-all/",
			async: true,
			success: function (response) {
				location.reload();
			}
		});

		return false;
	});
});
;
var mainShoppingCart;

$(document).ready(function () {	
	$('#shopping-cart-content').hide();
	$('#shopping-cart-wrapper').hide();

	mainShoppingCart = new shoppingCart({ sideBarVisible: false });

	$(".shopping-cart-toggler").click(function () {
		mainShoppingCart.toggleSideBar();
	});

	$("#shopping-cart-close-link-top").click(function () {
		mainShoppingCart.toggleSideBar();
	});

	$("#shopping-cart-close-link-bottom").click(function () {
		mainShoppingCart.toggleSideBar();
	});

	$(".btn-cart-view-cart").click(function (event) {
		event.preventDefault();

		$('#add-to-cart-modal').modal('hide');
		mainShoppingCart.showSideBar();
	});

	$("input[name='scReservation.Value.RewardID']").change(function () {
		var scId = $(this).attr('data-scid');
		var rewardId = $(this).val();

		$("#applyRewardsAmountButton").val(scId + "|" + rewardId);
		$("#applyRewardsAmountButton").click();
		return false;
	});

	$(document).on("click", ".btn-add-to-cart", function (event) {
		event.preventDefault();

		var addToCartButton = $(this);
		window.setTimeout(function () { addToCartButton.attr('disabled', 'disabled'); }, 0);

		var siteInfo = $(this).attr('data-href');

		var cartIcon = $('#shopping-cart-nav-link .shopping-cart-icon');

		if ($('#mainNavContent').css('display') == "none") {
			cartIcon = $('#shopping-cart-nav-link-mobile .shopping-cart-icon');
		}

		if (!cartIcon.length) {
			cartIcon = null;
		}

		if (!cartIcon) {
			mainShoppingCart.addToCart(null, siteInfo, addToCartButton);
			mainGa4DataLayer.addToCart(addToCartButton.data('siteid'),
			addToCartButton.data('nights'));
			return;
		}

		var imgToCart = $(this).closest('.reserve-sitetype-container').find("img.campsite-photo").eq(0);

		if (imgToCart) {
			var imgClone = imgToCart.clone()
				.offset({
					top: imgToCart.offset().top,
					left: imgToCart.offset().left
				})
				.css({
					'opacity': '0.5',
					'position': 'absolute',
					'z-index': '5000',
					'border': '0px',
					'width': imgToCart.width + "px",
					'height': imgToCart.height + "px"
				})
				.appendTo($('body'))
				.animate({
					'top': cartIcon.offset().top - 3,
					'left': cartIcon.offset().left + 1,
					'width': 25,
					'height': 25
				}, 1000, 'easeInOutExpo');

			imgClone.animate({
				height: 0,
				width: 0,
				top: '+=12px',
				left: '+=12px'
			}, function () {
				$(this).detach();

				mainShoppingCart.addToCart(cartIcon, siteInfo, addToCartButton);
				mainGa4DataLayer.addToCart(addToCartButton.data('siteid'),
				addToCartButton.data('nights'));
			});
		}
	});

	$('.btn-add-to-cart-step-3').on('click', function (event) {
		event.preventDefault();

		var addToCartButton = $(this);
		window.setTimeout(function () { addToCartButton.attr('disabled', 'disabled'); }, 0);

		var siteInfo = $(this).attr('data-href');
		var cartIcon = $('.shopping-cart-icon');

		mainShoppingCart.addToCart(cartIcon, siteInfo, addToCartButton);
	});

	$('.btn-add-to-cart-view-details').on('click', function (event) {
		event.preventDefault();

		var addToCartButton = $(this);
		window.setTimeout(function () { addToCartButton.attr('disabled', 'disabled'); }, 0);

		var siteInfo = $(this).attr('data-href');
		var cartIcon = $('.shopping-cart-icon');

		mainShoppingCart.addToCart(cartIcon, siteInfo, addToCartButton);
		mainGa4DataLayer.addToCart(addToCartButton.data('siteid'),
		addToCartButton.data('nights'));

		parent.$.fancybox.close();
	});

	$('.btn-select-site-add-to-cart').on('click', function (event) {
		event.preventDefault();		

		if (!$("#SiteID").val()) {
			$('#SiteID').addClass('is-invalid');
			$('#reserve-form-site-select-icon').show("fast");
			$('#SiteID').focus();
		}
		else {
			$('#SiteID').removeClass('is-invalid');
			$('#reserve-form-site-select-icon').hide("fast");

			var addToCartButton = $(this);
			window.setTimeout(function () { addToCartButton.attr('disabled', 'disabled'); }, 0);

			var siteInfo = $(this).attr('data-href');

			siteInfo += "&SiteID=" + $("#SiteID").val();
			siteInfo += "&SiteNumber=" + $("#SiteID option:selected").attr('name');
			var siteNumber = $("#SiteID option:selected").attr('name');

			if (self == top) {
				var cartIcon = $('.shopping-cart-icon');
				mainShoppingCart.addToCart(cartIcon, siteInfo, addToCartButton);				
				mainGa4DataLayer.addToCartSelectSite(siteNumber, addToCartButton.data('siteid'), addToCartButton.data('nights'));
			}
			else {
				var cartIcon = parent.$('.shopping-cart-icon');
				parent.mainShoppingCart.addToCart(cartIcon, siteInfo, addToCartButton);				
				mainGa4DataLayer.addToCartSelectSite(siteNumber, addToCartButton.data('siteid'), addToCartButton.data('nights'));
			}

			parent.$('#modal-window-iframe-extra-large').modal('hide');
		}
	});

	$(document).on("click", ".btn-cart-view-rates, .btn-checkout-view-rates", function (e) {
		e.preventDefault();

		var title = $(this).attr('title');
		var locationHref = $(this).attr('href');

		//append popup=true
		locationHref += "&popup=true";

		$('#modal-window-iframe-extra-large').modal({ show: true });

		$('#modal-window-iframe-extra-large').on('shown.bs.modal', function () {
			var modal = $(this);
			modal.find('iframe').attr("src", locationHref);
		});
		$('#modal-window-iframe-extra-large').on('hidden.bs.modal', function (e) {
			//clear the iframe url, so it does not show on the next load
			var modal = $(this);
			modal.find('iframe').attr("src", '/content/images/1px_trans.png');
		});
	});

	$('.btn-rates-add-to-cart').on('click', function (e) {
		e.preventDefault();

		parent.$('#modal-window-iframe-extra-large').modal('hide');
		parent.$('#' + $(this).attr('data-target')).click();

		return false;
	});

	$('.toggle-rewards-options').on('click', function () {
		let dataId = $(this).attr('data-id')
		$('.use-rewards-btn[data-id="' + dataId + '"]').hide();
		$('.rewards-points-options[data-id="' + dataId + '"]').show();
	});

	var elements = $(".using-points");

	elements.each(function () {
		$(this).find(".rewards-points-options").show();
	});
});

var shoppingCartUpdatedMonitor = function (options) {

	var vars = {
		shoppingCartMonitorCartUrl: "/api/shopping-cart/checkhascartupdated/",
		hashKey: ''
	};

	var root = this;
	var _allowMonitor = true;

	this.construct = function (options) {
		$.extend(vars, options);
	};

	this.beginMonitor = function () {
		beginMonitor();
	};

	this.stopMonitor = function () {
		stopMonitor();
	};

	var stopMonitor = function () {
		_allowMonitor = false;
	};

	var beginMonitor = function () {
		_allowMonitor = true;
		checkHash();
	};

	var checkHash = function () {

		var getData = vars.hashKey;

		$.get(vars.shoppingCartMonitorCartUrl + "?k=" + getData)
			.done(function (data) {
				if (data == "") {
					if (_allowMonitor) {
						setTimeout(checkHash, 10000);
					}
					return;
				}

				if (data.Valid) {
					if (_allowMonitor) {
						setTimeout(checkHash, 10000);
					}
				}
				else {
					if (_allowMonitor) {
						$('#add-to-cart-error-modal .modal-title').html("Cart Updated!");
						$('#add-to-cart-error-modal .error-message').html("Your cart has been updated and this checkout screen does not reflect those changes.  This page is being refreshed to reflect your updated cart.");
						$('#add-to-cart-error-modal').modal('show');

						setTimeout(() => window.location.reload(), 3000);
					}
				}
			})
			.fail(function () {
				if (_allowMonitor) {
					setTimeout(checkHash, 10000);
				}
			})
			.always(function () {

			});
	};

	this.construct(options);
};

var shoppingCart = function (options) {

	var vars = {
		shoppingCartAddToCartUrl: "/api/shopping-cart/add/",
		shoppingCartBookReservationUrl: "/api/shopping-cart/book/"		
	};

	var root = this;
	var _sideBarToggling = false
	var _sideBarVisible = false;
	var _currentBookingIndex = 0;
	var _reservationsToBook;

	this.construct = function (options) {
		$.extend(vars, options);
	};

	this.toggleSideBar = function () {
		toggleSideBar();
	};

	this.showSideBar = function () {
		showSideBar();
	};

	this.addToCart = function (cartIcon, siteInfo, addToCartButton) {
		addToCart(cartIcon, siteInfo, addToCartButton);
	};

	this.refreshCart = function () {
		refreshCart();
	};

	this.bookReservations = function (reservationsToBook) {		
		bookReservations(reservationsToBook);
	};

	this.continueBookingReservations = function (reservationsToBook) {
		bookReservations(reservationsToBook);
	};

	var toggleSideBar = function () {
		if (!_sideBarToggling) {
			_sideBarToggling = true;

			if (_sideBarVisible) {
				$('#shopping-cart-content').toggle("slide", { direction: 'right' }, function () {
					$("#shopping-cart-wrapper").hide();
					_sideBarVisible = false;
					_sideBarToggling = false;
				});
			}
			else {
				$("#shopping-cart-wrapper").show(0, function () {
					$('#shopping-cart-content').toggle("slide", { direction: 'right' });
					$("#shopping-cart-wrapper").show();
					_sideBarVisible = true;
					_sideBarToggling = false;
				});
			}
		}
	};

	var showSideBar = function () {
		if (!_sideBarVisible) {
			toggleSideBar();
		}
	};

	var refreshCart = function () {
		$.ajax({
			type: "POST",
			url: "/api/shopping-cart/get-all/",
			async: true,
			data: { id: $(this).attr("data-id") },
			success: function () {

			}
		});
	};

	var addToCart = function (cartIcon, siteInfo, addToCartButton) {

		if (cartIcon != null) {
			cartIcon.addClass('shopping-cart-loading-animation');
		}

		var postData = null;

		if (siteInfo !== 'undefined') {
			postData = siteInfo;
		}
		else {
			postData = addToCartButton.attr('data-href');
		}

		$.post(vars.shoppingCartAddToCartUrl, postData)
			.done(function (data) {
				$(document).trigger("OnShoppingCartAdd", data);
				if (data == "") {
					$('#add-to-cart-error-modal .error-message').html("Sorry, there was an error while adding your site to your cart.");
					$('#add-to-cart-error-modal').modal('show');

					return;
				}

				if (data.Success) {
					$('.shopping-cart-icon').attr('data-count', data.CartItemCount)
					$('#shopping-cart-cart-items-wrapper').html(data.CartItemsView);
					$('#add-to-cart-modal .warning-message').html('');

					if (data.CartItemCount == 0) {
						$('#shopping-cart-empty-cart-message').removeClass("d-none");
						$('#shopping-cart-checkout-button').addClass("d-none");
						$('#shopping-cart-clear-cart-wrapper').addClass("d-none");
					}
					else {
						$('#shopping-cart-empty-cart-message').addClass("d-none");
						$('#shopping-cart-checkout-button').removeClass("d-none");
						$('#shopping-cart-clear-cart-wrapper').removeClass("d-none");
					}

					if (data.WarningMessage) {
						$('#add-to-cart-modal .warning-message').html(data.WarningMessage);
					}

					$('#add-to-cart-modal').modal('show');
				}
				else {
					if (data.ErrorMessage) {
						$('#add-to-cart-error-modal .error-message').html(data.ErrorMessage);
						$('#add-to-cart-error-modal').modal('show');

						return false;
					}
				}
			})
			.fail(function () {
				$('#add-to-cart-error-modal .error-message').html("Sorry, there was an error while adding your site to your cart.");
				$('#add-to-cart-error-modal').modal('show');
			})
			.always(function () {
				if (cartIcon != null) {
					cartIcon.show();
					cartIcon.removeClass('shopping-cart-loading-animation');
				}
				window.setTimeout(function () { addToCartButton.removeAttr('disabled'); addToCartButton.blur(); }, 0);
			});
	};

	var bookReservations = function (reservationsToBook) {		
		bookReservation(_currentBookingIndex, reservationsToBook);
	};

	var bookReservation = function (currentIndex, reservationsToBook) {		
		if (currentIndex >= reservationsToBook.length) {

			_displayLeaveMessage = false;
			$("#shoppingCartConfirmationForm").submit();
			return false;
		}

		$("#shopping-cart-booking-modal-label").html("Booking Site " + (currentIndex + 1) + " of " + reservationsToBook.length);

		var shoppingCartID = reservationsToBook[currentIndex].id.replace('shopping-cart-modal-reservation-', '');

		reservationsToBook.each(function (index) {
			if (index == currentIndex) {
				$(this).removeClass('d-none');
			}
			else {
				$(this).addClass('d-none');
			}
		});

		var addonsArray = [];
		$('[name="Reservation.AddonsAccepted-' + shoppingCartID + '.Index"]').each(function () {
			var addonID = $(this).val();

			var addonValues = {
				"Index": addonID,
				"AddonID": $('[name="Reservation.AddonsAccepted-' + shoppingCartID + '['+addonID+'].AddonID"]').val(),
				"Quantity": $('[name="Reservation.AddonsAccepted-' + shoppingCartID + '[' + addonID + '].Quantity"]').val()
			};

			addonsArray.push(addonValues);
		});	
		var postData = {
			FirstName: $("#FirstName").val(),
			LastName: $("#LastName").val(),
			Address1: $("#Address1").val(),
			Address2: $("#Address2").val(),
			PhoneNumber: $("#PhoneNumber").val(),
			City: $("#City").val(),
			StateProvinceCode: $("#StateProvinceCode").val(),
			CountryCode: $("#CountryCode").val(),
			PostalCode: $("#PostalCode").val(),
			EmailAddress: $("#EmailAddress").val(),
			ConfirmEmailAddress: $("#ConfirmEmailAddress").val(),
			CreditCardNumber: $("#CreditCardNumber").val(),
			CreditCardType: $("#CreditCardType").val(),
			CreditCardExpMonth: $("#CreditCardExpMonth").val(),
			CreditCardExpYear: $("#CreditCardExpYear").val(),
			CreditCardSecurityCode: $("#CreditCardSecurityCode").val(),
			CreditCardToken: $("#CreditCardToken").val(),
			CreditCardConfirmationToken: $("#CreditCardConfirmationToken").val(),
			CartTransactionID: $("#CartTransactionID").val(),
			TermsAgree: $("#TermsAgree").val(),
			RewardsNumber: $("#RewardsNumber").val(),
			RewardsNumberPostalCode: $("#RewardsNumberPostalCode").val(),
			DonateCareCamps: currentIndex == 0 ? $("#DonateCareCamps").val() : "false",
			PersonID: $("#PersonID").val(),			

			//cart specific items
			SpecialRequests: $("#SpecialRequests-" + shoppingCartID).val(),
			EmailAddressCCs: $("#EmailAddressCCs-" + shoppingCartID).val(),
			CareCampsDonation: $("#CareCampsDonation-" + shoppingCartID).val(),
			BuyRewards: currentIndex == 0 ? $("#BuyRewards" + shoppingCartID).val() : "false",
			ShoppingCartReservationID: $("#ShoppingCartReservationID-" + shoppingCartID).val(),
			TransactionID: $("#ShoppingCartReservationID-" + shoppingCartID).val(),
			SecurityKey: $("#SecurityKey-" + shoppingCartID).val(),
			Order: currentIndex,
			TotalBookingCount: reservationsToBook.length,
			DateUpdated: $("#DateUpdated-" + shoppingCartID).val(),
			ExpectedDeposit: $("#ExpectedDeposit-" + shoppingCartID).val(),
			ExpectedTotal: $("#ExpectedTotal-" + shoppingCartID).val(),
			AddonsAccepted: addonsArray,
		};
		
		$.post(vars.shoppingCartBookReservationUrl, postData)		
			.done(function (data) {
				if (data == "") {
					$('#add-to-cart-error-modal .error-message').html("Sorry, there was an error while booking your site.");
					$('#add-to-cart-error-modal').modal('show');

					return;
				}

				if (data.Success) {

					if (data.VkrNumber && data.VkrExpiration) {
						$("#RewardsNumber").val(data.VkrNumber);
						$("#RewardsNumberPostalCode").val(data.VkrPostalCode);

						$("#Confirm_RewardsNumber").val(data.VkrNumber);
						$("#Confirm_RewardsNumberPostalCode").val(data.VkrPostalCode);
					}

					if (data.CartItem) {
						$("#Confirm-CartItems-" + currentIndex).val(JSON.stringify(data.CartItem));
						$("#Confirm-CartItems-Confirmations-" + currentIndex).val(data.ConfirmationNumber);
					}

					if (currentIndex == 0) {
						$("#Confirm_CareCampsDonationConfirmation").val(data.CareCampsDonationConfirmation);
						$("#Confirm_CareCampsDonationError").val(data.CareCampsDonationError);
					}

					if (currentIndex + 1 < reservationsToBook.length) {
						bookReservation(currentIndex + 1, reservationsToBook);
					}

					if (currentIndex + 1 == reservationsToBook.length) {
						reservationsToBook.each(function (index) {
							$(this).addClass('d-none');
						});

						$("#shopping-cart-booking-modal-label").html("Complete!");

						_displayLeaveMessage = false;

						//reservations complete. Submit privacy settings update.						
						updatePrivacySettings($("#PrivacyCustomerCare").val(), $("#PrivacyMarketing").is(":checked"), $("#PersonID").val());

						$("#shoppingCartConfirmationForm").submit();
					}
				}
				else {
					if (data.ErrorMessage) {
						$("#shopping-cart-booking-modal-label").html("Booking Site " + (currentIndex + 1) + " of " + reservationsToBook.length + " - Error!");
						$('#shopping-cart-booking-please-wait').hide();
						$('#shopping-cart-booking-response').removeClass('d-none');
						$('#shopping-cart-booking-error').removeClass('d-none');
						$('#shopping-cart-booking-error .error-message').html(data.ErrorMessage);
					}

					if (data.WarningMessage) {
						$("#shopping-cart-booking-modal-label").html("Booking Site " + (currentIndex + 1) + " of " + reservationsToBook.length + " - Warning!");
						$('#shopping-cart-booking-please-wait').hide();
						$('#shopping-cart-booking-response').removeClass('d-none');
						$('#shopping-cart-booking-warning').removeClass('d-none');

						$('#shopping-cart-booking-warning .error-message').html(data.WarningMessage);
					}

					if (data.ContinueOnConfirm) {
						$('#shopping-cart-booking-error-continue-button').removeClass('d-none');
					}
					else {
						$('#shopping-cart-booking-error-continue-button').addClass('d-none');
					}

					if (!data.BookOnContinue) {
						_currentBookingIndex = currentIndex + 1;
					}
				}
			})
			.fail(function () {
				$("#shopping-cart-booking-modal-label").html("Booking Site " + (currentIndex + 1) + " of " + reservationsToBook.length + " - Error!");
				$('#shopping-cart-booking-please-wait').hide();
				$('#shopping-cart-booking-response').removeClass('d-none');
				$('#shopping-cart-booking-error').removeClass('d-none');
				$('#shopping-cart-booking-error .error-message').html("Sorry, there was an error while trying to book your your site.");

				_currentBookingIndex = currentIndex;
			})
			.always(function () {

			});
	};

	var updatePrivacySettings = function (bPrivacyCustomerCare, bPrivacyMarketing, sPersonIdentifier) {		
		$.ajax({
			type: "POST",
			url: "/api/shopping-cart/update-person-privacy-settings/",
			async: true,
			data: {
				bPrivacyCustomerCare: bPrivacyCustomerCare,
				bPrivacyMarketing: bPrivacyMarketing,
				sPersonIdentifier: sPersonIdentifier
			},
			success: function (response) {
				//console.log("Privacy settings updated successfully:", response);
			},
			error: function (xhr, status, error) {
				//console.error("Error updating privacy settings:", error);
			}
		});
	};

	this.construct(options);
};






$(document).ready(function () {
	$(document).on("click", ".shopping-cart-delete-link", function (e) {
		e.preventDefault();

		var parentContainer = $("#shopping-cart-panel-" + $(this).attr("data-id"));

		var dataId = $(this).attr("data-id");

		$(document).trigger('onShoppingCartItemDeleting', [dataId]);

		$.ajax({
			type: "POST",
			url: "/api/shopping-cart/delete/",
			async: true,
			data: { id: $(this).attr("data-id") },
			success: function (data) {
				if (data.Success) {

					parentContainer.fadeOut("normal", function () {
						$(this).remove();

						$('.shopping-cart-icon').attr('data-count', data.CartItemCount)
						$('#shopping-cart-cart-items-wrapper').html(data.CartItemsView);

						if (data.CartItemCount == 0) {
							$('#shopping-cart-empty-cart-message').removeClass("d-none");
							$('#shopping-cart-checkout-button').addClass("d-none");
						}
						else {
							$('#shopping-cart-empty-cart-message').addClass("d-none");
							$('#shopping-cart-checkout-button').removeClass("d-none");
						}


					});

					if (data.CartItemDeleted) {
						mainGa4DataLayer.removeFromCartDataLayer(data.CartItemDeleted);
					}

					$(document).trigger('onShoppingCartItemDelete', [data, dataId]);
				}
				else {
					if (data.ErrorMessage) {
						$('#add-to-cart-error-modal .error-message').html(data.ErrorMessage);
						$('#add-to-cart-error-modal').modal('show');

						return false;
					}
				}
			}
		});

		return false;
	});


	$(document).on("click", ".shopping-cart-clear-cart", function (e) {
		e.preventDefault();

		if (!confirm('Are you sure you want to clear your entire shopping cart?')) {
			return;
		}

		$.ajax({
			type: "POST",
			url: "/api/shopping-cart/delete-all/",
			async: true,
			success: function (data) {
				var itemCount = $('.shopping-cart-icon').attr('data-count');

				$($(".shopping-cart-auto-save-panel").get().reverse()).each(function (index) {
					$(this).delay(400 * index).fadeOut("normal", function () {
						$(this).remove();

						if (index == itemCount - 1) {
							$('#shopping-cart-empty-cart-message').removeClass("d-none");
							$('#shopping-cart-checkout-button').addClass("d-none");
							$('#shopping-cart-panel-koa-rewards').addClass("d-none");
							$('.shopping-cart-icon').attr('data-count', 0);
							$('#shopping-cart-cart-items-wrapper').html('');
							$('#shopping-cart-clear-cart-wrapper').addClass("d-none");
						}
					});
				});

				if (data.Success) {
					if (data.CartItemDeleted) {
						mainGa4DataLayer.removeFromCartDataLayer(data.CartItemDeleted);
					}
				}


				//this calls the method on the home page
				$(document).trigger('onShoppingCartItemsDeleteAll', []);

			}
		});

		return false;
	});

	$(document).on("click", "#shopping-cart-booking-error-continue-button", function (e) {
		e.preventDefault();

		$('#shopping-cart-booking-please-wait').show();
		$('#shopping-cart-booking-response').addClass('d-none');
		$('#shopping-cart-booking-error').addClass('d-none');
		$('#shopping-cart-booking-warning').addClass('d-none');
		$('#shopping-cart-booking-warning .error-message').html('');
		$('#shopping-cart-booking-error .error-message').html('');

		mainShoppingCart.continueBookingReservations($('.shopping-cart-modal-reservation'));

		return false;
	});

	$(document).on("click", "#shopping-cart-booking-error-close-button", function (e) {
		e.preventDefault();

		_displayLeaveMessage = false;
		window.location.reload();

		return false;
	});
});

class Counter {
	constructor(counterContainerSelector, max = 99, min = 0) {
		this.counterContainers = $(counterContainerSelector);
		this.max = max;
		this.min = min;

		this.attachEventListeners();
	}

	attachEventListeners() {
		this.counterContainers.each((index, container) => {
			const $container = $(container);
			const $plusButton = $container.find('.counter-plus');
			const $minusButton = $container.find('.counter-minus');
			const $input = $container.find('.counter-input');

			$plusButton.off('click').on('click', () => this.increment($input));
			$minusButton.off('click').on('click', () => this.decrement($input));
		});
	}

	increment($input) {
		let currentValue = parseInt($input.val(), 10);
		if (currentValue < this.max) {
			$input.val(currentValue + 1);
		}
	}

	decrement($input) {
		let currentValue = parseInt($input.val(), 10);
		if (currentValue > this.min) {
			$input.val(currentValue - 1);
		}
	}
}
class shoppingCartLoadMoreHandler {
	constructor(containerSelector, itemSelector, loadMoreSelector, loadLessSelector, initialCount) {
		this.container = $(containerSelector);
		this.items = this.container.find(itemSelector);
		this.loadMoreButton = $(loadMoreSelector);
		this.loadLessButton = $(loadLessSelector);
		this.initialCount = initialCount;
		this.init();
	}

	updateCounts() {
		this.items.hide();
		this.items.slice(0, this.initialCount).show();

		this.loadMoreButton.show();
		this.loadLessButton.hide();
	}

	init() {
		this.loadMoreButton.on('click', (e) => this.showMore(e));
		this.loadLessButton.on('click', (e) => this.showLess(e));

		this.loadLessButton.hide();
	}

	showMore(e) {
		e.preventDefault();

		const hiddenItems = this.items.filter(':hidden');
		hiddenItems.slideDown();

		if (hiddenItems.length > 0) {
			this.loadMoreButton.hide();
			this.loadLessButton.fadeIn('slow');
		}
	}

	showLess(e) {
		e.preventDefault();

		this.items.not(`:lt(${this.initialCount})`).fadeOut();

		this.loadMoreButton.fadeIn('slow');
		this.loadLessButton.hide();
	}
}
;
/* =============================================================
 * bootstrap3-typeahead.js v3.1.0
 * https://github.com/bassjobsen/Bootstrap-3-Typeahead
 * =============================================================
 * Original written by @mdo and @fat
 * =============================================================
 * Copyright 2014 Bass Jobsen @bassjobsen
 *
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ============================================================ */


(function (root, factory) {

  'use strict';

  // CommonJS module is defined
  if (typeof module !== 'undefined' && module.exports) {
    module.exports = factory(require('jquery'));
  }
  // AMD module is defined
  else if (typeof define === 'function' && define.amd) {
    define(['jquery'], function ($) {
      return factory ($);
    });
  } else {
    factory(root.jQuery);
  }

}(this, function ($) {

  'use strict';
  // jshint laxcomma: true


 /* TYPEAHEAD PUBLIC CLASS DEFINITION
  * ================================= */

  var Typeahead = function (element, options) {
    this.$element = $(element);
    this.options = $.extend({}, $.fn.typeahead.defaults, options);
    this.matcher = this.options.matcher || this.matcher;
    this.sorter = this.options.sorter || this.sorter;
    this.select = this.options.select || this.select;
    this.autoSelect = typeof this.options.autoSelect == 'boolean' ? this.options.autoSelect : true;
    this.highlighter = this.options.highlighter || this.highlighter;
    this.render = this.options.render || this.render;
    this.updater = this.options.updater || this.updater;
    this.displayText = this.options.displayText || this.displayText;
    this.source = this.options.source;
    this.delay = this.options.delay;
    this.$menu = $(this.options.menu);
    this.$appendTo = this.options.appendTo ? $(this.options.appendTo) : null;   
    this.shown = false;
    this.listen();
    this.showHintOnFocus = typeof this.options.showHintOnFocus == 'boolean' ? this.options.showHintOnFocus : false;
    this.afterSelect = this.options.afterSelect;
    this.addItem = false;
  };

  Typeahead.prototype = {

    constructor: Typeahead,

    select: function () {
      var val = this.$menu.find('.active').data('value');
      this.$element.data('active', val);
      if(this.autoSelect || val) {
        var newVal = this.updater(val);
        this.$element
          .val(this.displayText(newVal) || newVal)
          .change();
        this.afterSelect(newVal);
      }
      return this.hide();
    },

    updater: function (item) {
      return item;
    },

    setSource: function (source) {
      this.source = source;
    },

    show: function () {
      var pos = $.extend({}, this.$element.position(), {
        height: this.$element[0].offsetHeight
      }), scrollHeight;

      scrollHeight = typeof this.options.scrollHeight == 'function' ?
          this.options.scrollHeight.call() :
          this.options.scrollHeight;

      (this.$appendTo ? this.$menu.appendTo(this.$appendTo) : this.$menu.insertAfter(this.$element))
        .css({
          top: pos.top + pos.height + scrollHeight
        , left: pos.left
        })
        .show();

      this.shown = true;
      return this;
    },

    hide: function () {
      this.$menu.hide();
      this.shown = false;
      return this;
    },

    lookup: function (query) {
      var items;
      if (typeof(query) != 'undefined' && query !== null) {
        this.query = query;
      } else {
        this.query = this.$element.val() ||  '';
      }

      if (this.query.length < this.options.minLength) {
        return this.shown ? this.hide() : this;
      }

      var worker = $.proxy(function() {
        
        if($.isFunction(this.source)) this.source(this.query, $.proxy(this.process, this));
        else if (this.source) {
          this.process(this.source);
        }
      }, this);

      clearTimeout(this.lookupWorker);
      this.lookupWorker = setTimeout(worker, this.delay);
    },

    process: function (items) {
      var that = this;

      items = $.grep(items, function (item) {
        return that.matcher(item);
      });

      items = this.sorter(items);

      if (!items.length && !this.options.addItem) {
        return this.shown ? this.hide() : this;
      }
      
      if (items.length > 0) {
        this.$element.data('active', items[0]);
      } else {
        this.$element.data('active', null);
      }
      
      // Add item
      if (this.options.addItem){
        items.push(this.options.addItem);
      }

      if (this.options.items == 'all') {
        return this.render(items).show();
      } else {
        return this.render(items.slice(0, this.options.items)).show();
      }
    },

    matcher: function (item) {
    var it = this.displayText(item);
      return ~it.toLowerCase().indexOf(this.query.toLowerCase());
    },

    sorter: function (items) {
      var beginswith = []
        , caseSensitive = []
        , caseInsensitive = []
        , item;

      while ((item = items.shift())) {
        var it = this.displayText(item);
        if (!it.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item);
        else if (~it.indexOf(this.query)) caseSensitive.push(item);
        else caseInsensitive.push(item);
      }

      return beginswith.concat(caseSensitive, caseInsensitive);
    },

    highlighter: function (item) {
          var html = $('<div></div>');
          var query = this.query;
          var i = item.toLowerCase().indexOf(query.toLowerCase());
          var len, leftPart, middlePart, rightPart, strong;
          len = query.length;
          if(len === 0){
              return html.text(item).html();
          }
          while (i > -1) {
              leftPart = item.substr(0, i);
              middlePart = item.substr(i, len);
              rightPart = item.substr(i + len);
              strong = $('<strong></strong>').text(middlePart);
              html
                  .append(document.createTextNode(leftPart))
                  .append(strong);
              item = rightPart;
              i = item.toLowerCase().indexOf(query.toLowerCase());
          }
          return html.append(document.createTextNode(item)).html();
    },

    render: function (items) {
      var that = this;
      var self = this;
      var activeFound = false;
      items = $(items).map(function (i, item) {
        var text = self.displayText(item);
        i = $(that.options.item).data('value', item);
        i.find('a').html(that.highlighter(text));
        if (text == self.$element.val()) {
            i.addClass('active');
            self.$element.data('active', item);
            activeFound = true;
        }
        return i[0];
      });

      if (this.autoSelect && !activeFound) {        
        items.first().addClass('active');
        this.$element.data('active', items.first().data('value'));
      }
      this.$menu.html(items);
      return this;
    },

    displayText: function(item) {
      return item.name || item;
    },

    next: function (event) {
      var active = this.$menu.find('.active').removeClass('active')
        , next = active.next();

      if (!next.length) {
        next = $(this.$menu.find('li')[0]);
      }

      next.addClass('active');
    },

    prev: function (event) {
      var active = this.$menu.find('.active').removeClass('active')
        , prev = active.prev();

      if (!prev.length) {
        prev = this.$menu.find('li').last();
      }

      prev.addClass('active');
    },

    listen: function () {
      this.$element
        .on('focus',    $.proxy(this.focus, this))
        .on('blur',     $.proxy(this.blur, this))
        .on('keypress', $.proxy(this.keypress, this))
        .on('keyup',    $.proxy(this.keyup, this));

      if (this.eventSupported('keydown')) {
        this.$element.on('keydown', $.proxy(this.keydown, this));
      }

      this.$menu
        .on('click', $.proxy(this.click, this))
        .on('mouseenter', 'li', $.proxy(this.mouseenter, this))
        .on('mouseleave', 'li', $.proxy(this.mouseleave, this));
    },
    
    destroy : function () {
      this.$element.data('typeahead',null);
      this.$element.data('active',null);
      this.$element
        .off('focus')
        .off('blur')
        .off('keypress')
        .off('keyup');

      if (this.eventSupported('keydown')) {
        this.$element.off('keydown');
      }

      this.$menu.remove();
    },
    
    eventSupported: function(eventName) {
      var isSupported = eventName in this.$element;
      if (!isSupported) {
        this.$element.setAttribute(eventName, 'return;');
        isSupported = typeof this.$element[eventName] === 'function';
      }
      return isSupported;
    },

    move: function (e) {
      if (!this.shown) return;

      switch(e.keyCode) {
        case 9: // tab
        case 13: // enter
        case 27: // escape
          e.preventDefault();
          break;

        case 38: // up arrow
          // with the shiftKey (this is actually the left parenthesis)
          if (e.shiftKey) return;
          e.preventDefault();
          this.prev();
          break;

        case 40: // down arrow
          // with the shiftKey (this is actually the right parenthesis)
          if (e.shiftKey) return;
          e.preventDefault();
          this.next();
          break;
      }

      e.stopPropagation();
    },

    keydown: function (e) {
      this.suppressKeyPressRepeat = ~$.inArray(e.keyCode, [40,38,9,13,27]);
      if (!this.shown && e.keyCode == 40) {
        this.lookup();
      } else {
        this.move(e);
      }
    },

    keypress: function (e) {
      if (this.suppressKeyPressRepeat) return;
      this.move(e);
    },

    keyup: function (e) {
      switch(e.keyCode) {
        case 40: // down arrow
        case 38: // up arrow
        case 16: // shift
        case 17: // ctrl
        case 18: // alt
          break;

        case 9: // tab
        case 13: // enter
          if (!this.shown) return;
          this.select();
          break;

        case 27: // escape
          if (!this.shown) return;
          this.hide();
          break;
        default:
          this.lookup();
      }

      e.stopPropagation();
      e.preventDefault();
   },

   focus: function (e) {
      if (!this.focused) {
        this.focused = true;
        if (this.options.showHintOnFocus) {
          this.lookup('');
        }
      }
    },

    blur: function (e) {
      this.focused = false;
      if (!this.mousedover && this.shown) this.hide();
    },

    click: function (e) {
      e.stopPropagation();
      e.preventDefault();
      this.select();
      this.$element.focus();
    },

    mouseenter: function (e) {
      this.mousedover = true;
      this.$menu.find('.active').removeClass('active');
      $(e.currentTarget).addClass('active');
    },

    mouseleave: function (e) {
      this.mousedover = false;
      if (!this.focused && this.shown) this.hide();
    }

  };


  /* TYPEAHEAD PLUGIN DEFINITION
   * =========================== */

  var old = $.fn.typeahead;

  $.fn.typeahead = function (option) {
	var arg = arguments;
     if (typeof option == 'string' && option == 'getActive') {
        return this.data('active');
     }
    return this.each(function () {
      var $this = $(this)
        , data = $this.data('typeahead')
        , options = typeof option == 'object' && option;
      if (!data) $this.data('typeahead', (data = new Typeahead(this, options)));
      if (typeof option == 'string') {
        if (arg.length > 1) {
          data[option].apply(data, Array.prototype.slice.call(arg ,1));
        } else {
          data[option]();
        }
      }
    });
  };

  $.fn.typeahead.defaults = {
    source: []
  , items: 8
  , menu: '<ul class="typeahead dropdown-menu" role="listbox"></ul>'
  , item: '<li><a href="#" role="option"></a></li>'
  , minLength: 1
  , scrollHeight: 0
  , autoSelect: true
  , afterSelect: $.noop
  , addItem: false
  , delay: 0
  };

  $.fn.typeahead.Constructor = Typeahead;


 /* TYPEAHEAD NO CONFLICT
  * =================== */

  $.fn.typeahead.noConflict = function () {
    $.fn.typeahead = old;
    return this;
  };


 /* TYPEAHEAD DATA-API
  * ================== */

  $(document).on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) {
    var $this = $(this);
    if ($this.data('typeahead')) return;
    $this.typeahead($this.data());
  });

}));
;
//     Underscore.js 1.8.3
//     http://underscorejs.org
//     (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
//     Underscore may be freely distributed under the MIT license.

(function () {

	// Baseline setup
	// --------------

	// Establish the root object, `window` in the browser, or `exports` on the server.
	var root = this;

	// Save the previous value of the `_` variable.
	var previousUnderscore = root._;

	// Save bytes in the minified (but not gzipped) version:
	var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;

	// Create quick reference variables for speed access to core prototypes.
	var
	  push = ArrayProto.push,
	  slice = ArrayProto.slice,
	  toString = ObjProto.toString,
	  hasOwnProperty = ObjProto.hasOwnProperty;

	// All **ECMAScript 5** native function implementations that we hope to use
	// are declared here.
	var
	  nativeIsArray = Array.isArray,
	  nativeKeys = Object.keys,
	  nativeBind = FuncProto.bind,
	  nativeCreate = Object.create;

	// Naked function reference for surrogate-prototype-swapping.
	var Ctor = function () { };

	// Create a safe reference to the Underscore object for use below.
	var _ = function (obj) {
		if (obj instanceof _) return obj;
		if (!(this instanceof _)) return new _(obj);
		this._wrapped = obj;
	};

	// Export the Underscore object for **Node.js**, with
	// backwards-compatibility for the old `require()` API. If we're in
	// the browser, add `_` as a global object.
	if (typeof exports !== 'undefined') {
		if (typeof module !== 'undefined' && module.exports) {
			exports = module.exports = _;
		}
		exports._ = _;
	} else {
		root._ = _;
	}

	// Current version.
	_.VERSION = '1.8.3';

	// Internal function that returns an efficient (for current engines) version
	// of the passed-in callback, to be repeatedly applied in other Underscore
	// functions.
	var optimizeCb = function (func, context, argCount) {
		if (context === void 0) return func;
		switch (argCount == null ? 3 : argCount) {
			case 1: return function (value) {
				return func.call(context, value);
			};
			case 2: return function (value, other) {
				return func.call(context, value, other);
			};
			case 3: return function (value, index, collection) {
				return func.call(context, value, index, collection);
			};
			case 4: return function (accumulator, value, index, collection) {
				return func.call(context, accumulator, value, index, collection);
			};
		}
		return function () {
			return func.apply(context, arguments);
		};
	};

	// A mostly-internal function to generate callbacks that can be applied
	// to each element in a collection, returning the desired result — either
	// identity, an arbitrary callback, a property matcher, or a property accessor.
	var cb = function (value, context, argCount) {
		if (value == null) return _.identity;
		if (_.isFunction(value)) return optimizeCb(value, context, argCount);
		if (_.isObject(value)) return _.matcher(value);
		return _.property(value);
	};
	_.iteratee = function (value, context) {
		return cb(value, context, Infinity);
	};

	// An internal function for creating assigner functions.
	var createAssigner = function (keysFunc, undefinedOnly) {
		return function (obj) {
			var length = arguments.length;
			if (length < 2 || obj == null) return obj;
			for (var index = 1; index < length; index++) {
				var source = arguments[index],
					keys = keysFunc(source),
					l = keys.length;
				for (var i = 0; i < l; i++) {
					var key = keys[i];
					if (!undefinedOnly || obj[key] === void 0) obj[key] = source[key];
				}
			}
			return obj;
		};
	};

	// An internal function for creating a new object that inherits from another.
	var baseCreate = function (prototype) {
		if (!_.isObject(prototype)) return {};
		if (nativeCreate) return nativeCreate(prototype);
		Ctor.prototype = prototype;
		var result = new Ctor;
		Ctor.prototype = null;
		return result;
	};

	var property = function (key) {
		return function (obj) {
			return obj == null ? void 0 : obj[key];
		};
	};

	// Helper for collection methods to determine whether a collection
	// should be iterated as an array or as an object
	// Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength
	// Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094
	var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
	var getLength = property('length');
	var isArrayLike = function (collection) {
		var length = getLength(collection);
		return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
	};

	// Collection Functions
	// --------------------

	// The cornerstone, an `each` implementation, aka `forEach`.
	// Handles raw objects in addition to array-likes. Treats all
	// sparse array-likes as if they were dense.
	_.each = _.forEach = function (obj, iteratee, context) {
		iteratee = optimizeCb(iteratee, context);
		var i, length;
		if (isArrayLike(obj)) {
			for (i = 0, length = obj.length; i < length; i++) {
				iteratee(obj[i], i, obj);
			}
		} else {
			var keys = _.keys(obj);
			for (i = 0, length = keys.length; i < length; i++) {
				iteratee(obj[keys[i]], keys[i], obj);
			}
		}
		return obj;
	};

	// Return the results of applying the iteratee to each element.
	_.map = _.collect = function (obj, iteratee, context) {
		iteratee = cb(iteratee, context);
		var keys = !isArrayLike(obj) && _.keys(obj),
			length = (keys || obj).length,
			results = Array(length);
		for (var index = 0; index < length; index++) {
			var currentKey = keys ? keys[index] : index;
			results[index] = iteratee(obj[currentKey], currentKey, obj);
		}
		return results;
	};

	// Create a reducing function iterating left or right.
	function createReduce(dir) {
		// Optimized iterator function as using arguments.length
		// in the main function will deoptimize the, see #1991.
		function iterator(obj, iteratee, memo, keys, index, length) {
			for (; index >= 0 && index < length; index += dir) {
				var currentKey = keys ? keys[index] : index;
				memo = iteratee(memo, obj[currentKey], currentKey, obj);
			}
			return memo;
		}

		return function (obj, iteratee, memo, context) {
			iteratee = optimizeCb(iteratee, context, 4);
			var keys = !isArrayLike(obj) && _.keys(obj),
				length = (keys || obj).length,
				index = dir > 0 ? 0 : length - 1;
			// Determine the initial value if none is provided.
			if (arguments.length < 3) {
				memo = obj[keys ? keys[index] : index];
				index += dir;
			}
			return iterator(obj, iteratee, memo, keys, index, length);
		};
	}

	// **Reduce** builds up a single result from a list of values, aka `inject`,
	// or `foldl`.
	_.reduce = _.foldl = _.inject = createReduce(1);

	// The right-associative version of reduce, also known as `foldr`.
	_.reduceRight = _.foldr = createReduce(-1);

	// Return the first value which passes a truth test. Aliased as `detect`.
	_.find = _.detect = function (obj, predicate, context) {
		var key;
		if (isArrayLike(obj)) {
			key = _.findIndex(obj, predicate, context);
		} else {
			key = _.findKey(obj, predicate, context);
		}
		if (key !== void 0 && key !== -1) return obj[key];
	};

	// Return all the elements that pass a truth test.
	// Aliased as `select`.
	_.filter = _.select = function (obj, predicate, context) {
		var results = [];
		predicate = cb(predicate, context);
		_.each(obj, function (value, index, list) {
			if (predicate(value, index, list)) results.push(value);
		});
		return results;
	};

	// Return all the elements for which a truth test fails.
	_.reject = function (obj, predicate, context) {
		return _.filter(obj, _.negate(cb(predicate)), context);
	};

	// Determine whether all of the elements match a truth test.
	// Aliased as `all`.
	_.every = _.all = function (obj, predicate, context) {
		predicate = cb(predicate, context);
		var keys = !isArrayLike(obj) && _.keys(obj),
			length = (keys || obj).length;
		for (var index = 0; index < length; index++) {
			var currentKey = keys ? keys[index] : index;
			if (!predicate(obj[currentKey], currentKey, obj)) return false;
		}
		return true;
	};

	// Determine if at least one element in the object matches a truth test.
	// Aliased as `any`.
	_.some = _.any = function (obj, predicate, context) {
		predicate = cb(predicate, context);
		var keys = !isArrayLike(obj) && _.keys(obj),
			length = (keys || obj).length;
		for (var index = 0; index < length; index++) {
			var currentKey = keys ? keys[index] : index;
			if (predicate(obj[currentKey], currentKey, obj)) return true;
		}
		return false;
	};

	// Determine if the array or object contains a given item (using `===`).
	// Aliased as `includes` and `include`.
	_.contains = _.includes = _.include = function (obj, item, fromIndex, guard) {
		if (!isArrayLike(obj)) obj = _.values(obj);
		if (typeof fromIndex != 'number' || guard) fromIndex = 0;
		return _.indexOf(obj, item, fromIndex) >= 0;
	};

	// Invoke a method (with arguments) on every item in a collection.
	_.invoke = function (obj, method) {
		var args = slice.call(arguments, 2);
		var isFunc = _.isFunction(method);
		return _.map(obj, function (value) {
			var func = isFunc ? method : value[method];
			return func == null ? func : func.apply(value, args);
		});
	};

	// Convenience version of a common use case of `map`: fetching a property.
	_.pluck = function (obj, key) {
		return _.map(obj, _.property(key));
	};

	// Convenience version of a common use case of `filter`: selecting only objects
	// containing specific `key:value` pairs.
	_.where = function (obj, attrs) {
		return _.filter(obj, _.matcher(attrs));
	};

	// Convenience version of a common use case of `find`: getting the first object
	// containing specific `key:value` pairs.
	_.findWhere = function (obj, attrs) {
		return _.find(obj, _.matcher(attrs));
	};

	// Return the maximum element (or element-based computation).
	_.max = function (obj, iteratee, context) {
		var result = -Infinity, lastComputed = -Infinity,
			value, computed;
		if (iteratee == null && obj != null) {
			obj = isArrayLike(obj) ? obj : _.values(obj);
			for (var i = 0, length = obj.length; i < length; i++) {
				value = obj[i];
				if (value > result) {
					result = value;
				}
			}
		} else {
			iteratee = cb(iteratee, context);
			_.each(obj, function (value, index, list) {
				computed = iteratee(value, index, list);
				if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
					result = value;
					lastComputed = computed;
				}
			});
		}
		return result;
	};

	// Return the minimum element (or element-based computation).
	_.min = function (obj, iteratee, context) {
		var result = Infinity, lastComputed = Infinity,
			value, computed;
		if (iteratee == null && obj != null) {
			obj = isArrayLike(obj) ? obj : _.values(obj);
			for (var i = 0, length = obj.length; i < length; i++) {
				value = obj[i];
				if (value < result) {
					result = value;
				}
			}
		} else {
			iteratee = cb(iteratee, context);
			_.each(obj, function (value, index, list) {
				computed = iteratee(value, index, list);
				if (computed < lastComputed || computed === Infinity && result === Infinity) {
					result = value;
					lastComputed = computed;
				}
			});
		}
		return result;
	};

	// Shuffle a collection, using the modern version of the
	// [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
	_.shuffle = function (obj) {
		var set = isArrayLike(obj) ? obj : _.values(obj);
		var length = set.length;
		var shuffled = Array(length);
		for (var index = 0, rand; index < length; index++) {
			rand = _.random(0, index);
			if (rand !== index) shuffled[index] = shuffled[rand];
			shuffled[rand] = set[index];
		}
		return shuffled;
	};

	// Sample **n** random values from a collection.
	// If **n** is not specified, returns a single random element.
	// The internal `guard` argument allows it to work with `map`.
	_.sample = function (obj, n, guard) {
		if (n == null || guard) {
			if (!isArrayLike(obj)) obj = _.values(obj);
			return obj[_.random(obj.length - 1)];
		}
		return _.shuffle(obj).slice(0, Math.max(0, n));
	};

	// Sort the object's values by a criterion produced by an iteratee.
	_.sortBy = function (obj, iteratee, context) {
		iteratee = cb(iteratee, context);
		return _.pluck(_.map(obj, function (value, index, list) {
			return {
				value: value,
				index: index,
				criteria: iteratee(value, index, list)
			};
		}).sort(function (left, right) {
			var a = left.criteria;
			var b = right.criteria;
			if (a !== b) {
				if (a > b || a === void 0) return 1;
				if (a < b || b === void 0) return -1;
			}
			return left.index - right.index;
		}), 'value');
	};

	// An internal function used for aggregate "group by" operations.
	var group = function (behavior) {
		return function (obj, iteratee, context) {
			var result = {};
			iteratee = cb(iteratee, context);
			_.each(obj, function (value, index) {
				var key = iteratee(value, index, obj);
				behavior(result, value, key);
			});
			return result;
		};
	};

	// Groups the object's values by a criterion. Pass either a string attribute
	// to group by, or a function that returns the criterion.
	_.groupBy = group(function (result, value, key) {
		if (_.has(result, key)) result[key].push(value); else result[key] = [value];
	});

	// Indexes the object's values by a criterion, similar to `groupBy`, but for
	// when you know that your index values will be unique.
	_.indexBy = group(function (result, value, key) {
		result[key] = value;
	});

	// Counts instances of an object that group by a certain criterion. Pass
	// either a string attribute to count by, or a function that returns the
	// criterion.
	_.countBy = group(function (result, value, key) {
		if (_.has(result, key)) result[key]++; else result[key] = 1;
	});

	// Safely create a real, live array from anything iterable.
	_.toArray = function (obj) {
		if (!obj) return [];
		if (_.isArray(obj)) return slice.call(obj);
		if (isArrayLike(obj)) return _.map(obj, _.identity);
		return _.values(obj);
	};

	// Return the number of elements in an object.
	_.size = function (obj) {
		if (obj == null) return 0;
		return isArrayLike(obj) ? obj.length : _.keys(obj).length;
	};

	// Split a collection into two arrays: one whose elements all satisfy the given
	// predicate, and one whose elements all do not satisfy the predicate.
	_.partition = function (obj, predicate, context) {
		predicate = cb(predicate, context);
		var pass = [], fail = [];
		_.each(obj, function (value, key, obj) {
			(predicate(value, key, obj) ? pass : fail).push(value);
		});
		return [pass, fail];
	};

	// Array Functions
	// ---------------

	// Get the first element of an array. Passing **n** will return the first N
	// values in the array. Aliased as `head` and `take`. The **guard** check
	// allows it to work with `_.map`.
	_.first = _.head = _.take = function (array, n, guard) {
		if (array == null) return void 0;
		if (n == null || guard) return array[0];
		return _.initial(array, array.length - n);
	};

	// Returns everything but the last entry of the array. Especially useful on
	// the arguments object. Passing **n** will return all the values in
	// the array, excluding the last N.
	_.initial = function (array, n, guard) {
		return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
	};

	// Get the last element of an array. Passing **n** will return the last N
	// values in the array.
	_.last = function (array, n, guard) {
		if (array == null) return void 0;
		if (n == null || guard) return array[array.length - 1];
		return _.rest(array, Math.max(0, array.length - n));
	};

	// Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
	// Especially useful on the arguments object. Passing an **n** will return
	// the rest N values in the array.
	_.rest = _.tail = _.drop = function (array, n, guard) {
		return slice.call(array, n == null || guard ? 1 : n);
	};

	// Trim out all falsy values from an array.
	_.compact = function (array) {
		return _.filter(array, _.identity);
	};

	// Internal implementation of a recursive `flatten` function.
	var flatten = function (input, shallow, strict, startIndex) {
		var output = [], idx = 0;
		for (var i = startIndex || 0, length = getLength(input) ; i < length; i++) {
			var value = input[i];
			if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {
				//flatten current level of array or arguments object
				if (!shallow) value = flatten(value, shallow, strict);
				var j = 0, len = value.length;
				output.length += len;
				while (j < len) {
					output[idx++] = value[j++];
				}
			} else if (!strict) {
				output[idx++] = value;
			}
		}
		return output;
	};

	// Flatten out an array, either recursively (by default), or just one level.
	_.flatten = function (array, shallow) {
		return flatten(array, shallow, false);
	};

	// Return a version of the array that does not contain the specified value(s).
	_.without = function (array) {
		return _.difference(array, slice.call(arguments, 1));
	};

	// Produce a duplicate-free version of the array. If the array has already
	// been sorted, you have the option of using a faster algorithm.
	// Aliased as `unique`.
	_.uniq = _.unique = function (array, isSorted, iteratee, context) {
		if (!_.isBoolean(isSorted)) {
			context = iteratee;
			iteratee = isSorted;
			isSorted = false;
		}
		if (iteratee != null) iteratee = cb(iteratee, context);
		var result = [];
		var seen = [];
		for (var i = 0, length = getLength(array) ; i < length; i++) {
			var value = array[i],
				computed = iteratee ? iteratee(value, i, array) : value;
			if (isSorted) {
				if (!i || seen !== computed) result.push(value);
				seen = computed;
			} else if (iteratee) {
				if (!_.contains(seen, computed)) {
					seen.push(computed);
					result.push(value);
				}
			} else if (!_.contains(result, value)) {
				result.push(value);
			}
		}
		return result;
	};

	// Produce an array that contains the union: each distinct element from all of
	// the passed-in arrays.
	_.union = function () {
		return _.uniq(flatten(arguments, true, true));
	};

	// Produce an array that contains every item shared between all the
	// passed-in arrays.
	_.intersection = function (array) {
		var result = [];
		var argsLength = arguments.length;
		for (var i = 0, length = getLength(array) ; i < length; i++) {
			var item = array[i];
			if (_.contains(result, item)) continue;
			for (var j = 1; j < argsLength; j++) {
				if (!_.contains(arguments[j], item)) break;
			}
			if (j === argsLength) result.push(item);
		}
		return result;
	};

	// Take the difference between one array and a number of other arrays.
	// Only the elements present in just the first array will remain.
	_.difference = function (array) {
		var rest = flatten(arguments, true, true, 1);
		return _.filter(array, function (value) {
			return !_.contains(rest, value);
		});
	};

	// Zip together multiple lists into a single array -- elements that share
	// an index go together.
	_.zip = function () {
		return _.unzip(arguments);
	};

	// Complement of _.zip. Unzip accepts an array of arrays and groups
	// each array's elements on shared indices
	_.unzip = function (array) {
		var length = array && _.max(array, getLength).length || 0;
		var result = Array(length);

		for (var index = 0; index < length; index++) {
			result[index] = _.pluck(array, index);
		}
		return result;
	};

	// Converts lists into objects. Pass either a single array of `[key, value]`
	// pairs, or two parallel arrays of the same length -- one of keys, and one of
	// the corresponding values.
	_.object = function (list, values) {
		var result = {};
		for (var i = 0, length = getLength(list) ; i < length; i++) {
			if (values) {
				result[list[i]] = values[i];
			} else {
				result[list[i][0]] = list[i][1];
			}
		}
		return result;
	};

	// Generator function to create the findIndex and findLastIndex functions
	function createPredicateIndexFinder(dir) {
		return function (array, predicate, context) {
			predicate = cb(predicate, context);
			var length = getLength(array);
			var index = dir > 0 ? 0 : length - 1;
			for (; index >= 0 && index < length; index += dir) {
				if (predicate(array[index], index, array)) return index;
			}
			return -1;
		};
	}

	// Returns the first index on an array-like that passes a predicate test
	_.findIndex = createPredicateIndexFinder(1);
	_.findLastIndex = createPredicateIndexFinder(-1);

	// Use a comparator function to figure out the smallest index at which
	// an object should be inserted so as to maintain order. Uses binary search.
	_.sortedIndex = function (array, obj, iteratee, context) {
		iteratee = cb(iteratee, context, 1);
		var value = iteratee(obj);
		var low = 0, high = getLength(array);
		while (low < high) {
			var mid = Math.floor((low + high) / 2);
			if (iteratee(array[mid]) < value) low = mid + 1; else high = mid;
		}
		return low;
	};

	// Generator function to create the indexOf and lastIndexOf functions
	function createIndexFinder(dir, predicateFind, sortedIndex) {
		return function (array, item, idx) {
			var i = 0, length = getLength(array);
			if (typeof idx == 'number') {
				if (dir > 0) {
					i = idx >= 0 ? idx : Math.max(idx + length, i);
				} else {
					length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1;
				}
			} else if (sortedIndex && idx && length) {
				idx = sortedIndex(array, item);
				return array[idx] === item ? idx : -1;
			}
			if (item !== item) {
				idx = predicateFind(slice.call(array, i, length), _.isNaN);
				return idx >= 0 ? idx + i : -1;
			}
			for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) {
				if (array[idx] === item) return idx;
			}
			return -1;
		};
	}

	// Return the position of the first occurrence of an item in an array,
	// or -1 if the item is not included in the array.
	// If the array is large and already in sort order, pass `true`
	// for **isSorted** to use binary search.
	_.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex);
	_.lastIndexOf = createIndexFinder(-1, _.findLastIndex);

	// Generate an integer Array containing an arithmetic progression. A port of
	// the native Python `range()` function. See
	// [the Python documentation](http://docs.python.org/library/functions.html#range).
	_.range = function (start, stop, step) {
		if (stop == null) {
			stop = start || 0;
			start = 0;
		}
		step = step || 1;

		var length = Math.max(Math.ceil((stop - start) / step), 0);
		var range = Array(length);

		for (var idx = 0; idx < length; idx++, start += step) {
			range[idx] = start;
		}

		return range;
	};

	// Function (ahem) Functions
	// ------------------

	// Determines whether to execute a function as a constructor
	// or a normal function with the provided arguments
	var executeBound = function (sourceFunc, boundFunc, context, callingContext, args) {
		if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args);
		var self = baseCreate(sourceFunc.prototype);
		var result = sourceFunc.apply(self, args);
		if (_.isObject(result)) return result;
		return self;
	};

	// Create a function bound to a given object (assigning `this`, and arguments,
	// optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
	// available.
	_.bind = function (func, context) {
		if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
		if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function');
		var args = slice.call(arguments, 2);
		var bound = function () {
			return executeBound(func, bound, context, this, args.concat(slice.call(arguments)));
		};
		return bound;
	};

	// Partially apply a function by creating a version that has had some of its
	// arguments pre-filled, without changing its dynamic `this` context. _ acts
	// as a placeholder, allowing any combination of arguments to be pre-filled.
	_.partial = function (func) {
		var boundArgs = slice.call(arguments, 1);
		var bound = function () {
			var position = 0, length = boundArgs.length;
			var args = Array(length);
			for (var i = 0; i < length; i++) {
				args[i] = boundArgs[i] === _ ? arguments[position++] : boundArgs[i];
			}
			while (position < arguments.length) args.push(arguments[position++]);
			return executeBound(func, bound, this, this, args);
		};
		return bound;
	};

	// Bind a number of an object's methods to that object. Remaining arguments
	// are the method names to be bound. Useful for ensuring that all callbacks
	// defined on an object belong to it.
	_.bindAll = function (obj) {
		var i, length = arguments.length, key;
		if (length <= 1) throw new Error('bindAll must be passed function names');
		for (i = 1; i < length; i++) {
			key = arguments[i];
			obj[key] = _.bind(obj[key], obj);
		}
		return obj;
	};

	// Memoize an expensive function by storing its results.
	_.memoize = function (func, hasher) {
		var memoize = function (key) {
			var cache = memoize.cache;
			var address = '' + (hasher ? hasher.apply(this, arguments) : key);
			if (!_.has(cache, address)) cache[address] = func.apply(this, arguments);
			return cache[address];
		};
		memoize.cache = {};
		return memoize;
	};

	// Delays a function for the given number of milliseconds, and then calls
	// it with the arguments supplied.
	_.delay = function (func, wait) {
		var args = slice.call(arguments, 2);
		return setTimeout(function () {
			return func.apply(null, args);
		}, wait);
	};

	// Defers a function, scheduling it to run after the current call stack has
	// cleared.
	_.defer = _.partial(_.delay, _, 1);

	// Returns a function, that, when invoked, will only be triggered at most once
	// during a given window of time. Normally, the throttled function will run
	// as much as it can, without ever going more than once per `wait` duration;
	// but if you'd like to disable the execution on the leading edge, pass
	// `{leading: false}`. To disable execution on the trailing edge, ditto.
	_.throttle = function (func, wait, options) {
		var context, args, result;
		var timeout = null;
		var previous = 0;
		if (!options) options = {};
		var later = function () {
			previous = options.leading === false ? 0 : _.now();
			timeout = null;
			result = func.apply(context, args);
			if (!timeout) context = args = null;
		};
		return function () {
			var now = _.now();
			if (!previous && options.leading === false) previous = now;
			var remaining = wait - (now - previous);
			context = this;
			args = arguments;
			if (remaining <= 0 || remaining > wait) {
				if (timeout) {
					clearTimeout(timeout);
					timeout = null;
				}
				previous = now;
				result = func.apply(context, args);
				if (!timeout) context = args = null;
			} else if (!timeout && options.trailing !== false) {
				timeout = setTimeout(later, remaining);
			}
			return result;
		};
	};

	// Returns a function, that, as long as it continues to be invoked, will not
	// be triggered. The function will be called after it stops being called for
	// N milliseconds. If `immediate` is passed, trigger the function on the
	// leading edge, instead of the trailing.
	_.debounce = function (func, wait, immediate) {
		var timeout, args, context, timestamp, result;

		var later = function () {
			var last = _.now() - timestamp;

			if (last < wait && last >= 0) {
				timeout = setTimeout(later, wait - last);
			} else {
				timeout = null;
				if (!immediate) {
					result = func.apply(context, args);
					if (!timeout) context = args = null;
				}
			}
		};

		return function () {
			context = this;
			args = arguments;
			timestamp = _.now();
			var callNow = immediate && !timeout;
			if (!timeout) timeout = setTimeout(later, wait);
			if (callNow) {
				result = func.apply(context, args);
				context = args = null;
			}

			return result;
		};
	};

	// Returns the first function passed as an argument to the second,
	// allowing you to adjust arguments, run code before and after, and
	// conditionally execute the original function.
	_.wrap = function (func, wrapper) {
		return _.partial(wrapper, func);
	};

	// Returns a negated version of the passed-in predicate.
	_.negate = function (predicate) {
		return function () {
			return !predicate.apply(this, arguments);
		};
	};

	// Returns a function that is the composition of a list of functions, each
	// consuming the return value of the function that follows.
	_.compose = function () {
		var args = arguments;
		var start = args.length - 1;
		return function () {
			var i = start;
			var result = args[start].apply(this, arguments);
			while (i--) result = args[i].call(this, result);
			return result;
		};
	};

	// Returns a function that will only be executed on and after the Nth call.
	_.after = function (times, func) {
		return function () {
			if (--times < 1) {
				return func.apply(this, arguments);
			}
		};
	};

	// Returns a function that will only be executed up to (but not including) the Nth call.
	_.before = function (times, func) {
		var memo;
		return function () {
			if (--times > 0) {
				memo = func.apply(this, arguments);
			}
			if (times <= 1) func = null;
			return memo;
		};
	};

	// Returns a function that will be executed at most one time, no matter how
	// often you call it. Useful for lazy initialization.
	_.once = _.partial(_.before, 2);

	// Object Functions
	// ----------------

	// Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed.
	var hasEnumBug = !{ toString: null }.propertyIsEnumerable('toString');
	var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString',
						'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'];

	function collectNonEnumProps(obj, keys) {
		var nonEnumIdx = nonEnumerableProps.length;
		var constructor = obj.constructor;
		var proto = (_.isFunction(constructor) && constructor.prototype) || ObjProto;

		// Constructor is a special case.
		var prop = 'constructor';
		if (_.has(obj, prop) && !_.contains(keys, prop)) keys.push(prop);

		while (nonEnumIdx--) {
			prop = nonEnumerableProps[nonEnumIdx];
			if (prop in obj && obj[prop] !== proto[prop] && !_.contains(keys, prop)) {
				keys.push(prop);
			}
		}
	}

	// Retrieve the names of an object's own properties.
	// Delegates to **ECMAScript 5**'s native `Object.keys`
	_.keys = function (obj) {
		if (!_.isObject(obj)) return [];
		if (nativeKeys) return nativeKeys(obj);
		var keys = [];
		for (var key in obj) if (_.has(obj, key)) keys.push(key);
		// Ahem, IE < 9.
		if (hasEnumBug) collectNonEnumProps(obj, keys);
		return keys;
	};

	// Retrieve all the property names of an object.
	_.allKeys = function (obj) {
		if (!_.isObject(obj)) return [];
		var keys = [];
		for (var key in obj) keys.push(key);
		// Ahem, IE < 9.
		if (hasEnumBug) collectNonEnumProps(obj, keys);
		return keys;
	};

	// Retrieve the values of an object's properties.
	_.values = function (obj) {
		var keys = _.keys(obj);
		var length = keys.length;
		var values = Array(length);
		for (var i = 0; i < length; i++) {
			values[i] = obj[keys[i]];
		}
		return values;
	};

	// Returns the results of applying the iteratee to each element of the object
	// In contrast to _.map it returns an object
	_.mapObject = function (obj, iteratee, context) {
		iteratee = cb(iteratee, context);
		var keys = _.keys(obj),
			  length = keys.length,
			  results = {},
			  currentKey;
		for (var index = 0; index < length; index++) {
			currentKey = keys[index];
			results[currentKey] = iteratee(obj[currentKey], currentKey, obj);
		}
		return results;
	};

	// Convert an object into a list of `[key, value]` pairs.
	_.pairs = function (obj) {
		var keys = _.keys(obj);
		var length = keys.length;
		var pairs = Array(length);
		for (var i = 0; i < length; i++) {
			pairs[i] = [keys[i], obj[keys[i]]];
		}
		return pairs;
	};

	// Invert the keys and values of an object. The values must be serializable.
	_.invert = function (obj) {
		var result = {};
		var keys = _.keys(obj);
		for (var i = 0, length = keys.length; i < length; i++) {
			result[obj[keys[i]]] = keys[i];
		}
		return result;
	};

	// Return a sorted list of the function names available on the object.
	// Aliased as `methods`
	_.functions = _.methods = function (obj) {
		var names = [];
		for (var key in obj) {
			if (_.isFunction(obj[key])) names.push(key);
		}
		return names.sort();
	};

	// Extend a given object with all the properties in passed-in object(s).
	_.extend = createAssigner(_.allKeys);

	// Assigns a given object with all the own properties in the passed-in object(s)
	// (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)
	_.extendOwn = _.assign = createAssigner(_.keys);

	// Returns the first key on an object that passes a predicate test
	_.findKey = function (obj, predicate, context) {
		predicate = cb(predicate, context);
		var keys = _.keys(obj), key;
		for (var i = 0, length = keys.length; i < length; i++) {
			key = keys[i];
			if (predicate(obj[key], key, obj)) return key;
		}
	};

	// Return a copy of the object only containing the whitelisted properties.
	_.pick = function (object, oiteratee, context) {
		var result = {}, obj = object, iteratee, keys;
		if (obj == null) return result;
		if (_.isFunction(oiteratee)) {
			keys = _.allKeys(obj);
			iteratee = optimizeCb(oiteratee, context);
		} else {
			keys = flatten(arguments, false, false, 1);
			iteratee = function (value, key, obj) { return key in obj; };
			obj = Object(obj);
		}
		for (var i = 0, length = keys.length; i < length; i++) {
			var key = keys[i];
			var value = obj[key];
			if (iteratee(value, key, obj)) result[key] = value;
		}
		return result;
	};

	// Return a copy of the object without the blacklisted properties.
	_.omit = function (obj, iteratee, context) {
		if (_.isFunction(iteratee)) {
			iteratee = _.negate(iteratee);
		} else {
			var keys = _.map(flatten(arguments, false, false, 1), String);
			iteratee = function (value, key) {
				return !_.contains(keys, key);
			};
		}
		return _.pick(obj, iteratee, context);
	};

	// Fill in a given object with default properties.
	_.defaults = createAssigner(_.allKeys, true);

	// Creates an object that inherits from the given prototype object.
	// If additional properties are provided then they will be added to the
	// created object.
	_.create = function (prototype, props) {
		var result = baseCreate(prototype);
		if (props) _.extendOwn(result, props);
		return result;
	};

	// Create a (shallow-cloned) duplicate of an object.
	_.clone = function (obj) {
		if (!_.isObject(obj)) return obj;
		return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
	};

	// Invokes interceptor with the obj, and then returns obj.
	// The primary purpose of this method is to "tap into" a method chain, in
	// order to perform operations on intermediate results within the chain.
	_.tap = function (obj, interceptor) {
		interceptor(obj);
		return obj;
	};

	// Returns whether an object has a given set of `key:value` pairs.
	_.isMatch = function (object, attrs) {
		var keys = _.keys(attrs), length = keys.length;
		if (object == null) return !length;
		var obj = Object(object);
		for (var i = 0; i < length; i++) {
			var key = keys[i];
			if (attrs[key] !== obj[key] || !(key in obj)) return false;
		}
		return true;
	};


	// Internal recursive comparison function for `isEqual`.
	var eq = function (a, b, aStack, bStack) {
		// Identical objects are equal. `0 === -0`, but they aren't identical.
		// See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
		if (a === b) return a !== 0 || 1 / a === 1 / b;
		// A strict comparison is necessary because `null == undefined`.
		if (a == null || b == null) return a === b;
		// Unwrap any wrapped objects.
		if (a instanceof _) a = a._wrapped;
		if (b instanceof _) b = b._wrapped;
		// Compare `[[Class]]` names.
		var className = toString.call(a);
		if (className !== toString.call(b)) return false;
		switch (className) {
			// Strings, numbers, regular expressions, dates, and booleans are compared by value.
			case '[object RegExp]':
				// RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')
			case '[object String]':
				// Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
				// equivalent to `new String("5")`.
				return '' + a === '' + b;
			case '[object Number]':
				// `NaN`s are equivalent, but non-reflexive.
				// Object(NaN) is equivalent to NaN
				if (+a !== +a) return +b !== +b;
				// An `egal` comparison is performed for other numeric values.
				return +a === 0 ? 1 / +a === 1 / b : +a === +b;
			case '[object Date]':
			case '[object Boolean]':
				// Coerce dates and booleans to numeric primitive values. Dates are compared by their
				// millisecond representations. Note that invalid dates with millisecond representations
				// of `NaN` are not equivalent.
				return +a === +b;
		}

		var areArrays = className === '[object Array]';
		if (!areArrays) {
			if (typeof a != 'object' || typeof b != 'object') return false;

			// Objects with different constructors are not equivalent, but `Object`s or `Array`s
			// from different frames are.
			var aCtor = a.constructor, bCtor = b.constructor;
			if (aCtor !== bCtor && !(_.isFunction(aCtor) && aCtor instanceof aCtor &&
									 _.isFunction(bCtor) && bCtor instanceof bCtor)
								&& ('constructor' in a && 'constructor' in b)) {
				return false;
			}
		}
		// Assume equality for cyclic structures. The algorithm for detecting cyclic
		// structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.

		// Initializing stack of traversed objects.
		// It's done here since we only need them for objects and arrays comparison.
		aStack = aStack || [];
		bStack = bStack || [];
		var length = aStack.length;
		while (length--) {
			// Linear search. Performance is inversely proportional to the number of
			// unique nested structures.
			if (aStack[length] === a) return bStack[length] === b;
		}

		// Add the first object to the stack of traversed objects.
		aStack.push(a);
		bStack.push(b);

		// Recursively compare objects and arrays.
		if (areArrays) {
			// Compare array lengths to determine if a deep comparison is necessary.
			length = a.length;
			if (length !== b.length) return false;
			// Deep compare the contents, ignoring non-numeric properties.
			while (length--) {
				if (!eq(a[length], b[length], aStack, bStack)) return false;
			}
		} else {
			// Deep compare objects.
			var keys = _.keys(a), key;
			length = keys.length;
			// Ensure that both objects contain the same number of properties before comparing deep equality.
			if (_.keys(b).length !== length) return false;
			while (length--) {
				// Deep compare each member
				key = keys[length];
				if (!(_.has(b, key) && eq(a[key], b[key], aStack, bStack))) return false;
			}
		}
		// Remove the first object from the stack of traversed objects.
		aStack.pop();
		bStack.pop();
		return true;
	};

	// Perform a deep comparison to check if two objects are equal.
	_.isEqual = function (a, b) {
		return eq(a, b);
	};

	// Is a given array, string, or object empty?
	// An "empty" object has no enumerable own-properties.
	_.isEmpty = function (obj) {
		if (obj == null) return true;
		if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0;
		return _.keys(obj).length === 0;
	};

	// Is a given value a DOM element?
	_.isElement = function (obj) {
		return !!(obj && obj.nodeType === 1);
	};

	// Is a given value an array?
	// Delegates to ECMA5's native Array.isArray
	_.isArray = nativeIsArray || function (obj) {
		return toString.call(obj) === '[object Array]';
	};

	// Is a given variable an object?
	_.isObject = function (obj) {
		var type = typeof obj;
		return type === 'function' || type === 'object' && !!obj;
	};

	// Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError.
	_.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function (name) {
		_['is' + name] = function (obj) {
			return toString.call(obj) === '[object ' + name + ']';
		};
	});

	// Define a fallback version of the method in browsers (ahem, IE < 9), where
	// there isn't any inspectable "Arguments" type.
	if (!_.isArguments(arguments)) {
		_.isArguments = function (obj) {
			return _.has(obj, 'callee');
		};
	}

	// Optimize `isFunction` if appropriate. Work around some typeof bugs in old v8,
	// IE 11 (#1621), and in Safari 8 (#1929).
	if (typeof /./ != 'function' && typeof Int8Array != 'object') {
		_.isFunction = function (obj) {
			return typeof obj == 'function' || false;
		};
	}

	// Is a given object a finite number?
	_.isFinite = function (obj) {
		return isFinite(obj) && !isNaN(parseFloat(obj));
	};

	// Is the given value `NaN`? (NaN is the only number which does not equal itself).
	_.isNaN = function (obj) {
		return _.isNumber(obj) && obj !== +obj;
	};

	// Is a given value a boolean?
	_.isBoolean = function (obj) {
		return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
	};

	// Is a given value equal to null?
	_.isNull = function (obj) {
		return obj === null;
	};

	// Is a given variable undefined?
	_.isUndefined = function (obj) {
		return obj === void 0;
	};

	// Shortcut function for checking if an object has a given property directly
	// on itself (in other words, not on a prototype).
	_.has = function (obj, key) {
		return obj != null && hasOwnProperty.call(obj, key);
	};

	// Utility Functions
	// -----------------

	// Run Underscore.js in *noConflict* mode, returning the `_` variable to its
	// previous owner. Returns a reference to the Underscore object.
	_.noConflict = function () {
		root._ = previousUnderscore;
		return this;
	};

	// Keep the identity function around for default iteratees.
	_.identity = function (value) {
		return value;
	};

	// Predicate-generating functions. Often useful outside of Underscore.
	_.constant = function (value) {
		return function () {
			return value;
		};
	};

	_.noop = function () { };

	_.property = property;

	// Generates a function for a given object that returns a given property.
	_.propertyOf = function (obj) {
		return obj == null ? function () { } : function (key) {
			return obj[key];
		};
	};

	// Returns a predicate for checking whether an object has a given set of
	// `key:value` pairs.
	_.matcher = _.matches = function (attrs) {
		attrs = _.extendOwn({}, attrs);
		return function (obj) {
			return _.isMatch(obj, attrs);
		};
	};

	// Run a function **n** times.
	_.times = function (n, iteratee, context) {
		var accum = Array(Math.max(0, n));
		iteratee = optimizeCb(iteratee, context, 1);
		for (var i = 0; i < n; i++) accum[i] = iteratee(i);
		return accum;
	};

	// Return a random integer between min and max (inclusive).
	_.random = function (min, max) {
		if (max == null) {
			max = min;
			min = 0;
		}
		return min + Math.floor(Math.random() * (max - min + 1));
	};

	// A (possibly faster) way to get the current timestamp as an integer.
	_.now = Date.now || function () {
		return new Date().getTime();
	};

	// List of HTML entities for escaping.
	var escapeMap = {
		'&': '&amp;',
		'<': '&lt;',
		'>': '&gt;',
		'"': '&quot;',
		"'": '&#x27;',
		'`': '&#x60;'
	};
	var unescapeMap = _.invert(escapeMap);

	// Functions for escaping and unescaping strings to/from HTML interpolation.
	var createEscaper = function (map) {
		var escaper = function (match) {
			return map[match];
		};
		// Regexes for identifying a key that needs to be escaped
		var source = '(?:' + _.keys(map).join('|') + ')';
		var testRegexp = RegExp(source);
		var replaceRegexp = RegExp(source, 'g');
		return function (string) {
			string = string == null ? '' : '' + string;
			return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
		};
	};
	_.escape = createEscaper(escapeMap);
	_.unescape = createEscaper(unescapeMap);

	// If the value of the named `property` is a function then invoke it with the
	// `object` as context; otherwise, return it.
	_.result = function (object, property, fallback) {
		var value = object == null ? void 0 : object[property];
		if (value === void 0) {
			value = fallback;
		}
		return _.isFunction(value) ? value.call(object) : value;
	};

	// Generate a unique integer id (unique within the entire client session).
	// Useful for temporary DOM ids.
	var idCounter = 0;
	_.uniqueId = function (prefix) {
		var id = ++idCounter + '';
		return prefix ? prefix + id : id;
	};

	// By default, Underscore uses ERB-style template delimiters, change the
	// following template settings to use alternative delimiters.
	_.templateSettings = {
		evaluate: /<%([\s\S]+?)%>/g,
		interpolate: /<%=([\s\S]+?)%>/g,
		escape: /<%-([\s\S]+?)%>/g
	};

	// When customizing `templateSettings`, if you don't want to define an
	// interpolation, evaluation or escaping regex, we need one that is
	// guaranteed not to match.
	var noMatch = /(.)^/;

	// Certain characters need to be escaped so that they can be put into a
	// string literal.
	var escapes = {
		"'": "'",
		'\\': '\\',
		'\r': 'r',
		'\n': 'n',
		'\u2028': 'u2028',
		'\u2029': 'u2029'
	};

	var escaper = /\\|'|\r|\n|\u2028|\u2029/g;

	var escapeChar = function (match) {
		return '\\' + escapes[match];
	};

	// JavaScript micro-templating, similar to John Resig's implementation.
	// Underscore templating handles arbitrary delimiters, preserves whitespace,
	// and correctly escapes quotes within interpolated code.
	// NB: `oldSettings` only exists for backwards compatibility.
	_.template = function (text, settings, oldSettings) {
		if (!settings && oldSettings) settings = oldSettings;
		settings = _.defaults({}, settings, _.templateSettings);

		// Combine delimiters into one regular expression via alternation.
		var matcher = RegExp([
		  (settings.escape || noMatch).source,
		  (settings.interpolate || noMatch).source,
		  (settings.evaluate || noMatch).source
		].join('|') + '|$', 'g');

		// Compile the template source, escaping string literals appropriately.
		var index = 0;
		var source = "__p+='";
		text.replace(matcher, function (match, escape, interpolate, evaluate, offset) {
			source += text.slice(index, offset).replace(escaper, escapeChar);
			index = offset + match.length;

			if (escape) {
				source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
			} else if (interpolate) {
				source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
			} else if (evaluate) {
				source += "';\n" + evaluate + "\n__p+='";
			}

			// Adobe VMs need the match returned to produce the correct offest.
			return match;
		});
		source += "';\n";

		// If a variable is not specified, place data values in local scope.
		if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';

		source = "var __t,__p='',__j=Array.prototype.join," +
		  "print=function(){__p+=__j.call(arguments,'');};\n" +
		  source + 'return __p;\n';

		try {
			var render = new Function(settings.variable || 'obj', '_', source);
		} catch (e) {
			e.source = source;
			throw e;
		}

		var template = function (data) {
			return render.call(this, data, _);
		};

		// Provide the compiled source as a convenience for precompilation.
		var argument = settings.variable || 'obj';
		template.source = 'function(' + argument + '){\n' + source + '}';

		return template;
	};

	// Add a "chain" function. Start chaining a wrapped Underscore object.
	_.chain = function (obj) {
		var instance = _(obj);
		instance._chain = true;
		return instance;
	};

	// OOP
	// ---------------
	// If Underscore is called as a function, it returns a wrapped object that
	// can be used OO-style. This wrapper holds altered versions of all the
	// underscore functions. Wrapped objects may be chained.

	// Helper function to continue chaining intermediate results.
	var result = function (instance, obj) {
		return instance._chain ? _(obj).chain() : obj;
	};

	// Add your own custom functions to the Underscore object.
	_.mixin = function (obj) {
		_.each(_.functions(obj), function (name) {
			var func = _[name] = obj[name];
			_.prototype[name] = function () {
				var args = [this._wrapped];
				push.apply(args, arguments);
				return result(this, func.apply(_, args));
			};
		});
	};

	// Add all of the Underscore functions to the wrapper object.
	_.mixin(_);

	// Add all mutator Array functions to the wrapper.
	_.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function (name) {
		var method = ArrayProto[name];
		_.prototype[name] = function () {
			var obj = this._wrapped;
			method.apply(obj, arguments);
			if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0];
			return result(this, obj);
		};
	});

	// Add all accessor Array functions to the wrapper.
	_.each(['concat', 'join', 'slice'], function (name) {
		var method = ArrayProto[name];
		_.prototype[name] = function () {
			return result(this, method.apply(this._wrapped, arguments));
		};
	});

	// Extracts the result from a wrapped and chained object.
	_.prototype.value = function () {
		return this._wrapped;
	};

	// Provide unwrapping proxy for some methods used in engine operations
	// such as arithmetic and JSON stringification.
	_.prototype.valueOf = _.prototype.toJSON = _.prototype.value;

	_.prototype.toString = function () {
		return '' + this._wrapped;
	};

	// AMD registration happens at the end for compatibility with AMD loaders
	// that may not enforce next-turn semantics on modules. Even though general
	// practice for AMD registration is to be anonymous, underscore registers
	// as a named module because, like jQuery, it is a base library that is
	// popular enough to be bundled in a third party lib, but not be part of
	// an AMD load request. Those cases could generate an error when an
	// anonymous define() is called outside of a loader request.
	if (typeof define === 'function' && define.amd) {
		define('underscore', [], function () {
			return _;
		});
	}
}.call(this));;
$.widget("custom.catcomplete", $.ui.autocomplete, {
	_create: function () {
		this._super();
		this.widget().menu("option", "items", "> :not(.ui-autocomplete-category)");
	},
	_renderItem: function (ul, item) {
		var searchMask = item.searchTerm;
		var regEx = new RegExp("(" + searchMask + ")", "ig");
		var replaceMask = "<b>$1</b>";

		return $("<li>")
			.append(item.label.replace(regEx, replaceMask))
			.appendTo(ul);
	},
	_renderMenu: function (ul, items) {
		var that = this,
		currentCategory = "";

		$.each(items, function (index, item) {
			// Set country indicator
			var countryIndicator = '';
			switch (item.state) {
				case "Alberta":
				case "British Columbia":
				case "Saskatchewan":
				case "Manitoba":
				case "Ontario":
				case "Quebec":
				case "New Brunswick":
				case "Nova Scotia":
				case "Newfoundland and Labrador":
				case "Prince Edward Island":
					countryIndicator = ' Canada';
					break;
				default:
					countryIndicator = '';
					break;
			}

			var li;
			if (item.isKoa == true)
			{
				li = that._renderItemData(ul, item);
				li.prepend("<img src='/content/images/icon_koa.png' alt='KOA Logo Icon' width='30' valign='middle' />");
				li.append(item.locationDetails);
			}
			else {
				li = that._renderItemData(ul, item);
			  li.prepend("<span aria-hidden=\"true\" class=\"fas fa-map-marker-alt fa-2x mr-1\"></span>");
				li.append(countryIndicator);
				if (item.category) {
					li.attr("aria-label", item.category + " : " + item.label);
				}
				li.append("<img src='/content/images/icon_koa.png' alt='KOA Logo Icon' width='30px' valign='middle' />");
				li.append(item.nearbyText);
				li.append(item.locationDetails);
			}
		});
	}
});
$(function () {
	var throttledRequest = _.debounce(function (request, response, channel) {
		$.ajax({
			url: '/handlers/autosearch.ashx?q=' + request.term + '&c=' + channel
			, cache: false
			, success: function (data) {

				var parsedData = [];
				var searchResult = JSON.parse(data);

				if (searchResult.campgroundsField != null) {
					$.each(searchResult.campgroundsField, function (index3, item3) {
						var campgroundResult = { searchTerm: request.term, label: item3.nameField, locationDetails: " <span class='city-name'>" + item3.cityField + ", " + item3.stateProvinceCodeField + "</span>", isKoa: true, state: item3.stateProvinceField };
						//add the label to the display array
						parsedData.push(campgroundResult);
					});
				}

				if (searchResult.searchLocationListField != null) {
					//add first 2 not in the list
					$.each(searchResult.searchLocationListField, function (index, item) {
						var additionalCount = 0;

						if (index == 0) { //only show the first result
							$.each(item.campgroundsField, function (index2, item2) {

								if (additionalCount < 2) {
									var result = $.grep(parsedData, function (e) { return e.label == item2.nameField; });
									if (result.length == 0) {
									  var campgroundResult = { searchTerm: request.term, label: item2.nameField, locationDetails: " <span class='city-name'>" + item2.cityField + ", " + item2.stateProvinceCodeField + "</span>", isKoa: true, isSubKoa: true, state: item2.stateProvinceField };
										parsedData.push(campgroundResult);
										additionalCount++;
									}
								}

							});
						}
					});

					$.each(searchResult.searchLocationListField, function (index, item) {

						var campgroundMatches = 0;
						var campgroundNotMatches = 0;
						$.each(item.campgroundsField, function (index2, item2) {
							if(item2.isMatchField)
							{
								campgroundMatches++;
							}
							else {
								campgroundNotMatches++;
							}
						});

						var nearbyText = "";

						if (campgroundMatches == campgroundMatches + campgroundNotMatches)
						{
							nearbyText = "<b>"+ campgroundMatches + " KOA" + ((item.campgroundsField.length > 1) ? "s" : "") + "</b> nearby";
						}
						else {
							nearbyText = "<b>" + campgroundMatches + " / " + campgroundNotMatches + "KOA " + ((item.campgroundsField.length > 1) ? "s" : "") + "</b> nearby";
						}

						var campgroundResult = { searchTerm: request.term, label: item.locationField, isKoa: false, nearbyText: nearbyText, state: "" };
						parsedData.push(campgroundResult);

					});
				}

				response(parsedData);
			}
		});
	}, 50);

	$("#txtLocation").catcomplete({
		delay: 0,
		minLength: 3,
		source: function (request, response) {
			throttledRequest(request, response, $("#txtLocation").attr("data-channel"));
		},
		appendTo: $("#txtLocationResults")
  });
  $("#txtLocationMobile").catcomplete({
		delay: 0,
		minLength: 3,
		source: function (request, response) {
			throttledRequest(request, response, $("#txtLocationMobile").attr("data-channel"));
		},
		appendTo: $("#txtLocationResultsMobile")
  });
	$("#input-find-nav").catcomplete({
		delay: 0,
		minLength: 3,
		source: function (request, response) {
			throttledRequest(request, response, $("#input-find-nav").attr("data-channel"));
		},
		appendTo: $("#qLocationResults")
	});
});

$(document).ready(function () {
	// Enable click event and hover on autocomplete categories so user can select destination or campground
	$("#txtLocationResults, #qLocationResults").on("click", ".ui-autocomplete-category", function () {
		var inputValue = $(this).html();
		var $input = $(this).closest(".form-group, .input-group").find(".ui-autocomplete-input");
		$input.val(inputValue);
		$input.catcomplete("close");
	});
	$(document).on("mouseover", ".ui-autocomplete-category", function () {
		$(this).addClass("koa-yellow-bg");
	});
	$(document).on("mouseleave", ".ui-autocomplete-category", function () {
		$(this).removeClass("koa-yellow-bg");
	});
});
;
/*!
 * enquire.js v2.1.6 - Awesome Media Queries in JavaScript
 * Copyright (c) 2017 Nick Williams - http://wicky.nillia.ms/enquire.js
 * License: MIT */

!function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,b.enquire=a()}}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);var j=new Error("Cannot find module '"+g+"'");throw j.code="MODULE_NOT_FOUND",j}var k=c[g]={exports:{}};b[g][0].call(k.exports,function(a){var c=b[g][1][a];return e(c?c:a)},k,k.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g<d.length;g++)e(d[g]);return e}({1:[function(a,b,c){function d(a,b){this.query=a,this.isUnconditional=b,this.handlers=[],this.mql=window.matchMedia(a);var c=this;this.listener=function(a){c.mql=a.currentTarget||a,c.assess()},this.mql.addListener(this.listener)}var e=a(3),f=a(4).each;d.prototype={constuctor:d,addHandler:function(a){var b=new e(a);this.handlers.push(b),this.matches()&&b.on()},removeHandler:function(a){var b=this.handlers;f(b,function(c,d){if(c.equals(a))return c.destroy(),!b.splice(d,1)})},matches:function(){return this.mql.matches||this.isUnconditional},clear:function(){f(this.handlers,function(a){a.destroy()}),this.mql.removeListener(this.listener),this.handlers.length=0},assess:function(){var a=this.matches()?"on":"off";f(this.handlers,function(b){b[a]()})}},b.exports=d},{3:3,4:4}],2:[function(a,b,c){function d(){if(!window.matchMedia)throw new Error("matchMedia not present, legacy browsers require a polyfill");this.queries={},this.browserIsIncapable=!window.matchMedia("only all").matches}var e=a(1),f=a(4),g=f.each,h=f.isFunction,i=f.isArray;d.prototype={constructor:d,register:function(a,b,c){var d=this.queries,f=c&&this.browserIsIncapable;return d[a]||(d[a]=new e(a,f)),h(b)&&(b={match:b}),i(b)||(b=[b]),g(b,function(b){h(b)&&(b={match:b}),d[a].addHandler(b)}),this},unregister:function(a,b){var c=this.queries[a];return c&&(b?c.removeHandler(b):(c.clear(),delete this.queries[a])),this}},b.exports=d},{1:1,4:4}],3:[function(a,b,c){function d(a){this.options=a,!a.deferSetup&&this.setup()}d.prototype={constructor:d,setup:function(){this.options.setup&&this.options.setup(),this.initialised=!0},on:function(){!this.initialised&&this.setup(),this.options.match&&this.options.match()},off:function(){this.options.unmatch&&this.options.unmatch()},destroy:function(){this.options.destroy?this.options.destroy():this.off()},equals:function(a){return this.options===a||this.options.match===a}},b.exports=d},{}],4:[function(a,b,c){function d(a,b){var c=0,d=a.length;for(c;c<d&&b(a[c],c)!==!1;c++);}function e(a){return"[object Array]"===Object.prototype.toString.apply(a)}function f(a){return"function"==typeof a}b.exports={isFunction:f,isArray:e,each:d}},{}],5:[function(a,b,c){var d=a(2);b.exports=new d},{2:2}]},{},[5])(5)});;
var Slider = (function () {
    var index = 0;

    var Previous = function () {
        index--;

        //fire load attached to stage
        $(this).parent().load();
    };

    var Next = function () {
        index++;

        //fire load attached to stage
        $(this).parent().load();
    };

    var LoadCarousel = function () {
        if (index == $(this).data("slider").options.data.length)
            index = 0;

        if (index == -1)
            index = $(this).data("slider").options.data.length - 1;

        $(this).find("img.carousel-image").attr({
            "src": $(this).data("slider").options.data[index].url + $(this).data("slider").options.preset,
            "alt": $(this).data("slider").options.data[index].title 
        });
    };

    return {
        init: function (options, elem) {
            var $elem = null;
            var $prev = null;
            var $next = null;

            // Mix in the passed in options with the default options
            this.options = $.extend({}, this.options, options);

            //save private variable options
            $options = this.options;

            // Save the element reference, both as a jQuery
            // reference and a normal reference
            this.elem = elem;
            $elem = $(elem);

            $prev = $('.carousel-prev', $elem);
            $next = $('.carousel-next', $elem);

            //load events
            $prev.click(Previous);
            $next.click(Next);

            //bind load event to stage
            $elem.load(LoadCarousel);

            // return this so we can chain/use the bridge with less code.
            return this;
        },
        options: {
            data: null,
            preset: ""
        }
    }
})();;
/**
 * Lightbox v2.7.1
 * by Lokesh Dhakar - http://lokeshdhakar.com/projects/lightbox2/
 *
 * @license http://creativecommons.org/licenses/by/2.5/
 * - Free for use in both personal and commercial projects
 * - Attribution requires leaving author name, author link, and the license info intact
 */
(function () { var a = jQuery, b = function () { function a() { this.fadeDuration = 500, this.fitImagesInViewport = !0, this.resizeDuration = 700, this.positionFromTop = 50, this.showImageNumberLabel = !0, this.alwaysShowNavOnTouchDevices = !1, this.wrapAround = !1 } return a.prototype.albumLabel = function (a, b) { return "Image " + a + " of " + b }, a }(), c = function () { function b(a) { this.options = a, this.album = [], this.currentImageIndex = void 0, this.init() } return b.prototype.init = function () { this.enable(), this.build() }, b.prototype.enable = function () { var b = this; a("body").on("click", "a[rel^=lightbox], area[rel^=lightbox], a[data-lightbox], area[data-lightbox]", function (c) { return b.start(a(c.currentTarget)), !1 }) }, b.prototype.build = function () { var b = this; a("<div id='lightboxOverlay' class='lightboxOverlay'></div><div id='lightbox' class='lightbox'><div class='lb-outerContainer'><div class='lb-container'><img class='lb-image' src='' alt='' /><div class='lb-nav'><a class='lb-prev' aria-label='Prev' href='' ></a><a class='lb-next' aria-label='Next' href='' ></a></div><div class='lb-loader'><a class='lb-cancel'></a></div></div></div><div class='lb-dataContainer'><div class='lb-data'><div class='lb-details'><span class='lb-caption'></span><span class='lb-number'></span></div><div class='lb-closeContainer'><a class='lb-close'></a></div></div></div></div>").appendTo(a("body")),this.$lightbox=a("#lightbox"),this.$overlay=a("#lightboxOverlay"),this.$outerContainer=this.$lightbox.find(".lb-outerContainer"),this.$container=this.$lightbox.find(".lb-container"),this.containerTopPadding=parseInt(this.$container.css("padding-top"),10),this.containerRightPadding=parseInt(this.$container.css("padding-right"),10),this.containerBottomPadding=parseInt(this.$container.css("padding-bottom"),10),this.containerLeftPadding=parseInt(this.$container.css("padding-left"),10),this.$overlay.hide().on("click",function(){return b.end(),!1}),this.$lightbox.hide().on("click",function(c){return"lightbox"===a(c.target).attr("id")&&b.end(),!1}),this.$outerContainer.on("click",function(c){return"lightbox"===a(c.target).attr("id")&&b.end(),!1}),this.$lightbox.find(".lb-prev").on("click",function(){return b.changeImage(0===b.currentImageIndex?b.album.length-1:b.currentImageIndex-1),!1}),this.$lightbox.find(".lb-next").on("click",function(){return b.changeImage(b.currentImageIndex===b.album.length-1?0:b.currentImageIndex+1),!1}),this.$lightbox.find(".lb-loader, .lb-close").on("click",function(){return b.end(),!1})},b.prototype.start=function(b){function c(a){d.album.push({link:a.attr("href"),title:a.attr("data-title")||a.attr("title")})}var d=this,e=a(window);e.on("resize",a.proxy(this.sizeOverlay,this)),a("select, object, embed").css({visibility:"hidden"}),this.sizeOverlay(),this.album=[];var f,g=0,h=b.attr("data-lightbox");if(h){f=a(b.prop("tagName")+'[data-lightbox="'+h+'"]');for(var i=0;i<f.length;i=++i)c(a(f[i])),f[i]===b[0]&&(g=i)}else if("lightbox"===b.attr("rel"))c(b);else{f=a(b.prop("tagName")+'[rel="'+b.attr("rel")+'"]');for(var j=0;j<f.length;j=++j)c(a(f[j])),f[j]===b[0]&&(g=j)}var k=e.scrollTop()+this.options.positionFromTop,l=e.scrollLeft();this.$lightbox.css({top:k+"px",left:l+"px"}).fadeIn(this.options.fadeDuration),this.changeImage(g)},b.prototype.changeImage=function(b){var c=this;this.disableKeyboardNav();var d=this.$lightbox.find(".lb-image");this.$overlay.fadeIn(this.options.fadeDuration),a(".lb-loader").fadeIn("slow"),this.$lightbox.find(".lb-image, .lb-nav, .lb-prev, .lb-next, .lb-dataContainer, .lb-numbers, .lb-caption").hide(),this.$outerContainer.addClass("animating");var e=new Image;e.onload=function(){var f,g,h,i,j,k,l;d.attr("src",c.album[b].link),f=a(e),d.width(e.width),d.height(e.height),c.options.fitImagesInViewport&&(l=a(window).width(),k=a(window).height(),j=l-c.containerLeftPadding-c.containerRightPadding-20,i=k-c.containerTopPadding-c.containerBottomPadding-120,(e.width>j||e.height>i)&&(e.width/j>e.height/i?(h=j,g=parseInt(e.height/(e.width/h),10),d.width(h),d.height(g)):(g=i,h=parseInt(e.width/(e.height/g),10),d.width(h),d.height(g)))),c.sizeContainer(d.width(),d.height())},e.src=this.album[b].link,this.currentImageIndex=b},b.prototype.sizeOverlay=function(){this.$overlay.width(a(window).width()).height(a(document).height())},b.prototype.sizeContainer=function(a,b){function c(){d.$lightbox.find(".lb-dataContainer").width(g),d.$lightbox.find(".lb-prevLink").height(h),d.$lightbox.find(".lb-nextLink").height(h),d.showImage()}var d=this,e=this.$outerContainer.outerWidth(),f=this.$outerContainer.outerHeight(),g=a+this.containerLeftPadding+this.containerRightPadding,h=b+this.containerTopPadding+this.containerBottomPadding;e!==g||f!==h?this.$outerContainer.animate({width:g,height:h},this.options.resizeDuration,"swing",function(){c()}):c()},b.prototype.showImage=function(){this.$lightbox.find(".lb-loader").hide(),this.$lightbox.find(".lb-image").fadeIn("slow"),this.updateNav(),this.updateDetails(),this.preloadNeighboringImages(),this.enableKeyboardNav()},b.prototype.updateNav=function(){var a=!1;try{document.createEvent("TouchEvent"),a=this.options.alwaysShowNavOnTouchDevices?!0:!1}catch(b){}this.$lightbox.find(".lb-nav").show(),this.album.length>1&&(this.options.wrapAround?(a&&this.$lightbox.find(".lb-prev, .lb-next").css("opacity","1"),this.$lightbox.find(".lb-prev, .lb-next").show()):(this.currentImageIndex>0&&(this.$lightbox.find(".lb-prev").show(),a&&this.$lightbox.find(".lb-prev").css("opacity","1")),this.currentImageIndex<this.album.length-1&&(this.$lightbox.find(".lb-next").show(),a&&this.$lightbox.find(".lb-next").css("opacity","1"))))},b.prototype.updateDetails=function(){var b=this;"undefined"!=typeof this.album[this.currentImageIndex].title&&""!==this.album[this.currentImageIndex].title&&this.$lightbox.find(".lb-caption").html(this.album[this.currentImageIndex].title).fadeIn("fast").find("a").on("click",function(){location.href=a(this).attr("href")}),this.album.length>1&&this.options.showImageNumberLabel?this.$lightbox.find(".lb-number").text(this.options.albumLabel(this.currentImageIndex+1,this.album.length)).fadeIn("fast"):this.$lightbox.find(".lb-number").hide(),this.$outerContainer.removeClass("animating"),this.$lightbox.find(".lb-dataContainer").fadeIn(this.options.resizeDuration,function(){return b.sizeOverlay()})},b.prototype.preloadNeighboringImages=function(){if(this.album.length>this.currentImageIndex+1){var a=new Image;a.src=this.album[this.currentImageIndex+1].link}if(this.currentImageIndex>0){var b=new Image;b.src=this.album[this.currentImageIndex-1].link}},b.prototype.enableKeyboardNav=function(){a(document).on("keyup.keyboard",a.proxy(this.keyboardAction,this))},b.prototype.disableKeyboardNav=function(){a(document).off(".keyboard")},b.prototype.keyboardAction=function(a){var b=27,c=37,d=39,e=a.keyCode,f=String.fromCharCode(e).toLowerCase();e===b||f.match(/x|o|c/)?this.end():"p"===f||e===c?0!==this.currentImageIndex?this.changeImage(this.currentImageIndex-1):this.options.wrapAround&&this.album.length>1&&this.changeImage(this.album.length-1):("n"===f||e===d)&&(this.currentImageIndex!==this.album.length-1?this.changeImage(this.currentImageIndex+1):this.options.wrapAround&&this.album.length>1&&this.changeImage(0))},b.prototype.end=function(){this.disableKeyboardNav(),a(window).off("resize",this.sizeOverlay),this.$lightbox.fadeOut(this.options.fadeDuration),this.$overlay.fadeOut(this.options.fadeDuration),a("select, object, embed").css({visibility:"visible"})},b}();a(function(){{var a=new b;new c(a)}})}).call(this);
;
var koaAI = function (options) {
	var vars = {
		parentWriteContainer: '#ai-chat-bubbles',
		parentChatContainer: '#ai-chat-history-list ul',
		userInput: '#ai-chat-ask-question-input',
		inputButtons: ['#ai-chat-btn-submit', '#ai-chat-btn-reset', '#ai-chat-btn-reset-mobile'],
		emptyMessageToast: '.toast.empty-question',
		chatErrorMessage: '.chat-history-error',
		aIApiUrl: 'https://api3.koa.com/ai-chatbot/v1/',
		aId: '',
		guestName: '',
		guestPhoto: '',
		hasCompletedWizard: false
	};

	var root = this;
	var _aIElement = '<div class="ai-message-bubble-wrapper d-flex pb-5">\
						<div id="ai-chat-ai-profile-picture-wrapper" class="d-flex flex-column justify-content-end align-items-center">\
							<div class="ai-profile-picture-wrapper mb-1"></div>\
							<p class="dot-flashing m-0"></p>\
						</div>\
						<div class="ai-message-container d-flex position-relative">\
							<div class="ai-rating-container w-100 position-absolute align-items-center">\
								<span class="ai-rating-message mr-2">Was this helpful?</span>\
								<a class="ai-rating-smile ai-rating-button text-white p-2 d-flex align-items-center" data-rating="5">\
									<span class="far fa-smile"></span>\
								</a>\
								<a class="ai-rating-frown ai-rating-button text-white p-2 d-flex align-items-center" data-rating="1">\
									<span class="far fa-frown"></span>\
								</a>\
							</div>\
							<div id="ai-chat-ai-message-bubble" class="ai-message-bubble chat-message p-4 ml-3 mb-0">\
								<div class="dot-flashing"></div>\
							<div>\
						</div>\
					</div>'; //TODO: Include or attach id
	var _userElement = '<div class="user-message-bubble-wrapper d-flex justify-content-end pb-4"><span class="user-message-bubble chat-message p-4 mr-3 mb-0"></span><div class="ai-profile-picture-user-wrapper mb-3 d-flex justify-content-center align-items-center"><span></span></></div>';
	var _conversationListElement = '<li class="ml-3 mr-3 pl-1 pt-1 pb-1 text-nowrap position-relative overflow-hidden ai-chat-history-item"><i class="koa-yellow-font fa fa-chevron-right pr-2"></i></li>';
	var _currentWriteIndex = 0;
	var _currentMessage;
	var _currentScrollTop;
	var _currentWriteElement;
	var _currentUserElement;
	var _currentConversationElement;
	var _currentConversationId;
	var _currentMessageId
	var _currentWriteId;
	var _userScrolled = false;
	var _isWriting;
	var _isReceivingMessage;
	var _isScrolling;
	var _requestError;
	var _xhr;
	var _converter;
	var _wizardInitialized = false;

	var _DISPLAY_MODE = {
		START: "start",
		CHATTING: "chatting",
		WIZARD: "wizard",
	}

	var _displayMode = _DISPLAY_MODE.START;

	var _preferedNameChatCookieId = "ai-chat-preffered-name";
	var _completedWizardChatCookieId = "ai-chat-completed-wizard";

	//Setting the logic for the disclaimer carousel
	var _wizardCurrentDisclaimerSlide = 0;

	this.construct = function (options) {
		$.extend(vars, options);

		//DEFAULTS
		//load guest name from cookie, if it wasn't supplied
		if (!vars.guestName) {
			vars.guestName = getCookie(_preferedNameChatCookieId);
		}

		vars.hasCompletedWizard = getCookie(_completedWizardChatCookieId);
		if (vars.hasCompletedWizard !== "true") {
			vars.hasCompletedWizard = "false";
		}

		//initialize the layout of the chatbot
		if (vars.hasCompletedWizard !== "true") {
			setDisplayMode(_DISPLAY_MODE.WIZARD);
		} else {
			setDisplayMode(_DISPLAY_MODE.START);
		}

		//Initialize converter
		_converter = new showdown.Converter({ disableForced4SpacesIndentedSublists: true, simplifiedAutoLink: true, openLinksInNewWindow: true });

		//HOOKS
		$('#btn-ai-stop-generating').on('click', function () {
			stopExecution();
		});

		$(document).on('click', '.ai-rating-button', function () {
			var rating = $(this).data('rating');
			var messageId = $(this).parents('.ai-message-container').attr('id');
			ratingResponse(messageId, rating); d
		});

		$('#ai-chat-btn-submit').on('click', function (e) {
			e.preventDefault();
			askQuestion($('#ai-chat-ask-question-input').val());
		});

		$('#ai-chat-btn-reset, #ai-chat-btn-reset-mobile').on('click', function () {
			clearChat();
		});

		$(document).on('click', '#ai-chat-history-list ul li', function () {
			getConversation($(this).attr('id'));
		});

		$(document).on('click', '#ai-chat-clear-history-confirm #clear-history', function (e) {
			e.preventDefault();
			$('#ai-chat-clear-history-confirm').modal('hide');
			clearConversationHistory();
		});

		$("#ai-chat-history-trigger, #ai-chat-area").on('click', function () {

			toggleConversationMenu($(this));
		});

		//reset button logic START
		$('#ai-chat-btn-reset, #ai-chat-btn-reset-mobile').on('click', function () {
			setDisplayMode(_DISPLAY_MODE.START);
		});

		//example prompt fill in search bar
		$('#ai-chat-prompt-examples div button').on('click', function () {
			let exampleQuestion = $(this)[0].innerText
			$('#ai-chat-ask-question-input').val(exampleQuestion);
			$('#ai-chat-btn-submit').click();
		});

		$('#close-history-modal, #exit-history-modal').on('click', function (e) {
			e.preventDefault();
			$('#ai-chat-clear-history-confirm').modal('hide');
		});

		$('#ai-chat-modal').on('hidden.bs.modal', function () {
			toggleConversationMenu($(this));
		})
	};

	this.askQuestion = function (question) {
		if (vars.hasCompletedWizard !== "true") {
			vars.pendingQuestion = question; //hold the question, to be asked later
			setDisplayMode(_DISPLAY_MODE.WIZARD);
		}
		else {
			setDisplayMode(_DISPLAY_MODE.CHATTING);
			askQuestion(question);
		}
	};

	var setDisplayMode = function (displayMode) {

		if (displayMode == _DISPLAY_MODE.CHATTING) {
			$('#ai-chat-prompt-examples').hide();
			$('#ai-chat-area-messages').hide();
			$('#ai-chat-bubble-wrapper').css('display', 'flex');
			$('#ai-chat-input').show();
			$('#ai-chat-history-title').show();
			$('#ai-chat-area').removeClass('col-md-12');
			$('#ai-chat-btn-reset-mobile, #ai-chat-btn-reset').show();

			setFocusOnInputPrompt();

			_displayMode = _DISPLAY_MODE.CHATTING;
		}
		else if (displayMode == _DISPLAY_MODE.START) {
			$('#ai-chat-disclaimer-wizard-container').hide();
			$('#ai-chat-area-row').removeClass('h-100');
			$('#ai-chat-area').removeClass('w-100');
			$('#ai-chat-area').removeClass('h-100');
			$('#ai-chat-area-messages').show();
			$('#ai-chat-prompt-examples').show();

			$('#ai-chat-bubble-wrapper').hide();
			$('#ai-chat-input').show();

			$('#ai-chat-history-title').show();
			$('#ai-chat-area').removeClass('col-md-12');

			if (vars.guestName !== '') {
				$('#ai-chat-prompt-examples h2 span').text(vars.guestName);
			}

			$('#ai-chat-btn-reset-mobile, #ai-chat-btn-reset').hide();

			setFocusOnInputPrompt();

			_displayMode = _DISPLAY_MODE.START;
		}
		else if (displayMode == _DISPLAY_MODE.WIZARD) {
			$('#ai-chat-disclaimer-wizard-container').show();
			$('#ai-chat-btn-reset-mobile, #ai-chat-btn-reset').hide();
			$('#ai-chat-bubble-wrapper').hide();
			$('#ai-chat-area-messages').show();
			$('#ai-chat-input').hide();
			$('#ai-chat-prompt-examples').hide();

			//TODO - should replace this - and cleanup how the events work in the carousel
			if (!_wizardInitialized) { //TODO: bug fix, remove all this later
				_wizardInitialized = true;
				initializeEventsForWizard();
			}

			_displayMode = _DISPLAY_MODE.WIZARD;
		}
	}

	var displayAnswer = function (text) {
		if (!_isWriting) {
			_currentMessage = '';
			_currentMessageId = null;
			_currentWriteIndex = 0;

			$(vars.parentWriteContainer).append(_aIElement);
			_currentWriteElement = $(vars.parentWriteContainer + ' .ai-message-bubble:last');

			if (text) {
				$(_currentWriteElement).html(sanitizeHtml(_converter.makeHtml(text.replace(/\[doc([0-9]*)\]/g, ''))));
				$(_currentWriteElement).siblings('.ai-rating-container').remove();
				$(_currentWriteElement).removeClass('pb-5').addClass('pb-4');
			}
			else {
				_isReceivingMessage = true;
				_isWriting = true;

				_currentScrollTop = $(vars.parentWriteContainer).parent().prop('scrollHeight') - $(vars.parentWriteContainer).parent().height();
				$(vars.parentWriteContainer).parent().animate({ scrollTop: _currentScrollTop }, 1000, function () {
					_isScrolling = false;
				});
				_isScrolling = true;
				_userScrolled = false;
				$(vars.parentWriteContainer).parent().on('mousewheel DOMMouseScroll touchmove', function () {
					_userScrolled = true;
					$(vars.parentWriteContainer).parent().off('mousewheel DOMMouseScroll touchmove');
				});


				toggleInput(false);
				write();
			}
		}
	};

	var displayQuestion = function (text, scroll = true) {
		$(vars.parentWriteContainer).append(_userElement);
		_currentUserElement = $(vars.parentWriteContainer + ' .user-message-bubble:last');
		$(_currentUserElement).text(text).html();

		//Scroll to bottom
		if (scroll) {
			$('#ai-chat-bubble-wrapper').scrollTop($('#ai-chat-bubble-wrapper').prop('scrollHeight'));
		}
	};

	var stopExecution = function () {
		//Probably need to expand this functionality a bit in the future.
		if (_xhr) {
			_xhr.abort();
			_xhr = null;
		}
		//stop writing process
		clearTimeout(_currentWriteId);
		//toggleInput(true);
		doneWriting();
		_isWriting = false;
		//remove the blinking cursor and "thinking" dots if needed.
		$('.blinking-cursor').remove();
		$('.dot-flashing').remove();

		//let the user know we stopped it for them
		$(_currentWriteElement).html(_currentMessage + ' [Message Stopped]');
	};

	var clearChat = function () {
		if (!$('.chat-window').hasClass('h-100')) {
			$('.chat-window').addClass('h-100').show();
		}

		stopExecution();
		_currentConversationId = null;
		_currentMessageId = null;
		$(vars.parentWriteContainer).empty();
		addRemoveRestartBtn();
	};

	var clearInput = function () {
		$(vars.userInput).val("");
	};

	var addRemoveRestartBtn = function () {
		if ($.trim($(vars.parentWriteContainer).html()).length) {
			$('#ai-chat-btn-reset-mobile').show();
			$('#ai-chat-btn-reset, #ai-chat-input p').css('display', 'flex');

		} else {
			$('#ai-chat-btn-reset-mobile, #ai-chat-btn-reset, #ai-chat-input p').hide();
		}
	};

	var toggleInput = function (enable) {
		if (enable) {
			$(vars.userInput).removeAttr('disabled');
			vars.inputButtons.forEach(function (item) {
				$(item).removeAttr('disabled');
			});
		}
		else {
			$(vars.userInput).prop('disabled', 'disabled');
			vars.inputButtons.forEach(function (item) {
				$(item).prop('disabled', 'disabled');
			});
		}
	};

	var write = function () {

		if (!$('#ai-chat-ai-message-bubble div').hasClass('dot-flashing')) {
			$('.ai-message-bubble-wrapper:last-child #ai-chat-ai-profile-picture-wrapper').css('top', '0px');
			$('.ai-message-bubble-wrapper:last-child #ai-chat-ai-profile-picture-wrapper p.dot-flashing').show();
		}

		$('#btn-ai-stop-generating').show();
		if (!_userScrolled && !_isScrolling) {
			var scrollTop = $(vars.parentWriteContainer).parent().prop('scrollHeight') - $(vars.parentWriteContainer).parent().height();;
			if (_currentScrollTop != scrollTop) {
				$(vars.parentWriteContainer).parent().animate({ scrollTop: scrollTop }, 1000, function () {
					_isScrolling = false;
				});
				_isScrolling = true;
				_currentScrollTop = scrollTop;
			}
		}
		if (_currentWriteIndex < _currentMessage.length) {
			var message = _currentMessage.slice(0, _currentWriteIndex)
			_currentWriteIndex++;
			if (!message.match(/<[^>]*$/)) {
				$(_currentWriteElement).html(sanitizeHtml(message, true));
				_currentWriteId = setTimeout(write, Math.random() * 5 + 5);
			}
			else {
				_currentWriteId = setTimeout(write, 0);
			}
		}
		else if (_isReceivingMessage) {
			_currentWriteId = setTimeout(write, Math.random() * 5 + 5);
		}
		else {
			$(_currentWriteElement).html(sanitizeHtml(_currentMessage.slice(0, _currentWriteIndex)));
			doneWriting();
			_isWriting = false;
		}
	};

	var updateMessage = function (text, finished) {
		if (!text.endsWith(']')) {
			text += ']';
		}
		var json = JSON.parse(text);
		if (!_currentConversationId || !_currentMessageId) {
			_currentConversationId = json[0].cid;
			_currentMessageId = json[0].mid;
		}
		var message = '';
		json.forEach(function (item) {
			if (item.m) {
				message += item.m;
			}
		});
		_currentMessage = _converter.makeHtml(message.replace(/\[doc([0-9]*)\]/g, ''));
		if (finished) {
			_isReceivingMessage = false;
			_xhr = null;
		}
	};

	var doneWriting = function () {

		if ($('#ai-chat-ai-profile-picture-wrapper p').hasClass('dot-flashing')) {
			$('.ai-message-bubble-wrapper:last-child #ai-chat-ai-profile-picture-wrapper').css('top', '10px');
			$('#ai-chat-ai-profile-picture-wrapper p.dot-flashing').hide();
		}

		toggleInput(true);
		$('#btn-ai-stop-generating').hide();
		if (!_requestError) {
			$(_currentWriteElement).parent().attr('id', _currentMessageId);
			$(vars.parentWriteContainer + ' .ai-rating-container:last').css('display', 'flex');
		}
		else {
			_requestError = false;
			//TODO:
		}
		setFocusOnInputPrompt();
	};

	var askQuestion = function (question) {
		if (!_isWriting) {
			if (validateQuestion(question)) {

				setDisplayMode(_DISPLAY_MODE.CHATTING);

				if (!_currentConversationId) {
					clearChat();
				}

				displayQuestion(question);
				clearInput();
				addRemoveRestartBtn();
				const form = new FormData();
				form.append('question', question);

				_xhr = new XMLHttpRequest();
				//TODO: Clean up logic and add error handling
				var url = vars.aIApiUrl + 'messages/ask-question/' + vars.aId;
				if (_currentConversationId) {
					url += '/' + _currentConversationId;
				}
				else {
					form.append('guestName', vars.guestName);
				}
				_xhr.open('POST', url);
				_xhr.setRequestHeader('Accept', 'text/json');
				_xhr.onprogress = () => updateMessage(_xhr.response);
				_xhr.onload = () => updateMessage(_xhr.response, true);
				_xhr.onreadystatechange = () => handleXhrError(_xhr.status);
				_xhr.send(form);
				displayAnswer();
				addUserInitial();
				//TODO: Will have to update elements with the conversation id and message id when we return those.
			}
			else {
				//TODO: Handle this better. Do we want to still show the question in the chat?
				//for now, we're only checking for an empty string. Do nothing with it.
				//alert("Sorry there was a problem with your question!");
			}
		}
	};

	var handleXhrError = function (status) {
		if ((status >= 200 && status < 400)) {
			// The request has been completed successfully
		} else {
			_currentMessage = 'Sorry there was a problem with your request. Please try again later.';
			_isReceivingMessage = false;
			_requestError = true;
		}
	};

	var showToastElement = function (element) {
		$(element).toast('show');
	};

	//Add the user initial to the user chat bubble
	function addUserInitial() {
		$('.ai-profile-picture-user-wrapper span').text(vars.guestName[0]).html();
	}

	var validateQuestion = function (question) {
		//TODO: We could check for bad words/etc. here? Or just handle that on the backend
		if (!question.trim()) {
			showToastElement(vars.emptyMessageToast);
			return false;
		}
		else {
			return true;
		}
	};

	var getConversation = function (conversationId) {
		var url = vars.aIApiUrl + 'conversations/' + vars.aId + '/' + conversationId;
		$.get(url)
			.done(function (data) {
				if (data) {
					showConversation(data);
				}
			})
			.fail(function () {
				//Show some error
			})
			.always(function () {

			});
	};

	var getConversations = function () {

		var url = vars.aIApiUrl + 'conversations/' + vars.aId;
		$.get(url)
			.done(function (data) {
				if (data.conversationList) {
					showConversations(data.conversationList);
					$(vars.chatErrorMessage).hide();
				}
			})
			.fail(function () {
				$(vars.chatErrorMessage).css('display', 'flex');
			})
			.always(function () {

			});
	};

	var showConversation = function (conversation) {

		setDisplayMode(_DISPLAY_MODE.CHATTING);

		clearChat(); //TODO: could probably move these call into DisplayMode -> Chatting

		//reset the conversation
		_currentConversationId = conversation.chatbotConversationId;
		conversation.messageList.forEach(function (item) {
			if (item.role == 4) {
				displayQuestion(item.messageText, false);
			}
			else {
				displayAnswer(item.messageText);
			}
		});
		toggleConversationMenu($(this));
		addRemoveRestartBtn();
		addUserInitial();
	};

	var showConversations = function (conversations) {

		$(vars.parentChatContainer).empty();
		var currentDate = moment().startOf('day').hour(12);
		conversations.forEach(function (item) {
			var date = moment(item.dateAdded);
			$(vars.parentChatContainer).append(_conversationListElement);
			_currentConversationElement = $(vars.parentChatContainer + ' li:last');
			var dateString;
			var daysAgo = currentDate.diff(date.set({ hour: 12, minute: 0, second: 0, millisecond: 0 }), 'days');
			switch (daysAgo) {
				case 0:
					dateString = moment(item.dateAdded).format("[Today] - hh:mma");
					break;
				case 1:
					dateString = moment(item.dateAdded).format("[Yesterday] - hh:mma");
					break;
				case 2:
				case 3:
				case 4:
				case 5:
				case 6:
					dateString = moment(item.dateAdded).format("[" + daysAgo + " Days Ago] - hh:mma");
					break;
				default:
					dateString = moment(item.dateAdded).format("ddd, MMM Do YYYY - hh:mma");
					break;
			}
			$(_currentConversationElement).html('<i class="koa-yellow-font fa fa-chevron-right pr-2"></i>' + dateString + '<div class="fade-out-gradient position-absolute h-100"></div>');
			//TODO: Assuming we want a way of encoding this or something
			$(_currentConversationElement).attr('id', item.chatbotConversationId);
		});
	};

	var clearConversationHistory = function (conversationId) {
		var url;
		if (conversationId) {
			url = vars.aIApiUrl + 'conversations/remove/' + vars.aId + '/' + conversationId;
		}
		else {
			url = vars.aIApiUrl + 'conversations/remove-all/' + vars.aId;
		}
		$.ajax({
			url: url,
			type: 'DELETE'
		}).done(function () {
			if (conversationId) {
				//Refresh list
				getConversations();
			}
			else {
				$(vars.parentChatContainer).empty();
			}
		}).fail(function () {
			//Show some error
		}).always(function () {
		});
	};

	var ratingResponse = function (messageId, rating) {
		var url = vars.aIApiUrl + 'ratings/add-rating/' + vars.aId + '/' + _currentConversationId + '/' + messageId;
		const form = new FormData();
		form.append('rating', rating);

		$.ajax({
			url: url,
			data: form,
			type: 'PUT',
			contentType: false,
			processData: false
		}).done(function () {
			$('#' + messageId + ' .ai-rating-container').hide('slide', { direction: 'down' }, 500, function () {
				$('#' + messageId + ' .ai-rating-container').remove();
			});
			$('#' + messageId).removeClass('pb-5');
		}).fail(function () {
			//Show some error
		}).always(function () {

		});
	};

	var setFocusOnInputPrompt = function () {
		if ($(window).width() >= 768) {
			$("#ai-chat-ask-question-input").focus();
		}
	};

	var sanitizeHtml = function (text, appendCursor) {
		if (appendCursor) {
			text += '<span class="blinking-cursor">|</span>';
		}
		return DOMPurify.sanitize(text, { ADD_ATTR: ['target'] });
	};

	var initializeEventsForWizard = function () {
		$('#ai-chat-disclaimer-wizard-child-1 .btn').on('click', function () {
			$('#ai-chat-disclaimer-wizard-child-1').hide();
			$('#ai-chat-disclaimer-wizard-child-2, .ai-chat-disclaimer-title:first-child').show();
			_wizardCurrentDisclaimerSlide += 1;
		})

		//Prevent disclaimer carousel from looping
		$('#ai-chat-disclaimer-carousel').carousel({
			wrap: false
		});

		$('.carousel-controls-next').on('click', function () {
			_wizardCurrentDisclaimerSlide += 1;
			changeDisclaimerTitle();
		})
		$('.carousel-controls-prev').on('click', function () {
			_wizardCurrentDisclaimerSlide -= 1;
			changeDisclaimerTitle();
		})

		$('.carousel-indicators li').on('click', function () {
			if ($(this).data('slide-to') == 0) {
				_wizardCurrentDisclaimerSlide = 1;
				changeDisclaimerTitle();
			}
			else if ($(this).data('slide-to') == 1) {
				_wizardCurrentDisclaimerSlide = 2;
				changeDisclaimerTitle();
			}
			else if ($(this).data('slide-to') == 2) {
				_wizardCurrentDisclaimerSlide = 3;
				changeDisclaimerTitle();
			}
		})

		function changeDisclaimerTitle() {
			if (_wizardCurrentDisclaimerSlide == 0) {
				$('#ai-chat-disclaimer-wizard-child-2').hide();
				$('#ai-chat-disclaimer-wizard-child-1').css('display', 'flex');
			}
			else if (_wizardCurrentDisclaimerSlide == 1) {
				$('.ai-chat-disclaimer-title:nth-child(2), .ai-chat-disclaimer-title:last-child').hide();
				$('.ai-chat-disclaimer-title:first-child').show();
			}
			else if (_wizardCurrentDisclaimerSlide == 2) {
				$('.ai-chat-disclaimer-title:first-child, .ai-chat-disclaimer-title:last-child').hide();
				$('.ai-chat-disclaimer-title:nth-child(2)').show();
			}
			else if (_wizardCurrentDisclaimerSlide == 3) {
				$('.ai-chat-disclaimer-title:first-child, .ai-chat-disclaimer-title:nth-child(2)').hide();
				$('.ai-chat-disclaimer-title:last-child').show();
			}
			else {
				$('#ai-chat-disclaimer-wizard-child-2').hide();
				$('#ai-chat-area-row').removeClass('h-100');
				$('#ai-chat-area').removeClass('h-100');
				$('#ai-chat-disclaimer-wizard-child-3').show();
			}
		}

		//Set the preferred name in local storage
		$('#ai-chat-preferred-name-form button').on('click', function (e) {
			let guestName = $('#ai-chat-preferred-name').val();
			if (validateGuestName(guestName)) {
				vars.guestName = guestName.charAt(0).toUpperCase() + guestName.slice(1);

				//set preferred name cookie
				setCookie(_preferedNameChatCookieId, vars.guestName);

				//set wizard complete cookie
				setCookie(_completedWizardChatCookieId, "true");
				vars.hasCompletedWizard = "true";

				addNameToPrompts(vars.guestName);

				if (vars.pendingQuestion) {
					setDisplayMode(_DISPLAY_MODE.CHATTING);

					//initiate the question that was asked - that is pending
					$('#ai-chat-ask-question-input').val(vars.pendingQuestion);
					$('#ai-chat-btn-submit').click();
					vars.pendingQuestion = "";
				}
				else {
					setDisplayMode(_DISPLAY_MODE.START);
				}
			}
		})

		function validateGuestName(guestName) {
			if (!guestName.trim()) {
				$("#ai-chat-preferred-name-error").show();
				return false;
			}
			else {
				$("#ai-chat-preferred-name-error").hide();
				return true;
			}
		}
	};

	var addRemoveChatHistory = function () {
		$('#ai-chat-history-title').show();
		$('#ai-chat-area').removeClass('col-md-12');
	};

	var addNameToPrompts = function (guestName) {
		$('#ai-chat-prompt-examples h2 span').text(guestName);
	};

	var toggleConversationMenu = function (e) {
		if (e.is('#ai-chat-area') || $("#ai-chat-history-wrapper").is(":visible") || e.is('#ai-chat-modal') || e.is('ai-chat-history-item')) {
			$("#ai-chat-history-wrapper").hide();
			$("#ai-chat-history-title").addClass('ai-chat-history-title-border');
			$('#ai-chat-history-title .fa-chevron-up').addClass('fa-history');
			$('#ai-chat-history-title .fa-history').removeClass('fa-chevron-up');
		}
		else {
			getConversations();
			$("#ai-chat-history-wrapper").show();
			$("#ai-chat-history-title").removeClass('ai-chat-history-title-border');
			$('#ai-chat-history-title .fa-history').addClass('fa-chevron-up');
			$('#ai-chat-history-title .fa-chevron-up').removeClass('fa-history');
		}
	};

	//Add the user initial to the user chat bubble
	var addUserInitial = function () {
		$('.ai-profile-picture-user-wrapper span').text(vars.guestName[0]);
	};

	var getCookie = function (cookieName) {
		return Utils.getCookie(cookieName);
	}

	var setCookie = function (cookieName, cookieValue) {
		Utils.setCookie(cookieName, cookieValue, 365, '/');
	}

	this.construct(options);
}
;
/*! showdown v 2.0.0 - 10-03-2022 */
!function(){function t(e){"use strict";var a={omitExtraWLInCodeBlocks:{defaultValue:!1,describe:"Omit the default extra whiteline added to code blocks",type:"boolean"},noHeaderId:{defaultValue:!1,describe:"Turn on/off generated header id",type:"boolean"},prefixHeaderId:{defaultValue:!1,describe:"Add a prefix to the generated header ids. Passing a string will prefix that string to the header id. Setting to true will add a generic 'section-' prefix",type:"string"},rawPrefixHeaderId:{defaultValue:!1,describe:'Setting this option to true will prevent showdown from modifying the prefix. This might result in malformed IDs (if, for instance, the " char is used in the prefix)',type:"boolean"},ghCompatibleHeaderId:{defaultValue:!1,describe:"Generate header ids compatible with github style (spaces are replaced with dashes, a bunch of non alphanumeric chars are removed)",type:"boolean"},rawHeaderId:{defaultValue:!1,describe:"Remove only spaces, ' and \" from generated header ids (including prefixes), replacing them with dashes (-). WARNING: This might result in malformed ids",type:"boolean"},headerLevelStart:{defaultValue:!1,describe:"The header blocks level start",type:"integer"},parseImgDimensions:{defaultValue:!1,describe:"Turn on/off image dimension parsing",type:"boolean"},simplifiedAutoLink:{defaultValue:!1,describe:"Turn on/off GFM autolink style",type:"boolean"},literalMidWordUnderscores:{defaultValue:!1,describe:"Parse midword underscores as literal underscores",type:"boolean"},literalMidWordAsterisks:{defaultValue:!1,describe:"Parse midword asterisks as literal asterisks",type:"boolean"},strikethrough:{defaultValue:!1,describe:"Turn on/off strikethrough support",type:"boolean"},tables:{defaultValue:!1,describe:"Turn on/off tables support",type:"boolean"},tablesHeaderId:{defaultValue:!1,describe:"Add an id to table headers",type:"boolean"},ghCodeBlocks:{defaultValue:!0,describe:"Turn on/off GFM fenced code blocks support",type:"boolean"},tasklists:{defaultValue:!1,describe:"Turn on/off GFM tasklist support",type:"boolean"},smoothLivePreview:{defaultValue:!1,describe:"Prevents weird effects in live previews due to incomplete input",type:"boolean"},smartIndentationFix:{defaultValue:!1,describe:"Tries to smartly fix indentation in es6 strings",type:"boolean"},disableForced4SpacesIndentedSublists:{defaultValue:!1,describe:"Disables the requirement of indenting nested sublists by 4 spaces",type:"boolean"},simpleLineBreaks:{defaultValue:!1,describe:"Parses simple line breaks as <br> (GFM Style)",type:"boolean"},requireSpaceBeforeHeadingText:{defaultValue:!1,describe:"Makes adding a space between `#` and the header text mandatory (GFM Style)",type:"boolean"},ghMentions:{defaultValue:!1,describe:"Enables github @mentions",type:"boolean"},ghMentionsLink:{defaultValue:"https://github.com/{u}",describe:"Changes the link generated by @mentions. Only applies if ghMentions option is enabled.",type:"string"},encodeEmails:{defaultValue:!0,describe:"Encode e-mail addresses through the use of Character Entities, transforming ASCII e-mail addresses into its equivalent decimal entities",type:"boolean"},openLinksInNewWindow:{defaultValue:!1,describe:"Open all links in new windows",type:"boolean"},backslashEscapesHTMLTags:{defaultValue:!1,describe:"Support for HTML Tag escaping. ex: <div>foo</div>",type:"boolean"},emoji:{defaultValue:!1,describe:"Enable emoji support. Ex: `this is a :smile: emoji`",type:"boolean"},underline:{defaultValue:!1,describe:"Enable support for underline. Syntax is double or triple underscores: `__underline word__`. With this option enabled, underscores no longer parses into `<em>` and `<strong>`",type:"boolean"},ellipsis:{defaultValue:!0,describe:"Replaces three dots with the ellipsis unicode character",type:"boolean"},completeHTMLDocument:{defaultValue:!1,describe:"Outputs a complete html document, including `<html>`, `<head>` and `<body>` tags",type:"boolean"},metadata:{defaultValue:!1,describe:"Enable support for document metadata (defined at the top of the document between `«««` and `»»»` or between `---` and `---`).",type:"boolean"},splitAdjacentBlockquotes:{defaultValue:!1,describe:"Split adjacent blockquote blocks",type:"boolean"},moreStyling:{defaultValue:!1,describe:"Adds some useful styling css classes in the generated html",type:"boolean"},relativePathBaseUrl:{defaultValue:!1,describe:"Prepends a base URL to relative paths",type:"string"}};if(!1===e)return JSON.parse(JSON.stringify(a));var r,t={};for(r in a)a.hasOwnProperty(r)&&(t[r]=a[r].defaultValue);return t}var e,P={},r={},h={},m=t(!0),d="vanilla",g={github:{omitExtraWLInCodeBlocks:!0,simplifiedAutoLink:!0,literalMidWordUnderscores:!0,strikethrough:!0,tables:!0,tablesHeaderId:!0,ghCodeBlocks:!0,tasklists:!0,disableForced4SpacesIndentedSublists:!0,simpleLineBreaks:!0,requireSpaceBeforeHeadingText:!0,ghCompatibleHeaderId:!0,ghMentions:!0,backslashEscapesHTMLTags:!0,emoji:!0,splitAdjacentBlockquotes:!0},original:{noHeaderId:!0,ghCodeBlocks:!1},ghost:{omitExtraWLInCodeBlocks:!0,parseImgDimensions:!0,simplifiedAutoLink:!0,literalMidWordUnderscores:!0,strikethrough:!0,tables:!0,tablesHeaderId:!0,ghCodeBlocks:!0,tasklists:!0,smoothLivePreview:!0,simpleLineBreaks:!0,requireSpaceBeforeHeadingText:!0,ghMentions:!1,encodeEmails:!0},vanilla:t(!0),allOn:function(){"use strict";var e,a=t(!0),r={};for(e in a)a.hasOwnProperty(e)&&(r[e]=!0);return r}()};function p(e,a){"use strict";var r=a?"Error in "+a+" extension->":"Error in unnamed extension",t={valid:!0,error:""};P.helper.isArray(e)||(e=[e]);for(var n=0;n<e.length;++n){var s=r+" sub-extension "+n+": ",i=e[n];if("object"!=typeof i)return t.valid=!1,t.error=s+"must be an object, but "+typeof i+" given",t;if(!P.helper.isString(i.type))return t.valid=!1,t.error=s+'property "type" must be a string, but '+typeof i.type+" given",t;var o=i.type=i.type.toLowerCase();if("lang"!==(o="html"===(o="language"===o?i.type="lang":o)?i.type="output":o)&&"output"!==o&&"listener"!==o)return t.valid=!1,t.error=s+"type "+o+' is not recognized. Valid values: "lang/language", "output/html" or "listener"',t;if("listener"===o){if(P.helper.isUndefined(i.listeners))return t.valid=!1,t.error=s+'. Extensions of type "listener" must have a property called "listeners"',t}else if(P.helper.isUndefined(i.filter)&&P.helper.isUndefined(i.regex))return t.valid=!1,t.error=s+o+' extensions must define either a "regex" property or a "filter" method',t;if(i.listeners){if("object"!=typeof i.listeners)return t.valid=!1,t.error=s+'"listeners" property must be an object but '+typeof i.listeners+" given",t;for(var l in i.listeners)if(i.listeners.hasOwnProperty(l)&&"function"!=typeof i.listeners[l])return t.valid=!1,t.error=s+'"listeners" property must be an hash of [event name]: [callback]. listeners.'+l+" must be a function but "+typeof i.listeners[l]+" given",t}if(i.filter){if("function"!=typeof i.filter)return t.valid=!1,t.error=s+'"filter" must be a function, but '+typeof i.filter+" given",t}else if(i.regex){if(P.helper.isString(i.regex)&&(i.regex=new RegExp(i.regex,"g")),!(i.regex instanceof RegExp))return t.valid=!1,t.error=s+'"regex" property must either be a string or a RegExp object, but '+typeof i.regex+" given",t;if(P.helper.isUndefined(i.replace))return t.valid=!1,t.error=s+'"regex" extensions must implement a replace string or function',t}}return t}function n(e,a){"use strict";return"¨E"+a.charCodeAt(0)+"E"}P.helper={},P.extensions={},P.setOption=function(e,a){"use strict";return m[e]=a,this},P.getOption=function(e){"use strict";return m[e]},P.getOptions=function(){"use strict";return m},P.resetOptions=function(){"use strict";m=t(!0)},P.setFlavor=function(e){"use strict";if(!g.hasOwnProperty(e))throw Error(e+" flavor was not found");P.resetOptions();var a,r=g[e];for(a in d=e,r)r.hasOwnProperty(a)&&(m[a]=r[a])},P.getFlavor=function(){"use strict";return d},P.getFlavorOptions=function(e){"use strict";if(g.hasOwnProperty(e))return g[e]},P.getDefaultOptions=t,P.subParser=function(e,a){"use strict";if(!P.helper.isString(e))throw Error("showdown.subParser function first argument must be a string (the name of the subparser)");if(void 0===a){if(r.hasOwnProperty(e))return r[e];throw Error("SubParser named "+e+" not registered!")}r[e]=a},P.extension=function(e,a){"use strict";if(!P.helper.isString(e))throw Error("Extension 'name' must be a string");if(e=P.helper.stdExtName(e),P.helper.isUndefined(a)){if(h.hasOwnProperty(e))return h[e];throw Error("Extension named "+e+" is not registered!")}"function"==typeof a&&(a=a());var r=p(a=P.helper.isArray(a)?a:[a],e);if(!r.valid)throw Error(r.error);h[e]=a},P.getAllExtensions=function(){"use strict";return h},P.removeExtension=function(e){"use strict";delete h[e]},P.resetExtensions=function(){"use strict";h={}},P.validateExtension=function(e){"use strict";e=p(e,null);return!!e.valid||(console.warn(e.error),!1)},P.hasOwnProperty("helper")||(P.helper={}),void 0===this&&"undefined"!=typeof window?P.helper.document=window.document:(void 0===this.document&&void 0===this.window&&(e=require("jsdom"),this.window=new e.JSDOM("",{}).window),P.helper.document=this.window.document),P.helper.isString=function(e){"use strict";return"string"==typeof e||e instanceof String},P.helper.isFunction=function(e){"use strict";return e&&"[object Function]"==={}.toString.call(e)},P.helper.isArray=function(e){"use strict";return Array.isArray(e)},P.helper.isUndefined=function(e){"use strict";return void 0===e},P.helper.forEach=function(e,a){"use strict";if(P.helper.isUndefined(e))throw new Error("obj param is required");if(P.helper.isUndefined(a))throw new Error("callback param is required");if(!P.helper.isFunction(a))throw new Error("callback param must be a function/closure");if("function"==typeof e.forEach)e.forEach(a);else if(P.helper.isArray(e))for(var r=0;r<e.length;r++)a(e[r],r,e);else{if("object"!=typeof e)throw new Error("obj does not seem to be an array or an iterable object");for(var t in e)e.hasOwnProperty(t)&&a(e[t],t,e)}},P.helper.stdExtName=function(e){"use strict";return e.replace(/[_?*+\/\\.^-]/g,"").replace(/\s/g,"").toLowerCase()},P.helper.escapeCharactersCallback=n,P.helper.escapeCharacters=function(e,a,r){"use strict";a="(["+a.replace(/([\[\]\\])/g,"\\$1")+"])",r&&(a="\\\\"+a),r=new RegExp(a,"g");return e=e.replace(r,n)};function u(e,a,r,t){"use strict";var n,s,i,o=-1<(t=t||"").indexOf("g"),l=new RegExp(a+"|"+r,"g"+t.replace(/g/g,"")),c=new RegExp(a,t.replace(/g/g,"")),u=[];do{for(n=0;m=l.exec(e);)if(c.test(m[0]))n++||(i=(s=l.lastIndex)-m[0].length);else if(n&&!--n){var h=m.index+m[0].length,m={left:{start:i,end:s},match:{start:s,end:m.index},right:{start:m.index,end:h},wholeMatch:{start:i,end:h}};if(u.push(m),!o)return u}}while(n&&(l.lastIndex=s));return u}var s;function i(o,l,c,u,h){return h=!!h,function(e,a,r,t,n,s,i){return/\n\n/.test(e)?e:b(_(o,l+".captureStart",e,a,r,t,i,c,u),c,u,h)}}function l(o,l,c,u,h){return function(e,a,r,t,n,s,i){return t=P.helper.applyBaseUrl(c.relativePathBaseUrl,t),b(_(o,l+".captureStart",e,a,r,t,i,c,u),c,u,h)}}function _(e,a,r,t,n,s,i,o,l){return l.converter._dispatch(a,r,o,l,{regexp:e,matches:{wholeMatch:r,text:t,id:n,url:s,title:i}})}function b(e,a,r,t){var n=e.getMatches().wholeMatch,s=e.getMatches().text,i=e.getMatches().id,o=e.getMatches().url,l="",e=(e=e.getMatches().title)||"",i=i?i.toLowerCase():"";if(t)o="";else if(!o){if(o="#"+(i=i||s.toLowerCase().replace(/ ?\n/g," ")),P.helper.isUndefined(r.gUrls[i]))return n;o=r.gUrls[i],P.helper.isUndefined(r.gTitles[i])||(e=r.gTitles[i])}o=o.replace(P.helper.regexes.asteriskDashTildeAndColon,P.helper.escapeCharactersCallback),""!==e&&null!==e&&(e=' title="'+(e=(e=e.replace(/"/g,"&quot;")).replace(P.helper.regexes.asteriskDashTildeAndColon,P.helper.escapeCharactersCallback))+'"'),a.openLinksInNewWindow&&!/^#/.test(o)&&(l=' rel="noopener noreferrer" target="¨E95Eblank"'),s=P.subParser("makehtml.codeSpans")(s,a,r),s=P.subParser("makehtml.emoji")(s,a,r),s=P.subParser("makehtml.underline")(s,a,r),s=P.subParser("makehtml.italicsAndBold")(s,a,r),s=P.subParser("makehtml.strikethrough")(s,a,r),s=P.subParser("makehtml.ellipsis")(s,a,r);t='<a href="'+o+'"'+e+l+">"+(s=P.subParser("makehtml.hashHTMLSpans")(s,a,r))+"</a>";return P.subParser("makehtml.hashHTMLSpans")(t,a,r)}P.helper.matchRecursiveRegExp=function(e,a,r,t){"use strict";for(var n=u(e,a,r,t),s=[],i=0;i<n.length;++i)s.push([e.slice(n[i].wholeMatch.start,n[i].wholeMatch.end),e.slice(n[i].match.start,n[i].match.end),e.slice(n[i].left.start,n[i].left.end),e.slice(n[i].right.start,n[i].right.end)]);return s},P.helper.replaceRecursiveRegExp=function(e,a,r,t,n){"use strict";P.helper.isFunction(a)||(s=a,a=function(){return s});var s,i=u(e,r,t,n),r=e,o=i.length;if(0<o){var l=[];0!==i[0].wholeMatch.start&&l.push(e.slice(0,i[0].wholeMatch.start));for(var c=0;c<o;++c)l.push(a(e.slice(i[c].wholeMatch.start,i[c].wholeMatch.end),e.slice(i[c].match.start,i[c].match.end),e.slice(i[c].left.start,i[c].left.end),e.slice(i[c].right.start,i[c].right.end))),c<o-1&&l.push(e.slice(i[c].wholeMatch.end,i[c+1].wholeMatch.start));i[o-1].wholeMatch.end<e.length&&l.push(e.slice(i[o-1].wholeMatch.end)),r=l.join("")}return r},P.helper.regexIndexOf=function(e,a,r){"use strict";if(!P.helper.isString(e))throw"InvalidArgumentError: first parameter of showdown.helper.regexIndexOf function must be a string";if(!(a instanceof RegExp))throw"InvalidArgumentError: second parameter of showdown.helper.regexIndexOf function must be an instance of RegExp";e=e.substring(r||0).search(a);return 0<=e?e+(r||0):e},P.helper.splitAtIndex=function(e,a){"use strict";if(P.helper.isString(e))return[e.substring(0,a),e.substring(a)];throw"InvalidArgumentError: first parameter of showdown.helper.regexIndexOf function must be a string"},P.helper.encodeEmailAddress=function(e){"use strict";var r=[function(e){return"&#"+e.charCodeAt(0)+";"},function(e){return"&#x"+e.charCodeAt(0).toString(16)+";"},function(e){return e}];return e=e.replace(/./g,function(e){var a;return e="@"===e?r[Math.floor(2*Math.random())](e):.9<(a=Math.random())?r[2](e):.45<a?r[1](e):r[0](e)})},P.helper.repeat=function(e,a){"use strict";if(!P.helper.isUndefined(String.prototype.repeat))return e.repeat(a);if(e=""+e,a<0)throw new RangeError("repeat count must be non-negative");if(a===1/0)throw new RangeError("repeat count must be less than infinity");if(a=Math.floor(a),0===e.length||0===a)return"";if(e.length*a>=1<<28)throw new RangeError("repeat count must not overflow maximum string size");var r=e.length*a;for(a=Math.floor(Math.log(a)/Math.log(2));a;)e+=e,a--;return e+=e.substring(0,r-e.length)},P.helper.padEnd=function(e,a,r){"use strict";return a>>=0,r=String(r||" "),e.length>a?String(e):((a-=e.length)>r.length&&(r+=P.helper.repeat(r,a/r.length)),String(e)+r.slice(0,a))},P.helper.unescapeHTMLEntities=function(e){"use strict";return e.replace(/&quot;/g,'"').replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&amp;/g,"&")},P.helper._hashHTMLSpan=function(e,a){return"¨C"+(a.gHtmlSpans.push(e)-1)+"C"},P.helper.applyBaseUrl=function(e,a){return a=e&&!this.isAbsolutePath(a)?(0,require("url").resolve)(e,a):a},P.helper.isAbsolutePath=function(e){return/(^([a-z]+:)?\/\/)|(^#)/i.test(e)},P.helper.Event=function(e,a,r){"use strict";var t=r.regexp||null,n=r.matches||{},s=r.options||{},i=r.converter||null,o=r.globals||{};this.getName=function(){return e},this.getEventName=function(){return e},this._stopExecution=!1,this.parsedText=r.parsedText||null,this.getRegexp=function(){return t},this.getOptions=function(){return s},this.getConverter=function(){return i},this.getGlobals=function(){return o},this.getCapturedText=function(){return a},this.getText=function(){return a},this.setText=function(e){a=e},this.getMatches=function(){return n},this.setMatches=function(e){n=e},this.preventDefault=function(e){this._stopExecution=!e}},"undefined"==typeof console&&(console={warn:function(e){"use strict";alert(e)},log:function(e){"use strict";alert(e)},error:function(e){"use strict";throw e}}),P.helper.regexes={asteriskDashTildeAndColon:/([*_:~])/g,asteriskDashAndTilde:/([*_~])/g},P.helper.emojis={100:"💯",1234:"🔢","+1":"👍","-1":"👎","1st_place_medal":"🥇","2nd_place_medal":"🥈","3rd_place_medal":"🥉","8ball":"🎱",a:"🅰️",ab:"🆎",abacus:"🧮",abc:"🔤",abcd:"🔡",accept:"🉑",adhesive_bandage:"🩹",adult:"🧑",aerial_tramway:"🚡",afghanistan:"🇦🇫",airplane:"✈️",aland_islands:"🇦🇽",alarm_clock:"⏰",albania:"🇦🇱",alembic:"⚗️",algeria:"🇩🇿",alien:"👽",ambulance:"🚑",american_samoa:"🇦🇸",amphora:"🏺",anchor:"⚓",andorra:"🇦🇩",angel:"👼",anger:"💢",angola:"🇦🇴",angry:"😠",anguilla:"🇦🇮",anguished:"😧",ant:"🐜",antarctica:"🇦🇶",antigua_barbuda:"🇦🇬",apple:"🍎",aquarius:"♒",argentina:"🇦🇷",aries:"♈",armenia:"🇦🇲",arrow_backward:"◀️",arrow_double_down:"⏬",arrow_double_up:"⏫",arrow_down:"⬇️",arrow_down_small:"🔽",arrow_forward:"▶️",arrow_heading_down:"⤵️",arrow_heading_up:"⤴️",arrow_left:"⬅️",arrow_lower_left:"↙️",arrow_lower_right:"↘️",arrow_right:"➡️",arrow_right_hook:"↪️",arrow_up:"⬆️",arrow_up_down:"↕️",arrow_up_small:"🔼",arrow_upper_left:"↖️",arrow_upper_right:"↗️",arrows_clockwise:"🔃",arrows_counterclockwise:"🔄",art:"🎨",articulated_lorry:"🚛",artificial_satellite:"🛰️",artist:"🧑‍🎨",aruba:"🇦🇼",ascension_island:"🇦🇨",asterisk:"*️⃣",astonished:"😲",astronaut:"🧑‍🚀",athletic_shoe:"👟",atm:"🏧",atom_symbol:"⚛️",australia:"🇦🇺",austria:"🇦🇹",auto_rickshaw:"🛺",avocado:"🥑",axe:"🪓",azerbaijan:"🇦🇿",b:"🅱️",baby:"👶",baby_bottle:"🍼",baby_chick:"🐤",baby_symbol:"🚼",back:"🔙",bacon:"🥓",badger:"🦡",badminton:"🏸",bagel:"🥯",baggage_claim:"🛄",baguette_bread:"🥖",bahamas:"🇧🇸",bahrain:"🇧🇭",balance_scale:"⚖️",bald_man:"👨‍🦲",bald_woman:"👩‍🦲",ballet_shoes:"🩰",balloon:"🎈",ballot_box:"🗳️",ballot_box_with_check:"☑️",bamboo:"🎍",banana:"🍌",bangbang:"‼️",bangladesh:"🇧🇩",banjo:"🪕",bank:"🏦",bar_chart:"📊",barbados:"🇧🇧",barber:"💈",baseball:"⚾",basket:"🧺",basketball:"🏀",basketball_man:"⛹️‍♂️",basketball_woman:"⛹️‍♀️",bat:"🦇",bath:"🛀",bathtub:"🛁",battery:"🔋",beach_umbrella:"🏖️",bear:"🐻",bearded_person:"🧔",bed:"🛏️",bee:"🐝",beer:"🍺",beers:"🍻",beetle:"🐞",beginner:"🔰",belarus:"🇧🇾",belgium:"🇧🇪",belize:"🇧🇿",bell:"🔔",bellhop_bell:"🛎️",benin:"🇧🇯",bento:"🍱",bermuda:"🇧🇲",beverage_box:"🧃",bhutan:"🇧🇹",bicyclist:"🚴",bike:"🚲",biking_man:"🚴‍♂️",biking_woman:"🚴‍♀️",bikini:"👙",billed_cap:"🧢",biohazard:"☣️",bird:"🐦",birthday:"🎂",black_circle:"⚫",black_flag:"🏴",black_heart:"🖤",black_joker:"🃏",black_large_square:"⬛",black_medium_small_square:"◾",black_medium_square:"◼️",black_nib:"✒️",black_small_square:"▪️",black_square_button:"🔲",blond_haired_man:"👱‍♂️",blond_haired_person:"👱",blond_haired_woman:"👱‍♀️",blonde_woman:"👱‍♀️",blossom:"🌼",blowfish:"🐡",blue_book:"📘",blue_car:"🚙",blue_heart:"💙",blue_square:"🟦",blush:"😊",boar:"🐗",boat:"⛵",bolivia:"🇧🇴",bomb:"💣",bone:"🦴",book:"📖",bookmark:"🔖",bookmark_tabs:"📑",books:"📚",boom:"💥",boot:"👢",bosnia_herzegovina:"🇧🇦",botswana:"🇧🇼",bouncing_ball_man:"⛹️‍♂️",bouncing_ball_person:"⛹️",bouncing_ball_woman:"⛹️‍♀️",bouquet:"💐",bouvet_island:"🇧🇻",bow:"🙇",bow_and_arrow:"🏹",bowing_man:"🙇‍♂️",bowing_woman:"🙇‍♀️",bowl_with_spoon:"🥣",bowling:"🎳",boxing_glove:"🥊",boy:"👦",brain:"🧠",brazil:"🇧🇷",bread:"🍞",breast_feeding:"🤱",bricks:"🧱",bride_with_veil:"👰",bridge_at_night:"🌉",briefcase:"💼",british_indian_ocean_territory:"🇮🇴",british_virgin_islands:"🇻🇬",broccoli:"🥦",broken_heart:"💔",broom:"🧹",brown_circle:"🟤",brown_heart:"🤎",brown_square:"🟫",brunei:"🇧🇳",bug:"🐛",building_construction:"🏗️",bulb:"💡",bulgaria:"🇧🇬",bullettrain_front:"🚅",bullettrain_side:"🚄",burkina_faso:"🇧🇫",burrito:"🌯",burundi:"🇧🇮",bus:"🚌",business_suit_levitating:"🕴️",busstop:"🚏",bust_in_silhouette:"👤",busts_in_silhouette:"👥",butter:"🧈",butterfly:"🦋",cactus:"🌵",cake:"🍰",calendar:"📆",call_me_hand:"🤙",calling:"📲",cambodia:"🇰🇭",camel:"🐫",camera:"📷",camera_flash:"📸",cameroon:"🇨🇲",camping:"🏕️",canada:"🇨🇦",canary_islands:"🇮🇨",cancer:"♋",candle:"🕯️",candy:"🍬",canned_food:"🥫",canoe:"🛶",cape_verde:"🇨🇻",capital_abcd:"🔠",capricorn:"♑",car:"🚗",card_file_box:"🗃️",card_index:"📇",card_index_dividers:"🗂️",caribbean_netherlands:"🇧🇶",carousel_horse:"🎠",carrot:"🥕",cartwheeling:"🤸",cat:"🐱",cat2:"🐈",cayman_islands:"🇰🇾",cd:"💿",central_african_republic:"🇨🇫",ceuta_melilla:"🇪🇦",chad:"🇹🇩",chains:"⛓️",chair:"🪑",champagne:"🍾",chart:"💹",chart_with_downwards_trend:"📉",chart_with_upwards_trend:"📈",checkered_flag:"🏁",cheese:"🧀",cherries:"🍒",cherry_blossom:"🌸",chess_pawn:"♟️",chestnut:"🌰",chicken:"🐔",child:"🧒",children_crossing:"🚸",chile:"🇨🇱",chipmunk:"🐿️",chocolate_bar:"🍫",chopsticks:"🥢",christmas_island:"🇨🇽",christmas_tree:"🎄",church:"⛪",cinema:"🎦",circus_tent:"🎪",city_sunrise:"🌇",city_sunset:"🌆",cityscape:"🏙️",cl:"🆑",clamp:"🗜️",clap:"👏",clapper:"🎬",classical_building:"🏛️",climbing:"🧗",climbing_man:"🧗‍♂️",climbing_woman:"🧗‍♀️",clinking_glasses:"🥂",clipboard:"📋",clipperton_island:"🇨🇵",clock1:"🕐",clock10:"🕙",clock1030:"🕥",clock11:"🕚",clock1130:"🕦",clock12:"🕛",clock1230:"🕧",clock130:"🕜",clock2:"🕑",clock230:"🕝",clock3:"🕒",clock330:"🕞",clock4:"🕓",clock430:"🕟",clock5:"🕔",clock530:"🕠",clock6:"🕕",clock630:"🕡",clock7:"🕖",clock730:"🕢",clock8:"🕗",clock830:"🕣",clock9:"🕘",clock930:"🕤",closed_book:"📕",closed_lock_with_key:"🔐",closed_umbrella:"🌂",cloud:"☁️",cloud_with_lightning:"🌩️",cloud_with_lightning_and_rain:"⛈️",cloud_with_rain:"🌧️",cloud_with_snow:"🌨️",clown_face:"🤡",clubs:"♣️",cn:"🇨🇳",coat:"🧥",cocktail:"🍸",coconut:"🥥",cocos_islands:"🇨🇨",coffee:"☕",coffin:"⚰️",cold_face:"🥶",cold_sweat:"😰",collision:"💥",colombia:"🇨🇴",comet:"☄️",comoros:"🇰🇲",compass:"🧭",computer:"💻",computer_mouse:"🖱️",confetti_ball:"🎊",confounded:"😖",confused:"😕",congo_brazzaville:"🇨🇬",congo_kinshasa:"🇨🇩",congratulations:"㊗️",construction:"🚧",construction_worker:"👷",construction_worker_man:"👷‍♂️",construction_worker_woman:"👷‍♀️",control_knobs:"🎛️",convenience_store:"🏪",cook:"🧑‍🍳",cook_islands:"🇨🇰",cookie:"🍪",cool:"🆒",cop:"👮",copyright:"©️",corn:"🌽",costa_rica:"🇨🇷",cote_divoire:"🇨🇮",couch_and_lamp:"🛋️",couple:"👫",couple_with_heart:"💑",couple_with_heart_man_man:"👨‍❤️‍👨",couple_with_heart_woman_man:"👩‍❤️‍👨",couple_with_heart_woman_woman:"👩‍❤️‍👩",couplekiss:"💏",couplekiss_man_man:"👨‍❤️‍💋‍👨",couplekiss_man_woman:"👩‍❤️‍💋‍👨",couplekiss_woman_woman:"👩‍❤️‍💋‍👩",cow:"🐮",cow2:"🐄",cowboy_hat_face:"🤠",crab:"🦀",crayon:"🖍️",credit_card:"💳",crescent_moon:"🌙",cricket:"🦗",cricket_game:"🏏",croatia:"🇭🇷",crocodile:"🐊",croissant:"🥐",crossed_fingers:"🤞",crossed_flags:"🎌",crossed_swords:"⚔️",crown:"👑",cry:"😢",crying_cat_face:"😿",crystal_ball:"🔮",cuba:"🇨🇺",cucumber:"🥒",cup_with_straw:"🥤",cupcake:"🧁",cupid:"💘",curacao:"🇨🇼",curling_stone:"🥌",curly_haired_man:"👨‍🦱",curly_haired_woman:"👩‍🦱",curly_loop:"➰",currency_exchange:"💱",curry:"🍛",cursing_face:"🤬",custard:"🍮",customs:"🛃",cut_of_meat:"🥩",cyclone:"🌀",cyprus:"🇨🇾",czech_republic:"🇨🇿",dagger:"🗡️",dancer:"💃",dancers:"👯",dancing_men:"👯‍♂️",dancing_women:"👯‍♀️",dango:"🍡",dark_sunglasses:"🕶️",dart:"🎯",dash:"💨",date:"📅",de:"🇩🇪",deaf_man:"🧏‍♂️",deaf_person:"🧏",deaf_woman:"🧏‍♀️",deciduous_tree:"🌳",deer:"🦌",denmark:"🇩🇰",department_store:"🏬",derelict_house:"🏚️",desert:"🏜️",desert_island:"🏝️",desktop_computer:"🖥️",detective:"🕵️",diamond_shape_with_a_dot_inside:"💠",diamonds:"♦️",diego_garcia:"🇩🇬",disappointed:"😞",disappointed_relieved:"😥",diving_mask:"🤿",diya_lamp:"🪔",dizzy:"💫",dizzy_face:"😵",djibouti:"🇩🇯",dna:"🧬",do_not_litter:"🚯",dog:"🐶",dog2:"🐕",dollar:"💵",dolls:"🎎",dolphin:"🐬",dominica:"🇩🇲",dominican_republic:"🇩🇴",door:"🚪",doughnut:"🍩",dove:"🕊️",dragon:"🐉",dragon_face:"🐲",dress:"👗",dromedary_camel:"🐪",drooling_face:"🤤",drop_of_blood:"🩸",droplet:"💧",drum:"🥁",duck:"🦆",dumpling:"🥟",dvd:"📀","e-mail":"📧",eagle:"🦅",ear:"👂",ear_of_rice:"🌾",ear_with_hearing_aid:"🦻",earth_africa:"🌍",earth_americas:"🌎",earth_asia:"🌏",ecuador:"🇪🇨",egg:"🥚",eggplant:"🍆",egypt:"🇪🇬",eight:"8️⃣",eight_pointed_black_star:"✴️",eight_spoked_asterisk:"✳️",eject_button:"⏏️",el_salvador:"🇸🇻",electric_plug:"🔌",elephant:"🐘",elf:"🧝",elf_man:"🧝‍♂️",elf_woman:"🧝‍♀️",email:"✉️",end:"🔚",england:"🏴󠁧󠁢󠁥󠁮󠁧󠁿",envelope:"✉️",envelope_with_arrow:"📩",equatorial_guinea:"🇬🇶",eritrea:"🇪🇷",es:"🇪🇸",estonia:"🇪🇪",ethiopia:"🇪🇹",eu:"🇪🇺",euro:"💶",european_castle:"🏰",european_post_office:"🏤",european_union:"🇪🇺",evergreen_tree:"🌲",exclamation:"❗",exploding_head:"🤯",expressionless:"😑",eye:"👁️",eye_speech_bubble:"👁️‍🗨️",eyeglasses:"👓",eyes:"👀",face_with_head_bandage:"🤕",face_with_thermometer:"🤒",facepalm:"🤦",facepunch:"👊",factory:"🏭",factory_worker:"🧑‍🏭",fairy:"🧚",fairy_man:"🧚‍♂️",fairy_woman:"🧚‍♀️",falafel:"🧆",falkland_islands:"🇫🇰",fallen_leaf:"🍂",family:"👪",family_man_boy:"👨‍👦",family_man_boy_boy:"👨‍👦‍👦",family_man_girl:"👨‍👧",family_man_girl_boy:"👨‍👧‍👦",family_man_girl_girl:"👨‍👧‍👧",family_man_man_boy:"👨‍👨‍👦",family_man_man_boy_boy:"👨‍👨‍👦‍👦",family_man_man_girl:"👨‍👨‍👧",family_man_man_girl_boy:"👨‍👨‍👧‍👦",family_man_man_girl_girl:"👨‍👨‍👧‍👧",family_man_woman_boy:"👨‍👩‍👦",family_man_woman_boy_boy:"👨‍👩‍👦‍👦",family_man_woman_girl:"👨‍👩‍👧",family_man_woman_girl_boy:"👨‍👩‍👧‍👦",family_man_woman_girl_girl:"👨‍👩‍👧‍👧",family_woman_boy:"👩‍👦",family_woman_boy_boy:"👩‍👦‍👦",family_woman_girl:"👩‍👧",family_woman_girl_boy:"👩‍👧‍👦",family_woman_girl_girl:"👩‍👧‍👧",family_woman_woman_boy:"👩‍👩‍👦",family_woman_woman_boy_boy:"👩‍👩‍👦‍👦",family_woman_woman_girl:"👩‍👩‍👧",family_woman_woman_girl_boy:"👩‍👩‍👧‍👦",family_woman_woman_girl_girl:"👩‍👩‍👧‍👧",farmer:"🧑‍🌾",faroe_islands:"🇫🇴",fast_forward:"⏩",fax:"📠",fearful:"😨",feet:"🐾",female_detective:"🕵️‍♀️",female_sign:"♀️",ferris_wheel:"🎡",ferry:"⛴️",field_hockey:"🏑",fiji:"🇫🇯",file_cabinet:"🗄️",file_folder:"📁",film_projector:"📽️",film_strip:"🎞️",finland:"🇫🇮",fire:"🔥",fire_engine:"🚒",fire_extinguisher:"🧯",firecracker:"🧨",firefighter:"🧑‍🚒",fireworks:"🎆",first_quarter_moon:"🌓",first_quarter_moon_with_face:"🌛",fish:"🐟",fish_cake:"🍥",fishing_pole_and_fish:"🎣",fist:"✊",fist_left:"🤛",fist_oncoming:"👊",fist_raised:"✊",fist_right:"🤜",five:"5️⃣",flags:"🎏",flamingo:"🦩",flashlight:"🔦",flat_shoe:"🥿",fleur_de_lis:"⚜️",flight_arrival:"🛬",flight_departure:"🛫",flipper:"🐬",floppy_disk:"💾",flower_playing_cards:"🎴",flushed:"😳",flying_disc:"🥏",flying_saucer:"🛸",fog:"🌫️",foggy:"🌁",foot:"🦶",football:"🏈",footprints:"👣",fork_and_knife:"🍴",fortune_cookie:"🥠",fountain:"⛲",fountain_pen:"🖋️",four:"4️⃣",four_leaf_clover:"🍀",fox_face:"🦊",fr:"🇫🇷",framed_picture:"🖼️",free:"🆓",french_guiana:"🇬🇫",french_polynesia:"🇵🇫",french_southern_territories:"🇹🇫",fried_egg:"🍳",fried_shrimp:"🍤",fries:"🍟",frog:"🐸",frowning:"😦",frowning_face:"☹️",frowning_man:"🙍‍♂️",frowning_person:"🙍",frowning_woman:"🙍‍♀️",fu:"🖕",fuelpump:"⛽",full_moon:"🌕",full_moon_with_face:"🌝",funeral_urn:"⚱️",gabon:"🇬🇦",gambia:"🇬🇲",game_die:"🎲",garlic:"🧄",gb:"🇬🇧",gear:"⚙️",gem:"💎",gemini:"♊",genie:"🧞",genie_man:"🧞‍♂️",genie_woman:"🧞‍♀️",georgia:"🇬🇪",ghana:"🇬🇭",ghost:"👻",gibraltar:"🇬🇮",gift:"🎁",gift_heart:"💝",giraffe:"🦒",girl:"👧",globe_with_meridians:"🌐",gloves:"🧤",goal_net:"🥅",goat:"🐐",goggles:"🥽",golf:"⛳",golfing:"🏌️",golfing_man:"🏌️‍♂️",golfing_woman:"🏌️‍♀️",gorilla:"🦍",grapes:"🍇",greece:"🇬🇷",green_apple:"🍏",green_book:"📗",green_circle:"🟢",green_heart:"💚",green_salad:"🥗",green_square:"🟩",greenland:"🇬🇱",grenada:"🇬🇩",grey_exclamation:"❕",grey_question:"❔",grimacing:"😬",grin:"😁",grinning:"😀",guadeloupe:"🇬🇵",guam:"🇬🇺",guard:"💂",guardsman:"💂‍♂️",guardswoman:"💂‍♀️",guatemala:"🇬🇹",guernsey:"🇬🇬",guide_dog:"🦮",guinea:"🇬🇳",guinea_bissau:"🇬🇼",guitar:"🎸",gun:"🔫",guyana:"🇬🇾",haircut:"💇",haircut_man:"💇‍♂️",haircut_woman:"💇‍♀️",haiti:"🇭🇹",hamburger:"🍔",hammer:"🔨",hammer_and_pick:"⚒️",hammer_and_wrench:"🛠️",hamster:"🐹",hand:"✋",hand_over_mouth:"🤭",handbag:"👜",handball_person:"🤾",handshake:"🤝",hankey:"💩",hash:"#️⃣",hatched_chick:"🐥",hatching_chick:"🐣",headphones:"🎧",health_worker:"🧑‍⚕️",hear_no_evil:"🙉",heard_mcdonald_islands:"🇭🇲",heart:"❤️",heart_decoration:"💟",heart_eyes:"😍",heart_eyes_cat:"😻",heartbeat:"💓",heartpulse:"💗",hearts:"♥️",heavy_check_mark:"✔️",heavy_division_sign:"➗",heavy_dollar_sign:"💲",heavy_exclamation_mark:"❗",heavy_heart_exclamation:"❣️",heavy_minus_sign:"➖",heavy_multiplication_x:"✖️",heavy_plus_sign:"➕",hedgehog:"🦔",helicopter:"🚁",herb:"🌿",hibiscus:"🌺",high_brightness:"🔆",high_heel:"👠",hiking_boot:"🥾",hindu_temple:"🛕",hippopotamus:"🦛",hocho:"🔪",hole:"🕳️",honduras:"🇭🇳",honey_pot:"🍯",honeybee:"🐝",hong_kong:"🇭🇰",horse:"🐴",horse_racing:"🏇",hospital:"🏥",hot_face:"🥵",hot_pepper:"🌶️",hotdog:"🌭",hotel:"🏨",hotsprings:"♨️",hourglass:"⌛",hourglass_flowing_sand:"⏳",house:"🏠",house_with_garden:"🏡",houses:"🏘️",hugs:"🤗",hungary:"🇭🇺",hushed:"😯",ice_cream:"🍨",ice_cube:"🧊",ice_hockey:"🏒",ice_skate:"⛸️",icecream:"🍦",iceland:"🇮🇸",id:"🆔",ideograph_advantage:"🉐",imp:"👿",inbox_tray:"📥",incoming_envelope:"📨",india:"🇮🇳",indonesia:"🇮🇩",infinity:"♾️",information_desk_person:"💁",information_source:"ℹ️",innocent:"😇",interrobang:"⁉️",iphone:"📱",iran:"🇮🇷",iraq:"🇮🇶",ireland:"🇮🇪",isle_of_man:"🇮🇲",israel:"🇮🇱",it:"🇮🇹",izakaya_lantern:"🏮",jack_o_lantern:"🎃",jamaica:"🇯🇲",japan:"🗾",japanese_castle:"🏯",japanese_goblin:"👺",japanese_ogre:"👹",jeans:"👖",jersey:"🇯🇪",jigsaw:"🧩",jordan:"🇯🇴",joy:"😂",joy_cat:"😹",joystick:"🕹️",jp:"🇯🇵",judge:"🧑‍⚖️",juggling_person:"🤹",kaaba:"🕋",kangaroo:"🦘",kazakhstan:"🇰🇿",kenya:"🇰🇪",key:"🔑",keyboard:"⌨️",keycap_ten:"🔟",kick_scooter:"🛴",kimono:"👘",kiribati:"🇰🇮",kiss:"💋",kissing:"😗",kissing_cat:"😽",kissing_closed_eyes:"😚",kissing_heart:"😘",kissing_smiling_eyes:"😙",kite:"🪁",kiwi_fruit:"🥝",kneeling_man:"🧎‍♂️",kneeling_person:"🧎",kneeling_woman:"🧎‍♀️",knife:"🔪",koala:"🐨",koko:"🈁",kosovo:"🇽🇰",kr:"🇰🇷",kuwait:"🇰🇼",kyrgyzstan:"🇰🇬",lab_coat:"🥼",label:"🏷️",lacrosse:"🥍",lantern:"🏮",laos:"🇱🇦",large_blue_circle:"🔵",large_blue_diamond:"🔷",large_orange_diamond:"🔶",last_quarter_moon:"🌗",last_quarter_moon_with_face:"🌜",latin_cross:"✝️",latvia:"🇱🇻",laughing:"😆",leafy_green:"🥬",leaves:"🍃",lebanon:"🇱🇧",ledger:"📒",left_luggage:"🛅",left_right_arrow:"↔️",left_speech_bubble:"🗨️",leftwards_arrow_with_hook:"↩️",leg:"🦵",lemon:"🍋",leo:"♌",leopard:"🐆",lesotho:"🇱🇸",level_slider:"🎚️",liberia:"🇱🇷",libra:"♎",libya:"🇱🇾",liechtenstein:"🇱🇮",light_rail:"🚈",link:"🔗",lion:"🦁",lips:"👄",lipstick:"💄",lithuania:"🇱🇹",lizard:"🦎",llama:"🦙",lobster:"🦞",lock:"🔒",lock_with_ink_pen:"🔏",lollipop:"🍭",loop:"➿",lotion_bottle:"🧴",lotus_position:"🧘",lotus_position_man:"🧘‍♂️",lotus_position_woman:"🧘‍♀️",loud_sound:"🔊",loudspeaker:"📢",love_hotel:"🏩",love_letter:"💌",love_you_gesture:"🤟",low_brightness:"🔅",luggage:"🧳",luxembourg:"🇱🇺",lying_face:"🤥",m:"Ⓜ️",macau:"🇲🇴",macedonia:"🇲🇰",madagascar:"🇲🇬",mag:"🔍",mag_right:"🔎",mage:"🧙",mage_man:"🧙‍♂️",mage_woman:"🧙‍♀️",magnet:"🧲",mahjong:"🀄",mailbox:"📫",mailbox_closed:"📪",mailbox_with_mail:"📬",mailbox_with_no_mail:"📭",malawi:"🇲🇼",malaysia:"🇲🇾",maldives:"🇲🇻",male_detective:"🕵️‍♂️",male_sign:"♂️",mali:"🇲🇱",malta:"🇲🇹",man:"👨",man_artist:"👨‍🎨",man_astronaut:"👨‍🚀",man_cartwheeling:"🤸‍♂️",man_cook:"👨‍🍳",man_dancing:"🕺",man_facepalming:"🤦‍♂️",man_factory_worker:"👨‍🏭",man_farmer:"👨‍🌾",man_firefighter:"👨‍🚒",man_health_worker:"👨‍⚕️",man_in_manual_wheelchair:"👨‍🦽",man_in_motorized_wheelchair:"👨‍🦼",man_in_tuxedo:"🤵",man_judge:"👨‍⚖️",man_juggling:"🤹‍♂️",man_mechanic:"👨‍🔧",man_office_worker:"👨‍💼",man_pilot:"👨‍✈️",man_playing_handball:"🤾‍♂️",man_playing_water_polo:"🤽‍♂️",man_scientist:"👨‍🔬",man_shrugging:"🤷‍♂️",man_singer:"👨‍🎤",man_student:"👨‍🎓",man_teacher:"👨‍🏫",man_technologist:"👨‍💻",man_with_gua_pi_mao:"👲",man_with_probing_cane:"👨‍🦯",man_with_turban:"👳‍♂️",mandarin:"🍊",mango:"🥭",mans_shoe:"👞",mantelpiece_clock:"🕰️",manual_wheelchair:"🦽",maple_leaf:"🍁",marshall_islands:"🇲🇭",martial_arts_uniform:"🥋",martinique:"🇲🇶",mask:"😷",massage:"💆",massage_man:"💆‍♂️",massage_woman:"💆‍♀️",mate:"🧉",mauritania:"🇲🇷",mauritius:"🇲🇺",mayotte:"🇾🇹",meat_on_bone:"🍖",mechanic:"🧑‍🔧",mechanical_arm:"🦾",mechanical_leg:"🦿",medal_military:"🎖️",medal_sports:"🏅",medical_symbol:"⚕️",mega:"📣",melon:"🍈",memo:"📝",men_wrestling:"🤼‍♂️",menorah:"🕎",mens:"🚹",mermaid:"🧜‍♀️",merman:"🧜‍♂️",merperson:"🧜",metal:"🤘",metro:"🚇",mexico:"🇲🇽",microbe:"🦠",micronesia:"🇫🇲",microphone:"🎤",microscope:"🔬",middle_finger:"🖕",milk_glass:"🥛",milky_way:"🌌",minibus:"🚐",minidisc:"💽",mobile_phone_off:"📴",moldova:"🇲🇩",monaco:"🇲🇨",money_mouth_face:"🤑",money_with_wings:"💸",moneybag:"💰",mongolia:"🇲🇳",monkey:"🐒",monkey_face:"🐵",monocle_face:"🧐",monorail:"🚝",montenegro:"🇲🇪",montserrat:"🇲🇸",moon:"🌔",moon_cake:"🥮",morocco:"🇲🇦",mortar_board:"🎓",mosque:"🕌",mosquito:"🦟",motor_boat:"🛥️",motor_scooter:"🛵",motorcycle:"🏍️",motorized_wheelchair:"🦼",motorway:"🛣️",mount_fuji:"🗻",mountain:"⛰️",mountain_bicyclist:"🚵",mountain_biking_man:"🚵‍♂️",mountain_biking_woman:"🚵‍♀️",mountain_cableway:"🚠",mountain_railway:"🚞",mountain_snow:"🏔️",mouse:"🐭",mouse2:"🐁",movie_camera:"🎥",moyai:"🗿",mozambique:"🇲🇿",mrs_claus:"🤶",muscle:"💪",mushroom:"🍄",musical_keyboard:"🎹",musical_note:"🎵",musical_score:"🎼",mute:"🔇",myanmar:"🇲🇲",nail_care:"💅",name_badge:"📛",namibia:"🇳🇦",national_park:"🏞️",nauru:"🇳🇷",nauseated_face:"🤢",nazar_amulet:"🧿",necktie:"👔",negative_squared_cross_mark:"❎",nepal:"🇳🇵",nerd_face:"🤓",netherlands:"🇳🇱",neutral_face:"😐",new:"🆕",new_caledonia:"🇳🇨",new_moon:"🌑",new_moon_with_face:"🌚",new_zealand:"🇳🇿",newspaper:"📰",newspaper_roll:"🗞️",next_track_button:"⏭️",ng:"🆖",ng_man:"🙅‍♂️",ng_woman:"🙅‍♀️",nicaragua:"🇳🇮",niger:"🇳🇪",nigeria:"🇳🇬",night_with_stars:"🌃",nine:"9️⃣",niue:"🇳🇺",no_bell:"🔕",no_bicycles:"🚳",no_entry:"⛔",no_entry_sign:"🚫",no_good:"🙅",no_good_man:"🙅‍♂️",no_good_woman:"🙅‍♀️",no_mobile_phones:"📵",no_mouth:"😶",no_pedestrians:"🚷",no_smoking:"🚭","non-potable_water":"🚱",norfolk_island:"🇳🇫",north_korea:"🇰🇵",northern_mariana_islands:"🇲🇵",norway:"🇳🇴",nose:"👃",notebook:"📓",notebook_with_decorative_cover:"📔",notes:"🎶",nut_and_bolt:"🔩",o:"⭕",o2:"🅾️",ocean:"🌊",octopus:"🐙",oden:"🍢",office:"🏢",office_worker:"🧑‍💼",oil_drum:"🛢️",ok:"🆗",ok_hand:"👌",ok_man:"🙆‍♂️",ok_person:"🙆",ok_woman:"🙆‍♀️",old_key:"🗝️",older_adult:"🧓",older_man:"👴",older_woman:"👵",om:"🕉️",oman:"🇴🇲",on:"🔛",oncoming_automobile:"🚘",oncoming_bus:"🚍",oncoming_police_car:"🚔",oncoming_taxi:"🚖",one:"1️⃣",one_piece_swimsuit:"🩱",onion:"🧅",open_book:"📖",open_file_folder:"📂",open_hands:"👐",open_mouth:"😮",open_umbrella:"☂️",ophiuchus:"⛎",orange:"🍊",orange_book:"📙",orange_circle:"🟠",orange_heart:"🧡",orange_square:"🟧",orangutan:"🦧",orthodox_cross:"☦️",otter:"🦦",outbox_tray:"📤",owl:"🦉",ox:"🐂",oyster:"🦪",package:"📦",page_facing_up:"📄",page_with_curl:"📃",pager:"📟",paintbrush:"🖌️",pakistan:"🇵🇰",palau:"🇵🇼",palestinian_territories:"🇵🇸",palm_tree:"🌴",palms_up_together:"🤲",panama:"🇵🇦",pancakes:"🥞",panda_face:"🐼",paperclip:"📎",paperclips:"🖇️",papua_new_guinea:"🇵🇬",parachute:"🪂",paraguay:"🇵🇾",parasol_on_ground:"⛱️",parking:"🅿️",parrot:"🦜",part_alternation_mark:"〽️",partly_sunny:"⛅",partying_face:"🥳",passenger_ship:"🛳️",passport_control:"🛂",pause_button:"⏸️",paw_prints:"🐾",peace_symbol:"☮️",peach:"🍑",peacock:"🦚",peanuts:"🥜",pear:"🍐",pen:"🖊️",pencil:"📝",pencil2:"✏️",penguin:"🐧",pensive:"😔",people_holding_hands:"🧑‍🤝‍🧑",performing_arts:"🎭",persevere:"😣",person_bald:"🧑‍🦲",person_curly_hair:"🧑‍🦱",person_fencing:"🤺",person_in_manual_wheelchair:"🧑‍🦽",person_in_motorized_wheelchair:"🧑‍🦼",person_red_hair:"🧑‍🦰",person_white_hair:"🧑‍🦳",person_with_probing_cane:"🧑‍🦯",person_with_turban:"👳",peru:"🇵🇪",petri_dish:"🧫",philippines:"🇵🇭",phone:"☎️",pick:"⛏️",pie:"🥧",pig:"🐷",pig2:"🐖",pig_nose:"🐽",pill:"💊",pilot:"🧑‍✈️",pinching_hand:"🤏",pineapple:"🍍",ping_pong:"🏓",pirate_flag:"🏴‍☠️",pisces:"♓",pitcairn_islands:"🇵🇳",pizza:"🍕",place_of_worship:"🛐",plate_with_cutlery:"🍽️",play_or_pause_button:"⏯️",pleading_face:"🥺",point_down:"👇",point_left:"👈",point_right:"👉",point_up:"☝️",point_up_2:"👆",poland:"🇵🇱",police_car:"🚓",police_officer:"👮",policeman:"👮‍♂️",policewoman:"👮‍♀️",poodle:"🐩",poop:"💩",popcorn:"🍿",portugal:"🇵🇹",post_office:"🏣",postal_horn:"📯",postbox:"📮",potable_water:"🚰",potato:"🥔",pouch:"👝",poultry_leg:"🍗",pound:"💷",pout:"😡",pouting_cat:"😾",pouting_face:"🙎",pouting_man:"🙎‍♂️",pouting_woman:"🙎‍♀️",pray:"🙏",prayer_beads:"📿",pregnant_woman:"🤰",pretzel:"🥨",previous_track_button:"⏮️",prince:"🤴",princess:"👸",printer:"🖨️",probing_cane:"🦯",puerto_rico:"🇵🇷",punch:"👊",purple_circle:"🟣",purple_heart:"💜",purple_square:"🟪",purse:"👛",pushpin:"📌",put_litter_in_its_place:"🚮",qatar:"🇶🇦",question:"❓",rabbit:"🐰",rabbit2:"🐇",raccoon:"🦝",racehorse:"🐎",racing_car:"🏎️",radio:"📻",radio_button:"🔘",radioactive:"☢️",rage:"😡",railway_car:"🚃",railway_track:"🛤️",rainbow:"🌈",rainbow_flag:"🏳️‍🌈",raised_back_of_hand:"🤚",raised_eyebrow:"🤨",raised_hand:"✋",raised_hand_with_fingers_splayed:"🖐️",raised_hands:"🙌",raising_hand:"🙋",raising_hand_man:"🙋‍♂️",raising_hand_woman:"🙋‍♀️",ram:"🐏",ramen:"🍜",rat:"🐀",razor:"🪒",receipt:"🧾",record_button:"⏺️",recycle:"♻️",red_car:"🚗",red_circle:"🔴",red_envelope:"🧧",red_haired_man:"👨‍🦰",red_haired_woman:"👩‍🦰",red_square:"🟥",registered:"®️",relaxed:"☺️",relieved:"😌",reminder_ribbon:"🎗️",repeat:"🔁",repeat_one:"🔂",rescue_worker_helmet:"⛑️",restroom:"🚻",reunion:"🇷🇪",revolving_hearts:"💞",rewind:"⏪",rhinoceros:"🦏",ribbon:"🎀",rice:"🍚",rice_ball:"🍙",rice_cracker:"🍘",rice_scene:"🎑",right_anger_bubble:"🗯️",ring:"💍",ringed_planet:"🪐",robot:"🤖",rocket:"🚀",rofl:"🤣",roll_eyes:"🙄",roll_of_paper:"🧻",roller_coaster:"🎢",romania:"🇷🇴",rooster:"🐓",rose:"🌹",rosette:"🏵️",rotating_light:"🚨",round_pushpin:"📍",rowboat:"🚣",rowing_man:"🚣‍♂️",rowing_woman:"🚣‍♀️",ru:"🇷🇺",rugby_football:"🏉",runner:"🏃",running:"🏃",running_man:"🏃‍♂️",running_shirt_with_sash:"🎽",running_woman:"🏃‍♀️",rwanda:"🇷🇼",sa:"🈂️",safety_pin:"🧷",safety_vest:"🦺",sagittarius:"♐",sailboat:"⛵",sake:"🍶",salt:"🧂",samoa:"🇼🇸",san_marino:"🇸🇲",sandal:"👡",sandwich:"🥪",santa:"🎅",sao_tome_principe:"🇸🇹",sari:"🥻",sassy_man:"💁‍♂️",sassy_woman:"💁‍♀️",satellite:"📡",satisfied:"😆",saudi_arabia:"🇸🇦",sauna_man:"🧖‍♂️",sauna_person:"🧖",sauna_woman:"🧖‍♀️",sauropod:"🦕",saxophone:"🎷",scarf:"🧣",school:"🏫",school_satchel:"🎒",scientist:"🧑‍🔬",scissors:"✂️",scorpion:"🦂",scorpius:"♏",scotland:"🏴󠁧󠁢󠁳󠁣󠁴󠁿",scream:"😱",scream_cat:"🙀",scroll:"📜",seat:"💺",secret:"㊙️",see_no_evil:"🙈",seedling:"🌱",selfie:"🤳",senegal:"🇸🇳",serbia:"🇷🇸",service_dog:"🐕‍🦺",seven:"7️⃣",seychelles:"🇸🇨",shallow_pan_of_food:"🥘",shamrock:"☘️",shark:"🦈",shaved_ice:"🍧",sheep:"🐑",shell:"🐚",shield:"🛡️",shinto_shrine:"⛩️",ship:"🚢",shirt:"👕",shit:"💩",shoe:"👞",shopping:"🛍️",shopping_cart:"🛒",shorts:"🩳",shower:"🚿",shrimp:"🦐",shrug:"🤷",shushing_face:"🤫",sierra_leone:"🇸🇱",signal_strength:"📶",singapore:"🇸🇬",singer:"🧑‍🎤",sint_maarten:"🇸🇽",six:"6️⃣",six_pointed_star:"🔯",skateboard:"🛹",ski:"🎿",skier:"⛷️",skull:"💀",skull_and_crossbones:"☠️",skunk:"🦨",sled:"🛷",sleeping:"😴",sleeping_bed:"🛌",sleepy:"😪",slightly_frowning_face:"🙁",slightly_smiling_face:"🙂",slot_machine:"🎰",sloth:"🦥",slovakia:"🇸🇰",slovenia:"🇸🇮",small_airplane:"🛩️",small_blue_diamond:"🔹",small_orange_diamond:"🔸",small_red_triangle:"🔺",small_red_triangle_down:"🔻",smile:"😄",smile_cat:"😸",smiley:"😃",smiley_cat:"😺",smiling_face_with_three_hearts:"🥰",smiling_imp:"😈",smirk:"😏",smirk_cat:"😼",smoking:"🚬",snail:"🐌",snake:"🐍",sneezing_face:"🤧",snowboarder:"🏂",snowflake:"❄️",snowman:"⛄",snowman_with_snow:"☃️",soap:"🧼",sob:"😭",soccer:"⚽",socks:"🧦",softball:"🥎",solomon_islands:"🇸🇧",somalia:"🇸🇴",soon:"🔜",sos:"🆘",sound:"🔉",south_africa:"🇿🇦",south_georgia_south_sandwich_islands:"🇬🇸",south_sudan:"🇸🇸",space_invader:"👾",spades:"♠️",spaghetti:"🍝",sparkle:"❇️",sparkler:"🎇",sparkles:"✨",sparkling_heart:"💖",speak_no_evil:"🙊",speaker:"🔈",speaking_head:"🗣️",speech_balloon:"💬",speedboat:"🚤",spider:"🕷️",spider_web:"🕸️",spiral_calendar:"🗓️",spiral_notepad:"🗒️",sponge:"🧽",spoon:"🥄",squid:"🦑",sri_lanka:"🇱🇰",st_barthelemy:"🇧🇱",st_helena:"🇸🇭",st_kitts_nevis:"🇰🇳",st_lucia:"🇱🇨",st_martin:"🇲🇫",st_pierre_miquelon:"🇵🇲",st_vincent_grenadines:"🇻🇨",stadium:"🏟️",standing_man:"🧍‍♂️",standing_person:"🧍",standing_woman:"🧍‍♀️",star:"⭐",star2:"🌟",star_and_crescent:"☪️",star_of_david:"✡️",star_struck:"🤩",stars:"🌠",station:"🚉",statue_of_liberty:"🗽",steam_locomotive:"🚂",stethoscope:"🩺",stew:"🍲",stop_button:"⏹️",stop_sign:"🛑",stopwatch:"⏱️",straight_ruler:"📏",strawberry:"🍓",stuck_out_tongue:"😛",stuck_out_tongue_closed_eyes:"😝",stuck_out_tongue_winking_eye:"😜",student:"🧑‍🎓",studio_microphone:"🎙️",stuffed_flatbread:"🥙",sudan:"🇸🇩",sun_behind_large_cloud:"🌥️",sun_behind_rain_cloud:"🌦️",sun_behind_small_cloud:"🌤️",sun_with_face:"🌞",sunflower:"🌻",sunglasses:"😎",sunny:"☀️",sunrise:"🌅",sunrise_over_mountains:"🌄",superhero:"🦸",superhero_man:"🦸‍♂️",superhero_woman:"🦸‍♀️",supervillain:"🦹",supervillain_man:"🦹‍♂️",supervillain_woman:"🦹‍♀️",surfer:"🏄",surfing_man:"🏄‍♂️",surfing_woman:"🏄‍♀️",suriname:"🇸🇷",sushi:"🍣",suspension_railway:"🚟",svalbard_jan_mayen:"🇸🇯",swan:"🦢",swaziland:"🇸🇿",sweat:"😓",sweat_drops:"💦",sweat_smile:"😅",sweden:"🇸🇪",sweet_potato:"🍠",swim_brief:"🩲",swimmer:"🏊",swimming_man:"🏊‍♂️",swimming_woman:"🏊‍♀️",switzerland:"🇨🇭",symbols:"🔣",synagogue:"🕍",syria:"🇸🇾",syringe:"💉","t-rex":"🦖",taco:"🌮",tada:"🎉",taiwan:"🇹🇼",tajikistan:"🇹🇯",takeout_box:"🥡",tanabata_tree:"🎋",tangerine:"🍊",tanzania:"🇹🇿",taurus:"♉",taxi:"🚕",tea:"🍵",teacher:"🧑‍🏫",technologist:"🧑‍💻",teddy_bear:"🧸",telephone:"☎️",telephone_receiver:"📞",telescope:"🔭",tennis:"🎾",tent:"⛺",test_tube:"🧪",thailand:"🇹🇭",thermometer:"🌡️",thinking:"🤔",thought_balloon:"💭",thread:"🧵",three:"3️⃣",thumbsdown:"👎",thumbsup:"👍",ticket:"🎫",tickets:"🎟️",tiger:"🐯",tiger2:"🐅",timer_clock:"⏲️",timor_leste:"🇹🇱",tipping_hand_man:"💁‍♂️",tipping_hand_person:"💁",tipping_hand_woman:"💁‍♀️",tired_face:"😫",tm:"™️",togo:"🇹🇬",toilet:"🚽",tokelau:"🇹🇰",tokyo_tower:"🗼",tomato:"🍅",tonga:"🇹🇴",tongue:"👅",toolbox:"🧰",tooth:"🦷",top:"🔝",tophat:"🎩",tornado:"🌪️",tr:"🇹🇷",trackball:"🖲️",tractor:"🚜",traffic_light:"🚥",train:"🚋",train2:"🚆",tram:"🚊",triangular_flag_on_post:"🚩",triangular_ruler:"📐",trident:"🔱",trinidad_tobago:"🇹🇹",tristan_da_cunha:"🇹🇦",triumph:"😤",trolleybus:"🚎",trophy:"🏆",tropical_drink:"🍹",tropical_fish:"🐠",truck:"🚚",trumpet:"🎺",tshirt:"👕",tulip:"🌷",tumbler_glass:"🥃",tunisia:"🇹🇳",turkey:"🦃",turkmenistan:"🇹🇲",turks_caicos_islands:"🇹🇨",turtle:"🐢",tuvalu:"🇹🇻",tv:"📺",twisted_rightwards_arrows:"🔀",two:"2️⃣",two_hearts:"💕",two_men_holding_hands:"👬",two_women_holding_hands:"👭",u5272:"🈹",u5408:"🈴",u55b6:"🈺",u6307:"🈯",u6708:"🈷️",u6709:"🈶",u6e80:"🈵",u7121:"🈚",u7533:"🈸",u7981:"🈲",u7a7a:"🈳",uganda:"🇺🇬",uk:"🇬🇧",ukraine:"🇺🇦",umbrella:"☔",unamused:"😒",underage:"🔞",unicorn:"🦄",united_arab_emirates:"🇦🇪",united_nations:"🇺🇳",unlock:"🔓",up:"🆙",upside_down_face:"🙃",uruguay:"🇺🇾",us:"🇺🇸",us_outlying_islands:"🇺🇲",us_virgin_islands:"🇻🇮",uzbekistan:"🇺🇿",v:"✌️",vampire:"🧛",vampire_man:"🧛‍♂️",vampire_woman:"🧛‍♀️",vanuatu:"🇻🇺",vatican_city:"🇻🇦",venezuela:"🇻🇪",vertical_traffic_light:"🚦",vhs:"📼",vibration_mode:"📳",video_camera:"📹",video_game:"🎮",vietnam:"🇻🇳",violin:"🎻",virgo:"♍",volcano:"🌋",volleyball:"🏐",vomiting_face:"🤮",vs:"🆚",vulcan_salute:"🖖",waffle:"🧇",wales:"🏴󠁧󠁢󠁷󠁬󠁳󠁿",walking:"🚶",walking_man:"🚶‍♂️",walking_woman:"🚶‍♀️",wallis_futuna:"🇼🇫",waning_crescent_moon:"🌘",waning_gibbous_moon:"🌖",warning:"⚠️",wastebasket:"🗑️",watch:"⌚",water_buffalo:"🐃",water_polo:"🤽",watermelon:"🍉",wave:"👋",wavy_dash:"〰️",waxing_crescent_moon:"🌒",waxing_gibbous_moon:"🌔",wc:"🚾",weary:"😩",wedding:"💒",weight_lifting:"🏋️",weight_lifting_man:"🏋️‍♂️",weight_lifting_woman:"🏋️‍♀️",western_sahara:"🇪🇭",whale:"🐳",whale2:"🐋",wheel_of_dharma:"☸️",wheelchair:"♿",white_check_mark:"✅",white_circle:"⚪",white_flag:"🏳️",white_flower:"💮",white_haired_man:"👨‍🦳",white_haired_woman:"👩‍🦳",white_heart:"🤍",white_large_square:"⬜",white_medium_small_square:"◽",white_medium_square:"◻️",white_small_square:"▫️",white_square_button:"🔳",wilted_flower:"🥀",wind_chime:"🎐",wind_face:"🌬️",wine_glass:"🍷",wink:"😉",wolf:"🐺",woman:"👩",woman_artist:"👩‍🎨",woman_astronaut:"👩‍🚀",woman_cartwheeling:"🤸‍♀️",woman_cook:"👩‍🍳",woman_dancing:"💃",woman_facepalming:"🤦‍♀️",woman_factory_worker:"👩‍🏭",woman_farmer:"👩‍🌾",woman_firefighter:"👩‍🚒",woman_health_worker:"👩‍⚕️",woman_in_manual_wheelchair:"👩‍🦽",woman_in_motorized_wheelchair:"👩‍🦼",woman_judge:"👩‍⚖️",woman_juggling:"🤹‍♀️",woman_mechanic:"👩‍🔧",woman_office_worker:"👩‍💼",woman_pilot:"👩‍✈️",woman_playing_handball:"🤾‍♀️",woman_playing_water_polo:"🤽‍♀️",woman_scientist:"👩‍🔬",woman_shrugging:"🤷‍♀️",woman_singer:"👩‍🎤",woman_student:"👩‍🎓",woman_teacher:"👩‍🏫",woman_technologist:"👩‍💻",woman_with_headscarf:"🧕",woman_with_probing_cane:"👩‍🦯",woman_with_turban:"👳‍♀️",womans_clothes:"👚",womans_hat:"👒",women_wrestling:"🤼‍♀️",womens:"🚺",woozy_face:"🥴",world_map:"🗺️",worried:"😟",wrench:"🔧",wrestling:"🤼",writing_hand:"✍️",x:"❌",yarn:"🧶",yawning_face:"🥱",yellow_circle:"🟡",yellow_heart:"💛",yellow_square:"🟨",yemen:"🇾🇪",yen:"💴",yin_yang:"☯️",yo_yo:"🪀",yum:"😋",zambia:"🇿🇲",zany_face:"🤪",zap:"⚡",zebra:"🦓",zero:"0️⃣",zimbabwe:"🇿🇼",zipper_mouth_face:"🤐",zombie:"🧟",zombie_man:"🧟‍♂️",zombie_woman:"🧟‍♀️",zzz:"💤",atom:'<img width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/atom.png?v8">',basecamp:'<img width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/basecamp.png?v8">',basecampy:'<img width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/basecampy.png?v8">',bowtie:'<img width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/bowtie.png?v8">',electron:'<img width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/electron.png?v8">',feelsgood:'<img width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/feelsgood.png?v8">',finnadie:'<img width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/finnadie.png?v8">',goberserk:'<img width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/goberserk.png?v8">',godmode:'<img width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/godmode.png?v8">',hurtrealbad:'<img width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/hurtrealbad.png?v8">',neckbeard:'<img width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/neckbeard.png?v8">',octocat:'<img width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/octocat.png?v8">',rage1:'<img width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/rage1.png?v8">',rage2:'<img width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/rage2.png?v8">',rage3:'<img width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/rage3.png?v8">',rage4:'<img width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/rage4.png?v8">',shipit:'<img width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/shipit.png?v8">',suspect:'<img width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/suspect.png?v8">',trollface:'<img width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/trollface.png?v8">',showdown:'<img width="20" height="20" align="absmiddle" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAAS1BMVEX///8jJS0jJS0jJS0jJS0jJS0jJS0jJS0jJS0jJS0jJS0jJS0jJS0jJS0jJS0jJS0jJS3b1q3b1q3b1q3b1q3b1q3b1q3b1q3b1q0565CIAAAAGXRSTlMAQHCAYCCw/+DQwPCQUBAwoHCAEP+wwFBgS2fvBgAAAUZJREFUeAHs1cGy7BAUheFFsEDw/k97VTq3T6ge2EmdM+pvrP6Iwd74XV9Kb52xuMU4/uc1YNgZLFOeV8FGdhGrNk5SEgUyPxAEdj4LlMRDyhVAMVEa2M7TBSeVZAFPdqHgzSZJwPKgcLFLAooHDJo4EDCw4gAtBoJA5UFj4Ng5LOGLwVXZuoIlji/jeQHFk7+baHxrCjeUwB9+s88KndvlhcyBN5BSkYNQIVVb4pV+Npm7hhuKDs/uMP5KxT3WzSNNLIuuoDpMmuAVMruMSeDyQBi24DTr43LAY7ILA1QYaWkgfHzFthYYzg67SQsCbB8GhJUEGCtO9n0rSaCLxgJQjS/JSgMTg2eBDEHAJ+H350AsjYNYscrErgI2e/l+mdR967TCX/v6N0EhPECYCP0i+IAoYQOE8BogNhQMEMdrgAQWHaMAAGi5I5euoY9NAAAAAElFTkSuQmCC">'},P.subParser("makehtml.blockGamut",function(e,a,r){"use strict";return e=r.converter._dispatch("makehtml.blockGamut.before",e,a,r).getText(),e=P.subParser("makehtml.blockQuotes")(e,a,r),e=P.subParser("makehtml.headers")(e,a,r),e=P.subParser("makehtml.horizontalRule")(e,a,r),e=P.subParser("makehtml.lists")(e,a,r),e=P.subParser("makehtml.codeBlocks")(e,a,r),e=P.subParser("makehtml.tables")(e,a,r),e=P.subParser("makehtml.hashHTMLBlocks")(e,a,r),e=P.subParser("makehtml.paragraphs")(e,a,r),e=r.converter._dispatch("makehtml.blockGamut.after",e,a,r).getText()}),P.subParser("makehtml.blockQuotes",function(e,a,r){"use strict";e=r.converter._dispatch("makehtml.blockQuotes.before",e,a,r).getText();var t=/(^ {0,3}>[ \t]?.+\n(.+\n)*\n*)+/gm;return a.splitAdjacentBlockquotes&&(t=/^ {0,3}>[\s\S]*?(?:\n\n)/gm),e=(e+="\n\n").replace(t,function(e){return e=(e=(e=e.replace(/^[ \t]*>[ \t]?/gm,"")).replace(/¨0/g,"")).replace(/^[ \t]+$/gm,""),e=P.subParser("makehtml.githubCodeBlocks")(e,a,r),e=(e=(e=P.subParser("makehtml.blockGamut")(e,a,r)).replace(/(^|\n)/g,"$1  ")).replace(/(\s*<pre>[^\r]+?<\/pre>)/gm,function(e,a){return a.replace(/^  /gm,"¨0").replace(/¨0/g,"")}),P.subParser("makehtml.hashBlock")("<blockquote>\n"+e+"\n</blockquote>",a,r)}),e=r.converter._dispatch("makehtml.blockQuotes.after",e,a,r).getText()}),P.subParser("makehtml.codeBlocks",function(e,n,s){"use strict";e=s.converter._dispatch("makehtml.codeBlocks.before",e,n,s).getText();return e=(e=(e+="¨0").replace(/(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=¨0))/g,function(e,a,r){var t="\n",a=P.subParser("makehtml.outdent")(a,n,s);return a=P.subParser("makehtml.encodeCode")(a,n,s),a="<pre><code>"+(a=(a=(a=P.subParser("makehtml.detab")(a,n,s)).replace(/^\n+/g,"")).replace(/\n+$/g,""))+(t=n.omitExtraWLInCodeBlocks?"":t)+"</code></pre>",P.subParser("makehtml.hashBlock")(a,n,s)+r})).replace(/¨0/,""),e=s.converter._dispatch("makehtml.codeBlocks.after",e,n,s).getText()}),P.subParser("makehtml.codeSpans",function(e,n,s){"use strict";return e=(e=void 0===(e=s.converter._dispatch("makehtml.codeSpans.before",e,n,s).getText())?"":e).replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,function(e,a,r,t){return t=(t=t.replace(/^([ \t]*)/g,"")).replace(/[ \t]*$/g,""),t=a+"<code>"+(t=P.subParser("makehtml.encodeCode")(t,n,s))+"</code>",t=P.subParser("makehtml.hashHTMLSpans")(t,n,s)}),e=s.converter._dispatch("makehtml.codeSpans.after",e,n,s).getText()}),P.subParser("makehtml.completeHTMLDocument",function(e,a,r){"use strict";if(!a.completeHTMLDocument)return e;e=r.converter._dispatch("makehtml.completeHTMLDocument.before",e,a,r).getText();var t,n="html",s="<!DOCTYPE HTML>\n",i="",o='<meta charset="utf-8">\n',l="",c="";for(t in void 0!==r.metadata.parsed.doctype&&(s="<!DOCTYPE "+r.metadata.parsed.doctype+">\n","html"!==(n=r.metadata.parsed.doctype.toString().toLowerCase())&&"html5"!==n||(o='<meta charset="utf-8">')),r.metadata.parsed)if(r.metadata.parsed.hasOwnProperty(t))switch(t.toLowerCase()){case"doctype":break;case"title":i="<title>"+r.metadata.parsed.title+"</title>\n";break;case"charset":o="html"===n||"html5"===n?'<meta charset="'+r.metadata.parsed.charset+'">\n':'<meta name="charset" content="'+r.metadata.parsed.charset+'">\n';break;case"language":case"lang":l=' lang="'+r.metadata.parsed[t]+'"',c+='<meta name="'+t+'" content="'+r.metadata.parsed[t]+'">\n';break;default:c+='<meta name="'+t+'" content="'+r.metadata.parsed[t]+'">\n'}return e=s+"<html"+l+">\n<head>\n"+i+o+c+"</head>\n<body>\n"+e.trim()+"\n</body>\n</html>",e=r.converter._dispatch("makehtml.completeHTMLDocument.after",e,a,r).getText()}),P.subParser("makehtml.detab",function(e,a,r){"use strict";return e=(e=(e=(e=(e=(e=r.converter._dispatch("makehtml.detab.before",e,a,r).getText()).replace(/\t(?=\t)/g,"    ")).replace(/\t/g,"¨A¨B")).replace(/¨B(.+?)¨A/g,function(e,a){for(var r=a,t=4-r.length%4,n=0;n<t;n++)r+=" ";return r})).replace(/¨A/g,"    ")).replace(/¨B/g,""),e=r.converter._dispatch("makehtml.detab.after",e,a,r).getText()}),P.subParser("makehtml.ellipsis",function(e,a,r){"use strict";return a.ellipsis?(e=(e=r.converter._dispatch("makehtml.ellipsis.before",e,a,r).getText()).replace(/\.\.\./g,"…"),r.converter._dispatch("makehtml.ellipsis.after",e,a,r).getText()):e}),P.subParser("makehtml.emoji",function(e,a,r){"use strict";if(!a.emoji)return e;return e=(e=r.converter._dispatch("makehtml.emoji.before",e,a,r).getText()).replace(/:([\S]+?):/g,function(e,a){return P.helper.emojis.hasOwnProperty(a)?P.helper.emojis[a]:e}),e=r.converter._dispatch("makehtml.emoji.after",e,a,r).getText()}),P.subParser("makehtml.encodeAmpsAndAngles",function(e,a,r){"use strict";return e=(e=(e=(e=(e=r.converter._dispatch("makehtml.encodeAmpsAndAngles.before",e,a,r).getText()).replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/g,"&amp;")).replace(/<(?![a-z\/?$!])/gi,"&lt;")).replace(/</g,"&lt;")).replace(/>/g,"&gt;"),e=r.converter._dispatch("makehtml.encodeAmpsAndAngles.after",e,a,r).getText()}),P.subParser("makehtml.encodeBackslashEscapes",function(e,a,r){"use strict";return e=(e=(e=r.converter._dispatch("makehtml.encodeBackslashEscapes.before",e,a,r).getText()).replace(/\\(\\)/g,P.helper.escapeCharactersCallback)).replace(/\\([`*_{}\[\]()>#+.!~=|:-])/g,P.helper.escapeCharactersCallback),e=r.converter._dispatch("makehtml.encodeBackslashEscapes.after",e,a,r).getText()}),P.subParser("makehtml.encodeCode",function(e,a,r){"use strict";return e=(e=r.converter._dispatch("makehtml.encodeCode.before",e,a,r).getText()).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/([*_{}\[\]\\=~-])/g,P.helper.escapeCharactersCallback),e=r.converter._dispatch("makehtml.encodeCode.after",e,a,r).getText()}),P.subParser("makehtml.escapeSpecialCharsWithinTagAttributes",function(e,a,r){"use strict";return e=(e=(e=r.converter._dispatch("makehtml.escapeSpecialCharsWithinTagAttributes.before",e,a,r).getText()).replace(/<\/?[a-z\d_:-]+(?:[\s]+[\s\S]+?)?>/gi,function(e){return e.replace(/(.)<\/?code>(?=.)/g,"$1`").replace(/([\\`*_~=|])/g,P.helper.escapeCharactersCallback)})).replace(/<!(--(?:(?:[^>-]|-[^>])(?:[^-]|-[^-])*)--)>/gi,function(e){return e.replace(/([\\`*_~=|])/g,P.helper.escapeCharactersCallback)}),e=r.converter._dispatch("makehtml.escapeSpecialCharsWithinTagAttributes.after",e,a,r).getText()}),P.subParser("makehtml.githubCodeBlocks",function(e,s,i){"use strict";return s.ghCodeBlocks?(e=i.converter._dispatch("makehtml.githubCodeBlocks.before",e,s,i).getText(),e=(e=(e+="¨0").replace(/(?:^|\n) {0,3}(```+|~~~+) *([^\n\t`~]*)\n([\s\S]*?)\n {0,3}\1/g,function(e,a,r,t){var n=s.omitExtraWLInCodeBlocks?"":"\n";return r=r.trim().split(" ")[0],t=P.subParser("makehtml.encodeCode")(t,s,i),t="<pre><code"+(r?' class="'+r+" language-"+r+'"':"")+">"+(t=(t=(t=P.subParser("makehtml.detab")(t,s,i)).replace(/^\n+/g,"")).replace(/\n+$/g,""))+n+"</code></pre>",t=P.subParser("makehtml.hashBlock")(t,s,i),"\n\n¨G"+(i.ghCodeBlocks.push({text:e,codeblock:t})-1)+"G\n\n"})).replace(/¨0/,""),i.converter._dispatch("makehtml.githubCodeBlocks.after",e,s,i).getText()):e}),P.subParser("makehtml.hashBlock",function(e,a,r){"use strict";return e=(e=r.converter._dispatch("makehtml.hashBlock.before",e,a,r).getText()).replace(/(^\n+|\n+$)/g,""),e="\n\n¨K"+(r.gHtmlBlocks.push(e)-1)+"K\n\n",e=r.converter._dispatch("makehtml.hashBlock.after",e,a,r).getText()}),P.subParser("makehtml.hashCodeTags",function(e,n,s){"use strict";e=s.converter._dispatch("makehtml.hashCodeTags.before",e,n,s).getText();return e=P.helper.replaceRecursiveRegExp(e,function(e,a,r,t){r=r+P.subParser("makehtml.encodeCode")(a,n,s)+t;return"¨C"+(s.gHtmlSpans.push(r)-1)+"C"},"<code\\b[^>]*>","</code>","gim"),e=s.converter._dispatch("makehtml.hashCodeTags.after",e,n,s).getText()}),P.subParser("makehtml.hashElement",function(e,a,r){"use strict";return function(e,a){return a=(a=(a=a.replace(/\n\n/g,"\n")).replace(/^\n/,"")).replace(/\n+$/g,""),a="\n\n¨K"+(r.gHtmlBlocks.push(a)-1)+"K\n\n"}}),P.subParser("makehtml.hashHTMLBlocks",function(e,a,n){"use strict";e=n.converter._dispatch("makehtml.hashHTMLBlocks.before",e,a,n).getText();function r(e,a,r,t){return-1!==r.search(/\bmarkdown\b/)&&(e=r+n.converter.makeHtml(a)+t),"\n\n¨K"+(n.gHtmlBlocks.push(e)-1)+"K\n\n"}var t=["pre","div","h1","h2","h3","h4","h5","h6","blockquote","table","dl","ol","ul","script","noscript","form","fieldset","iframe","math","style","section","header","footer","nav","article","aside","address","audio","canvas","figure","hgroup","output","video","details","p"];a.backslashEscapesHTMLTags&&(e=e.replace(/\\<(\/?[^>]+?)>/g,function(e,a){return"&lt;"+a+"&gt;"}));for(var s=0;s<t.length;++s)for(var i=new RegExp("^ {0,3}(<"+t[s]+"\\b[^>]*>)","im"),o="<"+t[s]+"\\b[^>]*>",l="</"+t[s]+">";-1!==(c=P.helper.regexIndexOf(e,i));){var c=P.helper.splitAtIndex(e,c),u=P.helper.replaceRecursiveRegExp(c[1],r,o,l,"im");if(u===c[1])break;e=c[0].concat(u)}return e=e.replace(/(\n {0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g,P.subParser("makehtml.hashElement")(e,a,n)),e=(e=P.helper.replaceRecursiveRegExp(e,function(e){return"\n\n¨K"+(n.gHtmlBlocks.push(e)-1)+"K\n\n"},"^ {0,3}\x3c!--","--\x3e","gm")).replace(/\n\n( {0,3}<([?%])[^\r]*?\2>[ \t]*(?=\n{2,}))/g,P.subParser("makehtml.hashElement")(e,a,n)),e=n.converter._dispatch("makehtml.hashHTMLBlocks.after",e,a,n).getText()}),P.subParser("makehtml.hashHTMLSpans",function(e,a,r){"use strict";return e=(e=(e=(e=(e=r.converter._dispatch("makehtml.hashHTMLSpans.before",e,a,r).getText()).replace(/<[^>]+?\/>/gi,function(e){return P.helper._hashHTMLSpan(e,r)})).replace(/<([^>]+?)>[\s\S]*?<\/\1>/g,function(e){return P.helper._hashHTMLSpan(e,r)})).replace(/<([^>]+?)\s[^>]+?>[\s\S]*?<\/\1>/g,function(e){return P.helper._hashHTMLSpan(e,r)})).replace(/<[^>]+?>/gi,function(e){return P.helper._hashHTMLSpan(e,r)}),e=r.converter._dispatch("makehtml.hashHTMLSpans.after",e,a,r).getText()}),P.subParser("makehtml.unhashHTMLSpans",function(e,a,r){"use strict";e=r.converter._dispatch("makehtml.unhashHTMLSpans.before",e,a,r).getText();for(var t=0;t<r.gHtmlSpans.length;++t){for(var n=r.gHtmlSpans[t],s=0;/¨C(\d+)C/.test(n);){var i=RegExp.$1,n=n.replace("¨C"+i+"C",r.gHtmlSpans[i]);if(10===s){console.error("maximum nesting of 10 spans reached!!!");break}++s}e=e.replace("¨C"+t+"C",n)}return e=r.converter._dispatch("makehtml.unhashHTMLSpans.after",e,a,r).getText()}),P.subParser("makehtml.hashPreCodeTags",function(e,n,s){"use strict";e=s.converter._dispatch("makehtml.hashPreCodeTags.before",e,n,s).getText();return e=P.helper.replaceRecursiveRegExp(e,function(e,a,r,t){r=r+P.subParser("makehtml.encodeCode")(a,n,s)+t;return"\n\n¨G"+(s.ghCodeBlocks.push({text:e,codeblock:r})-1)+"G\n\n"},"^ {0,3}<pre\\b[^>]*>\\s*<code\\b[^>]*>","^ {0,3}</code>\\s*</pre>","gim"),e=s.converter._dispatch("makehtml.hashPreCodeTags.after",e,n,s).getText()}),P.subParser("makehtml.headers",function(e,n,s){"use strict";e=s.converter._dispatch("makehtml.headers.before",e,n,s).getText();var i=isNaN(parseInt(n.headerLevelStart))?1:parseInt(n.headerLevelStart),a=n.smoothLivePreview?/^(.+)[ \t]*\n={2,}[ \t]*\n+/gm:/^(.+)[ \t]*\n=+[ \t]*\n+/gm,r=n.smoothLivePreview?/^(.+)[ \t]*\n-{2,}[ \t]*\n+/gm:/^(.+)[ \t]*\n-+[ \t]*\n+/gm,a=(e=(e=e.replace(a,function(e,a){var r=P.subParser("makehtml.spanGamut")(a,n,s),a=n.noHeaderId?"":' id="'+o(a)+'"',a="<h"+i+a+">"+r+"</h"+i+">";return P.subParser("makehtml.hashBlock")(a,n,s)})).replace(r,function(e,a){var r=P.subParser("makehtml.spanGamut")(a,n,s),a=n.noHeaderId?"":' id="'+o(a)+'"',t=i+1,a="<h"+t+a+">"+r+"</h"+t+">";return P.subParser("makehtml.hashBlock")(a,n,s)}),n.requireSpaceBeforeHeadingText?/^(#{1,6})[ \t]+(.+?)[ \t]*#*\n+/gm:/^(#{1,6})[ \t]*(.+?)[ \t]*#*\n+/gm);function o(e){var a=e=n.customizedHeaderId&&(a=e.match(/{([^{]+?)}\s*$/))&&a[1]?a[1]:e,e=P.helper.isString(n.prefixHeaderId)?n.prefixHeaderId:!0===n.prefixHeaderId?"section-":"";return n.rawPrefixHeaderId||(a=e+a),a=(n.ghCompatibleHeaderId?a.replace(/ /g,"-").replace(/&amp;/g,"").replace(/¨T/g,"").replace(/¨D/g,"").replace(/[&+$,\/:;=?@"#{}|^¨~\[\]`\\*)(%.!'<>]/g,""):n.rawHeaderId?a.replace(/ /g,"-").replace(/&amp;/g,"&").replace(/¨T/g,"¨").replace(/¨D/g,"$").replace(/["']/g,"-"):a.replace(/[^\w]/g,"")).toLowerCase(),n.rawPrefixHeaderId&&(a=e+a),s.hashLinkCounts[a]?a=a+"-"+s.hashLinkCounts[a]++:s.hashLinkCounts[a]=1,a}return e=e.replace(a,function(e,a,r){var t=r,t=(n.customizedHeaderId&&(t=r.replace(/\s?{([^{]+?)}\s*$/,"")),P.subParser("makehtml.spanGamut")(t,n,s)),r=n.noHeaderId?"":' id="'+o(r)+'"',a=i-1+a.length,r="<h"+a+r+">"+t+"</h"+a+">";return P.subParser("makehtml.hashBlock")(r,n,s)}),e=s.converter._dispatch("makehtml.headers.after",e,n,s).getText()}),P.subParser("makehtml.horizontalRule",function(e,a,r){"use strict";e=r.converter._dispatch("makehtml.horizontalRule.before",e,a,r).getText();var t=P.subParser("makehtml.hashBlock")("<hr />",a,r);return e=(e=(e=e.replace(/^ {0,2}( ?-){3,}[ \t]*$/gm,t)).replace(/^ {0,2}( ?\*){3,}[ \t]*$/gm,t)).replace(/^ {0,2}( ?_){3,}[ \t]*$/gm,t),e=r.converter._dispatch("makehtml.horizontalRule.after",e,a,r).getText()}),P.subParser("makehtml.images",function(e,l,h){"use strict";function a(e,a,r,t,n,s,i,o){return c(e,a,r,t=P.helper.applyBaseUrl(l.relativePathBaseUrl,t),n,s,0,o)}function c(e,a,r,t,n,s,i,o){var l=h.gUrls,c=h.gTitles,u=h.gDimensions;if(r=r.toLowerCase(),o=o||"",-1<e.search(/\(<?\s*>? ?(['"].*['"])?\)$/m))t="";else if(""===t||null===t){if(t="#"+(r=""!==r&&null!==r?r:a.toLowerCase().replace(/ ?\n/g," ")),P.helper.isUndefined(l[r]))return e;t=l[r],P.helper.isUndefined(c[r])||(o=c[r]),P.helper.isUndefined(u[r])||(n=u[r].width,s=u[r].height)}a=a.replace(/"/g,"&quot;").replace(P.helper.regexes.asteriskDashTildeAndColon,P.helper.escapeCharactersCallback);e='<img src="'+(t=t.replace(P.helper.regexes.asteriskDashTildeAndColon,P.helper.escapeCharactersCallback))+'" alt="'+a+'"';return o&&P.helper.isString(o)&&(e+=' title="'+(o=o.replace(/"/g,"&quot;").replace(P.helper.regexes.asteriskDashTildeAndColon,P.helper.escapeCharactersCallback))+'"'),n&&s&&(e=e+(' width="'+(n="*"===n?"auto":n))+'" height="'+(s="*"===s?"auto":s)+'"'),e+=" />"}return e=(e=(e=(e=(e=(e=h.converter._dispatch("makehtml.images.before",e,l,h).getText()).replace(/!\[([^\]]*?)] ?(?:\n *)?\[([\s\S]*?)]()()()()()/g,c)).replace(/!\[([^\]]*?)][ \t]*()\([ \t]?<?(data:.+?\/.+?;base64,[A-Za-z0-9+/=\n]+?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(["'])([^"]*?)\6)?[ \t]?\)/g,function(e,a,r,t,n,s,i,o){return c(e,a,r,t=t.replace(/\s/g,""),n,s,0,o)})).replace(/!\[([^\]]*?)][ \t]*()\([ \t]?<([^>]*)>(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(?:(["'])([^"]*?)\6))?[ \t]?\)/g,a)).replace(/!\[([^\]]*?)][ \t]*()\([ \t]?<?([\S]+?(?:\([\S]*?\)[\S]*?)?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(["'])([^"]*?)\6)?[ \t]?\)/g,a)).replace(/!\[([^\[\]]+)]()()()()()/g,c),e=h.converter._dispatch("makehtml.images.after",e,l,h).getText()}),P.subParser("makehtml.italicsAndBold",function(e,a,r){"use strict";return e=r.converter._dispatch("makehtml.italicsAndBold.before",e,a,r).getText(),e=(e=(e=(e=a.literalMidWordUnderscores?(e=(e=e.replace(/\b___(\S[\s\S]*?)___\b/g,function(e,a){return"<strong><em>"+a+"</em></strong>"})).replace(/\b__(\S[\s\S]*?)__\b/g,function(e,a){return"<strong>"+a+"</strong>"})).replace(/\b_(\S[\s\S]*?)_\b/g,function(e,a){return"<em>"+a+"</em>"}):(e=(e=e.replace(/___(\S[\s\S]*?)___/g,function(e,a){return/\S$/.test(a)?"<strong><em>"+a+"</em></strong>":e})).replace(/__(\S[\s\S]*?)__/g,function(e,a){return/\S$/.test(a)?"<strong>"+a+"</strong>":e})).replace(/_([^\s_][\s\S]*?)_/g,function(e,a){return/\S$/.test(a)?"<em>"+a+"</em>":e})).replace(/\*\*\*(\S[\s\S]*?)\*\*\*/g,function(e,a){return/\S$/.test(a)?"<strong><em>"+a+"</em></strong>":e})).replace(/\*\*(\S[\s\S]*?)\*\*/g,function(e,a){return/\S$/.test(a)?"<strong>"+a+"</strong>":e})).replace(/\*([^\s*][\s\S]*?)\*/g,function(e,a){return/\S$/.test(a)?"<em>"+a+"</em>":e}),e=r.converter._dispatch("makehtml.italicsAndBold.after",e,a,r).getText()}),s="makehtml.links",P.subParser("makehtml.links",function(e,a,r){return e=r.converter._dispatch(s+".start",e,a,r).getText(),e=P.subParser("makehtml.links.reference")(e,a,r),e=P.subParser("makehtml.links.inline")(e,a,r),e=P.subParser("makehtml.links.referenceShortcut")(e,a,r),e=P.subParser("makehtml.links.angleBrackets")(e,a,r),e=(e=(e=P.subParser("makehtml.links.ghMentions")(e,a,r)).replace(/<a\s[^>]*>[\s\S]*<\/a>/g,function(e){return P.helper._hashHTMLSpan(e,r)})).replace(/<img\s[^>]*\/?>/g,function(e){return P.helper._hashHTMLSpan(e,r)}),e=P.subParser("makehtml.links.naked")(e,a,r),e=r.converter._dispatch(s+".end",e,a,r).getText()}),P.subParser("makehtml.links.inline",function(e,a,r){var t=void 0+".inline",n=/\[(.*?)]()()()()\(<? ?>? ?(?:["'](.*)["'])?\)/g,s=/\[((?:\[[^\]]*]|[^\[\]])*)]()\s?\([ \t]?<([^>]*)>(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g,i=/\[([\S ]*?)]\s?()\( *<?([^\s'"]*?(?:\([\S]*?\)[\S]*?)?)>?\s*(?:()(['"])(.*?)\5)? *\)/g,o=/\[([\S ]*?)]\s?()\( *<?([^\s'"]*?(?:\([\S]*?\)[\S]*?)?)>?\s+()()\((.*?)\) *\)/g;return e=(e=(e=(e=(e=r.converter._dispatch(t+".start",e,a,r).getText()).replace(n,l(n,t,a,r,!0))).replace(s,l(s,t,a,r))).replace(i,l(i,t,a,r))).replace(o,l(o,t,a,r)),e=r.converter._dispatch(t+".end",e,a,r).getText()}),P.subParser("makehtml.links.reference",function(e,a,r){var t=void 0+".reference",n=/\[((?:\[[^\]]*]|[^\[\]])*)] ?(?:\n *)?\[(.*?)]()()()()/g;return e=(e=r.converter._dispatch(t+".start",e,a,r).getText()).replace(n,i(n,t,a,r)),e=r.converter._dispatch(t+".end",e,a,r).getText()}),P.subParser("makehtml.links.referenceShortcut",function(e,a,r){var t=void 0+".referenceShortcut",n=/\[([^\[\]]+)]()()()()()/g;return e=(e=r.converter._dispatch(t+".start",e,a,r).getText()).replace(n,i(n,t,a,r)),e=r.converter._dispatch(t+".end",e,a,r).getText()}),P.subParser("makehtml.links.ghMentions",function(e,s,i){var o=void 0+"ghMentions";if(!s.ghMentions)return e;e=i.converter._dispatch(o+".start",e,s,i).getText();var l=/(^|\s)(\\)?(@([a-z\d]+(?:[a-z\d._-]+?[a-z\d]+)*))/gi;return e=e.replace(l,function(e,a,r,t,n){if("\\"===r)return a+t;if(!P.helper.isString(s.ghMentionsLink))throw new Error("ghMentionsLink option must be a string");r=s.ghMentionsLink.replace(/{u}/g,n);return a+b(_(l,o+".captureStart",e,t,null,r,null,s,i),s,i)}),e=i.converter._dispatch(o+".end",e,s,i).getText()}),P.subParser("makehtml.links.angleBrackets",function(e,t,n){var s="makehtml.links.angleBrackets",i=(e=n.converter._dispatch(s+".start",e,t,n).getText(),/<(((?:https?|ftp):\/\/|www\.)[^'">\s]+)>/gi),o=(e=e.replace(i,function(e,a,r){return b(_(i,s+".captureStart",e,a,null,a="www."===r?"http://"+a:a,null,t,n),t,n)}),/<(?:mailto:)?([-.\w]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi);return e=e.replace(o,function(e,a){var r="mailto:";return a=P.subParser("makehtml.unescapeSpecialChars")(a,t,n),t.encodeEmails?(r=P.helper.encodeEmailAddress(r+a),a=P.helper.encodeEmailAddress(a)):r+=a,b(_(o,s+".captureStart",e,a,null,r,null,t,n),t,n)}),e=n.converter._dispatch(s+".end",e,t,n).getText()}),P.subParser("makehtml.links.naked",function(e,u,h){if(!u.simplifiedAutoLink)return e;var m="makehtml.links.naked",d=(e=h.converter._dispatch(m+".start",e,u,h).getText(),/([_*~]*?)(((?:https?|ftp):\/\/|www\.)[^\s<>"'`´.-][^\s<>"'`´]*?\.[a-z\d.]+[^\s<>"']*)\1/gi),n=(e=e.replace(d,function(e,a,r,t){for(var n="",s=r.length-1;0<=s;--s){var i=r.charAt(s);if(/[_*~,;:.!?]/.test(i))r=r.slice(0,-1),n=i+n;else if(/\)/.test(i)){var o=r.match(/\(/g)||[],l=r.match(/\)/g);if(!(o.length<l.length))break;r=r.slice(0,-1),n=i+n}else{if(!/]/.test(i))break;o=r.match(/\[/g)||[],l=r.match(/\]/g);if(!(o.length<l.length))break;r=r.slice(0,-1),n=i+n}}var c=r;return r="www."===t?"http://"+r:r,c=c.replace(P.helper.regexes.asteriskDashTildeAndColon,P.helper.escapeCharactersCallback),a+b(_(d,m+".captureStart",e,c,null,r,null,u,h),u,h)+n+a}),/(^|\s)(?:mailto:)?([A-Za-z0-9!#$%&'*+-/=?^_`{|}~.]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)(?=$|\s)/gim);return e=e.replace(n,function(e,a,r){var t="mailto:";return r=P.subParser("makehtml.unescapeSpecialChars")(r,u,h),u.encodeEmails?(t=P.helper.encodeEmailAddress(t+r),r=P.helper.encodeEmailAddress(r)):t+=r,a+b(_(n,m+".captureStart",e,r,null,t,null,u,h),u,h)}),e=h.converter._dispatch(m+".end",e,u,h).getText()}),P.subParser("makehtml.lists",function(e,g,p){"use strict";function h(e,a){p.gListLevel++,e=e.replace(/\n{2,}$/,"\n");var r=/(\n)?(^ {0,3})([*+-]|\d+[.])[ \t]+((\[([xX ])])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(¨0| {0,3}([*+-]|\d+[.])[ \t]+))/gm,d=/\n[ \t]*\n(?!¨0)/.test(e+="¨0");return g.disableForced4SpacesIndentedSublists&&(r=/(\n)?(^ {0,3})([*+-]|\d+[.])[ \t]+((\[([xX ])])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(¨0|\2([*+-]|\d+[.])[ \t]+))/gm),e=(e=e.replace(r,function(e,a,r,t,n,s,i){i=i&&""!==i.trim();var n=P.subParser("makehtml.outdent")(n,g,p),o="";if(s&&g.tasklists&&(o=' class="task-list-item',g.moreStyling&&(o+=i?" task-list-item-complete":""),o+='" style="list-style-type: none;"',n=n.replace(/^[ \t]*\[([xX ])?]/m,function(){var e='<input type="checkbox" disabled style="margin: 0px 0.35em 0.25em -1.6em; vertical-align: middle;"';return i&&(e+=" checked"),e+=">"})),n=n.replace(/^([-*+]|\d\.)[ \t]+[\S\n ]*/g,function(e){return"¨A"+e}),/^#+.+\n.+/.test(n)&&(n=n.replace(/^(#+.+)$/m,"$1\n")),a||-1<n.search(/\n{2,}/)){n=P.subParser("makehtml.githubCodeBlocks")(n,g,p),n=P.subParser("makehtml.blockQuotes")(n,g,p),n=P.subParser("makehtml.headers")(n,g,p),n=P.subParser("makehtml.lists")(n,g,p),n=P.subParser("makehtml.codeBlocks")(n,g,p),n=P.subParser("makehtml.tables")(n,g,p);for(var l=(n=(n=(n=P.subParser("makehtml.hashHTMLBlocks")(n,g,p)).replace(/^\n+/g,"")).replace(/\n+$/g,"")).split(/\n{2,}/g),c=[],u=l.length,h=0;h<u;h++){var m=l[h];0<=m.search(/¨([KG])(\d+)\1/g)?c.push(m):0<=m.search(/\S/)&&(m=(m=P.subParser("makehtml.spanGamut")(m,g,p)).replace(/^([ \t]*)/g,"<p>"),m+="</p>",c.push(m))}n=(n=(n=c.join("\n")).replace(/^\n+/g,"")).replace(/\n+$/g,"")}else n=(n=P.subParser("makehtml.lists")(n,g,p)).replace(/\n$/,""),n=(n=P.subParser("makehtml.hashHTMLBlocks")(n,g,p)).replace(/\n\n+/g,"\n\n"),n=(d?P.subParser("makehtml.paragraphs"):P.subParser("makehtml.spanGamut"))(n,g,p);return n="<li"+o+">"+(n=n.replace("¨A",""))+"</li>\n"})).replace(/¨0/g,""),p.gListLevel--,e=a?e.replace(/\s+$/,""):e}function m(e,a){if("ol"===a){a=e.match(/^ *(\d+)\./);if(a&&"1"!==a[1])return' start="'+a[1]+'"'}return""}function n(n,s,i){var e,o=g.disableForced4SpacesIndentedSublists?/^ ?\d+\.[ \t]/gm:/^ {0,3}\d+\.[ \t]/gm,l=g.disableForced4SpacesIndentedSublists?/^ ?[*+-][ \t]/gm:/^ {0,3}[*+-][ \t]/gm,c="ul"===s?o:l,u="";return-1!==n.search(c)?function e(a){var r=a.search(c),t=m(n,s);-1!==r?(u+="\n\n<"+s+t+">\n"+h(a.slice(0,r),!!i)+"</"+s+">\n",c="ul"===(s="ul"===s?"ol":"ul")?o:l,e(a.slice(r))):u+="\n\n<"+s+t+">\n"+h(a,!!i)+"</"+s+">\n"}(n):(e=m(n,s),u="\n\n<"+s+e+">\n"+h(n,!!i)+"</"+s+">\n"),u}return e=p.converter._dispatch("lists.before",e,g,p).getText(),e+="¨0",e=(e=p.gListLevel?e.replace(/^(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(¨0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm,function(e,a,r){return n(a,-1<r.search(/[*+-]/g)?"ul":"ol",!0)}):e.replace(/(\n\n|^\n?)(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(¨0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm,function(e,a,r,t){return n(r,-1<t.search(/[*+-]/g)?"ul":"ol",!1)})).replace(/¨0/,""),e=p.converter._dispatch("makehtml.lists.after",e,g,p).getText()}),P.subParser("makehtml.metadata",function(e,a,t){"use strict";return a.metadata?(e=(e=(e=(e=t.converter._dispatch("makehtml.metadata.before",e,a,t).getText()).replace(/^\s*«««+(\S*?)\n([\s\S]+?)\n»»»+\n/,function(e,a,r){return n(r),"¨M"})).replace(/^\s*---+(\S*?)\n([\s\S]+?)\n---+\n/,function(e,a,r){return a&&(t.metadata.format=a),n(r),"¨M"})).replace(/¨M/g,""),t.converter._dispatch("makehtml.metadata.after",e,a,t).getText()):e;function n(e){(e=(e=(e=(t.metadata.raw=e).replace(/&/g,"&amp;").replace(/"/g,"&quot;")).replace(/¨D/g,"$$").replace(/¨T/g,"¨")).replace(/\n {4}/g," ")).replace(/^([\S ]+): +([\s\S]+?)$/gm,function(e,a,r){return t.metadata.parsed[a]=r,""})}}),P.subParser("makehtml.outdent",function(e,a,r){"use strict";return e=(e=(e=r.converter._dispatch("makehtml.outdent.before",e,a,r).getText()).replace(/^(\t|[ ]{1,4})/gm,"¨0")).replace(/¨0/g,""),e=r.converter._dispatch("makehtml.outdent.after",e,a,r).getText()}),P.subParser("makehtml.paragraphs",function(e,a,r){"use strict";for(var t=(e=(e=(e=r.converter._dispatch("makehtml.paragraphs.before",e,a,r).getText()).replace(/^\n+/g,"")).replace(/\n+$/g,"")).split(/\n{2,}/g),n=[],s=t.length,i=0;i<s;i++){var o=t[i];0<=o.search(/¨(K|G)(\d+)\1/g)?n.push(o):0<=o.search(/\S/)&&(o=(o=P.subParser("makehtml.spanGamut")(o,a,r)).replace(/^([ \t]*)/g,"<p>"),o+="</p>",n.push(o))}for(s=n.length,i=0;i<s;i++){for(var l="",c=n[i],u=!1;/¨(K|G)(\d+)\1/.test(c);){var h=RegExp.$1,m=RegExp.$2;l=(l="K"===h?r.gHtmlBlocks[m]:u?P.subParser("makehtml.encodeCode")(r.ghCodeBlocks[m].text,a,r):r.ghCodeBlocks[m].codeblock).replace(/\$/g,"$$$$"),c=c.replace(/(\n\n)?¨(K|G)\d+\2(\n\n)?/,l),/^<pre\b[^>]*>\s*<code\b[^>]*>/.test(c)&&(u=!0)}n[i]=c}return e=(e=(e=n.join("\n")).replace(/^\n+/g,"")).replace(/\n+$/g,""),r.converter._dispatch("makehtml.paragraphs.after",e,a,r).getText()}),P.subParser("makehtml.runExtension",function(e,a,r,t){"use strict";return e.filter?a=e.filter(a,t.converter,r):e.regex&&((t=e.regex)instanceof RegExp||(t=new RegExp(t,"g")),a=a.replace(t,e.replace)),a}),P.subParser("makehtml.spanGamut",function(e,a,r){"use strict";return e=r.converter._dispatch("makehtml.span.before",e,a,r).getText(),e=P.subParser("makehtml.codeSpans")(e,a,r),e=P.subParser("makehtml.escapeSpecialCharsWithinTagAttributes")(e,a,r),e=P.subParser("makehtml.encodeBackslashEscapes")(e,a,r),e=P.subParser("makehtml.images")(e,a,r),e=r.converter._dispatch("smakehtml.links.before",e,a,r).getText(),e=P.subParser("makehtml.links")(e,a,r),e=r.converter._dispatch("smakehtml.links.after",e,a,r).getText(),e=P.subParser("makehtml.emoji")(e,a,r),e=P.subParser("makehtml.underline")(e,a,r),e=P.subParser("makehtml.italicsAndBold")(e,a,r),e=P.subParser("makehtml.strikethrough")(e,a,r),e=P.subParser("makehtml.ellipsis")(e,a,r),e=P.subParser("makehtml.hashHTMLSpans")(e,a,r),e=P.subParser("makehtml.encodeAmpsAndAngles")(e,a,r),a.simpleLineBreaks?/\n\n¨K/.test(e)||(e=e.replace(/\n+/g,"<br />\n")):e=e.replace(/  +\n/g,"<br />\n"),e=r.converter._dispatch("makehtml.spanGamut.after",e,a,r).getText()}),P.subParser("makehtml.strikethrough",function(e,a,r){"use strict";return a.strikethrough&&(e=(e=r.converter._dispatch("makehtml.strikethrough.before",e,a,r).getText()).replace(/(?:~){2}([\s\S]+?)(?:~){2}/g,function(e,a){return"<del>"+a+"</del>"}),e=r.converter._dispatch("makehtml.strikethrough.after",e,a,r).getText()),e}),P.subParser("makehtml.stripLinkDefinitions",function(o,l,c){"use strict";function e(e,a,r,t,n,s,i){return a=a.toLowerCase(),o.toLowerCase().split(a).length-1<2?e:(r.match(/^data:.+?\/.+?;base64,/)?c.gUrls[a]=r.replace(/\s/g,""):(r=P.helper.applyBaseUrl(l.relativePathBaseUrl,r),c.gUrls[a]=P.subParser("makehtml.encodeAmpsAndAngles")(r,l,c)),s?s+i:(i&&(c.gTitles[a]=i.replace(/"|'/g,"&quot;")),l.parseImgDimensions&&t&&n&&(c.gDimensions[a]={width:t,height:n}),""))}return o=(o=(o=(o+="¨0").replace(/^ {0,3}\[([^\]]+)]:[ \t]*\n?[ \t]*<?(data:.+?\/.+?;base64,[A-Za-z0-9+/=\n]+?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*\n?[ \t]*(?:(\n*)["|'(](.+?)["|')][ \t]*)?(?:\n\n|(?=¨0)|(?=\n\[))/gm,e)).replace(/^ {0,3}\[([^\]]+)]:[ \t]*\n?[ \t]*<?([^>\s]+)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*\n?[ \t]*(?:(\n*)["|'(](.+?)["|')][ \t]*)?(?:\n+|(?=¨0))/gm,e)).replace(/¨0/,"")}),P.subParser("makehtml.tables",function(e,y,x){"use strict";if(!y.tables)return e;function a(e){for(var a=e.split("\n"),r=0;r<a.length;++r)/^ {0,3}\|/.test(a[r])&&(a[r]=a[r].replace(/^ {0,3}\|/,"")),/\|[ \t]*$/.test(a[r])&&(a[r]=a[r].replace(/\|[ \t]*$/,"")),a[r]=P.subParser("makehtml.codeSpans")(a[r],y,x);var t,n,s,i,o,l=a[0].split("|").map(function(e){return e.trim()}),c=a[1].split("|").map(function(e){return e.trim()}),u=[],h=[],m=[],d=[];for(a.shift(),a.shift(),r=0;r<a.length;++r)""!==a[r].trim()&&u.push(a[r].split("|").map(function(e){return e.trim()}));if(l.length<c.length)return e;for(r=0;r<c.length;++r)m.push((t=c[r],/^:[ \t]*--*$/.test(t)?' style="text-align:left;"':/^--*[ \t]*:[ \t]*$/.test(t)?' style="text-align:right;"':/^:[ \t]*--*[ \t]*:$/.test(t)?' style="text-align:center;"':""));for(r=0;r<l.length;++r)P.helper.isUndefined(m[r])&&(m[r]=""),h.push((n=l[r],s=m[r],void 0,i="",n=n.trim(),"<th"+(i=y.tablesHeaderId||y.tableHeaderId?' id="'+n.replace(/ /g,"_").toLowerCase()+'"':i)+s+">"+(n=P.subParser("makehtml.spanGamut")(n,y,x))+"</th>\n"));for(r=0;r<u.length;++r){for(var g=[],p=0;p<h.length;++p)P.helper.isUndefined(u[r][p]),g.push((o=u[r][p],"<td"+m[p]+">"+P.subParser("makehtml.spanGamut")(o,y,x)+"</td>\n"));d.push(g)}for(var _=h,b=d,f="<table>\n<thead>\n<tr>\n",k=_.length,w=0;w<k;++w)f+=_[w];for(f+="</tr>\n</thead>\n<tbody>\n",w=0;w<b.length;++w){f+="<tr>\n";for(var v=0;v<k;++v)f+=b[w][v];f+="</tr>\n"}return f+="</tbody>\n</table>\n"}return e=(e=(e=(e=x.converter._dispatch("makehtml.tables.before",e,y,x).getText()).replace(/\\(\|)/g,P.helper.escapeCharactersCallback)).replace(/^ {0,3}\|?.+\|.+\n {0,3}\|?[ \t]*:?[ \t]*[-=]{2,}[ \t]*:?[ \t]*\|[ \t]*:?[ \t]*[-=]{2,}[\s\S]+?(?:\n\n|¨0)/gm,a)).replace(/^ {0,3}\|.+\|[ \t]*\n {0,3}\|[ \t]*:?[ \t]*[-=]{2,}[ \t]*:?[ \t]*\|[ \t]*\n( {0,3}\|.+\|[ \t]*\n)*(?:\n|¨0)/gm,a),e=x.converter._dispatch("makehtml.tables.after",e,y,x).getText()}),P.subParser("makehtml.underline",function(e,a,r){"use strict";return a.underline?(e=r.converter._dispatch("makehtml.underline.before",e,a,r).getText(),e=(e=a.literalMidWordUnderscores?(e=e.replace(/\b___(\S[\s\S]*?)___\b/g,function(e,a){return"<u>"+a+"</u>"})).replace(/\b__(\S[\s\S]*?)__\b/g,function(e,a){return"<u>"+a+"</u>"}):(e=e.replace(/___(\S[\s\S]*?)___/g,function(e,a){return/\S$/.test(a)?"<u>"+a+"</u>":e})).replace(/__(\S[\s\S]*?)__/g,function(e,a){return/\S$/.test(a)?"<u>"+a+"</u>":e})).replace(/(_)/g,P.helper.escapeCharactersCallback),r.converter._dispatch("makehtml.underline.after",e,a,r).getText()):e}),P.subParser("makehtml.unescapeSpecialChars",function(e,a,r){"use strict";return e=(e=r.converter._dispatch("makehtml.unescapeSpecialChars.before",e,a,r).getText()).replace(/¨E(\d+)E/g,function(e,a){a=parseInt(a);return String.fromCharCode(a)}),e=r.converter._dispatch("makehtml.unescapeSpecialChars.after",e,a,r).getText()}),P.subParser("makeMarkdown.blockquote",function(e,a){"use strict";var r="";if(e.hasChildNodes())for(var t=e.childNodes,n=t.length,s=0;s<n;++s){var i=P.subParser("makeMarkdown.node")(t[s],a);""!==i&&(r+=i)}return r="> "+(r=r.trim()).split("\n").join("\n> ")}),P.subParser("makeMarkdown.break",function(){"use strict";return"  \n"}),P.subParser("makeMarkdown.codeBlock",function(e,a){"use strict";var r=e.getAttribute("language"),e=e.getAttribute("precodenum");return"```"+r+"\n"+a.preList[e]+"\n```"}),P.subParser("makeMarkdown.codeSpan",function(e){"use strict";return"`"+e.innerHTML+"`"}),P.subParser("makeMarkdown.emphasis",function(e,a){"use strict";var r="";if(e.hasChildNodes()){r+="*";for(var t=e.childNodes,n=t.length,s=0;s<n;++s)r+=P.subParser("makeMarkdown.node")(t[s],a);r+="*"}return r}),P.subParser("makeMarkdown.header",function(e,a,r){"use strict";var r=new Array(r+1).join("#"),t="";if(e.hasChildNodes())for(var t=r+" ",n=e.childNodes,s=n.length,i=0;i<s;++i)t+=P.subParser("makeMarkdown.node")(n[i],a);return t}),P.subParser("makeMarkdown.hr",function(){"use strict";return"---"}),P.subParser("makeMarkdown.image",function(e){"use strict";var a="";return e.hasAttribute("src")&&(a=(a+="!["+e.getAttribute("alt")+"](")+"<"+e.getAttribute("src")+">",e.hasAttribute("width")&&e.hasAttribute("height")&&(a+=" ="+e.getAttribute("width")+"x"+e.getAttribute("height")),e.hasAttribute("title")&&(a+=' "'+e.getAttribute("title")+'"'),a+=")"),a}),P.subParser("makeMarkdown.input",function(e,a){"use strict";for(var r="",t=(null!==e.getAttribute("checked")?r+="[x]":r+="[ ]",e.childNodes),n=t.length,s=0;s<n;++s)r+=P.subParser("makeMarkdown.node")(t[s],a);return r}),P.subParser("makeMarkdown.links",function(e,a){"use strict";var r="";if(e.hasChildNodes()&&e.hasAttribute("href")){for(var t=e.childNodes,n=t.length,r="[",s=0;s<n;++s)r+=P.subParser("makeMarkdown.node")(t[s],a);r=(r+="](")+("<"+e.getAttribute("href")+">"),e.hasAttribute("title")&&(r+=' "'+e.getAttribute("title")+'"'),r+=")"}return r}),P.subParser("makeMarkdown.list",function(e,a,r){"use strict";var t="";if(!e.hasChildNodes())return"";for(var n=e.childNodes,s=n.length,i=e.getAttribute("start")||1,o=0;o<s;++o)void 0!==n[o].tagName&&"li"===n[o].tagName.toLowerCase()&&(t+=("ol"===r?i.toString()+". ":"- ")+P.subParser("makeMarkdown.listItem")(n[o],a),++i);return t.trim()}),P.subParser("makeMarkdown.listItem",function(e,a){"use strict";for(var r="",t=e.childNodes,n=t.length,s=0;s<n;++s)r+=P.subParser("makeMarkdown.node")(t[s],a);return/\n$/.test(r)?r=r.split("\n").join("\n    ").replace(/^ {4}$/gm,"").replace(/\n\n+/g,"\n\n"):r+="\n",r}),P.subParser("makeMarkdown.node",function(e,a,r){"use strict";r=r||!1;var t="";if(3===e.nodeType)return P.subParser("makeMarkdown.txt")(e,a);if(8===e.nodeType)return"\x3c!--"+e.data+"--\x3e\n\n";if(1!==e.nodeType)return"";switch(e.tagName.toLowerCase()){case"h1":r||(t=P.subParser("makeMarkdown.header")(e,a,1)+"\n\n");break;case"h2":r||(t=P.subParser("makeMarkdown.header")(e,a,2)+"\n\n");break;case"h3":r||(t=P.subParser("makeMarkdown.header")(e,a,3)+"\n\n");break;case"h4":r||(t=P.subParser("makeMarkdown.header")(e,a,4)+"\n\n");break;case"h5":r||(t=P.subParser("makeMarkdown.header")(e,a,5)+"\n\n");break;case"h6":r||(t=P.subParser("makeMarkdown.header")(e,a,6)+"\n\n");break;case"p":r||(t=P.subParser("makeMarkdown.paragraph")(e,a)+"\n\n");break;case"blockquote":r||(t=P.subParser("makeMarkdown.blockquote")(e,a)+"\n\n");break;case"hr":r||(t=P.subParser("makeMarkdown.hr")(e,a)+"\n\n");break;case"ol":r||(t=P.subParser("makeMarkdown.list")(e,a,"ol")+"\n\n");break;case"ul":r||(t=P.subParser("makeMarkdown.list")(e,a,"ul")+"\n\n");break;case"precode":r||(t=P.subParser("makeMarkdown.codeBlock")(e,a)+"\n\n");break;case"pre":r||(t=P.subParser("makeMarkdown.pre")(e,a)+"\n\n");break;case"table":r||(t=P.subParser("makeMarkdown.table")(e,a)+"\n\n");break;case"code":t=P.subParser("makeMarkdown.codeSpan")(e,a);break;case"em":case"i":t=P.subParser("makeMarkdown.emphasis")(e,a);break;case"strong":case"b":t=P.subParser("makeMarkdown.strong")(e,a);break;case"del":t=P.subParser("makeMarkdown.strikethrough")(e,a);break;case"a":t=P.subParser("makeMarkdown.links")(e,a);break;case"img":t=P.subParser("makeMarkdown.image")(e,a);break;case"br":t=P.subParser("makeMarkdown.break")(e,a);break;case"input":t=P.subParser("makeMarkdown.input")(e,a);break;default:t=e.outerHTML+"\n\n"}return t}),P.subParser("makeMarkdown.paragraph",function(e,a){"use strict";var r="";if(e.hasChildNodes())for(var t=e.childNodes,n=t.length,s=0;s<n;++s)r+=P.subParser("makeMarkdown.node")(t[s],a);return r=r.trim()}),P.subParser("makeMarkdown.pre",function(e,a){"use strict";e=e.getAttribute("prenum");return"<pre>"+a.preList[e]+"</pre>"}),P.subParser("makeMarkdown.strikethrough",function(e,a){"use strict";var r="";if(e.hasChildNodes()){r+="~~";for(var t=e.childNodes,n=t.length,s=0;s<n;++s)r+=P.subParser("makeMarkdown.node")(t[s],a);r+="~~"}return r}),P.subParser("makeMarkdown.strong",function(e,a){"use strict";var r="";if(e.hasChildNodes()){r+="**";for(var t=e.childNodes,n=t.length,s=0;s<n;++s)r+=P.subParser("makeMarkdown.node")(t[s],a);r+="**"}return r}),P.subParser("makeMarkdown.table",function(e,a){"use strict";for(var r="",t=[[],[]],n=e.querySelectorAll("thead>tr>th"),s=e.querySelectorAll("tbody>tr"),i=0;i<n.length;++i){var o=P.subParser("makeMarkdown.tableCell")(n[i],a),l="---";if(n[i].hasAttribute("style"))switch(n[i].getAttribute("style").toLowerCase().replace(/\s/g,"")){case"text-align:left;":l=":---";break;case"text-align:right;":l="---:";break;case"text-align:center;":l=":---:"}t[0][i]=o.trim(),t[1][i]=l}for(i=0;i<s.length;++i)for(var c=t.push([])-1,u=s[i].getElementsByTagName("td"),h=0;h<n.length;++h){var m=" ";void 0!==u[h]&&(m=P.subParser("makeMarkdown.tableCell")(u[h],a)),t[c].push(m)}var d=3;for(i=0;i<t.length;++i)for(h=0;h<t[i].length;++h){var g=t[i][h].length;d<g&&(d=g)}for(i=0;i<t.length;++i){for(h=0;h<t[i].length;++h)1===i?":"===t[i][h].slice(-1)?t[i][h]=P.helper.padEnd(t[i][h].slice(0,-1),d-1,"-")+":":t[i][h]=P.helper.padEnd(t[i][h],d,"-"):t[i][h]=P.helper.padEnd(t[i][h],d);r+="| "+t[i].join(" | ")+" |\n"}return r.trim()}),P.subParser("makeMarkdown.tableCell",function(e,a){"use strict";var r="";if(!e.hasChildNodes())return"";for(var t=e.childNodes,n=t.length,s=0;s<n;++s)r+=P.subParser("makeMarkdown.node")(t[s],a,!0);return r.trim()}),P.subParser("makeMarkdown.txt",function(e){"use strict";e=e.nodeValue;return e=(e=e.replace(/ +/g," ")).replace(/¨NBSP;/g," "),e=(e=(e=(e=(e=(e=(e=(e=(e=P.helper.unescapeHTMLEntities(e)).replace(/([*_~|`])/g,"\\$1")).replace(/^(\s*)>/g,"\\$1>")).replace(/^#/gm,"\\#")).replace(/^(\s*)([-=]{3,})(\s*)$/,"$1\\$2$3")).replace(/^( {0,3}\d+)\./gm,"$1\\.")).replace(/^( {0,3})([+-])/gm,"$1\\$2")).replace(/]([\s]*)\(/g,"\\]$1\\(")).replace(/^ {0,3}\[([\S \t]*?)]:/gm,"\\[$1]:")}),P.Converter=function(e){"use strict";var a,r,n={},o=[],l=[],c={},t=d,s={parsed:{},raw:"",format:""};for(a in e=e||{},m)m.hasOwnProperty(a)&&(n[a]=m[a]);if("object"!=typeof e)throw Error("Converter expects the passed parameter to be an object, but "+typeof e+" was passed instead.");for(r in e)e.hasOwnProperty(r)&&(n[r]=e[r]);function i(e,a){if(a=a||null,P.helper.isString(e)){if(a=e=P.helper.stdExtName(e),P.extensions[e]){console.warn("DEPRECATION WARNING: "+e+" is an old extension that uses a deprecated loading method.Please inform the developer that the extension should be updated!");var r=P.extensions[e],t=e;if("function"==typeof r&&(r=r(new P.Converter)),P.helper.isArray(r)||(r=[r]),!(t=p(r,t)).valid)throw Error(t.error);for(var n=0;n<r.length;++n)switch(r[n].type){case"lang":o.push(r[n]);break;case"output":l.push(r[n]);break;default:throw Error("Extension loader error: Type unrecognized!!!")}return}if(P.helper.isUndefined(h[e]))throw Error('Extension "'+e+'" could not be loaded. It was either not found or is not a valid extension.');e=h[e]}"function"==typeof e&&(e=e());t=p(e=P.helper.isArray(e)?e:[e],a);if(!t.valid)throw Error(t.error);for(var s=0;s<e.length;++s){switch(e[s].type){case"lang":o.push(e[s]);break;case"output":l.push(e[s])}if(e[s].hasOwnProperty("listeners"))for(var i in e[s].listeners)e[s].listeners.hasOwnProperty(i)&&u(i,e[s].listeners[i])}}function u(e,a){if(!P.helper.isString(e))throw Error("Invalid argument in converter.listen() method: name must be a string, but "+typeof e+" given");if("function"!=typeof a)throw Error("Invalid argument in converter.listen() method: callback must be a function, but "+typeof a+" given");e=e.toLowerCase(),c.hasOwnProperty(e)||(c[e]=[]),c[e].push(a)}n.extensions&&P.helper.forEach(n.extensions,i),this._dispatch=function(e,a,r,t,n){e=e.toLowerCase();var n=n||{},s=(n.converter=this,n.text=a,n.options=r,n.globals=t,new P.helper.Event(e,a,n));if(c.hasOwnProperty(e))for(var i=0;i<c[e].length;++i){var o=c[e][i](s);o&&void 0!==o&&s.setText(o)}return s},this.listen=function(e,a){return u(e,a),this},this.makeHtml=function(a){if(!a)return a;var e,r,t={gHtmlBlocks:[],gHtmlMdBlocks:[],gHtmlSpans:[],gUrls:{},gTitles:{},gDimensions:{},gListLevel:0,hashLinkCounts:{},langExtensions:o,outputModifiers:l,converter:this,ghCodeBlocks:[],metadata:{parsed:{},raw:"",format:""}};return a=(a=(a=(a=(a=a.replace(/¨/g,"¨T")).replace(/\$/g,"¨D")).replace(/\r\n/g,"\n")).replace(/\r/g,"\n")).replace(/\u00A0/g,"&nbsp;"),n.smartIndentationFix&&(r=(e=a).match(/^\s*/)[0].length,r=new RegExp("^\\s{0,"+r+"}","gm"),a=e.replace(r,"")),a="\n\n"+a+"\n\n",a=(a=P.subParser("makehtml.detab")(a,n,t)).replace(/^[ \t]+$/gm,""),P.helper.forEach(o,function(e){a=P.subParser("makehtml.runExtension")(e,a,n,t)}),a=P.subParser("makehtml.metadata")(a,n,t),a=P.subParser("makehtml.hashPreCodeTags")(a,n,t),a=P.subParser("makehtml.githubCodeBlocks")(a,n,t),a=P.subParser("makehtml.hashHTMLBlocks")(a,n,t),a=P.subParser("makehtml.hashCodeTags")(a,n,t),a=P.subParser("makehtml.stripLinkDefinitions")(a,n,t),a=P.subParser("makehtml.blockGamut")(a,n,t),a=P.subParser("makehtml.unhashHTMLSpans")(a,n,t),a=(a=(a=P.subParser("makehtml.unescapeSpecialChars")(a,n,t)).replace(/¨D/g,"$$")).replace(/¨T/g,"¨"),a=P.subParser("makehtml.completeHTMLDocument")(a,n,t),P.helper.forEach(l,function(e){a=P.subParser("makehtml.runExtension")(e,a,n,t)}),s=t.metadata,a},this.makeMarkdown=function(e){e=(e=(e=e.replace(/\r\n/g,"\n")).replace(/\r/g,"\n")).replace(/>[ \t]+</,">¨NBSP;<");for(var a=P.helper.document.createElement("div"),r=(a.innerHTML=e,{preList:function(e){for(var a=e.querySelectorAll("pre"),r=[],t=0;t<a.length;++t)if(1===a[t].childElementCount&&"code"===a[t].firstChild.tagName.toLowerCase()){var n=a[t].firstChild.innerHTML.trim(),s=a[t].firstChild.getAttribute("data-language")||"";if(""===s)for(var i=a[t].firstChild.className.split(" "),o=0;o<i.length;++o){var l=i[o].match(/^language-(.+)$/);if(null!==l){s=l[1];break}}n=P.helper.unescapeHTMLEntities(n),r.push(n),a[t].outerHTML='<precode language="'+s+'" precodenum="'+t.toString()+'"></precode>'}else r.push(a[t].innerHTML),a[t].innerHTML="",a[t].setAttribute("prenum",t.toString());return r}(a)}),t=(!function e(a){for(var r=0;r<a.childNodes.length;++r){var t=a.childNodes[r];3===t.nodeType?/\S/.test(t.nodeValue)||/^[ ]+$/.test(t.nodeValue)?(t.nodeValue=t.nodeValue.split("\n").join(" "),t.nodeValue=t.nodeValue.replace(/(\s)+/g,"$1")):(a.removeChild(t),--r):1===t.nodeType&&e(t)}}(a),a.childNodes),n="",s=0;s<t.length;s++)n+=P.subParser("makeMarkdown.node")(t[s],r);return n},this.setOption=function(e,a){n[e]=a},this.getOption=function(e){return n[e]},this.getOptions=function(){return n},this.addExtension=function(e,a){i(e,a=a||null)},this.useExtension=function(e){i(e)},this.setFlavor=function(e){if(!g.hasOwnProperty(e))throw Error(e+" flavor was not found");var a,r=g[e];for(a in t=e,r)r.hasOwnProperty(a)&&(n[a]=r[a])},this.getFlavor=function(){return t},this.removeExtension=function(e){P.helper.isArray(e)||(e=[e]);for(var a=0;a<e.length;++a){for(var r=e[a],t=0;t<o.length;++t)o[t]===r&&o.splice(t,1);for(var n=0;n<l.length;++n)l[n]===r&&l.splice(n,1)}},this.getAllExtensions=function(){return{language:o,output:l}},this.getMetadata=function(e){return e?s.raw:s.parsed},this.getMetadataFormat=function(){return s.format},this._setMetadataPair=function(e,a){s.parsed[e]=a},this._setMetadataFormat=function(e){s.format=e},this._setMetadataRaw=function(e){s.raw=e}};"function"==typeof define&&define.amd?define(function(){"use strict";return P}):"undefined"!=typeof module&&module.exports?module.exports=P:this.showdown=P}.call(this);
//# sourceMappingURL=showdown.min.js.map
;
/*! @license DOMPurify 3.0.6 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.0.6/LICENSE */
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).DOMPurify=t()}(this,(function(){"use strict";const{entries:e,setPrototypeOf:t,isFrozen:n,getPrototypeOf:o,getOwnPropertyDescriptor:r}=Object;let{freeze:i,seal:a,create:l}=Object,{apply:c,construct:s}="undefined"!=typeof Reflect&&Reflect;i||(i=function(e){return e}),a||(a=function(e){return e}),c||(c=function(e,t,n){return e.apply(t,n)}),s||(s=function(e,t){return new e(...t)});const u=N(Array.prototype.forEach),m=N(Array.prototype.pop),f=N(Array.prototype.push),p=N(String.prototype.toLowerCase),d=N(String.prototype.toString),h=N(String.prototype.match),g=N(String.prototype.replace),T=N(String.prototype.indexOf),y=N(String.prototype.trim),E=N(RegExp.prototype.test),A=(_=TypeError,function(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return s(_,t)});var _;function N(e){return function(t){for(var n=arguments.length,o=new Array(n>1?n-1:0),r=1;r<n;r++)o[r-1]=arguments[r];return c(e,t,o)}}function b(e,o){let r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:p;t&&t(e,null);let i=o.length;for(;i--;){let t=o[i];if("string"==typeof t){const e=r(t);e!==t&&(n(o)||(o[i]=e),t=e)}e[t]=!0}return e}function S(t){const n=l(null);for(const[o,i]of e(t))void 0!==r(t,o)&&(n[o]=i);return n}function R(e,t){for(;null!==e;){const n=r(e,t);if(n){if(n.get)return N(n.get);if("function"==typeof n.value)return N(n.value)}e=o(e)}return function(e){return console.warn("fallback value for",e),null}}const w=i(["a","abbr","acronym","address","area","article","aside","audio","b","bdi","bdo","big","blink","blockquote","body","br","button","canvas","caption","center","cite","code","col","colgroup","content","data","datalist","dd","decorator","del","details","dfn","dialog","dir","div","dl","dt","element","em","fieldset","figcaption","figure","font","footer","form","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","img","input","ins","kbd","label","legend","li","main","map","mark","marquee","menu","menuitem","meter","nav","nobr","ol","optgroup","option","output","p","picture","pre","progress","q","rp","rt","ruby","s","samp","section","select","shadow","small","source","spacer","span","strike","strong","style","sub","summary","sup","table","tbody","td","template","textarea","tfoot","th","thead","time","tr","track","tt","u","ul","var","video","wbr"]),D=i(["svg","a","altglyph","altglyphdef","altglyphitem","animatecolor","animatemotion","animatetransform","circle","clippath","defs","desc","ellipse","filter","font","g","glyph","glyphref","hkern","image","line","lineargradient","marker","mask","metadata","mpath","path","pattern","polygon","polyline","radialgradient","rect","stop","style","switch","symbol","text","textpath","title","tref","tspan","view","vkern"]),L=i(["feBlend","feColorMatrix","feComponentTransfer","feComposite","feConvolveMatrix","feDiffuseLighting","feDisplacementMap","feDistantLight","feDropShadow","feFlood","feFuncA","feFuncB","feFuncG","feFuncR","feGaussianBlur","feImage","feMerge","feMergeNode","feMorphology","feOffset","fePointLight","feSpecularLighting","feSpotLight","feTile","feTurbulence"]),v=i(["animate","color-profile","cursor","discard","font-face","font-face-format","font-face-name","font-face-src","font-face-uri","foreignobject","hatch","hatchpath","mesh","meshgradient","meshpatch","meshrow","missing-glyph","script","set","solidcolor","unknown","use"]),x=i(["math","menclose","merror","mfenced","mfrac","mglyph","mi","mlabeledtr","mmultiscripts","mn","mo","mover","mpadded","mphantom","mroot","mrow","ms","mspace","msqrt","mstyle","msub","msup","msubsup","mtable","mtd","mtext","mtr","munder","munderover","mprescripts"]),k=i(["maction","maligngroup","malignmark","mlongdiv","mscarries","mscarry","msgroup","mstack","msline","msrow","semantics","annotation","annotation-xml","mprescripts","none"]),C=i(["#text"]),O=i(["accept","action","align","alt","autocapitalize","autocomplete","autopictureinpicture","autoplay","background","bgcolor","border","capture","cellpadding","cellspacing","checked","cite","class","clear","color","cols","colspan","controls","controlslist","coords","crossorigin","datetime","decoding","default","dir","disabled","disablepictureinpicture","disableremoteplayback","download","draggable","enctype","enterkeyhint","face","for","headers","height","hidden","high","href","hreflang","id","inputmode","integrity","ismap","kind","label","lang","list","loading","loop","low","max","maxlength","media","method","min","minlength","multiple","muted","name","nonce","noshade","novalidate","nowrap","open","optimum","pattern","placeholder","playsinline","poster","preload","pubdate","radiogroup","readonly","rel","required","rev","reversed","role","rows","rowspan","spellcheck","scope","selected","shape","size","sizes","span","srclang","start","src","srcset","step","style","summary","tabindex","title","translate","type","usemap","valign","value","width","xmlns","slot"]),I=i(["accent-height","accumulate","additive","alignment-baseline","ascent","attributename","attributetype","azimuth","basefrequency","baseline-shift","begin","bias","by","class","clip","clippathunits","clip-path","clip-rule","color","color-interpolation","color-interpolation-filters","color-profile","color-rendering","cx","cy","d","dx","dy","diffuseconstant","direction","display","divisor","dur","edgemode","elevation","end","fill","fill-opacity","fill-rule","filter","filterunits","flood-color","flood-opacity","font-family","font-size","font-size-adjust","font-stretch","font-style","font-variant","font-weight","fx","fy","g1","g2","glyph-name","glyphref","gradientunits","gradienttransform","height","href","id","image-rendering","in","in2","k","k1","k2","k3","k4","kerning","keypoints","keysplines","keytimes","lang","lengthadjust","letter-spacing","kernelmatrix","kernelunitlength","lighting-color","local","marker-end","marker-mid","marker-start","markerheight","markerunits","markerwidth","maskcontentunits","maskunits","max","mask","media","method","mode","min","name","numoctaves","offset","operator","opacity","order","orient","orientation","origin","overflow","paint-order","path","pathlength","patterncontentunits","patterntransform","patternunits","points","preservealpha","preserveaspectratio","primitiveunits","r","rx","ry","radius","refx","refy","repeatcount","repeatdur","restart","result","rotate","scale","seed","shape-rendering","specularconstant","specularexponent","spreadmethod","startoffset","stddeviation","stitchtiles","stop-color","stop-opacity","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke","stroke-width","style","surfacescale","systemlanguage","tabindex","targetx","targety","transform","transform-origin","text-anchor","text-decoration","text-rendering","textlength","type","u1","u2","unicode","values","viewbox","visibility","version","vert-adv-y","vert-origin-x","vert-origin-y","width","word-spacing","wrap","writing-mode","xchannelselector","ychannelselector","x","x1","x2","xmlns","y","y1","y2","z","zoomandpan"]),M=i(["accent","accentunder","align","bevelled","close","columnsalign","columnlines","columnspan","denomalign","depth","dir","display","displaystyle","encoding","fence","frame","height","href","id","largeop","length","linethickness","lspace","lquote","mathbackground","mathcolor","mathsize","mathvariant","maxsize","minsize","movablelimits","notation","numalign","open","rowalign","rowlines","rowspacing","rowspan","rspace","rquote","scriptlevel","scriptminsize","scriptsizemultiplier","selection","separator","separators","stretchy","subscriptshift","supscriptshift","symmetric","voffset","width","xmlns"]),U=i(["xlink:href","xml:id","xlink:title","xml:space","xmlns:xlink"]),P=a(/\{\{[\w\W]*|[\w\W]*\}\}/gm),F=a(/<%[\w\W]*|[\w\W]*%>/gm),H=a(/\${[\w\W]*}/gm),z=a(/^data-[\-\w.\u00B7-\uFFFF]/),B=a(/^aria-[\-\w]+$/),W=a(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),G=a(/^(?:\w+script|data):/i),Y=a(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),j=a(/^html$/i);var q=Object.freeze({__proto__:null,MUSTACHE_EXPR:P,ERB_EXPR:F,TMPLIT_EXPR:H,DATA_ATTR:z,ARIA_ATTR:B,IS_ALLOWED_URI:W,IS_SCRIPT_OR_DATA:G,ATTR_WHITESPACE:Y,DOCTYPE_NAME:j});const X=function(){return"undefined"==typeof window?null:window};var K=function t(){let n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:X();const o=e=>t(e);if(o.version="3.0.6",o.removed=[],!n||!n.document||9!==n.document.nodeType)return o.isSupported=!1,o;let{document:r}=n;const a=r,c=a.currentScript,{DocumentFragment:s,HTMLTemplateElement:_,Node:N,Element:P,NodeFilter:F,NamedNodeMap:H=n.NamedNodeMap||n.MozNamedAttrMap,HTMLFormElement:z,DOMParser:B,trustedTypes:G}=n,Y=P.prototype,K=R(Y,"cloneNode"),V=R(Y,"nextSibling"),$=R(Y,"childNodes"),Z=R(Y,"parentNode");if("function"==typeof _){const e=r.createElement("template");e.content&&e.content.ownerDocument&&(r=e.content.ownerDocument)}let J,Q="";const{implementation:ee,createNodeIterator:te,createDocumentFragment:ne,getElementsByTagName:oe}=r,{importNode:re}=a;let ie={};o.isSupported="function"==typeof e&&"function"==typeof Z&&ee&&void 0!==ee.createHTMLDocument;const{MUSTACHE_EXPR:ae,ERB_EXPR:le,TMPLIT_EXPR:ce,DATA_ATTR:se,ARIA_ATTR:ue,IS_SCRIPT_OR_DATA:me,ATTR_WHITESPACE:fe}=q;let{IS_ALLOWED_URI:pe}=q,de=null;const he=b({},[...w,...D,...L,...x,...C]);let ge=null;const Te=b({},[...O,...I,...M,...U]);let ye=Object.seal(l(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),Ee=null,Ae=null,_e=!0,Ne=!0,be=!1,Se=!0,Re=!1,we=!1,De=!1,Le=!1,ve=!1,xe=!1,ke=!1,Ce=!0,Oe=!1,Ie=!0,Me=!1,Ue={},Pe=null;const Fe=b({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]);let He=null;const ze=b({},["audio","video","img","source","image","track"]);let Be=null;const We=b({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),Ge="http://www.w3.org/1998/Math/MathML",Ye="http://www.w3.org/2000/svg",je="http://www.w3.org/1999/xhtml";let qe=je,Xe=!1,Ke=null;const Ve=b({},[Ge,Ye,je],d);let $e=null;const Ze=["application/xhtml+xml","text/html"];let Je=null,Qe=null;const et=r.createElement("form"),tt=function(e){return e instanceof RegExp||e instanceof Function},nt=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(!Qe||Qe!==e){if(e&&"object"==typeof e||(e={}),e=S(e),$e=-1===Ze.indexOf(e.PARSER_MEDIA_TYPE)?"text/html":e.PARSER_MEDIA_TYPE,Je="application/xhtml+xml"===$e?d:p,de="ALLOWED_TAGS"in e?b({},e.ALLOWED_TAGS,Je):he,ge="ALLOWED_ATTR"in e?b({},e.ALLOWED_ATTR,Je):Te,Ke="ALLOWED_NAMESPACES"in e?b({},e.ALLOWED_NAMESPACES,d):Ve,Be="ADD_URI_SAFE_ATTR"in e?b(S(We),e.ADD_URI_SAFE_ATTR,Je):We,He="ADD_DATA_URI_TAGS"in e?b(S(ze),e.ADD_DATA_URI_TAGS,Je):ze,Pe="FORBID_CONTENTS"in e?b({},e.FORBID_CONTENTS,Je):Fe,Ee="FORBID_TAGS"in e?b({},e.FORBID_TAGS,Je):{},Ae="FORBID_ATTR"in e?b({},e.FORBID_ATTR,Je):{},Ue="USE_PROFILES"in e&&e.USE_PROFILES,_e=!1!==e.ALLOW_ARIA_ATTR,Ne=!1!==e.ALLOW_DATA_ATTR,be=e.ALLOW_UNKNOWN_PROTOCOLS||!1,Se=!1!==e.ALLOW_SELF_CLOSE_IN_ATTR,Re=e.SAFE_FOR_TEMPLATES||!1,we=e.WHOLE_DOCUMENT||!1,ve=e.RETURN_DOM||!1,xe=e.RETURN_DOM_FRAGMENT||!1,ke=e.RETURN_TRUSTED_TYPE||!1,Le=e.FORCE_BODY||!1,Ce=!1!==e.SANITIZE_DOM,Oe=e.SANITIZE_NAMED_PROPS||!1,Ie=!1!==e.KEEP_CONTENT,Me=e.IN_PLACE||!1,pe=e.ALLOWED_URI_REGEXP||W,qe=e.NAMESPACE||je,ye=e.CUSTOM_ELEMENT_HANDLING||{},e.CUSTOM_ELEMENT_HANDLING&&tt(e.CUSTOM_ELEMENT_HANDLING.tagNameCheck)&&(ye.tagNameCheck=e.CUSTOM_ELEMENT_HANDLING.tagNameCheck),e.CUSTOM_ELEMENT_HANDLING&&tt(e.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)&&(ye.attributeNameCheck=e.CUSTOM_ELEMENT_HANDLING.attributeNameCheck),e.CUSTOM_ELEMENT_HANDLING&&"boolean"==typeof e.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements&&(ye.allowCustomizedBuiltInElements=e.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements),Re&&(Ne=!1),xe&&(ve=!0),Ue&&(de=b({},C),ge=[],!0===Ue.html&&(b(de,w),b(ge,O)),!0===Ue.svg&&(b(de,D),b(ge,I),b(ge,U)),!0===Ue.svgFilters&&(b(de,L),b(ge,I),b(ge,U)),!0===Ue.mathMl&&(b(de,x),b(ge,M),b(ge,U))),e.ADD_TAGS&&(de===he&&(de=S(de)),b(de,e.ADD_TAGS,Je)),e.ADD_ATTR&&(ge===Te&&(ge=S(ge)),b(ge,e.ADD_ATTR,Je)),e.ADD_URI_SAFE_ATTR&&b(Be,e.ADD_URI_SAFE_ATTR,Je),e.FORBID_CONTENTS&&(Pe===Fe&&(Pe=S(Pe)),b(Pe,e.FORBID_CONTENTS,Je)),Ie&&(de["#text"]=!0),we&&b(de,["html","head","body"]),de.table&&(b(de,["tbody"]),delete Ee.tbody),e.TRUSTED_TYPES_POLICY){if("function"!=typeof e.TRUSTED_TYPES_POLICY.createHTML)throw A('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');if("function"!=typeof e.TRUSTED_TYPES_POLICY.createScriptURL)throw A('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');J=e.TRUSTED_TYPES_POLICY,Q=J.createHTML("")}else void 0===J&&(J=function(e,t){if("object"!=typeof e||"function"!=typeof e.createPolicy)return null;let n=null;const o="data-tt-policy-suffix";t&&t.hasAttribute(o)&&(n=t.getAttribute(o));const r="dompurify"+(n?"#"+n:"");try{return e.createPolicy(r,{createHTML:e=>e,createScriptURL:e=>e})}catch(e){return console.warn("TrustedTypes policy "+r+" could not be created."),null}}(G,c)),null!==J&&"string"==typeof Q&&(Q=J.createHTML(""));i&&i(e),Qe=e}},ot=b({},["mi","mo","mn","ms","mtext"]),rt=b({},["foreignobject","desc","title","annotation-xml"]),it=b({},["title","style","font","a","script"]),at=b({},[...D,...L,...v]),lt=b({},[...x,...k]),ct=function(e){f(o.removed,{element:e});try{e.parentNode.removeChild(e)}catch(t){e.remove()}},st=function(e,t){try{f(o.removed,{attribute:t.getAttributeNode(e),from:t})}catch(e){f(o.removed,{attribute:null,from:t})}if(t.removeAttribute(e),"is"===e&&!ge[e])if(ve||xe)try{ct(t)}catch(e){}else try{t.setAttribute(e,"")}catch(e){}},ut=function(e){let t=null,n=null;if(Le)e="<remove></remove>"+e;else{const t=h(e,/^[\r\n\t ]+/);n=t&&t[0]}"application/xhtml+xml"===$e&&qe===je&&(e='<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>'+e+"</body></html>");const o=J?J.createHTML(e):e;if(qe===je)try{t=(new B).parseFromString(o,$e)}catch(e){}if(!t||!t.documentElement){t=ee.createDocument(qe,"template",null);try{t.documentElement.innerHTML=Xe?Q:o}catch(e){}}const i=t.body||t.documentElement;return e&&n&&i.insertBefore(r.createTextNode(n),i.childNodes[0]||null),qe===je?oe.call(t,we?"html":"body")[0]:we?t.documentElement:i},mt=function(e){return te.call(e.ownerDocument||e,e,F.SHOW_ELEMENT|F.SHOW_COMMENT|F.SHOW_TEXT,null)},ft=function(e){return"function"==typeof N&&e instanceof N},pt=function(e,t,n){ie[e]&&u(ie[e],(e=>{e.call(o,t,n,Qe)}))},dt=function(e){let t=null;if(pt("beforeSanitizeElements",e,null),(n=e)instanceof z&&("string"!=typeof n.nodeName||"string"!=typeof n.textContent||"function"!=typeof n.removeChild||!(n.attributes instanceof H)||"function"!=typeof n.removeAttribute||"function"!=typeof n.setAttribute||"string"!=typeof n.namespaceURI||"function"!=typeof n.insertBefore||"function"!=typeof n.hasChildNodes))return ct(e),!0;var n;const r=Je(e.nodeName);if(pt("uponSanitizeElement",e,{tagName:r,allowedTags:de}),e.hasChildNodes()&&!ft(e.firstElementChild)&&E(/<[/\w]/g,e.innerHTML)&&E(/<[/\w]/g,e.textContent))return ct(e),!0;if(!de[r]||Ee[r]){if(!Ee[r]&&gt(r)){if(ye.tagNameCheck instanceof RegExp&&E(ye.tagNameCheck,r))return!1;if(ye.tagNameCheck instanceof Function&&ye.tagNameCheck(r))return!1}if(Ie&&!Pe[r]){const t=Z(e)||e.parentNode,n=$(e)||e.childNodes;if(n&&t){for(let o=n.length-1;o>=0;--o)t.insertBefore(K(n[o],!0),V(e))}}return ct(e),!0}return e instanceof P&&!function(e){let t=Z(e);t&&t.tagName||(t={namespaceURI:qe,tagName:"template"});const n=p(e.tagName),o=p(t.tagName);return!!Ke[e.namespaceURI]&&(e.namespaceURI===Ye?t.namespaceURI===je?"svg"===n:t.namespaceURI===Ge?"svg"===n&&("annotation-xml"===o||ot[o]):Boolean(at[n]):e.namespaceURI===Ge?t.namespaceURI===je?"math"===n:t.namespaceURI===Ye?"math"===n&&rt[o]:Boolean(lt[n]):e.namespaceURI===je?!(t.namespaceURI===Ye&&!rt[o])&&!(t.namespaceURI===Ge&&!ot[o])&&!lt[n]&&(it[n]||!at[n]):!("application/xhtml+xml"!==$e||!Ke[e.namespaceURI]))}(e)?(ct(e),!0):"noscript"!==r&&"noembed"!==r&&"noframes"!==r||!E(/<\/no(script|embed|frames)/i,e.innerHTML)?(Re&&3===e.nodeType&&(t=e.textContent,u([ae,le,ce],(e=>{t=g(t,e," ")})),e.textContent!==t&&(f(o.removed,{element:e.cloneNode()}),e.textContent=t)),pt("afterSanitizeElements",e,null),!1):(ct(e),!0)},ht=function(e,t,n){if(Ce&&("id"===t||"name"===t)&&(n in r||n in et))return!1;if(Ne&&!Ae[t]&&E(se,t));else if(_e&&E(ue,t));else if(!ge[t]||Ae[t]){if(!(gt(e)&&(ye.tagNameCheck instanceof RegExp&&E(ye.tagNameCheck,e)||ye.tagNameCheck instanceof Function&&ye.tagNameCheck(e))&&(ye.attributeNameCheck instanceof RegExp&&E(ye.attributeNameCheck,t)||ye.attributeNameCheck instanceof Function&&ye.attributeNameCheck(t))||"is"===t&&ye.allowCustomizedBuiltInElements&&(ye.tagNameCheck instanceof RegExp&&E(ye.tagNameCheck,n)||ye.tagNameCheck instanceof Function&&ye.tagNameCheck(n))))return!1}else if(Be[t]);else if(E(pe,g(n,fe,"")));else if("src"!==t&&"xlink:href"!==t&&"href"!==t||"script"===e||0!==T(n,"data:")||!He[e]){if(be&&!E(me,g(n,fe,"")));else if(n)return!1}else;return!0},gt=function(e){return e.indexOf("-")>0},Tt=function(e){pt("beforeSanitizeAttributes",e,null);const{attributes:t}=e;if(!t)return;const n={attrName:"",attrValue:"",keepAttr:!0,allowedAttributes:ge};let r=t.length;for(;r--;){const i=t[r],{name:a,namespaceURI:l,value:c}=i,s=Je(a);let f="value"===a?c:y(c);if(n.attrName=s,n.attrValue=f,n.keepAttr=!0,n.forceKeepAttr=void 0,pt("uponSanitizeAttribute",e,n),f=n.attrValue,n.forceKeepAttr)continue;if(st(a,e),!n.keepAttr)continue;if(!Se&&E(/\/>/i,f)){st(a,e);continue}Re&&u([ae,le,ce],(e=>{f=g(f,e," ")}));const p=Je(e.nodeName);if(ht(p,s,f)){if(!Oe||"id"!==s&&"name"!==s||(st(a,e),f="user-content-"+f),J&&"object"==typeof G&&"function"==typeof G.getAttributeType)if(l);else switch(G.getAttributeType(p,s)){case"TrustedHTML":f=J.createHTML(f);break;case"TrustedScriptURL":f=J.createScriptURL(f)}try{l?e.setAttributeNS(l,a,f):e.setAttribute(a,f),m(o.removed)}catch(e){}}}pt("afterSanitizeAttributes",e,null)},yt=function e(t){let n=null;const o=mt(t);for(pt("beforeSanitizeShadowDOM",t,null);n=o.nextNode();)pt("uponSanitizeShadowNode",n,null),dt(n)||(n.content instanceof s&&e(n.content),Tt(n));pt("afterSanitizeShadowDOM",t,null)};return o.sanitize=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=null,r=null,i=null,l=null;if(Xe=!e,Xe&&(e="\x3c!--\x3e"),"string"!=typeof e&&!ft(e)){if("function"!=typeof e.toString)throw A("toString is not a function");if("string"!=typeof(e=e.toString()))throw A("dirty is not a string, aborting")}if(!o.isSupported)return e;if(De||nt(t),o.removed=[],"string"==typeof e&&(Me=!1),Me){if(e.nodeName){const t=Je(e.nodeName);if(!de[t]||Ee[t])throw A("root node is forbidden and cannot be sanitized in-place")}}else if(e instanceof N)n=ut("\x3c!----\x3e"),r=n.ownerDocument.importNode(e,!0),1===r.nodeType&&"BODY"===r.nodeName||"HTML"===r.nodeName?n=r:n.appendChild(r);else{if(!ve&&!Re&&!we&&-1===e.indexOf("<"))return J&&ke?J.createHTML(e):e;if(n=ut(e),!n)return ve?null:ke?Q:""}n&&Le&&ct(n.firstChild);const c=mt(Me?e:n);for(;i=c.nextNode();)dt(i)||(i.content instanceof s&&yt(i.content),Tt(i));if(Me)return e;if(ve){if(xe)for(l=ne.call(n.ownerDocument);n.firstChild;)l.appendChild(n.firstChild);else l=n;return(ge.shadowroot||ge.shadowrootmode)&&(l=re.call(a,l,!0)),l}let m=we?n.outerHTML:n.innerHTML;return we&&de["!doctype"]&&n.ownerDocument&&n.ownerDocument.doctype&&n.ownerDocument.doctype.name&&E(j,n.ownerDocument.doctype.name)&&(m="<!DOCTYPE "+n.ownerDocument.doctype.name+">\n"+m),Re&&u([ae,le,ce],(e=>{m=g(m,e," ")})),J&&ke?J.createHTML(m):m},o.setConfig=function(){nt(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}),De=!0},o.clearConfig=function(){Qe=null,De=!1},o.isValidAttribute=function(e,t,n){Qe||nt({});const o=Je(e),r=Je(t);return ht(o,r,n)},o.addHook=function(e,t){"function"==typeof t&&(ie[e]=ie[e]||[],f(ie[e],t))},o.removeHook=function(e){if(ie[e])return m(ie[e])},o.removeHooks=function(e){ie[e]&&(ie[e]=[])},o.removeAllHooks=function(){ie={}},o}();return K}));
//# sourceMappingURL=purify.min.js.map
;
/**
 * SidebarIndicator Class
 * -----------------------------------------------------------------------------
 * A utility class for managing sidebar navigation indicators in a web interface.
 * This class dynamically highlights sidebar indicators based on the scroll position
 * of the associated content sections in the viewport. It supports manual selection
 * of indicators and automatically updates active indicators during scrolling unless
 * manually overridden.
 *
 * The class constructor accepts an optional `idPrefix` to filter section elements
 * by their `id` attribute, allowing flexibility in tying sidebar indicators to specific
 * sections of content.
 *
 * Author: Zach Yazzie
 * Date: January, 2024
 * Modified: April 12, 2024
 *
 * Usage:
 * -----------------------------------------------------------------------------
 * Instantiate the SidebarIndicator with a specific ID prefix if needed:
 * const sidebar = new SidebarIndicator('customPrefix');
 *
 * The default prefix is 'sec', which matches sections like <section id="sec-1">.
 *
 */
class SidebarIndicator {
	constructor(idPrefix = 'sec') {
		this.indicators = $('.sidebar-indicator');
		this.sections = $(`section[id*="${idPrefix}-"]`);
		this.bindEvents();
		this.updateIndicatorColorsOnLoad();
		this.enableTooltips();
	}

	bindEvents() {
		this.indicators.on('click', (event) => {
			this.indicators.removeClass('active-indicator');
			this.indicators.trigger("blur");
			$(event.currentTarget).addClass('active-indicator');
		});

		$(window).on('scroll', () => {
			this.updateIndicatorColors();
		});
	}

	updateIndicatorColors() {
		let closestSection = null;
		let minDistance = Number.MAX_VALUE;

		this.sections.each((_, section) => {
			const distance = Math.abs($(section).offset().top - $(window).scrollTop());
			if (distance < minDistance) {
				minDistance = distance;
				closestSection = section;
			}
		});

		if (closestSection) {
			const sectionId = $(closestSection).attr('id');
			this.indicators.removeClass('active-indicator');
			this.indicators.filter((_, indicator) => {
				return $(indicator).attr('href') === `#${sectionId}`;
			}).addClass('active-indicator');
		}
	}

	updateIndicatorColorsOnLoad() {
		$(window).on('load', () => this.updateIndicatorColors());
	}

	enableTooltips() {
		$('[data-toggle="tooltip"]').tooltip({
			trigger: 'hover'
		});
	}

}
;
/**
 *
 * Social Media Share Popup Plugin
 * -----------------------------------------------------------------------------
 * A jQuery plugin that facilitates social media sharing. This plugin attaches to
 * elements with the class `share-btn` and configures click events to open a popup
 * window centered on the screen. The popup window is pre-populated with share
 * information tailored to the social media network specified in the element's
 * data attributes, such as Twitter or Facebook.
 *
 * Author: Zach Yazzie
 * Date: April 12, 2024
 * Modified: April 12, 2024
 *
 * Usage:
 * -----------------------------------------------------------------------------
 * Activate the plugin on any element intended to serve as a share button by placing
 * placing the following wthin the document.ready() on the needed view:
 * $('.share-btn').socialShare();
 *
 * Optionally, customize the popup dimensions by passing an options object with
 * width and height properties:
 * $('.share-btn').socialShare({ width: 500, height: 300 });
 *
 * ToDo (Can be removed in once complete):
 * -----------------------------------------------------------------------------
 * [] Need to remove jquery.prettySocial.js
 * [] Need to remove prettySocial() from all .js files
 * [] Need to remove fb-Share function in Site.js
 */

class SocialShare {
	constructor(selector, options = { width: 600, height: 400 }) {
		this.elements = document.querySelectorAll(selector);
		this.options = options;
		this.init();
	}

	init() {
		this.elements.forEach(element => {
			element.addEventListener('click', (e) => this.handleShareClick(e));
		});
	}

	handleShareClick(e) {
		e.preventDefault();
		const network = e.target.dataset.network;
		const url = e.target.dataset.url;
		let shareUrl = '';

		switch (network) {
			case 'twitter':
				shareUrl = `https://twitter.com/intent/tweet?url=${encodeURIComponent(url)}&text=${encodeURIComponent(e.target.dataset.text)}`;
				break;
			case 'facebook':
				shareUrl = `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(url)}`;
				break;
			case 'pinterest':
				const media = encodeURIComponent(e.target.dataset.media);
				const description = encodeURIComponent(e.target.dataset.description);
				shareUrl = `https://www.pinterest.com/pin/create/button/?url=${encodeURIComponent(url)}&media=${media}&description=${description}`;
				break;
		}

		this.openPopup(shareUrl, this.options.width, this.options.height);
	}

	openPopup(url, width, height) {
		const isMobile = /Android|IEMobile|BlackBerry|iPhone|iPad|iPod|Opera Mini/i.test(navigator.userAgent);
		if (isMobile) {
			// Open in a new tab for mobile devices
			window.open(url, '_blank');
		} else {
			// Standard popup behavior for non-mobile devices
			const left = (window.screen.width / 2) - (width / 2);
			const top = (window.screen.height / 2) - (height / 2);
			window.open(url, 'SocialShare', `status=no, height=${height}, width=${width}, resizable=yes, left=${left}, top=${top}, screenX=${left}, screenY=${top}, toolbar=no, menubar=no, scrollbars=no, location=no, directories=no`);
		}
	}
}
;
