/* Minification failed. Returning unminified contents.
(5100,43-44): run-time error JS1013: Syntax error in regular expression: ;
(1814,9-14): run-time error JS1298: Assignment to constant: DEBUG
 */
//! moment.js
//! version : 2.14.1
//! authors : Tim Wood, Iskren Chernev, Moment.js contributors
//! license : MIT
//! momentjs.com
!function(a,b){"object"==typeof exports&&"undefined"!=typeof module?module.exports=b():"function"==typeof define&&define.amd?define(b):a.moment=b()}(this,function(){"use strict";function a(){return md.apply(null,arguments)}
// This is done to register the method called with moment()
// without creating circular dependencies.
function b(a){md=a}function c(a){return a instanceof Array||"[object Array]"===Object.prototype.toString.call(a)}function d(a){return"[object Object]"===Object.prototype.toString.call(a)}function e(a){var b;for(b in a)
// even if its not own property I'd still call it non-empty
return!1;return!0}function f(a){return a instanceof Date||"[object Date]"===Object.prototype.toString.call(a)}function g(a,b){var c,d=[];for(c=0;c<a.length;++c)d.push(b(a[c],c));return d}function h(a,b){return Object.prototype.hasOwnProperty.call(a,b)}function i(a,b){for(var c in b)h(b,c)&&(a[c]=b[c]);return h(b,"toString")&&(a.toString=b.toString),h(b,"valueOf")&&(a.valueOf=b.valueOf),a}function j(a,b,c,d){return qb(a,b,c,d,!0).utc()}function k(){
// We need to deep clone this object.
return{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1,parsedDateParts:[],meridiem:null}}function l(a){return null==a._pf&&(a._pf=k()),a._pf}function m(a){if(null==a._isValid){var b=l(a),c=nd.call(b.parsedDateParts,function(a){return null!=a});a._isValid=!isNaN(a._d.getTime())&&b.overflow<0&&!b.empty&&!b.invalidMonth&&!b.invalidWeekday&&!b.nullInput&&!b.invalidFormat&&!b.userInvalidated&&(!b.meridiem||b.meridiem&&c),a._strict&&(a._isValid=a._isValid&&0===b.charsLeftOver&&0===b.unusedTokens.length&&void 0===b.bigHour)}return a._isValid}function n(a){var b=j(NaN);return null!=a?i(l(b),a):l(b).userInvalidated=!0,b}function o(a){return void 0===a}function p(a,b){var c,d,e;if(o(b._isAMomentObject)||(a._isAMomentObject=b._isAMomentObject),o(b._i)||(a._i=b._i),o(b._f)||(a._f=b._f),o(b._l)||(a._l=b._l),o(b._strict)||(a._strict=b._strict),o(b._tzm)||(a._tzm=b._tzm),o(b._isUTC)||(a._isUTC=b._isUTC),o(b._offset)||(a._offset=b._offset),o(b._pf)||(a._pf=l(b)),o(b._locale)||(a._locale=b._locale),od.length>0)for(c in od)d=od[c],e=b[d],o(e)||(a[d]=e);return a}
// Moment prototype object
function q(b){p(this,b),this._d=new Date(null!=b._d?b._d.getTime():NaN),pd===!1&&(pd=!0,a.updateOffset(this),pd=!1)}function r(a){return a instanceof q||null!=a&&null!=a._isAMomentObject}function s(a){return 0>a?Math.ceil(a)||0:Math.floor(a)}function t(a){var b=+a,c=0;return 0!==b&&isFinite(b)&&(c=s(b)),c}
// compare two arrays, return the number of differences
function u(a,b,c){var d,e=Math.min(a.length,b.length),f=Math.abs(a.length-b.length),g=0;for(d=0;e>d;d++)(c&&a[d]!==b[d]||!c&&t(a[d])!==t(b[d]))&&g++;return g+f}function v(b){a.suppressDeprecationWarnings===!1&&"undefined"!=typeof console&&console.warn&&console.warn("Deprecation warning: "+b)}function w(b,c){var d=!0;return i(function(){return null!=a.deprecationHandler&&a.deprecationHandler(null,b),d&&(v(b+"\nArguments: "+Array.prototype.slice.call(arguments).join(", ")+"\n"+(new Error).stack),d=!1),c.apply(this,arguments)},c)}function x(b,c){null!=a.deprecationHandler&&a.deprecationHandler(b,c),qd[b]||(v(c),qd[b]=!0)}function y(a){return a instanceof Function||"[object Function]"===Object.prototype.toString.call(a)}function z(a){var b,c;for(c in a)b=a[c],y(b)?this[c]=b:this["_"+c]=b;this._config=a,
// Lenient ordinal parsing accepts just a number in addition to
// number + (possibly) stuff coming from _ordinalParseLenient.
this._ordinalParseLenient=new RegExp(this._ordinalParse.source+"|"+/\d{1,2}/.source)}function A(a,b){var c,e=i({},a);for(c in b)h(b,c)&&(d(a[c])&&d(b[c])?(e[c]={},i(e[c],a[c]),i(e[c],b[c])):null!=b[c]?e[c]=b[c]:delete e[c]);for(c in a)h(a,c)&&!h(b,c)&&d(a[c])&&(
// make sure changes to properties don't modify parent config
e[c]=i({},e[c]));return e}function B(a){null!=a&&this.set(a)}function C(a,b,c){var d=this._calendar[a]||this._calendar.sameElse;return y(d)?d.call(b,c):d}function D(a){var b=this._longDateFormat[a],c=this._longDateFormat[a.toUpperCase()];return b||!c?b:(this._longDateFormat[a]=c.replace(/MMMM|MM|DD|dddd/g,function(a){return a.slice(1)}),this._longDateFormat[a])}function E(){return this._invalidDate}function F(a){return this._ordinal.replace("%d",a)}function G(a,b,c,d){var e=this._relativeTime[c];return y(e)?e(a,b,c,d):e.replace(/%d/i,a)}function H(a,b){var c=this._relativeTime[a>0?"future":"past"];return y(c)?c(b):c.replace(/%s/i,b)}function I(a,b){var c=a.toLowerCase();zd[c]=zd[c+"s"]=zd[b]=a}function J(a){return"string"==typeof a?zd[a]||zd[a.toLowerCase()]:void 0}function K(a){var b,c,d={};for(c in a)h(a,c)&&(b=J(c),b&&(d[b]=a[c]));return d}function L(a,b){Ad[a]=b}function M(a){var b=[];for(var c in a)b.push({unit:c,priority:Ad[c]});return b.sort(function(a,b){return a.priority-b.priority}),b}function N(b,c){return function(d){return null!=d?(P(this,b,d),a.updateOffset(this,c),this):O(this,b)}}function O(a,b){return a.isValid()?a._d["get"+(a._isUTC?"UTC":"")+b]():NaN}function P(a,b,c){a.isValid()&&a._d["set"+(a._isUTC?"UTC":"")+b](c)}
// MOMENTS
function Q(a){return a=J(a),y(this[a])?this[a]():this}function R(a,b){if("object"==typeof a){a=K(a);for(var c=M(a),d=0;d<c.length;d++)this[c[d].unit](a[c[d].unit])}else if(a=J(a),y(this[a]))return this[a](b);return this}function S(a,b,c){var d=""+Math.abs(a),e=b-d.length,f=a>=0;return(f?c?"+":"":"-")+Math.pow(10,Math.max(0,e)).toString().substr(1)+d}
// token:    'M'
// padded:   ['MM', 2]
// ordinal:  'Mo'
// callback: function () { this.month() + 1 }
function T(a,b,c,d){var e=d;"string"==typeof d&&(e=function(){return this[d]()}),a&&(Ed[a]=e),b&&(Ed[b[0]]=function(){return S(e.apply(this,arguments),b[1],b[2])}),c&&(Ed[c]=function(){return this.localeData().ordinal(e.apply(this,arguments),a)})}function U(a){return a.match(/\[[\s\S]/)?a.replace(/^\[|\]$/g,""):a.replace(/\\/g,"")}function V(a){var b,c,d=a.match(Bd);for(b=0,c=d.length;c>b;b++)Ed[d[b]]?d[b]=Ed[d[b]]:d[b]=U(d[b]);return function(b){var e,f="";for(e=0;c>e;e++)f+=d[e]instanceof Function?d[e].call(b,a):d[e];return f}}
// format date using native date object
function W(a,b){return a.isValid()?(b=X(b,a.localeData()),Dd[b]=Dd[b]||V(b),Dd[b](a)):a.localeData().invalidDate()}function X(a,b){function c(a){return b.longDateFormat(a)||a}var d=5;for(Cd.lastIndex=0;d>=0&&Cd.test(a);)a=a.replace(Cd,c),Cd.lastIndex=0,d-=1;return a}function Y(a,b,c){Wd[a]=y(b)?b:function(a,d){return a&&c?c:b}}function Z(a,b){return h(Wd,a)?Wd[a](b._strict,b._locale):new RegExp($(a))}
// Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
function $(a){return _(a.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(a,b,c,d,e){return b||c||d||e}))}function _(a){return a.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function aa(a,b){var c,d=b;for("string"==typeof a&&(a=[a]),"number"==typeof b&&(d=function(a,c){c[b]=t(a)}),c=0;c<a.length;c++)Xd[a[c]]=d}function ba(a,b){aa(a,function(a,c,d,e){d._w=d._w||{},b(a,d._w,d,e)})}function ca(a,b,c){null!=b&&h(Xd,a)&&Xd[a](b,c._a,c,a)}function da(a,b){return new Date(Date.UTC(a,b+1,0)).getUTCDate()}function ea(a,b){return c(this._months)?this._months[a.month()]:this._months[(this._months.isFormat||fe).test(b)?"format":"standalone"][a.month()]}function fa(a,b){return c(this._monthsShort)?this._monthsShort[a.month()]:this._monthsShort[fe.test(b)?"format":"standalone"][a.month()]}function ga(a,b,c){var d,e,f,g=a.toLocaleLowerCase();if(!this._monthsParse)for(
// this is not used
this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[],d=0;12>d;++d)f=j([2e3,d]),this._shortMonthsParse[d]=this.monthsShort(f,"").toLocaleLowerCase(),this._longMonthsParse[d]=this.months(f,"").toLocaleLowerCase();return c?"MMM"===b?(e=sd.call(this._shortMonthsParse,g),-1!==e?e:null):(e=sd.call(this._longMonthsParse,g),-1!==e?e:null):"MMM"===b?(e=sd.call(this._shortMonthsParse,g),-1!==e?e:(e=sd.call(this._longMonthsParse,g),-1!==e?e:null)):(e=sd.call(this._longMonthsParse,g),-1!==e?e:(e=sd.call(this._shortMonthsParse,g),-1!==e?e:null))}function ha(a,b,c){var d,e,f;if(this._monthsParseExact)return ga.call(this,a,b,c);
// TODO: add sorting
// Sorting makes sure if one month (or abbr) is a prefix of another
// see sorting in computeMonthsParse
for(this._monthsParse||(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[]),d=0;12>d;d++){
// test the regex
if(e=j([2e3,d]),c&&!this._longMonthsParse[d]&&(this._longMonthsParse[d]=new RegExp("^"+this.months(e,"").replace(".","")+"$","i"),this._shortMonthsParse[d]=new RegExp("^"+this.monthsShort(e,"").replace(".","")+"$","i")),c||this._monthsParse[d]||(f="^"+this.months(e,"")+"|^"+this.monthsShort(e,""),this._monthsParse[d]=new RegExp(f.replace(".",""),"i")),c&&"MMMM"===b&&this._longMonthsParse[d].test(a))return d;if(c&&"MMM"===b&&this._shortMonthsParse[d].test(a))return d;if(!c&&this._monthsParse[d].test(a))return d}}
// MOMENTS
function ia(a,b){var c;if(!a.isValid())
// No op
return a;if("string"==typeof b)if(/^\d+$/.test(b))b=t(b);else
// TODO: Another silent failure?
if(b=a.localeData().monthsParse(b),"number"!=typeof b)return a;return c=Math.min(a.date(),da(a.year(),b)),a._d["set"+(a._isUTC?"UTC":"")+"Month"](b,c),a}function ja(b){return null!=b?(ia(this,b),a.updateOffset(this,!0),this):O(this,"Month")}function ka(){return da(this.year(),this.month())}function la(a){return this._monthsParseExact?(h(this,"_monthsRegex")||na.call(this),a?this._monthsShortStrictRegex:this._monthsShortRegex):(h(this,"_monthsShortRegex")||(this._monthsShortRegex=ie),this._monthsShortStrictRegex&&a?this._monthsShortStrictRegex:this._monthsShortRegex)}function ma(a){return this._monthsParseExact?(h(this,"_monthsRegex")||na.call(this),a?this._monthsStrictRegex:this._monthsRegex):(h(this,"_monthsRegex")||(this._monthsRegex=je),this._monthsStrictRegex&&a?this._monthsStrictRegex:this._monthsRegex)}function na(){function a(a,b){return b.length-a.length}var b,c,d=[],e=[],f=[];for(b=0;12>b;b++)c=j([2e3,b]),d.push(this.monthsShort(c,"")),e.push(this.months(c,"")),f.push(this.months(c,"")),f.push(this.monthsShort(c,""));for(
// Sorting makes sure if one month (or abbr) is a prefix of another it
// will match the longer piece.
d.sort(a),e.sort(a),f.sort(a),b=0;12>b;b++)d[b]=_(d[b]),e[b]=_(e[b]);for(b=0;24>b;b++)f[b]=_(f[b]);this._monthsRegex=new RegExp("^("+f.join("|")+")","i"),this._monthsShortRegex=this._monthsRegex,this._monthsStrictRegex=new RegExp("^("+e.join("|")+")","i"),this._monthsShortStrictRegex=new RegExp("^("+d.join("|")+")","i")}
// HELPERS
function oa(a){return pa(a)?366:365}function pa(a){return a%4===0&&a%100!==0||a%400===0}function qa(){return pa(this.year())}function ra(a,b,c,d,e,f,g){
//can't just apply() to create a date:
//http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply
var h=new Date(a,b,c,d,e,f,g);
//the date constructor remaps years 0-99 to 1900-1999
return 100>a&&a>=0&&isFinite(h.getFullYear())&&h.setFullYear(a),h}function sa(a){var b=new Date(Date.UTC.apply(null,arguments));
//the Date.UTC function remaps years 0-99 to 1900-1999
return 100>a&&a>=0&&isFinite(b.getUTCFullYear())&&b.setUTCFullYear(a),b}
// start-of-first-week - start-of-year
function ta(a,b,c){var// first-week day -- which january is always in the first week (4 for iso, 1 for other)
d=7+b-c,
// first-week day local weekday -- which local weekday is fwd
e=(7+sa(a,0,d).getUTCDay()-b)%7;return-e+d-1}
//http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
function ua(a,b,c,d,e){var f,g,h=(7+c-d)%7,i=ta(a,d,e),j=1+7*(b-1)+h+i;return 0>=j?(f=a-1,g=oa(f)+j):j>oa(a)?(f=a+1,g=j-oa(a)):(f=a,g=j),{year:f,dayOfYear:g}}function va(a,b,c){var d,e,f=ta(a.year(),b,c),g=Math.floor((a.dayOfYear()-f-1)/7)+1;return 1>g?(e=a.year()-1,d=g+wa(e,b,c)):g>wa(a.year(),b,c)?(d=g-wa(a.year(),b,c),e=a.year()+1):(e=a.year(),d=g),{week:d,year:e}}function wa(a,b,c){var d=ta(a,b,c),e=ta(a+1,b,c);return(oa(a)-d+e)/7}
// HELPERS
// LOCALES
function xa(a){return va(a,this._week.dow,this._week.doy).week}function ya(){return this._week.dow}function za(){return this._week.doy}
// MOMENTS
function Aa(a){var b=this.localeData().week(this);return null==a?b:this.add(7*(a-b),"d")}function Ba(a){var b=va(this,1,4).week;return null==a?b:this.add(7*(a-b),"d")}
// HELPERS
function Ca(a,b){return"string"!=typeof a?a:isNaN(a)?(a=b.weekdaysParse(a),"number"==typeof a?a:null):parseInt(a,10)}function Da(a,b){return"string"==typeof a?b.weekdaysParse(a)%7||7:isNaN(a)?null:a}function Ea(a,b){return c(this._weekdays)?this._weekdays[a.day()]:this._weekdays[this._weekdays.isFormat.test(b)?"format":"standalone"][a.day()]}function Fa(a){return this._weekdaysShort[a.day()]}function Ga(a){return this._weekdaysMin[a.day()]}function Ha(a,b,c){var d,e,f,g=a.toLocaleLowerCase();if(!this._weekdaysParse)for(this._weekdaysParse=[],this._shortWeekdaysParse=[],this._minWeekdaysParse=[],d=0;7>d;++d)f=j([2e3,1]).day(d),this._minWeekdaysParse[d]=this.weekdaysMin(f,"").toLocaleLowerCase(),this._shortWeekdaysParse[d]=this.weekdaysShort(f,"").toLocaleLowerCase(),this._weekdaysParse[d]=this.weekdays(f,"").toLocaleLowerCase();return c?"dddd"===b?(e=sd.call(this._weekdaysParse,g),-1!==e?e:null):"ddd"===b?(e=sd.call(this._shortWeekdaysParse,g),-1!==e?e:null):(e=sd.call(this._minWeekdaysParse,g),-1!==e?e:null):"dddd"===b?(e=sd.call(this._weekdaysParse,g),-1!==e?e:(e=sd.call(this._shortWeekdaysParse,g),-1!==e?e:(e=sd.call(this._minWeekdaysParse,g),-1!==e?e:null))):"ddd"===b?(e=sd.call(this._shortWeekdaysParse,g),-1!==e?e:(e=sd.call(this._weekdaysParse,g),-1!==e?e:(e=sd.call(this._minWeekdaysParse,g),-1!==e?e:null))):(e=sd.call(this._minWeekdaysParse,g),-1!==e?e:(e=sd.call(this._weekdaysParse,g),-1!==e?e:(e=sd.call(this._shortWeekdaysParse,g),-1!==e?e:null)))}function Ia(a,b,c){var d,e,f;if(this._weekdaysParseExact)return Ha.call(this,a,b,c);for(this._weekdaysParse||(this._weekdaysParse=[],this._minWeekdaysParse=[],this._shortWeekdaysParse=[],this._fullWeekdaysParse=[]),d=0;7>d;d++){
// test the regex
if(e=j([2e3,1]).day(d),c&&!this._fullWeekdaysParse[d]&&(this._fullWeekdaysParse[d]=new RegExp("^"+this.weekdays(e,"").replace(".",".?")+"$","i"),this._shortWeekdaysParse[d]=new RegExp("^"+this.weekdaysShort(e,"").replace(".",".?")+"$","i"),this._minWeekdaysParse[d]=new RegExp("^"+this.weekdaysMin(e,"").replace(".",".?")+"$","i")),this._weekdaysParse[d]||(f="^"+this.weekdays(e,"")+"|^"+this.weekdaysShort(e,"")+"|^"+this.weekdaysMin(e,""),this._weekdaysParse[d]=new RegExp(f.replace(".",""),"i")),c&&"dddd"===b&&this._fullWeekdaysParse[d].test(a))return d;if(c&&"ddd"===b&&this._shortWeekdaysParse[d].test(a))return d;if(c&&"dd"===b&&this._minWeekdaysParse[d].test(a))return d;if(!c&&this._weekdaysParse[d].test(a))return d}}
// MOMENTS
function Ja(a){if(!this.isValid())return null!=a?this:NaN;var b=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=a?(a=Ca(a,this.localeData()),this.add(a-b,"d")):b}function Ka(a){if(!this.isValid())return null!=a?this:NaN;var b=(this.day()+7-this.localeData()._week.dow)%7;return null==a?b:this.add(a-b,"d")}function La(a){if(!this.isValid())return null!=a?this:NaN;
// behaves the same as moment#day except
// as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
// as a setter, sunday should belong to the previous week.
if(null!=a){var b=Da(a,this.localeData());return this.day(this.day()%7?b:b-7)}return this.day()||7}function Ma(a){return this._weekdaysParseExact?(h(this,"_weekdaysRegex")||Pa.call(this),a?this._weekdaysStrictRegex:this._weekdaysRegex):(h(this,"_weekdaysRegex")||(this._weekdaysRegex=pe),this._weekdaysStrictRegex&&a?this._weekdaysStrictRegex:this._weekdaysRegex)}function Na(a){return this._weekdaysParseExact?(h(this,"_weekdaysRegex")||Pa.call(this),a?this._weekdaysShortStrictRegex:this._weekdaysShortRegex):(h(this,"_weekdaysShortRegex")||(this._weekdaysShortRegex=qe),this._weekdaysShortStrictRegex&&a?this._weekdaysShortStrictRegex:this._weekdaysShortRegex)}function Oa(a){return this._weekdaysParseExact?(h(this,"_weekdaysRegex")||Pa.call(this),a?this._weekdaysMinStrictRegex:this._weekdaysMinRegex):(h(this,"_weekdaysMinRegex")||(this._weekdaysMinRegex=re),this._weekdaysMinStrictRegex&&a?this._weekdaysMinStrictRegex:this._weekdaysMinRegex)}function Pa(){function a(a,b){return b.length-a.length}var b,c,d,e,f,g=[],h=[],i=[],k=[];for(b=0;7>b;b++)c=j([2e3,1]).day(b),d=this.weekdaysMin(c,""),e=this.weekdaysShort(c,""),f=this.weekdays(c,""),g.push(d),h.push(e),i.push(f),k.push(d),k.push(e),k.push(f);for(
// Sorting makes sure if one weekday (or abbr) is a prefix of another it
// will match the longer piece.
g.sort(a),h.sort(a),i.sort(a),k.sort(a),b=0;7>b;b++)h[b]=_(h[b]),i[b]=_(i[b]),k[b]=_(k[b]);this._weekdaysRegex=new RegExp("^("+k.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp("^("+i.join("|")+")","i"),this._weekdaysShortStrictRegex=new RegExp("^("+h.join("|")+")","i"),this._weekdaysMinStrictRegex=new RegExp("^("+g.join("|")+")","i")}
// FORMATTING
function Qa(){return this.hours()%12||12}function Ra(){return this.hours()||24}function Sa(a,b){T(a,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),b)})}
// PARSING
function Ta(a,b){return b._meridiemParse}
// LOCALES
function Ua(a){
// IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
// Using charAt should be more compatible.
return"p"===(a+"").toLowerCase().charAt(0)}function Va(a,b,c){return a>11?c?"pm":"PM":c?"am":"AM"}function Wa(a){return a?a.toLowerCase().replace("_","-"):a}
// pick the locale from the array
// try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
// substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
function Xa(a){for(var b,c,d,e,f=0;f<a.length;){for(e=Wa(a[f]).split("-"),b=e.length,c=Wa(a[f+1]),c=c?c.split("-"):null;b>0;){if(d=Ya(e.slice(0,b).join("-")))return d;if(c&&c.length>=b&&u(e,c,!0)>=b-1)
//the next array item is better than a shallower substring of this one
break;b--}f++}return null}function Ya(a){var b=null;
// TODO: Find a better way to register and load all the locales in Node
if(!we[a]&&"undefined"!=typeof module&&module&&module.exports)try{b=se._abbr,require("./locale/"+a),
// because defineLocale currently also sets the global locale, we
// want to undo that for lazy loaded locales
Za(b)}catch(c){}return we[a]}
// This function will load locale and then set the global locale.  If
// no arguments are passed in, it will simply return the current global
// locale key.
function Za(a,b){var c;
// moment.duration._locale = moment._locale = data;
return a&&(c=o(b)?ab(a):$a(a,b),c&&(se=c)),se._abbr}function $a(a,b){if(null!==b){var c=ve;
// treat as if there is no base config
// backwards compat for now: also set the locale
return b.abbr=a,null!=we[a]?(x("defineLocaleOverride","use moment.updateLocale(localeName, config) to change an existing locale. moment.defineLocale(localeName, config) should only be used for creating a new locale See http://momentjs.com/guides/#/warnings/define-locale/ for more info."),c=we[a]._config):null!=b.parentLocale&&(null!=we[b.parentLocale]?c=we[b.parentLocale]._config:x("parentLocaleUndefined","specified parentLocale is not defined yet. See http://momentjs.com/guides/#/warnings/parent-locale/")),we[a]=new B(A(c,b)),Za(a),we[a]}
// useful for testing
return delete we[a],null}function _a(a,b){if(null!=b){var c,d=ve;
// MERGE
null!=we[a]&&(d=we[a]._config),b=A(d,b),c=new B(b),c.parentLocale=we[a],we[a]=c,
// backwards compat for now: also set the locale
Za(a)}else
// pass null for config to unupdate, useful for tests
null!=we[a]&&(null!=we[a].parentLocale?we[a]=we[a].parentLocale:null!=we[a]&&delete we[a]);return we[a]}
// returns locale data
function ab(a){var b;if(a&&a._locale&&a._locale._abbr&&(a=a._locale._abbr),!a)return se;if(!c(a)){if(b=Ya(a))return b;a=[a]}return Xa(a)}function bb(){return rd(we)}function cb(a){var b,c=a._a;return c&&-2===l(a).overflow&&(b=c[Zd]<0||c[Zd]>11?Zd:c[$d]<1||c[$d]>da(c[Yd],c[Zd])?$d:c[_d]<0||c[_d]>24||24===c[_d]&&(0!==c[ae]||0!==c[be]||0!==c[ce])?_d:c[ae]<0||c[ae]>59?ae:c[be]<0||c[be]>59?be:c[ce]<0||c[ce]>999?ce:-1,l(a)._overflowDayOfYear&&(Yd>b||b>$d)&&(b=$d),l(a)._overflowWeeks&&-1===b&&(b=de),l(a)._overflowWeekday&&-1===b&&(b=ee),l(a).overflow=b),a}
// date from iso format
function db(a){var b,c,d,e,f,g,h=a._i,i=xe.exec(h)||ye.exec(h);if(i){for(l(a).iso=!0,b=0,c=Ae.length;c>b;b++)if(Ae[b][1].exec(i[1])){e=Ae[b][0],d=Ae[b][2]!==!1;break}if(null==e)return void(a._isValid=!1);if(i[3]){for(b=0,c=Be.length;c>b;b++)if(Be[b][1].exec(i[3])){
// match[2] should be 'T' or space
f=(i[2]||" ")+Be[b][0];break}if(null==f)return void(a._isValid=!1)}if(!d&&null!=f)return void(a._isValid=!1);if(i[4]){if(!ze.exec(i[4]))return void(a._isValid=!1);g="Z"}a._f=e+(f||"")+(g||""),jb(a)}else a._isValid=!1}
// date from iso format or fallback
function eb(b){var c=Ce.exec(b._i);return null!==c?void(b._d=new Date(+c[1])):(db(b),void(b._isValid===!1&&(delete b._isValid,a.createFromInputFallback(b))))}
// Pick the first defined of two or three arguments.
function fb(a,b,c){return null!=a?a:null!=b?b:c}function gb(b){
// hooks is actually the exported moment object
var c=new Date(a.now());return b._useUTC?[c.getUTCFullYear(),c.getUTCMonth(),c.getUTCDate()]:[c.getFullYear(),c.getMonth(),c.getDate()]}
// convert an array to a date.
// the array should mirror the parameters below
// note: all values past the year are optional and will default to the lowest possible value.
// [year, month, day , hour, minute, second, millisecond]
function hb(a){var b,c,d,e,f=[];if(!a._d){
// Default to current date.
// * if no year, month, day of month are given, default to today
// * if day of month is given, default month and year
// * if month is given, default only year
// * if year is given, don't default anything
for(d=gb(a),a._w&&null==a._a[$d]&&null==a._a[Zd]&&ib(a),a._dayOfYear&&(e=fb(a._a[Yd],d[Yd]),a._dayOfYear>oa(e)&&(l(a)._overflowDayOfYear=!0),c=sa(e,0,a._dayOfYear),a._a[Zd]=c.getUTCMonth(),a._a[$d]=c.getUTCDate()),b=0;3>b&&null==a._a[b];++b)a._a[b]=f[b]=d[b];
// Zero out whatever was not defaulted, including time
for(;7>b;b++)a._a[b]=f[b]=null==a._a[b]?2===b?1:0:a._a[b];
// Check for 24:00:00.000
24===a._a[_d]&&0===a._a[ae]&&0===a._a[be]&&0===a._a[ce]&&(a._nextDay=!0,a._a[_d]=0),a._d=(a._useUTC?sa:ra).apply(null,f),
// Apply timezone offset from input. The actual utcOffset can be changed
// with parseZone.
null!=a._tzm&&a._d.setUTCMinutes(a._d.getUTCMinutes()-a._tzm),a._nextDay&&(a._a[_d]=24)}}function ib(a){var b,c,d,e,f,g,h,i;b=a._w,null!=b.GG||null!=b.W||null!=b.E?(f=1,g=4,c=fb(b.GG,a._a[Yd],va(rb(),1,4).year),d=fb(b.W,1),e=fb(b.E,1),(1>e||e>7)&&(i=!0)):(f=a._locale._week.dow,g=a._locale._week.doy,c=fb(b.gg,a._a[Yd],va(rb(),f,g).year),d=fb(b.w,1),null!=b.d?(e=b.d,(0>e||e>6)&&(i=!0)):null!=b.e?(e=b.e+f,(b.e<0||b.e>6)&&(i=!0)):e=f),1>d||d>wa(c,f,g)?l(a)._overflowWeeks=!0:null!=i?l(a)._overflowWeekday=!0:(h=ua(c,d,e,f,g),a._a[Yd]=h.year,a._dayOfYear=h.dayOfYear)}
// date from string and format string
function jb(b){
// TODO: Move this to another part of the creation flow to prevent circular deps
if(b._f===a.ISO_8601)return void db(b);b._a=[],l(b).empty=!0;
// This array is used to make a Date, either with `new Date` or `Date.UTC`
var c,d,e,f,g,h=""+b._i,i=h.length,j=0;for(e=X(b._f,b._locale).match(Bd)||[],c=0;c<e.length;c++)f=e[c],d=(h.match(Z(f,b))||[])[0],d&&(g=h.substr(0,h.indexOf(d)),g.length>0&&l(b).unusedInput.push(g),h=h.slice(h.indexOf(d)+d.length),j+=d.length),Ed[f]?(d?l(b).empty=!1:l(b).unusedTokens.push(f),ca(f,d,b)):b._strict&&!d&&l(b).unusedTokens.push(f);
// add remaining unparsed input length to the string
l(b).charsLeftOver=i-j,h.length>0&&l(b).unusedInput.push(h),
// clear _12h flag if hour is <= 12
b._a[_d]<=12&&l(b).bigHour===!0&&b._a[_d]>0&&(l(b).bigHour=void 0),l(b).parsedDateParts=b._a.slice(0),l(b).meridiem=b._meridiem,
// handle meridiem
b._a[_d]=kb(b._locale,b._a[_d],b._meridiem),hb(b),cb(b)}function kb(a,b,c){var d;
// Fallback
return null==c?b:null!=a.meridiemHour?a.meridiemHour(b,c):null!=a.isPM?(d=a.isPM(c),d&&12>b&&(b+=12),d||12!==b||(b=0),b):b}
// date from string and array of format strings
function lb(a){var b,c,d,e,f;if(0===a._f.length)return l(a).invalidFormat=!0,void(a._d=new Date(NaN));for(e=0;e<a._f.length;e++)f=0,b=p({},a),null!=a._useUTC&&(b._useUTC=a._useUTC),b._f=a._f[e],jb(b),m(b)&&(f+=l(b).charsLeftOver,f+=10*l(b).unusedTokens.length,l(b).score=f,(null==d||d>f)&&(d=f,c=b));i(a,c||b)}function mb(a){if(!a._d){var b=K(a._i);a._a=g([b.year,b.month,b.day||b.date,b.hour,b.minute,b.second,b.millisecond],function(a){return a&&parseInt(a,10)}),hb(a)}}function nb(a){var b=new q(cb(ob(a)));
// Adding is smart enough around DST
return b._nextDay&&(b.add(1,"d"),b._nextDay=void 0),b}function ob(a){var b=a._i,d=a._f;return a._locale=a._locale||ab(a._l),null===b||void 0===d&&""===b?n({nullInput:!0}):("string"==typeof b&&(a._i=b=a._locale.preparse(b)),r(b)?new q(cb(b)):(c(d)?lb(a):f(b)?a._d=b:d?jb(a):pb(a),m(a)||(a._d=null),a))}function pb(b){var d=b._i;void 0===d?b._d=new Date(a.now()):f(d)?b._d=new Date(d.valueOf()):"string"==typeof d?eb(b):c(d)?(b._a=g(d.slice(0),function(a){return parseInt(a,10)}),hb(b)):"object"==typeof d?mb(b):"number"==typeof d?
// from milliseconds
b._d=new Date(d):a.createFromInputFallback(b)}function qb(a,b,f,g,h){var i={};
// object construction must be done this way.
// https://github.com/moment/moment/issues/1423
return"boolean"==typeof f&&(g=f,f=void 0),(d(a)&&e(a)||c(a)&&0===a.length)&&(a=void 0),i._isAMomentObject=!0,i._useUTC=i._isUTC=h,i._l=f,i._i=a,i._f=b,i._strict=g,nb(i)}function rb(a,b,c,d){return qb(a,b,c,d,!1)}
// Pick a moment m from moments so that m[fn](other) is true for all
// other. This relies on the function fn to be transitive.
//
// moments should either be an array of moment objects or an array, whose
// first element is an array of moment objects.
function sb(a,b){var d,e;if(1===b.length&&c(b[0])&&(b=b[0]),!b.length)return rb();for(d=b[0],e=1;e<b.length;++e)b[e].isValid()&&!b[e][a](d)||(d=b[e]);return d}
// TODO: Use [].sort instead?
function tb(){var a=[].slice.call(arguments,0);return sb("isBefore",a)}function ub(){var a=[].slice.call(arguments,0);return sb("isAfter",a)}function vb(a){var b=K(a),c=b.year||0,d=b.quarter||0,e=b.month||0,f=b.week||0,g=b.day||0,h=b.hour||0,i=b.minute||0,j=b.second||0,k=b.millisecond||0;
// representation for dateAddRemove
this._milliseconds=+k+1e3*j+// 1000
6e4*i+// 1000 * 60
1e3*h*60*60,//using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978
// Because of dateAddRemove treats 24 hours as different from a
// day when working around DST, we need to store them separately
this._days=+g+7*f,
// It is impossible translate months into days without knowing
// which months you are are talking about, so we have to store
// it separately.
this._months=+e+3*d+12*c,this._data={},this._locale=ab(),this._bubble()}function wb(a){return a instanceof vb}
// FORMATTING
function xb(a,b){T(a,0,0,function(){var a=this.utcOffset(),c="+";return 0>a&&(a=-a,c="-"),c+S(~~(a/60),2)+b+S(~~a%60,2)})}function yb(a,b){var c=(b||"").match(a)||[],d=c[c.length-1]||[],e=(d+"").match(Ge)||["-",0,0],f=+(60*e[1])+t(e[2]);return"+"===e[0]?f:-f}
// Return a moment from input, that is local/utc/zone equivalent to model.
function zb(b,c){var d,e;
// Use low-level api, because this fn is low-level api.
return c._isUTC?(d=c.clone(),e=(r(b)||f(b)?b.valueOf():rb(b).valueOf())-d.valueOf(),d._d.setTime(d._d.valueOf()+e),a.updateOffset(d,!1),d):rb(b).local()}function Ab(a){
// On Firefox.24 Date#getTimezoneOffset returns a floating point.
// https://github.com/moment/moment/pull/1871
return 15*-Math.round(a._d.getTimezoneOffset()/15)}
// MOMENTS
// keepLocalTime = true means only change the timezone, without
// affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->
// 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset
// +0200, so we adjust the time as needed, to be valid.
//
// Keeping the time actually adds/subtracts (one hour)
// from the actual represented time. That is why we call updateOffset
// a second time. In case it wants us to change the offset again
// _changeInProgress == true case, then we have to adjust, because
// there is no such time in the given timezone.
function Bb(b,c){var d,e=this._offset||0;return this.isValid()?null!=b?("string"==typeof b?b=yb(Td,b):Math.abs(b)<16&&(b=60*b),!this._isUTC&&c&&(d=Ab(this)),this._offset=b,this._isUTC=!0,null!=d&&this.add(d,"m"),e!==b&&(!c||this._changeInProgress?Sb(this,Mb(b-e,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,a.updateOffset(this,!0),this._changeInProgress=null)),this):this._isUTC?e:Ab(this):null!=b?this:NaN}function Cb(a,b){return null!=a?("string"!=typeof a&&(a=-a),this.utcOffset(a,b),this):-this.utcOffset()}function Db(a){return this.utcOffset(0,a)}function Eb(a){return this._isUTC&&(this.utcOffset(0,a),this._isUTC=!1,a&&this.subtract(Ab(this),"m")),this}function Fb(){return this._tzm?this.utcOffset(this._tzm):"string"==typeof this._i&&this.utcOffset(yb(Sd,this._i)),this}function Gb(a){return this.isValid()?(a=a?rb(a).utcOffset():0,(this.utcOffset()-a)%60===0):!1}function Hb(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()}function Ib(){if(!o(this._isDSTShifted))return this._isDSTShifted;var a={};if(p(a,this),a=ob(a),a._a){var b=a._isUTC?j(a._a):rb(a._a);this._isDSTShifted=this.isValid()&&u(a._a,b.toArray())>0}else this._isDSTShifted=!1;return this._isDSTShifted}function Jb(){return this.isValid()?!this._isUTC:!1}function Kb(){return this.isValid()?this._isUTC:!1}function Lb(){return this.isValid()?this._isUTC&&0===this._offset:!1}function Mb(a,b){var c,d,e,f=a,
// matching against regexp is expensive, do it on demand
g=null;// checks for null or undefined
return wb(a)?f={ms:a._milliseconds,d:a._days,M:a._months}:"number"==typeof a?(f={},b?f[b]=a:f.milliseconds=a):(g=He.exec(a))?(c="-"===g[1]?-1:1,f={y:0,d:t(g[$d])*c,h:t(g[_d])*c,m:t(g[ae])*c,s:t(g[be])*c,ms:t(g[ce])*c}):(g=Ie.exec(a))?(c="-"===g[1]?-1:1,f={y:Nb(g[2],c),M:Nb(g[3],c),w:Nb(g[4],c),d:Nb(g[5],c),h:Nb(g[6],c),m:Nb(g[7],c),s:Nb(g[8],c)}):null==f?f={}:"object"==typeof f&&("from"in f||"to"in f)&&(e=Pb(rb(f.from),rb(f.to)),f={},f.ms=e.milliseconds,f.M=e.months),d=new vb(f),wb(a)&&h(a,"_locale")&&(d._locale=a._locale),d}function Nb(a,b){
// We'd normally use ~~inp for this, but unfortunately it also
// converts floats to ints.
// inp may be undefined, so careful calling replace on it.
var c=a&&parseFloat(a.replace(",","."));
// apply sign while we're at it
return(isNaN(c)?0:c)*b}function Ob(a,b){var c={milliseconds:0,months:0};return c.months=b.month()-a.month()+12*(b.year()-a.year()),a.clone().add(c.months,"M").isAfter(b)&&--c.months,c.milliseconds=+b-+a.clone().add(c.months,"M"),c}function Pb(a,b){var c;return a.isValid()&&b.isValid()?(b=zb(b,a),a.isBefore(b)?c=Ob(a,b):(c=Ob(b,a),c.milliseconds=-c.milliseconds,c.months=-c.months),c):{milliseconds:0,months:0}}function Qb(a){return 0>a?-1*Math.round(-1*a):Math.round(a)}
// TODO: remove 'name' arg after deprecation is removed
function Rb(a,b){return function(c,d){var e,f;
//invert the arguments, but complain about it
return null===d||isNaN(+d)||(x(b,"moment()."+b+"(period, number) is deprecated. Please use moment()."+b+"(number, period). See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info."),f=c,c=d,d=f),c="string"==typeof c?+c:c,e=Mb(c,d),Sb(this,e,a),this}}function Sb(b,c,d,e){var f=c._milliseconds,g=Qb(c._days),h=Qb(c._months);b.isValid()&&(e=null==e?!0:e,f&&b._d.setTime(b._d.valueOf()+f*d),g&&P(b,"Date",O(b,"Date")+g*d),h&&ia(b,O(b,"Month")+h*d),e&&a.updateOffset(b,g||h))}function Tb(a,b){var c=a.diff(b,"days",!0);return-6>c?"sameElse":-1>c?"lastWeek":0>c?"lastDay":1>c?"sameDay":2>c?"nextDay":7>c?"nextWeek":"sameElse"}function Ub(b,c){
// We want to compare the start of today, vs this.
// Getting start-of-today depends on whether we're local/utc/offset or not.
var d=b||rb(),e=zb(d,this).startOf("day"),f=a.calendarFormat(this,e)||"sameElse",g=c&&(y(c[f])?c[f].call(this,d):c[f]);return this.format(g||this.localeData().calendar(f,this,rb(d)))}function Vb(){return new q(this)}function Wb(a,b){var c=r(a)?a:rb(a);return this.isValid()&&c.isValid()?(b=J(o(b)?"millisecond":b),"millisecond"===b?this.valueOf()>c.valueOf():c.valueOf()<this.clone().startOf(b).valueOf()):!1}function Xb(a,b){var c=r(a)?a:rb(a);return this.isValid()&&c.isValid()?(b=J(o(b)?"millisecond":b),"millisecond"===b?this.valueOf()<c.valueOf():this.clone().endOf(b).valueOf()<c.valueOf()):!1}function Yb(a,b,c,d){return d=d||"()",("("===d[0]?this.isAfter(a,c):!this.isBefore(a,c))&&(")"===d[1]?this.isBefore(b,c):!this.isAfter(b,c))}function Zb(a,b){var c,d=r(a)?a:rb(a);return this.isValid()&&d.isValid()?(b=J(b||"millisecond"),"millisecond"===b?this.valueOf()===d.valueOf():(c=d.valueOf(),this.clone().startOf(b).valueOf()<=c&&c<=this.clone().endOf(b).valueOf())):!1}function $b(a,b){return this.isSame(a,b)||this.isAfter(a,b)}function _b(a,b){return this.isSame(a,b)||this.isBefore(a,b)}function ac(a,b,c){var d,e,f,g;// 1000
// 1000 * 60
// 1000 * 60 * 60
// 1000 * 60 * 60 * 24, negate dst
// 1000 * 60 * 60 * 24 * 7, negate dst
return this.isValid()?(d=zb(a,this),d.isValid()?(e=6e4*(d.utcOffset()-this.utcOffset()),b=J(b),"year"===b||"month"===b||"quarter"===b?(g=bc(this,d),"quarter"===b?g/=3:"year"===b&&(g/=12)):(f=this-d,g="second"===b?f/1e3:"minute"===b?f/6e4:"hour"===b?f/36e5:"day"===b?(f-e)/864e5:"week"===b?(f-e)/6048e5:f),c?g:s(g)):NaN):NaN}function bc(a,b){
// difference in months
var c,d,e=12*(b.year()-a.year())+(b.month()-a.month()),
// b is in (anchor - 1 month, anchor + 1 month)
f=a.clone().add(e,"months");
//check for negative zero, return zero if negative zero
// linear across the month
// linear across the month
return 0>b-f?(c=a.clone().add(e-1,"months"),d=(b-f)/(f-c)):(c=a.clone().add(e+1,"months"),d=(b-f)/(c-f)),-(e+d)||0}function cc(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")}function dc(){var a=this.clone().utc();return 0<a.year()&&a.year()<=9999?y(Date.prototype.toISOString)?this.toDate().toISOString():W(a,"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]"):W(a,"YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]")}function ec(b){b||(b=this.isUtc()?a.defaultFormatUtc:a.defaultFormat);var c=W(this,b);return this.localeData().postformat(c)}function fc(a,b){return this.isValid()&&(r(a)&&a.isValid()||rb(a).isValid())?Mb({to:this,from:a}).locale(this.locale()).humanize(!b):this.localeData().invalidDate()}function gc(a){return this.from(rb(),a)}function hc(a,b){return this.isValid()&&(r(a)&&a.isValid()||rb(a).isValid())?Mb({from:this,to:a}).locale(this.locale()).humanize(!b):this.localeData().invalidDate()}function ic(a){return this.to(rb(),a)}
// If passed a locale key, it will set the locale for this
// instance.  Otherwise, it will return the locale configuration
// variables for this instance.
function jc(a){var b;return void 0===a?this._locale._abbr:(b=ab(a),null!=b&&(this._locale=b),this)}function kc(){return this._locale}function lc(a){
// the following switch intentionally omits break keywords
// to utilize falling through the cases.
switch(a=J(a)){case"year":this.month(0);/* falls through */
case"quarter":case"month":this.date(1);/* falls through */
case"week":case"isoWeek":case"day":case"date":this.hours(0);/* falls through */
case"hour":this.minutes(0);/* falls through */
case"minute":this.seconds(0);/* falls through */
case"second":this.milliseconds(0)}
// weeks are a special case
// quarters are also special
return"week"===a&&this.weekday(0),"isoWeek"===a&&this.isoWeekday(1),"quarter"===a&&this.month(3*Math.floor(this.month()/3)),this}function mc(a){
// 'date' is an alias for 'day', so it should be considered as such.
return a=J(a),void 0===a||"millisecond"===a?this:("date"===a&&(a="day"),this.startOf(a).add(1,"isoWeek"===a?"week":a).subtract(1,"ms"))}function nc(){return this._d.valueOf()-6e4*(this._offset||0)}function oc(){return Math.floor(this.valueOf()/1e3)}function pc(){return new Date(this.valueOf())}function qc(){var a=this;return[a.year(),a.month(),a.date(),a.hour(),a.minute(),a.second(),a.millisecond()]}function rc(){var a=this;return{years:a.year(),months:a.month(),date:a.date(),hours:a.hours(),minutes:a.minutes(),seconds:a.seconds(),milliseconds:a.milliseconds()}}function sc(){
// new Date(NaN).toJSON() === null
return this.isValid()?this.toISOString():null}function tc(){return m(this)}function uc(){return i({},l(this))}function vc(){return l(this).overflow}function wc(){return{input:this._i,format:this._f,locale:this._locale,isUTC:this._isUTC,strict:this._strict}}function xc(a,b){T(0,[a,a.length],0,b)}
// MOMENTS
function yc(a){return Cc.call(this,a,this.week(),this.weekday(),this.localeData()._week.dow,this.localeData()._week.doy)}function zc(a){return Cc.call(this,a,this.isoWeek(),this.isoWeekday(),1,4)}function Ac(){return wa(this.year(),1,4)}function Bc(){var a=this.localeData()._week;return wa(this.year(),a.dow,a.doy)}function Cc(a,b,c,d,e){var f;return null==a?va(this,d,e).year:(f=wa(a,d,e),b>f&&(b=f),Dc.call(this,a,b,c,d,e))}function Dc(a,b,c,d,e){var f=ua(a,b,c,d,e),g=sa(f.year,0,f.dayOfYear);return this.year(g.getUTCFullYear()),this.month(g.getUTCMonth()),this.date(g.getUTCDate()),this}
// MOMENTS
function Ec(a){return null==a?Math.ceil((this.month()+1)/3):this.month(3*(a-1)+this.month()%3)}
// HELPERS
// MOMENTS
function Fc(a){var b=Math.round((this.clone().startOf("day")-this.clone().startOf("year"))/864e5)+1;return null==a?b:this.add(a-b,"d")}function Gc(a,b){b[ce]=t(1e3*("0."+a))}
// MOMENTS
function Hc(){return this._isUTC?"UTC":""}function Ic(){return this._isUTC?"Coordinated Universal Time":""}function Jc(a){return rb(1e3*a)}function Kc(){return rb.apply(null,arguments).parseZone()}function Lc(a){return a}function Mc(a,b,c,d){var e=ab(),f=j().set(d,b);return e[c](f,a)}function Nc(a,b,c){if("number"==typeof a&&(b=a,a=void 0),a=a||"",null!=b)return Mc(a,b,c,"month");var d,e=[];for(d=0;12>d;d++)e[d]=Mc(a,d,c,"month");return e}
// ()
// (5)
// (fmt, 5)
// (fmt)
// (true)
// (true, 5)
// (true, fmt, 5)
// (true, fmt)
function Oc(a,b,c,d){"boolean"==typeof a?("number"==typeof b&&(c=b,b=void 0),b=b||""):(b=a,c=b,a=!1,"number"==typeof b&&(c=b,b=void 0),b=b||"");var e=ab(),f=a?e._week.dow:0;if(null!=c)return Mc(b,(c+f)%7,d,"day");var g,h=[];for(g=0;7>g;g++)h[g]=Mc(b,(g+f)%7,d,"day");return h}function Pc(a,b){return Nc(a,b,"months")}function Qc(a,b){return Nc(a,b,"monthsShort")}function Rc(a,b,c){return Oc(a,b,c,"weekdays")}function Sc(a,b,c){return Oc(a,b,c,"weekdaysShort")}function Tc(a,b,c){return Oc(a,b,c,"weekdaysMin")}function Uc(){var a=this._data;return this._milliseconds=Ue(this._milliseconds),this._days=Ue(this._days),this._months=Ue(this._months),a.milliseconds=Ue(a.milliseconds),a.seconds=Ue(a.seconds),a.minutes=Ue(a.minutes),a.hours=Ue(a.hours),a.months=Ue(a.months),a.years=Ue(a.years),this}function Vc(a,b,c,d){var e=Mb(b,c);return a._milliseconds+=d*e._milliseconds,a._days+=d*e._days,a._months+=d*e._months,a._bubble()}
// supports only 2.0-style add(1, 's') or add(duration)
function Wc(a,b){return Vc(this,a,b,1)}
// supports only 2.0-style subtract(1, 's') or subtract(duration)
function Xc(a,b){return Vc(this,a,b,-1)}function Yc(a){return 0>a?Math.floor(a):Math.ceil(a)}function Zc(){var a,b,c,d,e,f=this._milliseconds,g=this._days,h=this._months,i=this._data;
// if we have a mix of positive and negative values, bubble down first
// check: https://github.com/moment/moment/issues/2166
// The following code bubbles up values, see the tests for
// examples of what that means.
// convert days to months
// 12 months -> 1 year
return f>=0&&g>=0&&h>=0||0>=f&&0>=g&&0>=h||(f+=864e5*Yc(_c(h)+g),g=0,h=0),i.milliseconds=f%1e3,a=s(f/1e3),i.seconds=a%60,b=s(a/60),i.minutes=b%60,c=s(b/60),i.hours=c%24,g+=s(c/24),e=s($c(g)),h+=e,g-=Yc(_c(e)),d=s(h/12),h%=12,i.days=g,i.months=h,i.years=d,this}function $c(a){
// 400 years have 146097 days (taking into account leap year rules)
// 400 years have 12 months === 4800
return 4800*a/146097}function _c(a){
// the reverse of daysToMonths
return 146097*a/4800}function ad(a){var b,c,d=this._milliseconds;if(a=J(a),"month"===a||"year"===a)return b=this._days+d/864e5,c=this._months+$c(b),"month"===a?c:c/12;switch(b=this._days+Math.round(_c(this._months)),a){case"week":return b/7+d/6048e5;case"day":return b+d/864e5;case"hour":return 24*b+d/36e5;case"minute":return 1440*b+d/6e4;case"second":return 86400*b+d/1e3;
// Math.floor prevents floating point math errors here
case"millisecond":return Math.floor(864e5*b)+d;default:throw new Error("Unknown unit "+a)}}
// TODO: Use this.as('ms')?
function bd(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*t(this._months/12)}function cd(a){return function(){return this.as(a)}}function dd(a){return a=J(a),this[a+"s"]()}function ed(a){return function(){return this._data[a]}}function fd(){return s(this.days()/7)}
// helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
function gd(a,b,c,d,e){return e.relativeTime(b||1,!!c,a,d)}function hd(a,b,c){var d=Mb(a).abs(),e=jf(d.as("s")),f=jf(d.as("m")),g=jf(d.as("h")),h=jf(d.as("d")),i=jf(d.as("M")),j=jf(d.as("y")),k=e<kf.s&&["s",e]||1>=f&&["m"]||f<kf.m&&["mm",f]||1>=g&&["h"]||g<kf.h&&["hh",g]||1>=h&&["d"]||h<kf.d&&["dd",h]||1>=i&&["M"]||i<kf.M&&["MM",i]||1>=j&&["y"]||["yy",j];return k[2]=b,k[3]=+a>0,k[4]=c,gd.apply(null,k)}
// This function allows you to set the rounding function for relative time strings
function id(a){return void 0===a?jf:"function"==typeof a?(jf=a,!0):!1}
// This function allows you to set a threshold for relative time strings
function jd(a,b){return void 0===kf[a]?!1:void 0===b?kf[a]:(kf[a]=b,!0)}function kd(a){var b=this.localeData(),c=hd(this,!a,b);return a&&(c=b.pastFuture(+this,c)),b.postformat(c)}function ld(){
// for ISO strings we do not use the normal bubbling rules:
//  * milliseconds bubble up until they become hours
//  * days do not bubble at all
//  * months bubble up until they become years
// This is because there is no context-free conversion between hours and days
// (think of clock changes)
// and also not between days and months (28-31 days per month)
var a,b,c,d=lf(this._milliseconds)/1e3,e=lf(this._days),f=lf(this._months);a=s(d/60),b=s(a/60),d%=60,a%=60,c=s(f/12),f%=12;
// inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
var g=c,h=f,i=e,j=b,k=a,l=d,m=this.asSeconds();return m?(0>m?"-":"")+"P"+(g?g+"Y":"")+(h?h+"M":"")+(i?i+"D":"")+(j||k||l?"T":"")+(j?j+"H":"")+(k?k+"M":"")+(l?l+"S":""):"P0D"}var md,nd;nd=Array.prototype.some?Array.prototype.some:function(a){for(var b=Object(this),c=b.length>>>0,d=0;c>d;d++)if(d in b&&a.call(this,b[d],d,b))return!0;return!1};
// Plugins that add properties should also add the key here (null value),
// so we can properly clone ourselves.
var od=a.momentProperties=[],pd=!1,qd={};a.suppressDeprecationWarnings=!1,a.deprecationHandler=null;var rd;rd=Object.keys?Object.keys:function(a){var b,c=[];for(b in a)h(a,b)&&c.push(b);return c};var sd,td={sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},ud={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},vd="Invalid date",wd="%d",xd=/\d{1,2}/,yd={future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},zd={},Ad={},Bd=/(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,Cd=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,Dd={},Ed={},Fd=/\d/,Gd=/\d\d/,Hd=/\d{3}/,Id=/\d{4}/,Jd=/[+-]?\d{6}/,Kd=/\d\d?/,Ld=/\d\d\d\d?/,Md=/\d\d\d\d\d\d?/,Nd=/\d{1,3}/,Od=/\d{1,4}/,Pd=/[+-]?\d{1,6}/,Qd=/\d+/,Rd=/[+-]?\d+/,Sd=/Z|[+-]\d\d:?\d\d/gi,Td=/Z|[+-]\d\d(?::?\d\d)?/gi,Ud=/[+-]?\d+(\.\d{1,3})?/,Vd=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,Wd={},Xd={},Yd=0,Zd=1,$d=2,_d=3,ae=4,be=5,ce=6,de=7,ee=8;sd=Array.prototype.indexOf?Array.prototype.indexOf:function(a){
// I know
var b;for(b=0;b<this.length;++b)if(this[b]===a)return b;return-1},T("M",["MM",2],"Mo",function(){return this.month()+1}),T("MMM",0,0,function(a){return this.localeData().monthsShort(this,a)}),T("MMMM",0,0,function(a){return this.localeData().months(this,a)}),I("month","M"),L("month",8),Y("M",Kd),Y("MM",Kd,Gd),Y("MMM",function(a,b){return b.monthsShortRegex(a)}),Y("MMMM",function(a,b){return b.monthsRegex(a)}),aa(["M","MM"],function(a,b){b[Zd]=t(a)-1}),aa(["MMM","MMMM"],function(a,b,c,d){var e=c._locale.monthsParse(a,d,c._strict);null!=e?b[Zd]=e:l(c).invalidMonth=a});
// LOCALES
var fe=/D[oD]?(\[[^\[\]]*\]|\s+)+MMMM?/,ge="January_February_March_April_May_June_July_August_September_October_November_December".split("_"),he="Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),ie=Vd,je=Vd;
// FORMATTING
T("Y",0,0,function(){var a=this.year();return 9999>=a?""+a:"+"+a}),T(0,["YY",2],0,function(){return this.year()%100}),T(0,["YYYY",4],0,"year"),T(0,["YYYYY",5],0,"year"),T(0,["YYYYYY",6,!0],0,"year"),
// ALIASES
I("year","y"),
// PRIORITIES
L("year",1),
// PARSING
Y("Y",Rd),Y("YY",Kd,Gd),Y("YYYY",Od,Id),Y("YYYYY",Pd,Jd),Y("YYYYYY",Pd,Jd),aa(["YYYYY","YYYYYY"],Yd),aa("YYYY",function(b,c){c[Yd]=2===b.length?a.parseTwoDigitYear(b):t(b)}),aa("YY",function(b,c){c[Yd]=a.parseTwoDigitYear(b)}),aa("Y",function(a,b){b[Yd]=parseInt(a,10)}),
// HOOKS
a.parseTwoDigitYear=function(a){return t(a)+(t(a)>68?1900:2e3)};
// MOMENTS
var ke=N("FullYear",!0);
// FORMATTING
T("w",["ww",2],"wo","week"),T("W",["WW",2],"Wo","isoWeek"),
// ALIASES
I("week","w"),I("isoWeek","W"),
// PRIORITIES
L("week",5),L("isoWeek",5),
// PARSING
Y("w",Kd),Y("ww",Kd,Gd),Y("W",Kd),Y("WW",Kd,Gd),ba(["w","ww","W","WW"],function(a,b,c,d){b[d.substr(0,1)]=t(a)});var le={dow:0,// Sunday is the first day of the week.
doy:6};
// FORMATTING
T("d",0,"do","day"),T("dd",0,0,function(a){return this.localeData().weekdaysMin(this,a)}),T("ddd",0,0,function(a){return this.localeData().weekdaysShort(this,a)}),T("dddd",0,0,function(a){return this.localeData().weekdays(this,a)}),T("e",0,0,"weekday"),T("E",0,0,"isoWeekday"),
// ALIASES
I("day","d"),I("weekday","e"),I("isoWeekday","E"),
// PRIORITY
L("day",11),L("weekday",11),L("isoWeekday",11),
// PARSING
Y("d",Kd),Y("e",Kd),Y("E",Kd),Y("dd",function(a,b){return b.weekdaysMinRegex(a)}),Y("ddd",function(a,b){return b.weekdaysShortRegex(a)}),Y("dddd",function(a,b){return b.weekdaysRegex(a)}),ba(["dd","ddd","dddd"],function(a,b,c,d){var e=c._locale.weekdaysParse(a,d,c._strict);
// if we didn't get a weekday name, mark the date as invalid
null!=e?b.d=e:l(c).invalidWeekday=a}),ba(["d","e","E"],function(a,b,c,d){b[d]=t(a)});
// LOCALES
var me="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),ne="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),oe="Su_Mo_Tu_We_Th_Fr_Sa".split("_"),pe=Vd,qe=Vd,re=Vd;T("H",["HH",2],0,"hour"),T("h",["hh",2],0,Qa),T("k",["kk",2],0,Ra),T("hmm",0,0,function(){return""+Qa.apply(this)+S(this.minutes(),2)}),T("hmmss",0,0,function(){return""+Qa.apply(this)+S(this.minutes(),2)+S(this.seconds(),2)}),T("Hmm",0,0,function(){return""+this.hours()+S(this.minutes(),2)}),T("Hmmss",0,0,function(){return""+this.hours()+S(this.minutes(),2)+S(this.seconds(),2)}),Sa("a",!0),Sa("A",!1),
// ALIASES
I("hour","h"),
// PRIORITY
L("hour",13),Y("a",Ta),Y("A",Ta),Y("H",Kd),Y("h",Kd),Y("HH",Kd,Gd),Y("hh",Kd,Gd),Y("hmm",Ld),Y("hmmss",Md),Y("Hmm",Ld),Y("Hmmss",Md),aa(["H","HH"],_d),aa(["a","A"],function(a,b,c){c._isPm=c._locale.isPM(a),c._meridiem=a}),aa(["h","hh"],function(a,b,c){b[_d]=t(a),l(c).bigHour=!0}),aa("hmm",function(a,b,c){var d=a.length-2;b[_d]=t(a.substr(0,d)),b[ae]=t(a.substr(d)),l(c).bigHour=!0}),aa("hmmss",function(a,b,c){var d=a.length-4,e=a.length-2;b[_d]=t(a.substr(0,d)),b[ae]=t(a.substr(d,2)),b[be]=t(a.substr(e)),l(c).bigHour=!0}),aa("Hmm",function(a,b,c){var d=a.length-2;b[_d]=t(a.substr(0,d)),b[ae]=t(a.substr(d))}),aa("Hmmss",function(a,b,c){var d=a.length-4,e=a.length-2;b[_d]=t(a.substr(0,d)),b[ae]=t(a.substr(d,2)),b[be]=t(a.substr(e))});var se,te=/[ap]\.?m?\.?/i,ue=N("Hours",!0),ve={calendar:td,longDateFormat:ud,invalidDate:vd,ordinal:wd,ordinalParse:xd,relativeTime:yd,months:ge,monthsShort:he,week:le,weekdays:me,weekdaysMin:oe,weekdaysShort:ne,meridiemParse:te},we={},xe=/^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?/,ye=/^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?/,ze=/Z|[+-]\d\d(?::?\d\d)?/,Ae=[["YYYYYY-MM-DD",/[+-]\d{6}-\d\d-\d\d/],["YYYY-MM-DD",/\d{4}-\d\d-\d\d/],["GGGG-[W]WW-E",/\d{4}-W\d\d-\d/],["GGGG-[W]WW",/\d{4}-W\d\d/,!1],["YYYY-DDD",/\d{4}-\d{3}/],["YYYY-MM",/\d{4}-\d\d/,!1],["YYYYYYMMDD",/[+-]\d{10}/],["YYYYMMDD",/\d{8}/],
// YYYYMM is NOT allowed by the standard
["GGGG[W]WWE",/\d{4}W\d{3}/],["GGGG[W]WW",/\d{4}W\d{2}/,!1],["YYYYDDD",/\d{7}/]],Be=[["HH:mm:ss.SSSS",/\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss,SSSS",/\d\d:\d\d:\d\d,\d+/],["HH:mm:ss",/\d\d:\d\d:\d\d/],["HH:mm",/\d\d:\d\d/],["HHmmss.SSSS",/\d\d\d\d\d\d\.\d+/],["HHmmss,SSSS",/\d\d\d\d\d\d,\d+/],["HHmmss",/\d\d\d\d\d\d/],["HHmm",/\d\d\d\d/],["HH",/\d\d/]],Ce=/^\/?Date\((\-?\d+)/i;a.createFromInputFallback=w("moment construction falls back to js Date. This is discouraged and will be removed in upcoming major release. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.",function(a){a._d=new Date(a._i+(a._useUTC?" UTC":""))}),
// constant that refers to the ISO standard
a.ISO_8601=function(){};var De=w("moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/",function(){var a=rb.apply(null,arguments);return this.isValid()&&a.isValid()?this>a?this:a:n()}),Ee=w("moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/",function(){var a=rb.apply(null,arguments);return this.isValid()&&a.isValid()?a>this?this:a:n()}),Fe=function(){return Date.now?Date.now():+new Date};xb("Z",":"),xb("ZZ",""),
// PARSING
Y("Z",Td),Y("ZZ",Td),aa(["Z","ZZ"],function(a,b,c){c._useUTC=!0,c._tzm=yb(Td,a)});
// HELPERS
// timezone chunker
// '+10:00' > ['10',  '00']
// '-1530'  > ['-15', '30']
var Ge=/([\+\-]|\d\d)/gi;
// HOOKS
// This function will be called whenever a moment is mutated.
// It is intended to keep the offset in sync with the timezone.
a.updateOffset=function(){};
// ASP.NET json date format regex
var He=/^(\-)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?\d*)?$/,Ie=/^(-)?P(?:(-?[0-9,.]*)Y)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)W)?(?:(-?[0-9,.]*)D)?(?:T(?:(-?[0-9,.]*)H)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)S)?)?$/;Mb.fn=vb.prototype;var Je=Rb(1,"add"),Ke=Rb(-1,"subtract");a.defaultFormat="YYYY-MM-DDTHH:mm:ssZ",a.defaultFormatUtc="YYYY-MM-DDTHH:mm:ss[Z]";var Le=w("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(a){return void 0===a?this.localeData():this.locale(a)});
// FORMATTING
T(0,["gg",2],0,function(){return this.weekYear()%100}),T(0,["GG",2],0,function(){return this.isoWeekYear()%100}),xc("gggg","weekYear"),xc("ggggg","weekYear"),xc("GGGG","isoWeekYear"),xc("GGGGG","isoWeekYear"),
// ALIASES
I("weekYear","gg"),I("isoWeekYear","GG"),
// PRIORITY
L("weekYear",1),L("isoWeekYear",1),
// PARSING
Y("G",Rd),Y("g",Rd),Y("GG",Kd,Gd),Y("gg",Kd,Gd),Y("GGGG",Od,Id),Y("gggg",Od,Id),Y("GGGGG",Pd,Jd),Y("ggggg",Pd,Jd),ba(["gggg","ggggg","GGGG","GGGGG"],function(a,b,c,d){b[d.substr(0,2)]=t(a)}),ba(["gg","GG"],function(b,c,d,e){c[e]=a.parseTwoDigitYear(b)}),
// FORMATTING
T("Q",0,"Qo","quarter"),
// ALIASES
I("quarter","Q"),
// PRIORITY
L("quarter",7),
// PARSING
Y("Q",Fd),aa("Q",function(a,b){b[Zd]=3*(t(a)-1)}),
// FORMATTING
T("D",["DD",2],"Do","date"),
// ALIASES
I("date","D"),
// PRIOROITY
L("date",9),
// PARSING
Y("D",Kd),Y("DD",Kd,Gd),Y("Do",function(a,b){return a?b._ordinalParse:b._ordinalParseLenient}),aa(["D","DD"],$d),aa("Do",function(a,b){b[$d]=t(a.match(Kd)[0],10)});
// MOMENTS
var Me=N("Date",!0);
// FORMATTING
T("DDD",["DDDD",3],"DDDo","dayOfYear"),
// ALIASES
I("dayOfYear","DDD"),
// PRIORITY
L("dayOfYear",4),
// PARSING
Y("DDD",Nd),Y("DDDD",Hd),aa(["DDD","DDDD"],function(a,b,c){c._dayOfYear=t(a)}),
// FORMATTING
T("m",["mm",2],0,"minute"),
// ALIASES
I("minute","m"),
// PRIORITY
L("minute",14),
// PARSING
Y("m",Kd),Y("mm",Kd,Gd),aa(["m","mm"],ae);
// MOMENTS
var Ne=N("Minutes",!1);
// FORMATTING
T("s",["ss",2],0,"second"),
// ALIASES
I("second","s"),
// PRIORITY
L("second",15),
// PARSING
Y("s",Kd),Y("ss",Kd,Gd),aa(["s","ss"],be);
// MOMENTS
var Oe=N("Seconds",!1);
// FORMATTING
T("S",0,0,function(){return~~(this.millisecond()/100)}),T(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),T(0,["SSS",3],0,"millisecond"),T(0,["SSSS",4],0,function(){return 10*this.millisecond()}),T(0,["SSSSS",5],0,function(){return 100*this.millisecond()}),T(0,["SSSSSS",6],0,function(){return 1e3*this.millisecond()}),T(0,["SSSSSSS",7],0,function(){return 1e4*this.millisecond()}),T(0,["SSSSSSSS",8],0,function(){return 1e5*this.millisecond()}),T(0,["SSSSSSSSS",9],0,function(){return 1e6*this.millisecond()}),
// ALIASES
I("millisecond","ms"),
// PRIORITY
L("millisecond",16),
// PARSING
Y("S",Nd,Fd),Y("SS",Nd,Gd),Y("SSS",Nd,Hd);var Pe;for(Pe="SSSS";Pe.length<=9;Pe+="S")Y(Pe,Qd);for(Pe="S";Pe.length<=9;Pe+="S")aa(Pe,Gc);
// MOMENTS
var Qe=N("Milliseconds",!1);
// FORMATTING
T("z",0,0,"zoneAbbr"),T("zz",0,0,"zoneName");var Re=q.prototype;Re.add=Je,Re.calendar=Ub,Re.clone=Vb,Re.diff=ac,Re.endOf=mc,Re.format=ec,Re.from=fc,Re.fromNow=gc,Re.to=hc,Re.toNow=ic,Re.get=Q,Re.invalidAt=vc,Re.isAfter=Wb,Re.isBefore=Xb,Re.isBetween=Yb,Re.isSame=Zb,Re.isSameOrAfter=$b,Re.isSameOrBefore=_b,Re.isValid=tc,Re.lang=Le,Re.locale=jc,Re.localeData=kc,Re.max=Ee,Re.min=De,Re.parsingFlags=uc,Re.set=R,Re.startOf=lc,Re.subtract=Ke,Re.toArray=qc,Re.toObject=rc,Re.toDate=pc,Re.toISOString=dc,Re.toJSON=sc,Re.toString=cc,Re.unix=oc,Re.valueOf=nc,Re.creationData=wc,
// Year
Re.year=ke,Re.isLeapYear=qa,
// Week Year
Re.weekYear=yc,Re.isoWeekYear=zc,
// Quarter
Re.quarter=Re.quarters=Ec,
// Month
Re.month=ja,Re.daysInMonth=ka,
// Week
Re.week=Re.weeks=Aa,Re.isoWeek=Re.isoWeeks=Ba,Re.weeksInYear=Bc,Re.isoWeeksInYear=Ac,
// Day
Re.date=Me,Re.day=Re.days=Ja,Re.weekday=Ka,Re.isoWeekday=La,Re.dayOfYear=Fc,
// Hour
Re.hour=Re.hours=ue,
// Minute
Re.minute=Re.minutes=Ne,
// Second
Re.second=Re.seconds=Oe,
// Millisecond
Re.millisecond=Re.milliseconds=Qe,
// Offset
Re.utcOffset=Bb,Re.utc=Db,Re.local=Eb,Re.parseZone=Fb,Re.hasAlignedHourOffset=Gb,Re.isDST=Hb,Re.isLocal=Jb,Re.isUtcOffset=Kb,Re.isUtc=Lb,Re.isUTC=Lb,
// Timezone
Re.zoneAbbr=Hc,Re.zoneName=Ic,
// Deprecations
Re.dates=w("dates accessor is deprecated. Use date instead.",Me),Re.months=w("months accessor is deprecated. Use month instead",ja),Re.years=w("years accessor is deprecated. Use year instead",ke),Re.zone=w("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",Cb),Re.isDSTShifted=w("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",Ib);var Se=Re,Te=B.prototype;Te.calendar=C,Te.longDateFormat=D,Te.invalidDate=E,Te.ordinal=F,Te.preparse=Lc,Te.postformat=Lc,Te.relativeTime=G,Te.pastFuture=H,Te.set=z,
// Month
Te.months=ea,Te.monthsShort=fa,Te.monthsParse=ha,Te.monthsRegex=ma,Te.monthsShortRegex=la,
// Week
Te.week=xa,Te.firstDayOfYear=za,Te.firstDayOfWeek=ya,
// Day of Week
Te.weekdays=Ea,Te.weekdaysMin=Ga,Te.weekdaysShort=Fa,Te.weekdaysParse=Ia,Te.weekdaysRegex=Ma,Te.weekdaysShortRegex=Na,Te.weekdaysMinRegex=Oa,
// Hours
Te.isPM=Ua,Te.meridiem=Va,Za("en",{ordinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(a){var b=a%10,c=1===t(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c}}),
// Side effect imports
a.lang=w("moment.lang is deprecated. Use moment.locale instead.",Za),a.langData=w("moment.langData is deprecated. Use moment.localeData instead.",ab);var Ue=Math.abs,Ve=cd("ms"),We=cd("s"),Xe=cd("m"),Ye=cd("h"),Ze=cd("d"),$e=cd("w"),_e=cd("M"),af=cd("y"),bf=ed("milliseconds"),cf=ed("seconds"),df=ed("minutes"),ef=ed("hours"),ff=ed("days"),gf=ed("months"),hf=ed("years"),jf=Math.round,kf={s:45,// seconds to minute
m:45,// minutes to hour
h:22,// hours to day
d:26,// days to month
M:11},lf=Math.abs,mf=vb.prototype;mf.abs=Uc,mf.add=Wc,mf.subtract=Xc,mf.as=ad,mf.asMilliseconds=Ve,mf.asSeconds=We,mf.asMinutes=Xe,mf.asHours=Ye,mf.asDays=Ze,mf.asWeeks=$e,mf.asMonths=_e,mf.asYears=af,mf.valueOf=bd,mf._bubble=Zc,mf.get=dd,mf.milliseconds=bf,mf.seconds=cf,mf.minutes=df,mf.hours=ef,mf.days=ff,mf.weeks=fd,mf.months=gf,mf.years=hf,mf.humanize=kd,mf.toISOString=ld,mf.toString=ld,mf.toJSON=ld,mf.locale=jc,mf.localeData=kc,
// Deprecations
mf.toIsoString=w("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",ld),mf.lang=Le,
// Side effect imports
// FORMATTING
T("X",0,0,"unix"),T("x",0,0,"valueOf"),
// PARSING
Y("x",Rd),Y("X",Ud),aa("X",function(a,b,c){c._d=new Date(1e3*parseFloat(a,10))}),aa("x",function(a,b,c){c._d=new Date(t(a))}),
// Side effect imports
a.version="2.14.1",b(rb),a.fn=Se,a.min=tb,a.max=ub,a.now=Fe,a.utc=j,a.unix=Jc,a.months=Pc,a.isDate=f,a.locale=Za,a.invalid=n,a.duration=Mb,a.isMoment=r,a.weekdays=Rc,a.parseZone=Kc,a.localeData=ab,a.isDuration=wb,a.monthsShort=Qc,a.weekdaysMin=Tc,a.defineLocale=$a,a.updateLocale=_a,a.locales=bb,a.weekdaysShort=Sc,a.normalizeUnits=J,a.relativeTimeRounding=id,a.relativeTimeThreshold=jd,a.calendarFormat=Tb,a.prototype=Se;var nf=a;return nf});;
// https://stackoverflow.com/questions/1215392/how-to-quickly-and-conveniently-disable-all-console-log-statements-in-my-code

//var Logger = (function () {

//    if (!window.console) window.console = {};

//    var _console = window.console;
//    var _methods = ["log", "error", "info", "debug", "warn"];

//    function enableAll() {
//        for (var i = 0; i < _methods.length; i++) {
//            console[_methods[i]] = _console[_methods[i]];
//        }
//    }

//    function disableAll() {
//        //for (var i = 0; i < _methods.length; i++) {
//        //    console[_methods[i]] = function () { };
//        //}
//        for (let func in console) {
//            console[func] = function () { };
//        }
//    }

//    return {
//        Enable: enableAll,
//        Disable: disableAll
//    }
//})();


//(function (original) {
//    console.enableLogging = function () {
//        console.log = original;
//    };
//    console.disableLogging = function () {
//        console.log = function () { };
//    };
//})(console.log);


//window.console = (function (original) {
//    var api = {};
//    var props = Object.keys(original);
//    for (var i = 0; i < props.length; i++) {
//        api[props[i]] = function () { };
//    }
//    return api;
//})(window.console);



///**
// * Disable all user events on the page
// *
// * @returns {function()} a function to cancel the disabling
// */
//const disableAllUserEvents = () => {
//    const events = ["click", "contextmenu", "dblclick", "mousedown", "mouseenter", "mouseleave", "mousemove",
//        "mouseover", "mouseout", "mouseup", "keydown", "keypress", "keyup", "blur", "change", "focus", "focusin",
//        "focusout", "input", "invalid", "reset", "search", "select", "submit", "drag", "dragend", "dragenter",
//        "dragleave", "dragover", "dragstart", "drop", "copy", "cut", "paste", "mousewheel", "wheel", "touchcancel",
//        "touchend", "touchmove", "touchstart"];

//    const handler = event => {
//        event.stopPropagation();
//        event.preventDefault();

//        return false;
//    };

//    for (let i = 0, l = events.length; i < l; i++) {
//        document.addEventListener(events[i], handler, true);
//    }

//    return () => {
//        for (let i = 0, l = events.length; i < l; i++) {
//            document.removeEventListener(events[i], handler, true);
//        }
//    };
//};





//#region Browser

//navigator.sayswho = (function () {
//	var N = navigator.appName, ua = navigator.userAgent, tem;
//	var M = ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
//	if (M && (tem = ua.match(/version\/([\.\d]+)/i)) != null) M[2] = tem[1];
//	M = M ? [M[1], M[2]] : [N, navigator.appVersion, '-?'];
//	return M;
//})();


var Browser = (function (nav) {
    var ua = nav.userAgent;
    function create(nodeName) {
        return document.createElement(nodeName)
    }
    //function getOS() {
    //	var av = nav.appVersion;
    //	if (ua.indexOf('Win') != -1) return 'Windows';
    //	if (ua.indexOf('Mac') != -1) return 'MacOS';
    //	if (ua.indexOf('Linux') != -1) return 'Linux';
    //	if (ua.indexOf('X11') != -1) return 'UNIX';
    //	return 'Unknown OS';
    //}
    return {
        IsChrome: /Google Inc/.test(nav.vendor),
        IsChromeIOS: /CriOS/.test(ua),
        IsChromiumBased: !!window.chrome && !/Edge/.test(ua),
        IsCordova: !!window.cordova,
        IsEdge: /Edge/.test(ua),
        IsFirefox: /Firefox/.test(ua),
        IsIE: /Trident/.test(ua),
        IsOpera: /OPR/.test(ua),
        IsSafari: /Safari/.test(ua) && !/Chrome/.test(ua),

        // Mobile
        IsAndroid: (/Android/).test(ua),
        IsIOS: (/(iPhone|iPad|iPod)/).test(nav.platform),
        IsBlackBerry: (/BlackBerry/).test(ua),
        IsWindowsMobile: (/IEMobile/).test(ua),
        IsOperaMini: (/Opera Mini/).test(ua),
        IsMobile: (/Mobile|Android|webOS|iPhone|iPad|iPod|BlackBerry/i).test(ua),
        IsTouchScreen: ('ontouchstart' in window) || !!(window.DocumentTouch && document instanceof DocumentTouch),
        IsWebComponentsSupported: 'registerElement' in document && 'import' in create('link') && 'content' in create('template')
    }
})(navigator);

//#endregion


//#region QueryString

var QueryString = (function (href) {
    var _query = parse(href);
    function parse(str) {
        var dict = {};
        var decoded = decodeURIComponent(str.slice(str.indexOf('?') + 1));
        decoded.split('&').forEach(function (val, key) {
            var parts = val.split('=', 2);
            dict[parts[0]] = parts[1];
        })
        return dict;
    }
    return {
        Find: function (prop, str) {
            if (prop && typeof prop === 'string') {
                var query = (typeof str === 'string') ? parse(str) : _query;
                return (prop in query) ? query[prop] : null;
            }
            return null;
        }
    }
})(window.location.href);

//console.log('QueryString', QueryString.Find('key'));

//#endregion


//#region Framed

function IsFramed() {
    try { return window.self !== window.top }
    catch (e) { return true }
}

function IsTravelSafe() {
    return document.body.classList.contains('tsa');
}


(function Framed(self) {

    //var MonitorSession = true;

    function changeFrameSrc(frame, src) {
        var clone = frame.cloneNode();
        clone.src = src;
        frame.parentNode.replaceChild(clone, frame);
    }

    function setTargetSelf(element) {
        element = element || document.body;
        var list = element.querySelectorAll('[target="_blank"]');
        Array.prototype.forEach.call(list, function (node) {
            node.setAttribute('target', '_self');
        });
    }

    function getScrollbarWidth(element) {
        if (element && element != document.body) {
            return element.offsetWidth - element.clientWidth;
        }
        return window.innerWidth - document.documentElement.clientWidth;
    }

    function addPageTransitions(element) {
        element = element || document.body;
        window.addEventListener('beforeunload', function (event) {
            var scrollBarWidth = getScrollbarWidth(element);
            if (scrollBarWidth > 0) {
                element.style.paddingRight = scrollBarWidth + 'px';
            }
            element.classList.add('load-area', 'loading', 'hide');
        });
        window.addEventListener('load', function (event) {
            if (element.classList.contains('load-area')) {
                element.classList.remove('loading', 'hide');
                setTimeout(function () {
                    element.classList.remove('load-area');
                }, 500)
            }
        });
    }


    var _body = document.body;

    if (IsFramed()) {
        $(document).ready(function () {

            // We have iframe
            _body.classList.add('framed');

            var referrer = (window.location != window.parent.location)
                ? document.referrer
                : document.location.href;

            //console.log(window.location.href);

            var matches = referrer.match(/^https?\:\/\/([^\/?#]+)(?:[\/?#]|$)/i);
            var domain = matches && matches[1];
            //console.log('domain', domain);//localhost:63128

            if (domain) {
                domain = domain.replace('www.', '');
            }
            if (domain == 'trawickinternational.com' || domain == 'localhost:63128') {
                _body.classList.add('trawick');
            }

            if (_body.classList.contains('tsa')) {
                // TravelSafe Agent (AgentPortal?)
                if (_body.dataset.agent) {
                    createTravelSafeAgentBar(_body.dataset.agent);
                }
            }

            // Prevent new windows
            //setTargetSelf(_body);

            // Add page transitions
            addPageTransitions(_body.querySelector('main'));


            _body.addEventListener('click', function (event) {
                if (event.target.nodeName === 'A' && event.target.href) {
                    history.replaceState(null, null, event.target.href);
                }
            }, false);

            //_body.addEventListener('submit', function (event) {
            //	if (event.target.nodeName === 'A' && event.target.href) {
            //		history.replaceState(null, null, event.target.href);
            //	}
            //}, false);


            if (window.performance && window.performance.navigation.type == 2) {
                //console.log('Back button was pressed.');
            }

            // Handle frame height
            postHeightToParent(_body.querySelector('main'));

            // Monitor Session for Agent Portal
            getParentFrameParams();
        })
    } else {
        _body.classList.remove('framed');
    }


    // PostMessage Events

    function postHeightToParent(element) {
        element = element || document.body;
        var style = window.getComputedStyle(element);
        var margins = parseInt(style['margin-top'], 10)
            + parseInt(style['margin-bottom'], 10);
        function onResize(event) {
            var height = (element.offsetHeight + margins);
            var scrollHeight = element.scrollHeight;
            var message = { 'frame': { 'height': height, 'scrollHeight': scrollHeight }, 'frameHeight': height };
            if (!event) { message.pageLoaded = true; }
            window.parent.postMessage(message, '*');
        }
        if ('ResizeObserver' in window) {
            new ResizeObserver(onResize).observe(element);
        }
        else {
            window.addEventListener('resize', onResize);
        }
        onResize(null);
    }


    function getParentFrameParams() {
        window.parent.postMessage('getFrameParams', '*');
        window.addEventListener('message', function (event) {
            // { frame: true, agent: 3458, tsauth: true }
            if (typeof event.data == 'object' && event.data.frameParams) {
                var params = event.data.frameParams;
                //console.log('params', params);
                if ('agent' in params && !isNaN(params.agent)) {
                    var agentId = parseInt(params['agent']);
                    //agentId = 1;
                    if (_body.dataset.agent && (_body.dataset.agent != agentId)) {
                        var qs = { 'agent': agentId };
                        if ('tsauth' in params) {
                            qs['tsauth'] = params['tsauth'];
                        }
                        var redirectUrl = updateQueryParams(window.location.href, qs);
                        console.log('redirected: ', params, redirectUrl);
                        for (let func in console) { console[func] = function () { }; }
                        window.location.replace(redirectUrl);
                        console.clear();
                    }
                }
            }
        });

        function updateQueryParams(uri, params) {
            for (key in params) {
                var value = params[key],
                    re = new RegExp("([?&])" + key + "=.*?(&|$)", "i"),
                    separator = uri.indexOf('?') !== -1 ? "&" : "?";
                if (uri.match(re)) {
                    uri = uri.replace(re, '$1' + key + "=" + value + '$2');
                } else {
                    uri = uri + separator + key + "=" + value;
                }
            }
            return uri;
        }
    }


    function createTravelSafeAgentBar(agentId) {
        var html = '<div class="container-fluid"><div class="text-end py-1">';
        html += '<strong class="font-condensed me-2">TravelSafe Agent</strong>';
        html += '<span class="text-white-50">#</span><span>' + agentId + '</span>';
        html += '</div></div>';
        let userBar = document.createElement('section');
        userBar.className = 'agentbar text-white sticky-top';
        userBar.style.backgroundColor = '#64C290';
        userBar.innerHTML = html;
        //let main = document.getElementById('page-content');
        //main.insertBefore(userBar, main.firstChild);
        _body.insertBefore(userBar, _body.firstChild);
    }

})(this);

//#endregion



//#region StorageAccess


// https://github.com/vitr/safari-cookie-in-iframe



(function StorageAccess(self) {

    var DEBUG = false;

    let date = new Date();

    if (DEBUG) console.log("StorageAccess => time", date.toLocaleTimeString());

    var url = (window.location != window.parent.location)
        ? document.referrer
        : document.location.href;


    if (url.indexOf('://safetreker.com') < 0) {
        return false;
    }

    if (DEBUG) {
        console.log("StorageAccess => Browser.IsIOS", Browser.IsIOS);
        console.log("StorageAccess => Browser.IsSafari", Browser.IsSafari);
        console.log("StorageAccess => IsFramed", IsFramed());
    }


    if (IsFramed() && ('hasStorageAccess' in document)) {

        /*
        So, the workaround still kinda works, as long as the new window is storing the cookie that you want to store.
        The iframe still can't store it's own cookies.
        In my case, all I needed was the session id cookie.
        So, I open a small popup window when the user grants storage access.
        It gets and stores the session id cookie, closes, and reloads the iframe.
        The iframe then has access to the session id cookie and sends it in subsequent requests.
        I think this is just temporary though, it looks like they're going to remove storage access from popup windows sometime in the future. 
        Maybe they'll fix the iframe not being able to store cookies by then.
        */




        ////https://www.mmbyte.com/article/41318.html
        //async requestStorageAccessAndServe() {
        //    let thisObject = this;
        //    let hasCookieAccess = await document.hasStorageAccess();
        //    if (!hasCookieAccess) {
        //        document.requestStorageAccess().then(
        //            function successful() {
        //                window.location.reload();
        //            },
        //            function fail() {
        //                thisObject.serveContent();
        //            });

        //    } else {
        //        thisObject.serveContent();
        //    }
        //}

        var cookieName = 'safix';

        window.addEventListener('load', function (event) {

            if (DEBUG) console.log("StorageAccess => window (loaded)", (new Date() - date));

            document.hasStorageAccess().then(
                function (hasAccess) {
                    if (DEBUG) console.log("StorageAccess => hasAccess", hasAccess);

                    if (!hasAccess) {

                        var cookieSet = window.localStorage[cookieName];
                        if (DEBUG) console.log("StorageAccess => '" + cookieName + "' cookie set", !!cookieSet);

                        // (1) This WILL NOT work without a cookie set for portal! Cookies cannot be read from iframe, but localStorage can, for now.
                        if (!window.localStorage[cookieName]) {
                            // No "cookie" set on this browser, need to load into new window from first-party, which will be listening for message.
                            window.parent.postMessage({ 'setCookieName': cookieName }, '*');

                        } else {

                            // (2) Still no access, but "cookie" was found, create clickable layer to request access.
                            createAccessLayer();
                        }

                    } else {
                        if (DEBUG) console.log("StorageAccess => Has Access, Yay!");

                        // (3) Access was granted, now just let the parent page know.
                        postWindowMessage(true);
                    }
                },
                function (reason) {
                    // Promise was rejected for some reason.
                    console.error("StorageAccess => Rejected", reason);
                }
            );
        }, false);




        // Post Messages

        window.addEventListener('message', function (event) {
            if (typeof event.data == 'object') {

                //var origin = event.origin;

                if ('requestAccess' in event.data) {

                    if (DEBUG) console.log("StorageAccess => (message from Sandbox) -> 'requestAccess'", event.data.requestAccess);

                    if (event.data.requestAccess) {

                        // Make sure cookie exists
                        document.cookie = (cookieName + "=1");
                        var cookieSet = (document.cookie.indexOf(cookieName) !== -1);
                        if (DEBUG) console.log("StorageAccess => '" + cookieName + "' cookie set", !!cookieSet);

                        // https://gist.github.com/iansltx/18caf551baaa60b79206


                        createAccessLayer();
                    }
                }

                if ('clientCookie' in event.data) {

                    var cookies = {};
                    var cookieArray = event.data.clientCookie.split(';');

                    for (var i = 0; i < cookieArray.length; i++) {
                        var kvp = cookieArray[i].split('=');
                        cookies[kvp[0]] = kvp[1];
                    }

                    if (DEBUG) console.log("StorageAccess => (message from Sandbox) -> 'clientCookies'", cookies);

                }

            }
        });


        function postWindowMessage(hasAccess) {
            var message = {
                'hasStorageAccess': hasAccess,
            };
            if (hasAccess) {
                message.frame = {
                    'instructions': 'Set iframes "sandbox" attribute',
                    'sandbox': 'allow-storage-access-by-user-activation allow-scripts allow-forms allow-same-origin'
                };
            }
            window.parent.postMessage(message, '*');
        }


        function createAccessLayer() {
            if (DEBUG) console.log("StorageAccess => createAccessLayer");

            var accessLayer = $('<button/>').addClass('iframe-access');
            accessLayer.on('click', requestSafariAccess);
            $('body').append(accessLayer);
        }


        function requestSafariAccess(event) {

            //if (DEBUG) console.log("StorageAccess => requestSafariAccess => event:", event);
            if (DEBUG) console.log("StorageAccess => requestSafariAccess -> event", event);

            var accessLayer = $(event.target);


            try {
                document.requestStorageAccess()
                    .then(accessGranted, accessDenied)
                    .catch(accessCatch);
            } catch (err) {
                if (DEBUG) console.log("StorageAccess => requestSafariAccess -> error", err);
            }


            function accessGranted() {
                // Now we have first-party storage access!
                if (DEBUG) {
                    console.log("Got cookie access for Safari workaround");
                    console.log("3rd party: document.cookie=", document.cookie);
                }

                postWindowMessage(true);

                //window.location.reload();
                removeAccessLayer();
            }

            function accessDenied() {
                postWindowMessage(false);
                if (DEBUG) console.log("Safari access denied");
                // Launch popup
            }

            function accessCatch(error) {
                // error obtaining storage access.
                postWindowMessage(false);
                console.error("Could not get access for Safari workaround: " + error);
                //console.log("Some promise have failed, reason=", error);
            }

            function removeAccessLayer() {
                if (DEBUG) console.log("removeAccessLayer", accessLayer);

                if (accessLayer.is('.iframe-access')) {
                    //if (DEBUG) console.log("removeAccessLayer", layer);
                    accessLayer.remove();
                }
            }

        }


    }

})(this);

//#endregion



//#region Benchmark

var Benchmark = (function () {

    function bench(func, input, iterations) {
        /* any boilerplate code you want to have happen before the timer starts, perhaps copying a variable so it isn't mutated */
        var start = new Date();

        for (var i = 0; i < iterations; i++) {
            func(input);
        }

        var finish = new Date();
        return (finish - start);
    }

    return {
        Test: bench
    }
})();

//https://medium.com/@daniellempesis/quick-and-dirty-way-to-benchmark-js-code-19f5da659cb7

//#endregion



/*
// https://gist.github.com/iansltx/18caf551baaa60b79206
<script>
  // Safari now suddenly blocks iframe cookie access, so we need to call this during some user interaction
  function safariFix() {
    if (navigator.userAgent.search("Safari") >= 0 && navigator.userAgent.search("Chrome") < 0) {
      document.requestStorageAccess().then(() => {
          // Now we have first-party storage access!
          console.log("Got cookie access for Safari workaround");
          // Let's access some items from the first-party cookie jar
          document.cookie = "foo=bar";              // drop a test cookie
        },  () => { console.log('access denied') }).catch((error) => {
          // error obtaining storage access.
          console.log("Could not get access for Safari workaround: " + error);
        });
      }
  }
</script>
*/

//// Checking for storage access
//document.addEventListener("DOMContentLoaded", function() {

//    if (document.hasStorageAccess) {
//        document.hasStorageAccess().then(function(hasAccess) {
//            if (hasAccess) { redirectToSetCookies(); }
//        }).catch(function (err) { console.error(err) });
//    } else { redirectToSetCookies(); }

//    //ReactDOM.render(<RequestStorageAccess />, document.body.appendChild(document.createElement("div")));
//});


//// Requesting storage access
//const requestStorageAccess = function () {
//    document.requestStorageAccess().then(function () {
//        redirectToSetCookies();
//    }).catch(function (err) { requestFullWindowLaunch() });
//};

//const buttonText = "Continue to LTI Tool";
//const promptText = "Safari requires your interaction with this tool inside Canvas to keep you logged in.\n" +
//    "A dialog may appear asking you to allow this tool to use cookies while browsing Canvas.\n" +
//    "For the best experience, click Allow.";

//return (<InteractionPrompt action={requestStorageAccess} buttonText={buttonText} promptText={promptText} size="medium" />);



//// Requesting a full window launch
//const requestFullWindowLaunch = function () {
//    window.parent.postMessage({ messageType: "requestFullWindowLaunch", data: FULL_WINDOW_LAUNCH_URL, }, "*");
//};



//// Interact with user in a first-party context
//const SafariLaunch = function () {

//    const redirect = function () {
//        window.location.replace(PLATFORM_REDIRECT_URL);
//    };

//    const buttonText = "Continue to LTI Tool";
//    const promptText = "Safari requires your interaction with this tool outside of Canvas before continuing.";
//    return (<InteractionPrompt action={redirect} buttonText={buttonText} promptText={promptText} />);
//};

//document.addEventListener("DOMContentLoaded", function () {
//    ReactDOM.render(<SafariLaunch />, document.body.appendChild(document.createElement("div")));
//});



//// Handle different types of launches, including full window, Safari, and non-Safari

////# Safari launch: Full-window launch, solely for first-party user interaction.
////# Redirect to Canvas for inline relaunch.

////if safari_redirect_required ?  @platform_redirect_url = params[: platform_redirect_url]
////return render('safari/full_window_launch')
////endif browser.safari ?  
////# Safari launch: request Storage Access, then redirect to  #: relaunch_after_storage_access_request with pertinent cookie info  # If Storage Access request fails, request a full window launch instead.  @id_token = id_token  @state = state  return render('safari/request_storage_access')end# Non - Safari launch: set cookies and render app launch‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍





















































//var Valid = (function () {

//	var USER_NAME = "^[A-Za-z0-9_-]{min number of character,max number of character}$";
//	var TELEPHONE = "(^\\+)?[0-9()-]*";
//	var TELEPHONE_OPTIONAL = "^($|(^\\+)?[0-9()-]*)$";
//	//var EMAIL = "[a-zA-Z0-9_\\.\\+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-\\.]+";
//	//var EMAIL_OPTIONAL = "^($|[a-zA-Z0-9_\\.\\+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-\\.]+)$";
//	var WEB_URL = "^($|(http:\\/\\/|https:\\/\\/)?(www.)?([a-zA-Z0-9]+).[a-zA-Z0-9]*.[a-z]{3}.?([a-z]+)?)$";
//	var WEB_URL_YOUTUBE_BE = "https?\\:\\/\\/(www\\.)?youtu(\\.)?be(\\.com)?\\/.*(\\?v=|\\/v\\/)?[a-zA-Z0-9_\\-]+";
//	var POSTAL_ADDRESS = "[a-zA-Z\\d\\s\\-\\,\\#\\.\\+]+";
//	var FIELD_NOT_EMPTY = "[^\\s]*";
//	var PINCODE = "^([0-9]{6})?$";
//	var IFSC_CODE = "^[^\\s]{4}\\d{7}$";
//	var SWIFT_CODE = "^([0-9]{10})?$";
//	var PINCODE = "^([0-9]{6})?$";




//	function validate(type, value, regex) {
//		var input = document.createElement('input');
//		input.type = type;
//		input.required = true;
//		input.value = value;
//		return typeof input.checkValidity === 'function' ? input.checkValidity() : regex.test(value);
//	}

//	return {
//		Phone: function (value) {
//			var digits = value.replace(/\D/g, '');
//			//return validate('tel', digits, /^[2-9]\d{2}[2-9]\d{2}\d{4}$/)
//			// /^\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$/
//			return new RegExp(TELEPHONE_OPTIONAL).test(value);
//		},
//		Email: function (value) {
//			//return validate('email', value, /\S+@\S+\.\S+/)
//			return EMAIL.test(value);
//		},
//		Url: function (value) {
//			return new RegExp(WEB_URL).test(value);
//		},
//		YouTube: function (value) {
//			return new RegExp(WEB_URL_YOUTUBE_BE).test(value);
//		},
//		PostalCode: function (value) {
//			return new RegExp(POSTAL_ADDRESS).test(value);
//		}
//	}

//})();













// https://stackoverflow.com/questions/10787782/full-height-of-a-html-element-div-including-border-padding-and-margin
//function outerHeight(element) {
//	var height = element.offsetHeight, style = window.getComputedStyle(element);
//	return ['top', 'bottom']
//		.map(function (side) { return parseInt(style['margin-' + side], 10) })
//		.reduce(function (total, side) { return total + side }, height);
//}




//// https://stackoverflow.com/questions/7134584/how-do-i-use-transitionend-in-jquery
//var oneTransition = (function () {
//    var $parent,
//        type,
//        callback,
//        unlockCallback,
//        newCallback,
//        start = 'webkitTransitionStart otransitionstart oTransitionStart msTransitionStart transitionstart',
//        end = 'webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend';

//    unlockCallback = function () {
//        $parent.data('oneTransitionLock', false);
//    };

//    newCallback = function (e) {
//        if ($parent.data('oneTransitionLock'))
//            return;
//        else
//            $parent.data('oneTransitionLock', true);

//        callback(e);
//    };

//    return function () {
//        var args = Array.prototype.slice.call(arguments, 0);

//        $parent = $(args[0]);     // 1st arg
//        type = args[1];           // 2nd arg
//        callback = args[2];       // 3rd arg

//        if ((args.length < 3) || ((type != 'start') && (type != 'end')) || (typeof (callback) != 'function'))
//            return;

//        $parent.off(start).off(end);
//        if (type == 'start') {
//            $parent.data('oneTransitionLock', false);
//            $parent.on(start, newCallback);
//            $parent.on(end, unlockCallback);
//        } else if (type == 'end') {
//            $parent.on(start, unlockCallback);
//            $parent.on(end, newCallback);
//        }
//    }
//})();


////oneTransition(node, 'start' or 'end', funcion(){ ...});;

// https://www.cookiebot.com/en/
// https://github.com/js-cookie/js-cookie/tree/master/src
// https://javascript.info/cookie




// https://web.dev/samesite-cookie-recipes/
// https://blog.elmah.io/the-ultimate-guide-to-secure-cookies-with-web-config-in-net/

/*
https://www.youtube.com/watch?v=Fet6-IiX69E
first_party=cookievalue; SameSite=Lax;
third_party=cookievalue; SameSite=None; Secure; (Third Party / Chrome)
*/



var SameSiteSupport = (function () {

    "use strict";


    // https://github.com/blowdart/AspNetSameSiteSamples/blob/master/SameSiteSupport.cs
    function disallowsSameSiteNone(userAgent) {

        var ua = userAgent || navigator.userAgent;

        function uaContains(search) {
            //console.log('userAgent', ua);
            return ua.indexOf(search) !== -1;
        }

        // Cover all iOS based browsers here. This includes:
        // - Safari on iOS 12 for iPhone, iPod Touch, iPad
        // - WkWebview on iOS 12 for iPhone, iPod Touch, iPad
        // - Chrome on iOS 12 for iPhone, iPod Touch, iPad
        // All of which are broken by SameSite=None, because they use the iOS networking stack
        if (uaContains("CPU iPhone OS 12") || uaContains("iPad; CPU OS 12")) {
            return true;
        }

        // Cover Mac OS X based browsers that use the Mac OS networking stack. This includes:
        // - Safari on Mac OS X.
        // This does not include:
        // - Chrome on Mac OS X
        // Because they do not use the Mac OS networking stack.
        if (/*uaContains("Macintosh; Intel Mac OS X 10_14") &&*/
            uaContains("Macintosh; Intel Mac OS X 10_14") &&
            uaContains("Version/") && uaContains("Safari")) {
            return true;
        }

        // Cover Chrome 50-69, because some versions are broken by SameSite=None,
        // and none in this range require it.
        // Note: this covers some pre-Chromium Edge versions,
        // but pre-Chromium Edge does not require SameSite=None.
        if (uaContains("Chrome/5") || uaContains("Chrome/6")) {
            return true;
        }

        // Unreal Engine runs Chromium 59, but does not advertise as Chrome until 4.23. Treat versions of Unreal
        // that don't specify their Chrome version as lacking support for SameSite=None.
        if (uaContains("UnrealEngine") && !uaContains("Chrome")) {
            return true;
        }

        return false;
    }

    function allowsSameSiteNone(userAgent) {
        return !disallowsSameSiteNone(userAgent);
    }

    function getCookieString(userAgent) {
        if (allowsSameSiteNone(userAgent)) {
            return "; sameSite=none; secure";
        }
        return "; sameSite=lax";
    }

    return {
        NoneAllowed: allowsSameSiteNone,
        CookieString: getCookieString
    }

})();



var Cookies = (function () {

    "use strict";


    function getAll() {
        var cookies = {};
        if (document.cookie && document.cookie != "") {
            var cookieArr = document.cookie.split(";");
            for (var i = 0; i < cookieArr.length; i++) {
                var cookiePair = cookieArr[i].split("=");
                // Remove leading whitespace from the cookie name
                var name = cookiePair[0].trim();
                cookies[name] = decodeURIComponent(cookiePair[1]);
            }
        }
        return cookies;
    }


    function getCookie(name) {
        // Split cookie string and get all individual name=value pairs in an array
        var cookieArr = document.cookie.split(";");
        // Loop through the array elements
        for (var i = 0; i < cookieArr.length; i++) {
            var cookiePair = cookieArr[i].split("=");
            // Remove leading whitespace from the cookie name
            if (name == cookiePair[0].trim()) {
                // Decode the cookie value and return
                return decodeURIComponent(cookiePair[1]);
            }
        }
        // Return null if not found
        return null;
    }


    function setCookie(name, value, days) {
        // Encode value in order to escape semicolons, commas, and whitespace
        var cookie = name + "=" + encodeURIComponent(value);

        // Add sameSite/secure
        cookie += SameSiteSupport.CookieString();

        if (typeof days === "number") {
            /* Sets the max-age attribute so that the cookie expires
            after the specified number of days */
            cookie += "; max-age=" + (days * 24 * 60 * 60);
        }
        document.cookie = cookie;
        //console.log('setCookie', cookie);
    }


    function deleteCookie(name) {
        setCookie(name, "", -1);
    }


    function enabled() {
        // Quick test if browser has cookieEnabled host property
        //if (navigator.cookieEnabled) return true;
        var DEBUG = false;

        var version = '4.7.2';
        var isEnabled = false;

        if (QueryString && QueryString.Find) {
            var topUrl = IsFramed() ? document.referrer : window.location.href;
            var debug = QueryString.Find('debug', topUrl);
            if (debug) DEBUG = (debug == "true");

            version = QueryString.Find('version', topUrl) || '4.7.2';
            if (DEBUG) console.log('version', version);
        }

        var sameSiteString = SameSiteSupport.CookieString();
        if (DEBUG) {
            console.log('sameSiteString', sameSiteString);
        }

        if (version == '4.7.2') {
            // Create - modern browsers
            document.cookie = "3p-cookie=value" + sameSiteString;
            // Create - older browsers
            document.cookie = "3p-cookie-legacy=value; secure";

            // Check existence
            isEnabled = (document.cookie.indexOf("3p-cookie") !== -1);
            if (DEBUG) console.log('document.cookie', document.cookie);

            // Delete - modern browsers
            document.cookie = "3p-cookie=value" + sameSiteString + "; max-age=0";
            // Delete - older browsers
            document.cookie = "3p-cookie-legacy=value; secure; expires=Thu, 01-Jan-1970 00:00:01 GMT";
        }
        else {
            // Create cookie
            document.cookie = "cookietest=1;";

            // Check existence
            isEnabled = document.cookie.indexOf("cookietest=") !== -1;
            if (DEBUG) console.log('document.cookie', document.cookie);

            // Delete cookie
            document.cookie = "cookietest=1; expires=Thu, 01-Jan-1970 00:00:01 GMT";
        }

        return isEnabled;
    }


    return {
        Get: getCookie,
        Set: setCookie,
        Delete: deleteCookie,
        Enabled: enabled
    }

})();



(function EnsureCookies() {


    if (!Cookies.Enabled()) {

        //$('html').addClass('no-cookies');
        //var alert = createAlert();
        //$('main').append(alert);
        //alert.addClass('show');

        console.error((IsFramed() ? 'Third-party ' : '') + 'Cookies Disabled');
        //logError();
    }


    //if (!IsFramed() && !Cookies.Enabled()) {

    //    //$('html').addClass('no-cookies');
    //    //var alert = createAlert();
    //    //$('main').append(alert);
    //    //alert.addClass('show');

    //    console.error('Cookies Disabled');
    //    //logError();
    //}


    function createAlert() {
        var alert = $('<div class="page-alert cookie-alert" role="alert"/>');
        var html = '<div class="message">';

        if ((cookieEnabled in navigator) && !navigator.cookieEnabled) {
            // Browser disabled
            html += '<h5>Your cookies appear to be disabled in your browser and we need them to function</h5>';
        }
        else {
            // Must be third-party suppressed
            html += '<h6 class="mt-2">Third-Party cookies are required for frames.</h6>';

            var isSafari = !!navigator.userAgent.match(/Version\/[\d\.]+.*Safari/);
            if (isSafari) {
                var iOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;// You are using Safari on iOS!

                html += '<h5>Third-Party cookies are required. Safari blocks all third-party cookies as "Cross-Site Tracking" by default.</h5>';
                html += '<a class="text-reset" href="https://www.whatismybrowser.com/detect/are-third-party-cookies-enabled" target="_blank">Find out more here</a>.';
            } else {
                var year = new Date().getFullYear();
                html += '<h5>Your cookies are disabled and we need them to function</h5>';
                html += '<p class="mb-0">It\'s ' + year + ', all websites require them at this point. Help us both out, enable them.</p>';
            }
        }
        return alert.html(html + '</div>');
    }


    function logError() {

        if (!Browser) return;

        var navi = {};
        for (var key in navigator) {
            var value = navigator[key];
            if (value) {
                var type = typeof (value);
                if (type == 'string' || type == 'boolean' || type == 'number') {
                    navi[key] = value;
                }
            }
        }

        //$.getJSON('http://ip-api.com/json?callback=?', function (data) {
        //    console.log(JSON.stringify(data, null, 2));
        //});

        var data = {
            framed: IsFramed(),
            navigator: navi,
            cookieEnabled: navigator.cookieEnabled,
            browser: {
                isChrome: Browser.IsChrome,
                isChromeIOS: Browser.IsChromeIOS,
                isChromiumBased: Browser.IsChromiumBased,
                isCordova: Browser.IsCordova,
                isEdge: Browser.IsEdge,
                isFirefox: Browser.IsFirefox,
                isIE: Browser.IsIE,
                isOpera: Browser.IsOpera,
                isSafari: Browser.IsSafari,
                isAndroid: Browser.IsAndroid,
                isIOS: Browser.IsIOS,
                isBlackBerry: Browser.IsBlackBerry,
                isWindowsMobile: Browser.IsWindowsMobile,
                isOperaMini: Browser.IsOperaMini,
                isMobile: Browser.IsMobile,
                isTouchScreen: Browser.IsTouchScreen,
                isWebComponentsSupported: Browser.IsWebComponentsSupported
            }
        };

        var json = JSON.stringify(data);

        console.log(data);
        console.log(json);

        //$.post('/Test/LogCookieMessage?data=' + json);
    }

})();





(function CookieConsent() {
    "use strict";

    return;

    //https://www.tenpixelsleft.com/build-a-cookie-consent-popup-using-javascript-and-a-bootstrap-modal/
    //https://blog.formpl.us/how-to-create-a-simple-cookie-consent-pop-up-for-your-website-dad17a174b60

    var cookieName = 'tplCookieConsent'; // The cookie name
    var cookieLifetime = 365; // Cookie expiry in days

    /**
     * Set a cookie
     * @param cname - cookie name
     * @param cvalue - cookie value
     * @param exdays - expiry in days
     */
    var _setCookie = function (cname, cvalue, exdays) {
        var d = new Date();
        d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
        var expires = "expires=" + d.toUTCString();
        document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
    };

    /**
     * Get a cookie
     * @param cname - cookie name
     * @returns string
     */
    var _getCookie = function (cname) {
        var name = cname + "=";
        var ca = document.cookie.split(';');
        for (var i = 0; i < ca.length; i++) {
            var c = ca[i];
            while (c.charAt(0) == ' ') {
                c = c.substring(1);
            }
            if (c.indexOf(name) == 0) {
                return c.substring(name.length, c.length);
            }
        }
        return "";
    };

    /**
     * Should the cookie popup be shown?
     */
    var _shouldShowPopup = function () {
        if (_getCookie(cookieName)) {
            return false;
        } else {
            return true;
        }
    };

    // Show the cookie popup on load if not previously accepted
    if (_shouldShowPopup()) {
        const popup = $('#cookieModal');
        if (popup.length) { popup.modal('show'); }
    }

    // Modal dismiss btn - consent
    $('#cookieModalConsent').on('click', function () {
        _setCookie(cookieName, 1, cookieLifetime);
    });

})();


/*
<div class="modal fade cookieModal" id="cookieModal" tabindex="-1" role="dialog" aria-labelledby="cookieModalLabel">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <h2 id="cookieModalLabel">Cookie Information and Consent Request</h2>
            </div>
            <div class="modal-body">
                <h4>Cookie Policy</h4>
                <p>[COOKIE MESSAGE HERE]</p>
                <p>
                    <a href="/privacy-statement" target="_blank">Click here to view our cookie policy</a>
                </p>
            </div>
            <div class="modal-footer">
                <button id="cookieModalConsent" type="button" class="btn btn-primary btn-lg btn-block" data-bs-dismiss="modal">Accept</button>
            </div>
        </div>
    </div>
</div>
*/;
var Tealium = (function () {

    // getScript

    const DEBUG = false;
    const POST_DATA = true;


    if (DEBUG && POST_DATA) {
        DEBUG = false;
        document.cookie = "utagdb=true;path=/";
    }

    const USER_ID = get_UserId();


    //#region Helpers


    function get_Form(form) {
        return form.jquery ? form : $(form);
    }


    function get_FormData(id) {
        const ignore = ['__RequestVerificationToken'];
        const attr = '[data-product-id="' + id + '"]';
        var data = $(attr + ' :input').serializeObject();
        for (var key in data) {
            if (key.indexOf('item.') == 0) {
                if (data.hasOwnProperty(key)) {
                    var newKey = key.replace('item.', '');
                    data[newKey] = data[key];
                    delete data[key];
                }
            }
            if (ignore.indexOf(key) >= 0) {
                delete data[key];
            }
        }
        return data;
    }


    function get_UserId() {
        let cookie = null;
        document.cookie.split(';').forEach(function (item) {
            let parts = item.split('=');
            if (parts[0].trim() == 'tiGAUID') {
                cookie = (parts.length == 3 ? parts[2] : parts[1]);
                return;
            }
        });
        return cookie;
    }


    function get_Checked(selector, context) {
        try {
            const array = (selector.jquery ? selector : $(selector, context)).toArray();
            if (array.every((x) => (x.type == 'radio' || x.type == 'checkbox'))) {
                return $(array.filter(x => x.checked));
            }
        } catch (error) { }
        return null;
    }

    function get_Value(selector, context) {
        try {
            const m = selector.jquery ? selector : $(selector, context);
            if (m.length > 1) {
                const array = m.toArray();
                if (array.every((x) => (x.type == 'radio' || x.type == 'checkbox'))) {
                    const values = array.filter(x => x.checked).map(x => x.value);
                    return values.length == 1 ? values[0] : values;
                }
            }
            return m.val();
        } catch (error) { }
        return null;
    }

    function is_Numeric(value) {
        return (!isNaN(parseFloat(value)) && !isNaN(+value));
    }

    function to_Typed(value) {
        value = (value + '');
        const lower = value.toLowerCase();
        if (lower == 'false') { return false; }
        if (lower == 'true') { return true; }
        if (is_Numeric(value)) {
            if (value == 0) { return 0; }
            if (value === String(Math.round(Number(value)))) {
                return parseInt(value);
            }
            return parseFloat(value).toFixed(2);
        }
        const ms = Date.parse(value);
        if (!isNaN(ms)) { return new Date(ms); }
        return value;
    }

    //#endregion


    //#region Quote


    function get_QuoteData(form) {

        form = get_Form(form);

        const quoteFormId = form.find('[name$="QuoteFormId"]:first');
        const type = parseInt(form.find(':radio[name$="PlanType"]:checked').val());

        const travAges = [];
        const ages = form.find('#Quote_Ages');
        if (ages.length) {
            ages.val().split(',').each(function () {
                travAges.push(parseInt(this));
            })
        } else {
            form.find('.traveler-dob').each(function () {
                travAges.push(moment().diff(moment(this.value, 'MM/DD/YYYY'), 'years'));
            })
        }

        let tripCost = 0;
        form.find('[name$="TripCost"]').each(function () {
            if (is_Numeric(this.value)) {
                tripCost += parseInt(this.value);
            }
        });

        function getValue(name) {
            try {
                return form.find('[name$="' + name + '"]:first').val();
            } catch (error) { }
            return null;
        }

        return {
            quote_id: (quoteFormId ? parseInt(quoteFormId.val()) : 0),
            plan_type: type,
            destination: getValue('Destination'),
            home_country: getValue('Origin'),
            state: getValue('PrimaryResidence'),
            start: getValue('DepartureDate'),
            end: getValue('ReturnDate'),
            student_traveler: (type == 4),
            traveler_ages: travAges,
            trip_protection: (type == 2),
            total_trip_cost: tripCost,
            trip_deposit_date: getValue('DepositDate')
        }
    }

    function get_PlanData_ById(id) {

        const data = to_PlanData(get_FormData(id));

        const plan = $('.plan[data-product-id="' + id + '"]:first');
        if (plan.length) {
            const price = plan.find('.cost').first();
            data['name'] = plan.find('.plan-name:first').text();
            data['price'] = (price ? parseFloat(price.text().replace('$', '')).toFixed(2) : 0);
        }

        return data;
    }

    function to_PlanData(form) {

        const propConvertions = {
            cover_rentalcar: ['CDW', 'CarRentalCollission'],
            cover_cfar: ['CancelForAny'],
            cover_add: ['AD_D'],
            cover_fadd: ['FlightAD_D', 'ADDAirOnly'],
            cover_delay: ['TripDelayMax'],
            cover_eppp: ['ExtendedPersonalProperty'],
            cover_medup: ['EnhancedMedUpgrade', 'MedicalUpgrade']
        };

        const productId = form['ProductId'];
        const baseFormId = form['BaseFormId'];

        const data = {
            id: (productId ? parseInt(productId) : 0),
            quote_id: (baseFormId ? parseInt(baseFormId) : 0),
        };

        for (const prop in propConvertions) {
            propConvertions[prop].forEach(function (name) {
                if (form['ProductQuote.' + name]) {
                    data[prop] = to_Typed(form['ProductQuote.' + name]);
                }
            })
        }

        return data;
    }


    function set_StoredPlanData(data) {

        sessionStorage.setItem('uplan', JSON.stringify(data));
    }

    function get_StoredPlanData() {

        let json = sessionStorage.getItem('uplan');
        if (json) { return JSON.parse(json); }
        return null;
    }


    //ALSO: link_QuoteUpdate
    function link_Quote(form) {

        const formData = get_QuoteData(form);

        const udata = {
            tealium_event: (formData.quote_id > 0) ? 'update quote' : 'get quote',
            form: {
                name: (formData.quote_id > 0) ? 'update my quote' : 'get a quote',
                data: formData
            }
        };

        if (DEBUG) console.log('link_Quote => udata', udata);

        if (POST_DATA) {
            utag.link(udata)
        }
    }


    function link_QuoteEdit(quoteId) {

        const udata = {
            tealium_event: 'edit quote',
            quote_id: quoteId
        };

        if (DEBUG) console.log('link_QuoteEdit => udata', udata);

        if (POST_DATA) {
            utag.link(udata)
        }
    }


    function view_QuoteResults() {

        const results = [];

        const productIds = $('.plan[data-product-id]').map(function () {
            return this.dataset.productId;
        }).get();

        const uniqueIds = productIds.filter(function (value, index, self) {
            return self.indexOf(value) === index;
        });

        uniqueIds.forEach(function (value, index) {

            const data = get_PlanData_ById(value);

            data['position'] = (index + 1);
            data['list'] = 'quote';

            results.push(data);
        });

        let quoteId = 0, tripCost = 0, tripSpan = 0;
        const details = $('[data-quoteform-id]');
        if (details.length) {
            quoteId = parseInt(details.attr('data-quoteform-id')) || 0;
            tripSpan = parseInt(details.attr('data-trip-span')) || 0;
            tripCost = parseInt(details.attr('data-trip-cost')) || 0;
        }

        const udata = {
            page_name: 'quote results',
            page_type: 'quote results',
            quote_id: quoteId,
            coverage_length: tripSpan,
            total_trip_cost: tripCost,
            product: results,
            userid: get_UserId()
        };

        if (DEBUG) console.log('view_QuoteResults => udata', udata);

        if (POST_DATA) {
            utag.view(udata)
        }
    }


    function link_BuyNow(id) {

        const data = get_PlanData_ById(id);
        set_StoredPlanData(data);

        data['quantity'] = 1;
        data['variant'] = '';

        let quoteId = 0, tripCost = 0, tripSpan = 0;
        const quote = $('[data-quoteform-id]');
        if (quote.length) {
            quoteId = parseInt(quote.attr('data-quoteform-id')) || 0;
            tripSpan = parseInt(quote.attr('data-trip-span')) || 0;
            tripCost = parseInt(quote.attr('data-trip-cost')) || 0;
        }

        const udata = {
            tealium_event: 'cart add',
            total_trip_cost: tripCost,
            product: [data]
        };

        if (DEBUG) console.log('link_BuyNow => udata', udata);

        if (POST_DATA) {
            utag.link(udata)
        }
    }





    function link_QuoteEmail(form) {

        form = get_Form(form);

        const quoteFormId = form.find('#ParentId');

        const formData = {
            customer_name: form.find('#Primary_Name').val(), //primary_name
            customer_email: form.find('#Primary_Email').val()//primary_email
        };

        if (form.find('#CcFriend').is(':checked')) {
            const friends = [];
            form.find('.friend').each(function () {
                const friend = $(this);
                const name = friend.find('input[name$="Name"]').val();
                const email = friend.find('input[name$="Email"]').val();
                if (name && email) { friends.push({ name: name, email: email }) }
            });
            if (friends.length) { formData.cc = friends }
        }

        if (form.find('#AddMessage').is(':checked')) {
            const message = form.find('#Message').val();
            if (message) { formData.message = message }
        }

        formData.product_id = [];
        form.find('[name="ProductIds"]:checked').each(function () {
            formData.product_id.push(parseInt(this.value));
        })

        const udata = {
            tealium_event: 'email quote',
            quote_id: (quoteFormId ? parseInt(quoteFormId.val()) : 0),
            form: {
                name: 'email quote',
                data: formData
            }
        };

        if (DEBUG) console.log('link_QuoteEmail => udata', udata);

        if (POST_DATA) {
            utag.link(udata)
        }
    }


    //#endregion


    //#region Member


    // TODO
    function view_MemberLanding() {

        const udata = {
            page_name: 'customer information',
            page_type: 'checkout',
            checkout_step: '1',
            //total_trip_cost: '',
            //product: [{
            //    id: '200',
            //    name: 'safe travels outbound cost saver',
            //    variant: '<string>',
            //    price: '58.17',
            //    quantity: 1,
            //    cover_rentalcar: '',
            //    cover_cfar: ''
            //}],
            product: [get_StoredPlanData()],
            userid: get_UserId()
        };

        if (DEBUG) console.log('view_MemberLanding => udata', udata);

        if (POST_DATA) {
            utag.view(udata)
        }
    }


    function link_MemberSubmit(form) {

        form = get_Form(form);

        const travData = [];
        form.find('.member').each(function () {
            const member = $(this);
            travData.push({
                first_name: member.find('input[name$="FirstName"]').val(),
                last_name: member.find('input[name$="LastName"]').val(),
                birthdate: member.find('input[name$="BirthDate"]').val(),
                age: parseInt(member.find('.age').text())
            })
        });

        const udata = {
            tealium_event: 'form submit',
            form: {
                name: 'customer information',
                data: {
                    travellers: travData,
                    address: form.find('#Address').val(),
                    state: form.find('#State').val(),
                    home_country: form.find('#Country').val(),
                    email: form.find('#Email').val(),
                    phone: form.find('#Phone').val()
                }
            }
        };

        if (DEBUG) console.log('link_MemberConfirm => udata', udata);

        if (POST_DATA) {
            utag.link(udata)
        }
    }


    //#endregion


    //#region Purchase


    function view_PaymentLanding() {

        const udata = {
            page_name: 'payment information',
            page_type: 'checkout',
            checkout_step: '2',
            //total_trip_cost: '',
            //product: [{
            //    id: '200',
            //    name: 'safe travels outbound cost saver',
            //    variant: '<string>',
            //    price: '58.17',
            //    quantity: 1,
            //    cover_rentalcar: '',
            //    cover_cfar: ''
            //}],
            product: [get_StoredPlanData()],
            userid: get_UserId()
        };

        if (DEBUG) console.log('view_PaymentLanding => udata', udata);

        if (POST_DATA) {
            utag.view(udata)
        }
    }


    function link_PaymentSubmit(form) {

        const udata = {
            tealium_event: 'form submit',
            form: {
                name: 'payment information'
            }
        };

        if (DEBUG) console.log('link_PaymentSubmit => udata', udata);

        if (POST_DATA) {
            utag.link(udata)
        }
    }


    function view_PaymentConfirm() {

        const udata = {
            page_name: 'purchase confirmation',
            page_type: 'checkout',
            tealium_event: 'purchase',
            //total_trip_cost: '',
            //order: {
            //    id: '<string>',
            //    grand_total: '58.17',
            //    tax_amount: '0.00',
            //    shipping_amount: '0.00',
            //    promo_code: '<string>',
            //    currency_code: 'USD'
            //},
            product: [get_StoredPlanData()],
            userid: get_UserId()
        };

        const receipt = $('#receipt .receipt:first');
        if (receipt.length) {
            udata['order'] = {
                id: receipt.attr('data-order-id'),
                grand_total: receipt.attr('data-premium'),
                tax_amount: '0.00',
                shipping_amount: '0.00',
                promo_code: '',
                currency_code: 'USD'
            };
        }

        if (DEBUG) console.log('view_PaymentConfirm => udata', udata);

        if (POST_DATA) {
            utag.view(udata)
        }
    }


    //#endregion



    return {

        UserId: USER_ID,

        GetQuoteData: function (form) {
            if (get_Form(form).valid()) {
                try { return get_QuoteData(form) }
                catch (error) { }
                return null;
            }
        },


        View: {

            QuoteResults: function () {
                try { view_QuoteResults() }
                catch (error) { }
            },

            MemberLanding: function () {
                try { view_MemberLanding() }
                catch (error) { }
            },

            PaymentLanding: function () {
                try { view_PaymentLanding() }
                catch (error) { }
            },

            PaymentConfirm: function () {
                try { view_PaymentConfirm() }
                catch (error) { }
            },


        },

        Link: {

            Quote: function (form) {
                if (get_Form(form).valid()) {
                    try { link_Quote(form) }
                    catch (error) { }
                }
            },

            BuyNow: function (id) {
                try { link_BuyNow(id) }
                catch (error) { }
            },

            QuoteEdit: function (id) {
                try { link_QuoteEdit(id) }
                catch (error) { }
            },

            QuoteEmail: function (form) {
                if (get_Form(form).valid()) {
                    try { link_QuoteEmail(form) }
                    catch (error) { }
                }
            },

            MemberSubmit: function (form) {
                if (get_Form(form).valid()) {
                    try { link_MemberSubmit(form) }
                    catch (error) { }
                }
            },

            PaymentSubmit: function (form) {
                if (get_Form(form).valid()) {
                    try { link_PaymentSubmit(form) }
                    catch (error) { }
                }
            },




        }
    }

}());





$(function () {


    const isLocalhost = Boolean(
        window.location.hostname === 'localhost' ||
        // [::1] is the IPv6 localhost address.
        window.location.hostname === '[::1]' ||
        // 127.0.0.1/8 is considered localhost for IPv4.
        window.location.hostname.match(
            /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/,
        ),
    );

    if (true) {


        const _doc = $(document);

        // => The user clicks on the "Edit Quote" button to reveal the criteria change form modal.
        _doc.on('quote-form:show', function (e) {
            try { Tealium.Link.QuoteEdit(e.quoteId); } catch (err) { }
        });

        // => User provides required information and clicks the "Get Quote" button (ADD)
        // => The user clicks on the "Update Quote" button to change quote criteria. (UPDATE)
        // FEEDBACK: no event detected; page refresh detected with utag.view (UPDATE)
        _doc.on('quote-form:insert', function (e) {
            try { Tealium.Link.Quote(e.form); } catch (err) { }
        });

        _doc.on('quote-form:update', function (e) {
            try { Tealium.Link.Quote(e.form); } catch (err) { }
        });

        // => The user has submitted the entry form and landed on the Quote Results page. 
        // FEEDBACK: userid not populated correctly
        _doc.on('quote-results:shown', function (e) {
            try { Tealium.View.QuoteResults(); } catch (err) { }
        });

        //_doc.on("quote-item:show", function (e) {
        //    console.log('EVENT => quote-item:show', this, e);
        //});

        //_doc.on("quote-item:shown", function (e) {
        //    console.log('EVENT => quote-item:shown', this, e);
        //});




        // => The user clicks the "Email" button and then clicks "Send" on the subsequent form.
        _doc.on('submit', '#form-email', function (e) {
            try { Tealium.Link.QuoteEmail(this); } catch (err) { }
        });

        // => The user provides required information and clicks continue
        _doc.on('submit', '#form-member', function (e) {
            try { Tealium.Link.MemberSubmit(this); } catch (err) { }
        });

        // => The user provides valid payment information and clicks "Complete Purchase" button
        _doc.on('submit', '#form-payment', function (e) {
            try { Tealium.Link.PaymentSubmit(this); } catch (err) { }
        });

        // => The user clicks one of the "Buy Now" button
        _doc.on('submit', 'form[action^="/quote/buynow"]', function (e) {
            try { Tealium.Link.BuyNow(this.dataset.productId); } catch (err) { }
        });

        _doc.on('click', '.table-compare .btn-select', function (e) {
            const btn = $(this);
            if (!btn.is(':disabled')) {
                const plan = btn.closest('[data-product-id]');
                if (plan.length) {
                    try { Tealium.Link.BuyNow(plan.attr('data-product-id')); } catch (err) { }
                }
            }
        });



        window.addEventListener('load', function (e) {

            if (is_Page('/Members/Add')) {
                try { Tealium.View.MemberLanding(); } catch (err) { }
            }

            if (is_Page('/Payment/Credit')) {
                try { Tealium.View.PaymentLanding(); } catch (err) { }
            }

            if (is_Page('/Payment/Thanks')) {
                try { Tealium.View.PaymentConfirm(); } catch (err) { }
            }

        })

        function is_Page(path) {
            const loc = window.location.pathname.toLowerCase();
            return (loc.indexOf((path + '').toLowerCase()) == 0);
        }
    }
});


(function PerPageView(path) {

    if (path.charAt(0) === '/') {
        path = path.substring(1);
    }

    var pages = path.split('/');

    function post() {
        var data = {
            userId: Tealium.UserId
        };
        //if (pages.length > 0) {
        //    data['page_type'] = (pages[0] || 'home').replace('-', ' ');
        //}
        //if (pages.length > 1) {
        //    data['page_name'] = pages[1].replace('-', ' ');
        //}
        utag.view(data)
    }

    var interval = setInterval(function () {
        if ('utag' in window) {
            clearInterval(interval);
            post();
        }
    }, 100);

})(window.location.pathname);;
// Updated 1/27/2020


// http://subpopular.github.io/d-calendar/components/d-calendar/demo.html


var TEST_MOBILE = false;

var DEBUG = false;


// https://tempusdominus.github.io/bootstrap-4/

var dateFormat = "MM/DD/YYYY";
var mobiFormat = "YYYY-MM-DD";


var IsMobile = false;


// USING NATIVE MOBILE DATEPICKER DOES NOT FORMAT DATE CORRECTLY ON CARD EXPIRATION !!!
//var IsMobile = (function () {
//    var isMobile = (/Mobile|Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent));
//    return isMobile || TEST_MOBILE;
//})();



// Config.GlobalDefaults
function SetDatepickerDefaults() {
    // Datepicker defaults
    $.fn.datepicker.defaults.enableOnReadonly = false;
    $.fn.datepicker.defaults.assumeNearbyYear = true;
    $.fn.datepicker.defaults.autoclose = true;
    $.fn.datepicker.defaults.todayHighlight = true;
    $.fn.datepicker.defaults.format = 'mm/dd/yyyy';
    $.fn.datepicker.defaults.zIndexOffset = 1000;
    $.fn.datepicker.defaults.templates = {
        leftArrow: '<i class="fa fa-caret-left"></i>',
        rightArrow: '<i class="fa fa-caret-right"></i>'
    };
}


// Config.PickerActions
function defaultPickerActions(element) {
    //var input = element.is(':input') ? element : element.find('input');
    element.on('hide', function (e) {
        if (!this.firstHide) {
            if (!$(this).is(":focus")) {
                this.firstHide = true;
                // this will inadvertently call show (we're trying to hide!)
                this.focus();
            }
        } else {
            this.firstHide = false;
        }
        //element.attr('value', element.val());
    }).on('show', function (e) {
        updateCalendar(element);
        if (this.firstHide) {
            // careful, we have an infinite loop!
            $(this).datepicker('hide').blur();
        }
    })
}

function updateCalendar(element) {
    var datePicker = element.data('datepicker');
    var picker = datePicker.picker;
    picker.addClass('notranslate');
}




// Pickers.Create
function BindDatepickerEvents(context) {

    context = context || document;

    //var start = $('[data-daterange="start"]', context),
    //    end = $('[data-daterange="end"]', context);

    //if (start.length) {
    //    var maxStartTime = parseInt(start.attr('data-max-time') || 0);
    //    var minTime = parseInt(end.attr('data-min-time') || 0);
    //    var maxTime = parseInt(end.attr('data-max-time') || 0);
    //    addRangePickers(start, end, maxTime, minTime, maxStartTime);
    //}

    $('[data-date-range-end]', context).each(function () {

        const start = $(this);
        const end = $(this.dataset.dateRangeEnd);

        const iniTime = parseInt(start.attr('data-max-time') || 0);
        const minTime = parseInt(end.attr('data-min-time') || 0);
        const maxTime = parseInt(end.attr('data-max-time') || 0);

        addRangePickers(start, end, maxTime, minTime, iniTime);
    });


    $('.date-purchase', context).each(addPurchaseDateAttr);
    $('.date-expire', context).each(addCCExpDateAttr);
    $('.date-dob', context).each(addBirthDateAttr);

    $('[data-val-date],[data-provide="datepicker"]').each(function () {
        this.setAttribute('autocomplete', 'off');
        //this.classList.add('notranslate');
    });
}





// NEW METHODS


function fixDateYear(picker) {
    var input = picker.is(':input') ? picker : picker.find('input');
    picker.on('changeDate', function (e) {
        if (input.val().length > 10) {
            // format year to only 4 characters
            var year = e.date.getFullYear().toString();
            e.date.setFullYear(year.substr(0, 4));
            picker.datepicker('update', e.date);
        }
    })
}





// Pickers.PurchaseDate
function addPurchaseDateAttr(e) {
    var input = $(this);
    if (IsMobile) {
        var val = this.value;
        input.attr({
            'type': 'date',
            'min': moment().add(-5, 'y').format(mobiFormat),
            'max': moment().format(mobiFormat),
        });
        if (val) {
            this.value = moment(val).format(mobiFormat);
        }
        return;
    }
    else {
        input.attr({
            'data-provide': 'datepicker',
            'data-date-start-date': moment().add(-5, 'y').format(dateFormat),
            'data-date-end-date': moment().format(dateFormat)
        });
        defaultPickerActions(input);
    }
}





// Pickers.CCExpiryDate
function addCCExpDateAttr(e) {
    var input = $(this);
    if (IsMobile) {
        var val = this.value;
        var m = moment().startOf('month');
        input.attr({
            'type': 'month',
            'min': m.format('YYYY-MM'),
            'max': m.add(20, 'y').format('YYYY-MM')
        });
        if (val) {
            this.value = moment(val).format('YYYY-MM');
        }
        return;
    }
    else {
        input.attr({
            'data-provide': 'datepicker',
            'data-date-format': 'mm/yyyy',
            'data-date-start-date': '0d',
            'data-date-end-date': '+20y',
            'data-date-start-view': 'years',
            'data-date-min-view-mode': 'months',
            //'placeholder': 'mm/yy'
        });
        defaultPickerActions(input);
    }
}





// Pickers.BirthDate
function GetDepartDate(input) {
    var depart = $('[data-daterange="start"]:first') || $('.date-depart:first');
    var date = depart.length ? depart.val() : input ? $(input).data('effDate') : null;
    return date ? moment(date, dateFormat) : null;
}

function isBornOn(date, input) {
    var onDate = GetDepartDate(input);
    if (!onDate) return true;
    return onDate.diff(moment(date), 'days', false) > 0;
}


function hasBeenBorn(dobs, depart) {
    dobs = $(dobs), depart = $(depart);
    if (!dobs.length) return false;
    if (!depart.length) return true;
    var onDate, bornDate, isBorn, age;
    try {
        onDate = moment(depart.val(), dateFormat);
        dobs.each(function () {
            var dob = $(this);
            if (!dob.val() || !depart.val()) {
                isBorn = true;
            } else {
                bornDate = moment(dob.val(), dateFormat);
                isBorn = bornDate.isSameOrBefore(onDate);
                //age = isBorn ? bornDate.to(onDate, true) : null;
                age = isBorn ? onDate.diff(bornDate, 'years') : null;
            }
            handleValidation(dob, isBorn);
            handleAgeDisplay(dob, age);
        })
    } catch (ex) {
        console.error(ex.message);
        throw ex;
    }
    function handleValidation(dob, isBorn) {
        var valmsg = $('[data-valmsg-for="' + dob.attr('name') + '"]');
        if (!isBorn) {
            valmsg.text('Your Birthdate must be on or before ' + onDate.format(dateFormat));
            dob.val('');
        } else { valmsg.text(''); }
        dob.toggleClass('is-invalid', !isBorn);
        if (!dob.val()) dob.removeClass('is-valid');
    }
    function handleAgeDisplay(dob, age) {
        var popover = dob.next('[data-bs-toggle="popover"]');
        if (popover.length) {
            var title = popover.attr('data-bs-original-title');
            if (title) {
                title = title.replace(/<small[\s\S]*?\<\/small>/g, '');
            }
            if (dob.val() && age != null) {
                title += '<small class="badge badge-pill badge-dark float-end">' + (age || '<1') + '</small>';
            }
            popover.attr('data-bs-original-title', title);
        }
    }
    return isBorn;
}




function addBirthDateAttr(e) {
    var input = $(this), viewDate = '';
    var effDate = GetDepartDate(input);
    var age = input.data('memberAge');

    if (effDate && age != undefined) {
        viewDate = moment(effDate, dateFormat)
            .subtract(age, 'y')
            .format(dateFormat);
    }

    if (IsMobile) {
        var val = this.value;
        input.attr({
            'type': 'date',
            //'max': endDate.format(mobiFormat)
            'max': moment().add(1, 'd').format(mobiFormat)
        }).on('input', function (e) {
            //var isBorn = hasBeenBorn(input, '.date-depart:first');
        });
        if (val) {
            this.value = moment(val).format(mobiFormat);
        }
        return;
    }
    else {
        input.attr({
            'data-provide': 'datepicker',
            'data-date-default-view-date': viewDate,
            //'data-date-end-date': '0d',
            'data-date-end-date': moment().format(dateFormat),
            'data-date-start-view': 'decades'
        }).on('hide', function (e) {
            //if (DEBUG) console.log('dob => onHide: ', e);
            //var isBorn = hasBeenBorn(input, '.date-depart:first');

            var prev = input.data('prev-val');
            if (input.val() != prev) {
                input.data('prev-val', input.val());
                if ('AgeBands' in window) {
                    var isBorn = hasBeenBorn(input, '.date-depart:first');
                    if (!isBorn) {
                        AgeBands.NotBornYet(input);
                    }
                    else {
                        AgeBands.Confirm(input);
                    }
                }
            }
        });
        defaultPickerActions(input);
    }
}



//function blah(date, input) {
//	// Age at time of travel.
//	var effDate = GetDepartDate(input);
//	var isBorn = effDate.diff(moment(date), 'days', false) > 0;

//	if (!isBorn) {
//		AgeBands.notBorn(input);
//	}
//	else {
//		var selectedAge = effDate.diff(moment(date), 'years', false);
//		$('#output').append('<li><strong>Selected Age: </strong> ' + selectedAge + '</li>');
//		AgeBands.checkAge(input, selectedAge);
//		//if (input.data('update')) $(input.data('update')).text(selectedAge);
//	}
//}






// Pickers.TripDateRange
function getTimeSpan(start, end, callback) {
    var min = start.datepicker('getDate');
    var max = end.datepicker('getDate');
    //console.log('getTimeSpan: ', start.datepicker(), end.datepicker());
    if (min && max) {
        var days = moment(max).diff(moment(min), 'd') + 1;
        if (callback) callback(days);
        else return days;
    } else {
        return false;
    }
}


//var maxStartLength = parseInt(start.attr('data-max-time') || 0);
//var minLength = parseInt(end.attr('data-min-time') || 0);
//var maxLength = parseInt(end.attr('data-max-time') || 0);

function addRangePickers(start, end, maxLength, minLength, maxStartLength) {

    if (DEBUG) {
        console.log('Datepicker => AddRangePickers',
            '\nstart:\t\t', start.val(),
            '\nend:\t\t', end.val(),
            '\nminLength:\t', minLength,
            '\nmaxLength:\t', maxLength,
            '\nmaxStartLength:\t', maxStartLength,
            '\nisMobile:\t', IsMobile);
    }

    //var range = start.closest('.date-range');
    //if (range.length) {
    //    range.datepicker({
    //        inputs: range.find('.form-control')
    //    });
    //}



    if (maxLength && minLength && maxLength > 0) {
        end.prop('readonly', maxLength == minLength);
    }

    if (maxStartLength && maxStartLength == 1) {
        var sDate = moment().add(1, 'd').format(dateFormat);

        start.datepicker('update', sDate);
        start.prop('readonly', true);

        var minDate = moment(sDate).add(minLength || 1, 'd');
        end.datepicker('update', minDate.format(dateFormat));
    }

    if (IsMobile) {
        addRangePickersMobile(start, end, maxLength, minLength);
        return;
    }
    else {

        start.datepicker({
            startDate: moment().add(1, 'd').format(dateFormat)
        })
            .on('hide', function (e) {
                if (DEBUG) console.log('start => onHide: ', e);

                if (e.date) {
                    var endDate = end.datepicker('getDate');
                    var minDate = moment(e.date).add(minLength || 1, 'd');

                    var endMinDate = end.datepicker('getStartDate');
                    if (!endMinDate || (moment.utc(endMinDate).format(dateFormat) != minDate.format(dateFormat))) {
                        end.datepicker('setStartDate', minDate.format(dateFormat));
                    }

                    if (maxLength > 0) {
                        var maxDate = moment(e.date).add(maxLength, 'd').format(dateFormat);
                        end.datepicker('setEndDate', maxDate);
                    }

                    //if (end.is('[readonly]')) {
                    //    var endDate = end.datepicker('getDate');
                    //    if (!endDate || endDate < minDate) {
                    //        end.datepicker('update', minDate.toDate()).trigger('hide');
                    //    }
                    //}

                    //console.log(end.is('[readonly]'), endDate, minDate);

                    if (end.is('[readonly]')) {
                        if (!endDate || endDate < minDate) {
                            end.datepicker('update', minDate.toDate()).trigger('hide');
                        }
                    } else {
                        if (endDate && endDate < minDate) {
                            end.datepicker('update', '').trigger('hide');
                            end.removeClass('valid is-valid');
                        }
                        //else if (!endDate) {
                        //    end.datepicker('update', '').trigger('hide');
                        //}
                    }

                    //end.focus();
                    //end.datepicker('show');
                    //var isBorn = hasBeenBorn('.date-dob', start);
                }
            });

        end.datepicker({
            startDate: moment().add(2, 'd').format(dateFormat)
        })
        .on('hide', function (e) {
            if (DEBUG) console.log('end => onHide: ', e);
            if (e.date) {
                //var maxDate = moment(e.date).subtract(1, 'd').format(dateFormat);
                //start.datepicker('setEndDate', maxDate);

                //var startDate = start.datepicker('getDate');

                //if (startDate && startDate > maxDate) {
                //    start.datepicker('update', '').trigger('hide');
                //    start.removeClass('valid is-valid');
                //}

            }
        });


        //function addRangeClasses(element, start) {
        //    var datePicker = element.data('datepicker');
        //    var picker = datePicker.picker;
        //    picker.addClass('notranslate');

        //    var tdStart = picker.find('td.disabled:last');

        //}


        if (maxStartLength && maxStartLength == 1) {
            var sDate = moment().add(1, 'd').format(dateFormat);
            start.datepicker('update', sDate).trigger('hide');
        }

        defaultPickerActions(start);
        defaultPickerActions(end);
    }
}



function addRangePickersMobile(start, end, maxLength, minLength) {
    var startVal = start.val();
    var endVal = end.val();

    start.attr({
        'type': 'date',
        'min': moment().add(1, 'd').format(mobiFormat)
    })
        .on('input', function (e) {
            var minDate = moment(this.value).add(1, 'd');
            end.attr('min', minDate.format(mobiFormat));
            if (maxLength) {
                var maxDate = moment(this.value).add(maxLength - 1, 'd');
                end.attr('max', maxDate.format(mobiFormat));
            }
            //var isBorn = hasBeenBorn('.date-dob', start);
        });

    end.attr({
        'type': 'date',
        'min': moment().add(2, 'd').format(mobiFormat)
    })
        .on('input', function (e) {
            var maxDate = moment(this.value).subtract(1, 'd');
            start.attr('max', maxDate.format(mobiFormat));
        });

    if (startVal) {
        start.attr('value', moment(startVal).format(mobiFormat));
    }
    if (endVal) {
        end.attr('value', moment(endVal).format(mobiFormat));
    }
}






/* <input type="date" id="cal"> */
//function openPicker(inputDateElem) {
//	var ev = document.createEvent('KeyboardEvent');
//	ev.initKeyboardEvent('keydown', true, true, document.defaultView, 'F4', 0);
//	inputDateElem.dispatchEvent(ev);
//}

//var cal = document.querySelector('#cal');
//cal.focus();
//openPicker(cal);














// OLD METHODS

function getTravelDate() {
    var date = $('#effDate').datepicker('getDate');
    return date ? moment(date, dateFormat) : moment();
}


function updateAllAgeBadges() {
    $('[name$="travelerDOB"]').each(function () {
        var input = $(this), dob = input.val();
        if (dob) {
            var age = getTravelDate().diff(moment(dob, dateFormat), 'years');
            input.closest('.row').find('[name$="travelerAge"]').val(age);
            input.closest('.row').find('label>.badge').text(age);
        }
    })
}





function bindEvents() {
    //alert('bindEvents');
    SetDatepickerDefaults();
    BindDatepickerEvents();
}




$(function () {


    bindEvents();


    //$(document).on('show hide', 'input[data-val-date]', function (e) {
    //	$(this).toggleClass('focus', e.type != 'hide');
    //});


});






//function WalkTabIndex() {

//	function getTabStops(o, a, el) {
//		// Check if this element is a tab stop
//		if (el.tabIndex > 0) {
//			if (o[el.tabIndex]) {
//				o[el.tabIndex].push(el);
//			} else {
//				o[el.tabIndex] = [el];
//			}
//		} else if (el.tabIndex === 0) {
//			// Tab index "0" comes last so we accumulate it seperately
//			a.push(el);
//		}
//		// Check if children are tab stops
//		for (var i = 0, l = el.children.length; i < l; i++) {
//			getTabStops(o, a, el.children[i]);
//		}
//	}

//	function focusNext() {
//		var o = [],
//				a = [],
//				stops = [],
//				active = document.activeElement;

//		getTabStops(o, a, document.body);

//		// Use simple loops for maximum browser support
//		for (var i = 0, l = o.length; i < l; i++) {
//			if (o[i]) {
//				for (var j = 0, m = o[i].length; j < m; j++) {
//					stops.push(o[i][j]);
//				}
//			}
//		}
//		for (var i = 0, l = a.length; i < l; i++) {
//			stops.push(a[i]);
//		}
//		// If no items are focusable, then blur
//		if (stops.length === 0) {
//			active.blur();
//			return;
//		}
//		// Shortcut if current element is not focusable
//		if (active.tabIndex < 0) {
//			stops[0].focus();
//			return;
//		}
//		// Attempt to find the current element in the stops
//		for (var i = 0, l = stops.length; i < l; i++) {
//			if (stops[i] === active) {
//				if (i + 1 === stops.length) {
//					active.blur();
//					return;
//				}
//				stops[i + 1].focus();
//				return;
//			}
//		}
//		// We shouldn't make it this far
//		active.blur();
//	}

//	document.addEventListener('keypress', function (e) {
//		if (e.which === 13) {
//			e.preventDefault();
//			focusNext();
//		}
//	});
//}

//WalkTabIndex();
;
// Avoid 'console' errors in browsers that lack a console.
(function () {
    var method;
    var noop = function () { };
    var methods = [
        'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',
        'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',
        'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',
        'timeline', 'timelineEnd', 'timeStamp', 'trace', 'warn'
    ];
    var length = methods.length;
    var console = (window.console = window.console || {});

    while (length--) {
        method = methods[length];

        // Only stub undefined methods.
        if (!console[method]) {
            console[method] = noop;
        }
    }
}());




//const AdBlocker = (function () {
//    let detected = false;
//    setTimeout(function () {
//        fetch('https://www3.doubleclick.net', {
//            method: 'HEAD',
//            mode: 'no-cors',
//            cache: 'no-store',
//        }).catch(() => {
//            detected = true;
//            console.log('AdBlock detected');
//        });
//    }, 3500);
//    return {
//        Detected: detected
//    }
//}());



function isValidEmail(str) {
    return (/^[a-zA-Z0-9.!#$%&'*+\/=?\^_`{|}~\-]+@[a-zA-Z0-9\-]+(?:\.[a-zA-Z0-9\-]+)*$/).test(str);
}



//#region Track Events

(function TrackAllEvents() {

    const trackEvents = false;

    function addEventListenerAll(target, listener, ...otherArguments) {
        // install listeners for all natively triggered events
        for (const key in target) {
            if (/^on/.test(key)) {
                const eventType = key.substr(2);
                target.addEventListener(eventType, listener, ...otherArguments);
            }
        }
        // dynamically install listeners for all manually triggered events, just-in-time before they're dispatched ;D
        const dispatchEvent_original = EventTarget.prototype.dispatchEvent;
        function dispatchEvent(event) {
            target.addEventListener(event.type, listener, ...otherArguments); // multiple identical listeners are automatically discarded
            dispatchEvent_original.apply(this, arguments);
        }
        EventTarget.prototype.dispatchEvent = dispatchEvent;
        if (EventTarget.prototype.dispatchEvent !== dispatchEvent) {
            throw new Error(`Browser is smarter than you think!`);
        }
    }

    if (trackEvents) {
        addEventListenerAll(document, (evt) => {
            if (evt.type.indexOf('mouse') < 0 && evt.type.indexOf('pointer') < 0) {
                var cn = evt.target.className;
                //if (cn.baseVal) { cn = cn.baseVal }
                if (cn && typeof cn === 'string') {
                    if (cn.indexOf('goog-') >= 0) {
                        console.log(evt);
                    }
                }
            }
        })
    }
}());


//#endregion

//#region Suppress Errors


const Errors = (function () {

    const on_Error = window.onerror;

    function disable() {
        window.onerror = function (message, url, lineNumber) {
            // code to execute on an error  
            return true; // prevents browser error messages  
        };
    }

    function enable() {
        window.onerror = on_Error;
    }

    return {
        Disable: disable,
        Enable: enable
    }
}());

if (location.host.indexOf('localhost') == 0) {
    //Errors.Disable();
}


//#endregion



//#region jQuery Extentions

(function ($) {

    $.fn.redraw = function () {
        return $(this).each(function () {
            var redraw = this.offsetHeight;
        });
    };
    //$('.theElement').redraw();


    $.fn.equalHeights = function () {
        return this.height('').outerHeight(Math.max.apply(this,
            this.map(function () { return $(this).outerHeight(true) }))
        );
    };

    // auto-initialize plugin
    const eqHts = $('[data-equal-heights]');
    if (eqHts.length) {
        $(window).on('resize', function (e) {
            eqHts.each(function () {
                $(this).find(this.dataset.equalHeights).equalHeights();
            });
        }).resize();
    }


    $.fn.serializeObject = function () {
        var o = {}, a = this.serializeArray();
        $.each(a, function () {
            var n = this.name, v = this.value;
            if (o[n]) {
                if ((typeof (v) === "boolean") ||
                    (typeof (v) === "string" && v != undefined &&
                        (v.toLowerCase() === "true" || v.toLowerCase() === "false"))) {
                    o[n] = ((o[n] == "true") | (v == "true")) ? true : false;
                } else {
                    if (!o[n].push) { o[n] = [o[n]]; }
                    o[n].push(v || '');
                }
            } else { o[n] = v || ''; }
        });
        return o;
    };

    $.expr[":"].onScreen = function (elem) {
        var $window = $(window)
        var viewport_top = $window.scrollTop()
        var viewport_height = $window.height()
        var viewport_bottom = viewport_top + viewport_height
        var $elem = $(elem)
        var top = $elem.offset().top
        var height = $elem.height()
        var bottom = top + height

        return (top >= viewport_top && top < viewport_bottom) ||
            (bottom > viewport_top && bottom <= viewport_bottom) ||
            (height > viewport_height && top <= viewport_top && bottom >= viewport_bottom)
    }
    /*
     $(function() {
      setInterval(function() {
        $("h2")                             // get all &lt;h2&gt;s
          .css("background-color", "")      // reset their background colours
          .filter(":onScreen")              // get only &lt;h2&gt;s on screen
            .css("background-color", "red") // give them a red background
      }, 1000)                              // repeat every second
    })*/
})(jQuery);

//#endregion


//#region AddressByZip

function AddressByZip(_zip, _city, _state, _readonly) {
    // when the zip code changes…
    function SetReadOnly(input) {
        //input.nextElementSibling.textContent = '';
        input.prop('readonly', true);
    }

    $(_zip).on('keyup', function () {
        var googleUrl = 'http://maps.googleapis.com/maps/api/geocode/json?';
        var getParams = { address: '', sensor: true };
        if (this.value.length === 5) {
            getParams.address = this.value;
            var finalUrl = googleUrl + $.param(getParams);
            //this.nextElementSibling.textContent = '';
            this.blur();
            $.get(finalUrl, function (data) {
                if (data.status === 'OK') {
                    var city, state, comp = data.results[0].address_components;
                    for (var i = 0; i < comp.length; i++) {
                        if (comp[i].types[0] === 'locality') {
                            city = $(_city).val(comp[i].long_name);
                            if (_readonly) SetReadOnly(city);
                        }
                        else if (comp[i].types[0] === 'administrative_area_level_1') {
                            state = $(_state).val(comp[i].long_name);
                            if (_readonly) SetReadOnly(state);
                        }
                    }
                }
            });
        }
    })
}

//#endregion



//#region Country/States [Obsolete]

//function selectValueByOptionText(selectId, textToFind) {
//	const dd = document.getElementById(selectId);
//	dd.selectedIndex = [...dd.options].findIndex(option => option.text === textToFind);
//}

function SyncCountryToStates(country, state, stateSelect) {

    const DEBUG = false;

    country = $(country);
    state = $(state);
    stateSelect = $(stateSelect);


    if (DEBUG) {
        console.log('country', country.val());
        console.log('state', state.val());
        console.log('stateSelect', stateSelect.val());
    }


    var observer = new MutationObserver(function (mutations) {
        stateSelect.toggleClass('valid', !!state.val() || state.hasClass('valid'));
        stateSelect.toggleClass('input-validation-error', state.hasClass('input-validation-error'));
    });

    observer.observe(state[0], {
        attributes: true,
        attributeFilter: ['class'],
        childList: false,
        characterData: false
    });


    const stateArray = get_SelectArray(stateSelect);
    if (DEBUG) console.log('stateArray', stateArray);


    country.on('change', function (e) {

        const is_US = (country.val() == (!isNaN(country.val()) ? '0' : 'US'));

        stateSelect.toggleClass('sr-only', !is_US);
        state.toggleClass('sr-only', is_US);

        const stateName = state.val();
        const stateAbbr = stateSelect.val();

        if (DEBUG) {
            console.log('country.change => is_US', is_US);
            console.log('country.change => input', stateName);
            console.log('country.change => select', stateAbbr);
        }

        //if (!is_US && is_USState(state.val())) {
        //    stateSelect.val('').change();
        //}

        if (!is_US) {
            if (stateSelect.val()) {
                state.val(stateSelect.find('option:selected').text());
                stateSelect.val('');
            }
        }
        else {
            //state.val('');
            const isState = is_USState(stateName);
            if (DEBUG) console.log('country.change => is_USState', stateName, isState);
            if (isState) {
                const found = stateArray.find(function (item) { return item.text == state.val() });
                if (DEBUG) console.log('country.change => found', found);
                if (found != null) { stateSelect.val(found.value).change(); }
            }
        }

        if (DEBUG) console.log('country.change => select:', stateSelect.val(), ', input:', state.val());

    }).change();


    state.removeClass('d-none').on('input', function (e) {
        const optionIndex = find_StateOptionIndex(this.value);

        if (DEBUG) console.log('state.input => select:option', this.value, optionIndex);

        if (optionIndex) {
            stateSelect[0].selectedIndex = optionIndex;
        } else {
            stateSelect.val('');
        }
        if (DEBUG) console.log('state.input => select:', stateSelect.val(), ', input:', state.val());
    });


    stateSelect.removeClass('d-none').on('change', function (e) {
        state.val(this.value).blur();
        if (DEBUG) console.log('stateSelect.change => select:', stateSelect.val(), ', input:', state.val());
    }).change();


    function find_StateOptionIndex(input) {
        const search = (input + '').toUpperCase().trim();
        //console.log('find_StateOption', input, search);

        let found = false;
        let index = 0;
        stateSelect.find('option').each(function () {
            if (!found &&
                (search.length == 2 && this.value == search) ||
                (this.textContent + '').toUpperCase().trim() == search
            ) {
                // a 'return' here won't work!!
                //console.log('stateSelect:found = index', this.value, search, this.index);
                found = true;
                index = this.index;
            }
        });
        return index;
    }

    function is_USState(value) {
        const prop = value.length == 2 ? 'value' : 'text';
        const found = stateArray.find(function (item) { return item[prop] == value });
        return (found != null);
    }

    function get_SelectArray(select) {
        const options = select.find('option[value]:not([value=""])');
        return (options.map(function () {
            return {
                value: this.value,
                text: this.textContent
            }
        }).get()) || [];
    }
}

//#endregion


//#region ExpandAll

function CreateToggleAll(toggle, elements, persist) {

    var ALL_ATTR = 'data-all';
    var ACTIVE_CLASS = 'show';
    var STORE_NAME = 'Active';

    function AnyHidden() {
        return elements.not('.' + ACTIVE_CLASS).length > 0;
    }

    function AllHidden() {
        return !elements.hasClass(ACTIVE_CLASS);
    }

    function AllShown() {
        return elements.not('.' + ACTIVE_CLASS).length == 0;
    }

    function Indeterminate() {
        return !AllHidden() && !AllShown();
    }

    function ToggleCheckbox() {
        toggle.prop('indeterminate', Indeterminate());
        toggle.prop('checked', AllShown());
    }


    function SetStore(id, active) {
        var store = sessionStorage.getItem(STORE_NAME);
        var array = store ? JSON.parse(store) : [];
        var index = array.indexOf(id);
        if (active != true) array.splice(index, 1);
        else if (index < 0) array.push(id);
        sessionStorage.setItem(STORE_NAME, JSON.stringify(array));
    }

    function InitFromStore() {
        var store = sessionStorage.getItem(STORE_NAME);
        var array = store ? JSON.parse(store) : [];
        //elements.collapse('hide');
        elements.removeClass('show');
        [].forEach.call(array, function (id) {
            var element = $('#' + id);
            if (element.hasClass('collapse')) {
                //element.collapse('show');
                element.addClass('show');
            }
        })
    }

    elements.removeAttr('data-parent')
        .on('shown.bs.collapse hidden.bs.collapse', function (e) {
            if (!this.hasAttribute(ALL_ATTR)) ToggleCheckbox();
            if (persist) SetStore(this.id, e.type == 'shown');
            this.removeAttribute(ALL_ATTR);
        });

    toggle.on('change', function (e) {
        elements.attr(ALL_ATTR, true)
            .collapse(this.checked ? 'show' : 'hide');
    });

    if (persist == true) {
        InitFromStore();
    }

    ToggleCheckbox();
}

//#endregion


//#region Print

function PrintPageAreaById(areaID, styles) {
    var global = '/bundles/css/global';
    if (styles) global += ',' + styles;

    const area = $('#' + areaID);
    if (area.length) { area.print(global) }
    else { console.error('Area not found by that ID') }
}

function PrintPageAreaByUrl(url, areaID, styles) {
    var global = '/bundles/css/global';
    if (styles) global += ',' + styles;

    const button = this;
    const useAjax = ('Ajax' in window);

    if (useAjax) {
        Ajax.AddLoadingIcon.apply(button);
    }

    const request = $.ajax({
        method: 'GET',
        url: url
    });

    request.done(function (data) {

        var output = $('<div class="print-items">').html(data);

        if (areaID) {
            var results = output.find('#' + areaID);
            if (results.length) { output = results }
        }

        if (useAjax) {
            Ajax.RemoveLoadingIcon.apply(button);
        }

        console.log('output', output);
        output.print(global);
    });
}


$.fn.extend({
    print: function (cssPath) {
        const frameName = 'printIframe';
        let doc = window.self.frames[frameName];
        if (!doc) {
            $('<iframe>').hide().attr('name', frameName).appendTo(document.body);
            doc = window.self.frames[frameName];
        }

        //console.log(this, arguments);

        const htmlDoc = (new DOMParser().parseFromString(this[0].outerHTML, 'text/html'));
        const htmlContent = htmlDoc.body.outerHTML;

        //console.log('htmlContent', htmlContent);

        if (cssPath) {
            let styleSection = '';
            function getCssData(array) {
                $.get(array.shift().trim(), function (data) {
                    styleSection += data;
                    if (array.length) {
                        getCssData(array);
                    } else {
                        doc.document.head.innerHTML += '<style>' + styleSection + '</style>';
                        doc.document.body.innerHTML = htmlContent;
                        doc.window.print();
                    }
                })
            }
            getCssData(cssPath.split(','));
        } else {
            doc.document.body.innerHTML = htmlContent;
            doc.window.print();
        }

        //doc.window.onafterprint = function (e) {
        //    $(doc).remove();
        //}

        return this;
    }
});


$(document).on('click', '[data-print-id],[data-print-url]', function (e) {

    var areaId = this.getAttribute('data-print-id');
    var styles = this.getAttribute('data-print-css');

    if (this.hasAttribute('data-print-url')) {
        var url = this.getAttribute('data-print-url');
        PrintPageAreaByUrl.call(this, url, areaId, styles);
    } else {
        PrintPageAreaById.call(this, areaId, styles);
    }
});

//#endregion


//#region FormChanges

function FormChanges(form) {
    // get form
    if (typeof form == "string") form = document.getElementById(form);
    if (!form || !form.nodeName || form.nodeName.toLowerCase() != "form") return null;

    // find changed elements
    var changed = [], n, c, def, o, ol, opt;
    for (var e = 0, el = form.elements.length; e < el; e++) {
        n = form.elements[e];
        c = false;

        switch (n.nodeName.toLowerCase()) {
            // select boxes
            case "select":
                def = 0;
                for (o = 0, ol = n.options.length; o < ol; o++) {
                    opt = n.options[o];
                    c = c || (opt.selected != opt.defaultSelected);
                    if (opt.defaultSelected) def = o;
                }
                if (c && !n.multiple) c = (def != n.selectedIndex);
                break;
            // input / textarea
            case "textarea":
            case "input":
                switch (n.type.toLowerCase()) {
                    case "checkbox":
                    case "radio":
                        // checkbox / radio
                        c = (n.checked != n.defaultChecked);
                        break;
                    default:
                        // standard values
                        c = (n.value != n.defaultValue);
                        break;
                }
                break;
        }
        if (c) changed.push(n);
    }
    return changed;
}

//#endregion



(function InitPopups() {

    var DATA_KEY = 'bs.popup';

    //console.log(window.Popper);

    $(document)
        .on('click', '[data-toggle="popup"]', _togglePopup)
        .on('click', _clickOutside);

    function _clickOutside(event) {
        //console.log('_clickOutside');
        var target = $(event.target),
            parent = target.closest('.popup'),
            popups = $('.popup.show');
        if (!event.isDefaultPrevented()) {
            if (parent.length) {
                popups = popups.not(parent);
            }
            popups.each(function () {
                //console.log('_clickOutside');
                var popup = $(this);
                _removePopper(popup);
            })
        }
    }

    function _togglePopup(event) {
        //console.log('_togglePopup');
        var popup = $(this).blur().closest('.popup');
        if (!popup.hasClass('show')) {
            _createPopper(popup);
        } else {
            _removePopper(popup);
        }
    }

    function _createPopper(popup) {
        //console.log('_createPopper');
        popup.trigger('show.' + DATA_KEY).addClass('show');

        var _placement = popup.hasClass('down') ? 'bottom' : 'top';
        if (popup.hasClass('left')) { _placement += '-start' }
        else if (popup.hasClass('right')) { _placement += '-end' }

        var isCentered = _placement.indexOf('-') < 0;
        var _offset = popup.attr('data-offset') || ((isCentered ? '0' : '-10') + ', 10');

        if (popup.attr('data-add-focus') == 'true') {
            popup.find('.popup-content :input:not(:hidden):empty').first().focus();
        }

        //var ref = popup[0];
        //ref = document.getElementsByTagName('main')[0];
        popup.data(DATA_KEY, new Popper(popup[0], popup.find('.popup-content')[0], {
            placement: _placement,
            //positionFixed: true,
            modifiers: {
                offset: { offset: _offset },
                flip: { behavior: 'flip' },
                //preventOverflow: { boundariesElement: 'viewport', enabled: true },
                hide: { enabled: false }
            },
            onCreate: function onCreate(data) {
                popup.trigger('shown.' + DATA_KEY);
            }//,
            //onUpdate: function onUpdate(data) {
            //	console.log('popup update');
            //}
        }));

        popup.find('[data-dismiss="popup"]').on('click', function (e) {
            _removePopper(popup);
        })
    }

    function _removePopper(popup) {

        var valid = true;

        if (popup.attr('data-validate') == 'true' && $.validator) {
            valid = false;
            popup.closest('form').validate();
            var invalid = popup.find('.invalid, .is-invalid');
            if (!invalid.length) { valid = true }
        }
        if (!valid) return false;

        if (popup.data(DATA_KEY) !== null) {
            //console.log('_removePopper');
            popup.trigger('hide.' + DATA_KEY);
            popup.data(DATA_KEY).destroy();
            //popup.removeData(DATA_KEY);
            popup.removeClass('show');
            popup.removeAttr('x-placement style');
            //popup.off('.' + DATA_KEY);
            popup.find('[data-dismiss="popup"]').off('click');
            popup.trigger('hidden.' + DATA_KEY);
        }
    }
}());

(function InitListControls(listSelector) {

    $(listSelector || '.list-control').each(function () {
        var listControl = $(this),
            selectControl = $(this.dataset.select),
            defaultValue = selectControl.val();

        listControl.find('[data-value]').on('click', function (e) {
            var a = $(this), active = a.is('.active');
            selectControl.val(active ? defaultValue : a.data('value')).change();
            e.preventDefault();
        });

        selectControl.on('change', function (e) {
            listControl.find('a').removeClass('active');
            listControl.find('a[data-value="' + this.value + '"]').addClass('active');
        });

        // Hide all list items that are not options
        var optionVals = selectControl.find('option').map(function () { return this.value }).get();
        listControl.find('a').each(function () {
            if (optionVals.indexOf(this.dataset.value) < 0) {
                $(this).addClass('d-none');
            }
        })
    })
}());

(function Carousels() {

    var carousels = $('.carousel[data-image="cover"]');

    if (carousels.length) {

        carousels.each(function (index, element) {
            $(this).find('.carousel-item > img').each(function () {
                //$(this).attr('class', 'sr-only').closest('.carousel-item')
                //.css('background-image', 'url(' + this.src + ')').addClass('background');
                var item = this.parentElement;
                item.style.backgroundImage = 'url(' + this.src + ')';
                item.classList.add('background');
                this.setAttribute('class', 'sr-only');
            })
        })

        $(window).on('resize', function (e) {
            carousels.each(function (index, element) {
                var carousel = $(this);
                var items = carousel.find('.carousel-item:not(.active)').addClass('active');
                carousel.height('').height(carousel.height());
                items.removeClass('active');
            })
        }).resize();
    }

}());

(function ScrollTo(pageTop) {
    // https://perishablepress.com/vanilla-javascript-scroll-anchor/

    // Just add the scroll class to any page link to scroll smoothly
    const links = document.querySelectorAll('a[href^="#"].scroll');

    if (links.length) {

        [].forEach.call(links, function (link) {
            link.addEventListener('click', scrollAnchors);
        });


        function distanceToTop(node) {
            var bounds = node.getBoundingClientRect();
            //const header = document.querySelector('header.sticky-top');
            var top = Math.floor(bounds.top);
            //if (header) { top -= header.clientHeight; }
            return top;
        }

        function getValidNumber(value) {
            try {
                if (value && !isNaN(value) && parseInt(value) > 0) {
                    return parseInt(value);
                }
            } catch (error) { }
            return 0;
        }

        function canFocus(element) {
            var focusable = (element.type || element.href);
            var tabIndex = getValidNumber(element.tabIndex);
            if (focusable && tabIndex >= 0) {
                return ('disabled' in element) ? !element.disabled : true;
            }
            return false;
        }

        function scrollAnchors(e, respond) {
            e.preventDefault();

            var targetID = (respond) ? respond.getAttribute('href') : this.getAttribute('href');
            var targetTop = (targetID === '#');
            var targetAnchor = document.querySelector(targetTop ? pageTop : targetID);
            if (!targetAnchor) return;

            var scrollClass = this.getAttribute('data-scroll-class');
            if (scrollClass && !targetTop) {
                targetAnchor.classList.add(scrollClass);
                var timer = getValidNumber(this.getAttribute('data-scroll-class-timer'));
                if (timer > 0) {
                    setTimeout(function () { targetAnchor.classList.remove(scrollClass) }, timer);
                }
            }

            var scrollFocus = this.getAttribute('data-scroll-focus');
            if (scrollFocus) {
                if (scrollFocus.indexOf(targetID) == 0) {
                    scrollFocus = scrollFocus.slice(targetID.length).trim();
                }
                var focusTarget = targetAnchor.querySelector(scrollFocus);
                if (focusTarget && canFocus(focusTarget)) { focusTarget.focus(); }
            }

            var scrollDuration = Math.max(getValidNumber(this.getAttribute('data-scroll-duration')), 500);
            $('html, body').animate({ scrollTop: $(targetAnchor).offset().top }, scrollDuration);


            //const originalTop = distanceToTop(targetAnchor);
            //window.scrollBy({ top: originalTop, left: 0, behavior: 'smooth' });

            //const checkIfDone = setInterval(function () {
            //    const atBottom = window.innerHeight + window.pageYOffset >= document.body.offsetHeight - 2;
            //    if (distanceToTop(targetAnchor) === 0 || atBottom) {
            //        targetAnchor.tabIndex = '-1';
            //        targetAnchor.focus();
            //        window.history.pushState('', '', targetID);
            //        clearInterval(checkIfDone);
            //    }
            //}, 100);
        }

    }

    //// For Ajax loaded links
    //document.addEventListener('click', function (e) {
    //    //event = e || window.e;
    //    //var target = e.target || e.srcElement;
    //    var respond = document.getElementById('respond-link');
    //    if (e.target.classList.contains('scroll-live')) scrollAnchors(e, respond);
    //});

}('main'));

(function StickyStacker() {
    //var sticky = $('.sticky-top');
    var sticky = $('.sticky-top,.sticky-sm-top,.sticky-md-top,.sticky-lg-top,.sticky-xl-top');
    if (sticky.length > 1) {
        $(window).on('scroll', function (e) {
            var scrollTop = window.pageYOffset;
            var ypos = 0;
            sticky.each(function (index) {
                var elem = $(this);
                if (index > 0) { elem.css({ 'top': ypos }); }
                var top = elem.offset().top;
                var height = elem.outerHeight();
                var bottom = Math.max((top - scrollTop) + height, 0);

                var gap = Math.max(top - scrollTop - ypos, 0);
                elem.toggleClass('stacked', Math.floor(gap) == 0);

                //elem.attr('data-top', top);
                //elem.attr('data-height', height);
                //elem.attr('data-bottom', bottom);
                //elem.attr('data-gap', gap);
                ypos = bottom;
            })
        }).scroll();
    }
}());

(function VisitorMatrix() {

    var SELECTED_CLASS = 'selected';
    var STATIC_BTN_CLASS = 'btn-default';
    var ACTIVE_BTN_CLASS = 'btn-success';

    $('.table-matrix').each(function () {
        var matrix = $(this);
        var rates = matrix.find('.btn[data-plan]');
        var select = $(matrix.data('select'));

        rates.on('click', function (e) {
            var btn = $(this),
                planId = btn.data('plan'),
                deductible = btn.data('deductible'),
                index = btn.closest('td').index();

            matrix.find('thead th').removeClass(SELECTED_CLASS)
                .eq(index).addClass(SELECTED_CLASS);

            rates.removeClass(ACTIVE_BTN_CLASS).addClass(STATIC_BTN_CLASS);
            btn.removeClass(STATIC_BTN_CLASS).addClass(ACTIVE_BTN_CLASS);

            btn.closest('tr').addClass(SELECTED_CLASS)
                .siblings().removeClass(SELECTED_CLASS);

            select.val(planId);
        });

        // Do page load stuff
        var selPlanId = select.val();
        if (selPlanId) {
            var selRate = rates.filter('[data-plan="' + selPlanId + '"]')
            var selIndex = selRate.closest('td').index();
            matrix.find('thead th').eq(selIndex).addClass('selected');
            selRate.removeClass(STATIC_BTN_CLASS).addClass(ACTIVE_BTN_CLASS);
            selRate.closest('tr').addClass(SELECTED_CLASS);
        }
    })
}());

(function MonitorLanguage() {

    var handleByReload = false;
    var localeLanguage = 'en';
    var selectLanguage = null;

    var html = document.querySelector('html');

    // https://developer.mozilla.org/en-US/docs/Web/API/Window/languagechange_event
    // ResponseHeaders: "content-language" => "{lang}"


    //html.addEventListener('DOMAttrModified', function (event) {
    //    if (event.target.tagName === 'HTML' && event.attrName === 'lang') {

    //        var prev = event.prevValue;
    //        var next = event.newValue;

    //        console.log('html => DOMAttrModified, prev:', prev, ', next:', next);

    //        //console.log('html => DOMAttrModified', event);
    //    }
    //    //console.log('html => DOMAttrModified', event);
    //}, false);


    if (IsFramed()) {
        window.addEventListener('message', function (event) {
            if (typeof event.data == 'object' && event.data.lang) {
                triggerTranslate(event.data.lang);// { lang: 'auto' }
            }
        })
    }


    var langObserver = new MutationObserver(function (mutations) {
        mutations.forEach(function (mutation) {
            if (mutation.attributeName === 'lang') {
                var lang = html.getAttribute('lang');
                //console.log('observer => lang', lang);

                // lang:auto happens when closing banner
                // check if triggered by banner closing and just update lang attribute

                //if (lang == 'auto') {
                //    lang = selectLanguage || localeLanguage;
                //    selectLanguage = null;// Only allow to re-run once
                //    triggerTranslate(lang);
                //} else {
                //    setDatePickerLanguage(lang);
                //    updateButtonLanguage(lang);
                //    //if (lang === 'en') { hideBanner(); }
                //}

                if (lang != 'auto') {
                    setDatePickerLanguage(lang);
                    updateButtonLanguage(lang);
                    updateDocumentLinks(lang);
                    //sendFramesLanguage(lang);
                    //if (lang === 'en') { hideBanner(); }
                } else if (selectLanguage) {
                    //console.log('observer => selectLanguage', selectLanguage);
                    triggerTranslate(selectLanguage);
                }
                // Remove here. Only allow to re-run once.
                selectLanguage = null;

                //clearTimeout(triggerTimeout);
                if (handleByReload) {
                    var loc = window.location;
                    if (loc.hash.indexOf('googtrans') >= 0) {
                        history.pushState("", document.title, loc.pathname + loc.search);
                    }
                }
            }
        })
    });

    langObserver.observe(html, {
        attributes: true,
        //attributeFilter: ['lang'],
        childList: false,
        subtree: false
    });



    function setDatePickerLanguage(lang) {
        // Requires: datepicker translation files 
        try {
            var dates = $.fn.datepicker.dates;

            if (!dates[lang]) {
                lang = lang.split('-')[0];
                if (!dates[lang]) {
                    lang = $.fn.datepicker.defaults.language;
                }
            }

            $('[data-val-date],[data-provide="datepicker"]').each(function () {
                $(this).datepicker('destroy');
            });

            $.fn.datepicker.defaults.language = lang;
            BindDatepickerEvents(document);
        }
        catch (error) {
            console.log('setDatePickerLanguage => error', error);
        }
    }

    function updateButtonLanguage(lang) {
        // Requires: top menu language selector dropdown
        var list = $('.languages');
        var link = list.find('[data-lang="' + lang + '"]');
        if (link.length) {
            var toggle = list.find('[data-bs-toggle="dropdown"]').addClass('disabled');
            link.addClass('active').siblings('.active').removeClass('active');
            toggle.html(link.html()).removeClass('disabled');
        }
    }
    // Set dropdown language on page load
    updateButtonLanguage(html.getAttribute('lang'));

    function updateDocumentLinks(lang) {
        // Requires: links (<a>) to documents (w/ class ".url-lang")
        var regex = /(lang=).*?(&|$)/i;
        $('a.url-lang').each(function () {
            if (this.href.indexOf('lang=') > 0) {
                if (lang == 'en') {// remove
                    var parts = this.href.split('?');
                    var search = parts[parts.length - 1].replace(regex, '').replace('&&', '&');
                    this.href = (parts.length > 1 && search) ? parts[0] + '?' + search : parts[0];
                } else {// update
                    this.href = this.href.replace(regex, '$1' + lang + '$2');
                }
            } else if (lang != 'en') {
                this.href += ((this.href.indexOf('?') >= 0) ? '&' : '?') + 'lang=' + lang;
            }
        })
    }

    function sendFramesLanguage(lang) {
        // Requires: setup on other end of iframes
        const frames = document.querySelectorAll('iframe');
        Array.prototype.forEach.call(frames, function (frame) {
            frame.contentWindow.postMessage({ lang: lang }, '*');
        })
    }



    function getBanner() {
        return $('.goog-te-banner-frame').parent();
    }

    function bannerVisible() {
        var banner = getBanner();
        if (banner.length) {
            return banner.is(':visible');
        }
        return false;
    }

    function hideBanner() {
        // Only needs a class now
        $('html').addClass('no-googbar');
        //if (bannerVisible()) {
        //    getBanner().hide();
        //    $('body').css('top', 0);
        //}
    }

    var triggerTimeout = 0;
    function triggerTranslate(lang) {
        var element = $('#translate select');
        if (element.length) {
            //if (handleByReload) {
            //    element.on('change', function (e) {
            //        triggerTimeout = setTimeout(function () {
            //            if (lang != html.getAttribute('lang')) {
            //                window.location = '#googtrans(en|' + lang + ')';
            //                window.location.reload();
            //            }
            //        }, 1000)
            //    });
            //}
            element.val(lang);
            if (document.createEvent) {
                var ev = document.createEvent('HTMLEvents');
                ev.initEvent('change', true, true);
                element.get(0).dispatchEvent(ev);
            } else {
                var ev = document.createEventObject();
                element.get(0).fireEvent('onchange', ev);
            }
        }
    }


    $('.languages').on('click', '[data-lang]', function (e) {
        e.preventDefault();
        if (this.classList.contains('active')) {
            e.stopPropagation();
            return false;
        }
        //console.log('click => lang', this.dataset.lang);
        if (handleByReload) {
            window.location = $(this).attr('href');
            window.location.reload();
        } else {
            selectLanguage = this.dataset.lang;
            triggerTranslate(selectLanguage);
        }
    });


    $('[data-set-lang]').on('click', function (e) {
        triggerButtonClick(this.dataset.setLang)
        e.stopPropagation();
        e.preventDefault();
    });

    function triggerButtonClick(lang) {
        var list = $('.languages');
        if (list.length) {
            if (!list.is(':visible')) {
                var navCol = list.closest('.navbar').find('.navbar-collapse');
                if (navCol.length) {
                    navCol.on('shown.bs.collapse', function (e) {
                        navCol.off('shown.bs.collapse');
                        setLang();
                    }).collapse('show');
                }
            } else {
                setLang();
            }
        }
        function setLang() {
            var link = list.find('[data-lang="' + lang + '"]');
            if (link.length) { link.trigger('click'); }
            else { list.find('[data-bs-toggle="dropdown"]').dropdown('show'); }
        }
    }


    //var langDrop = $('.languages');

    //langDrop.on('show.bs.dropdown', function (e) {
    //    console.log('dropdown => show');
    //});

    //langDrop.on('hide.bs.dropdown', function (e) {
    //    console.log('dropdown => hide');
    //});

}());

(function CookieBar() {

    const Cookies = {
        get: function (name) {
            let ca = document.cookie.split(';');
            for (let i = 0; i < ca.length; i++) {
                let pair = ca[i].split('=');
                if (name == pair[0].trim()) {
                    return decodeURIComponent(pair[1]);
                }
            }
            return null;
        },
        set: function (name, value, expires, domain, secure) {
            let cookie = name + '=' + encodeURIComponent(value);
            const date = (expires instanceof Date) ? expires : new Date();
            if (Number.isInteger(expires)) {
                date.setTime(date.getTime() + (expires * 24 * 60 * 60 * 1000));
            }
            let path = ';path=/';
            if (typeof domain === 'string') path += ';domain=' + domain;
            if (secure) path += ';secure';
            document.cookie = cookie + ';expires=' + date.toUTCString() + path;
        },
        delete: function (name) {
            Cookies.set(name, '', -1);
        }
    };

    function create(pplink) {
        let html = '<div class="cookie-bar"><div class="cookie-bar-inner">';
        html += '<div>By using this site, you agree to our <a href="' + pplink + '" target="_blank">Privacy Policy</a>.</div>';
        html += '<div><button class="btn btn-lg btn-purple btn-cookie-close"><i title="Accept" class="fa fa-times"></i> Accept</button></div>';
        html += '</div></div>';
        return html;
    }

    function init() {
        const isLocal = window.location.hostname.includes('localhost');
        const domain = null;// !isLocal ? '.trawickinternational.com' : null;
        const pplink = '//www.trawickinternational.com/privacy-policy';
        if (!Cookies.get('cookie-bar-closed')) {
            const element = $('.cookie-bar');
            if (!element.length) {
                $(document.body).append(create(pplink));
            }
        }
        $(document).on('click', '.cookie-bar .btn-cookie-close', function (e) {
            e.preventDefault();
            $(e.currentTarget).closest('.cookie-bar').remove();
            Cookies.set('cookie-bar-closed', 'true', new Date(2050, 0), domain);
        })
    }

    //init();
}());

(function ModalVideo() {

    $(document).on('click', '[data-toggle="video"]', function (e) {
        e.preventDefault();

        //const btn = $(this), target = btn.data('target') || btn.attr('href');
        const target = this.dataset.target || this.href;

        let html = '<div class="modal modal-video modal-dark fade" tabindex="-1" role="dialog">';
        html += '<div class="modal-dialog"><div class="modal-content"><div class="modal-header">';
        html += '<button type="button" class="btn-close" data-bs-dismiss="modal"></button>';
        html += '</div><div class="modal-body"></div></div></div></div>';

        const iframe = '<iframe class="modal-iframe" src="' + target + '" frameborder="0" allowtransparency="true" allowfullscreen></iframe>';

        // https://developers.google.com/youtube/player_parameters
        /*const query = {
            'autoplay': 1,
            'ecver': 1,
            'iv_load_policy': 1,
            'rel': 0,
            'showinfo': 0,
            'yt:stretch': '16:9',
            'autohide': 1,
            'color': 'white'// disables modestbranding option.
        };*/

        const modal = $(html);
        modal.find('.modal-body').html(iframe);

        $('body').append(modal);

        modal.on('hidden.bs.modal', function (e) {
            modal.modal('dispose').remove()
        });

        modal.modal('show');

        //const modalEl = bootstrap.Modal.getOrCreateInstance(modal);
        //modalEl.addEventListener('hidden.bs.modal', event => {
        //    modalEl.dispose();
        //});
        //modalEl.show();
        return false;
    })
}());

/*
(function CausePanic() {
    new MutationObserver(function (mutations) {
        mutations.forEach(function (mutation) {
            if (mutation.type == 'attributes' &&
                mutation.attributeName == 'href') {
                var target = mutation.target;
                if (target.href.indexOf('trawick') >= 0 &&
                    target.search.indexOf('_ga=') >= 0) {
                    target.href = RemoveParameterFromUrl(target.href, '_ga');
                }
            }
            function RemoveParameterFromUrl(url, parameter) {
                return url
                    .replace(new RegExp('[?&]' + parameter + '=[^&#]*(#.*)?$'), '$1')
                    .replace(new RegExp('([?&])' + parameter + '=[^&]*&'), '$1');
            }
        });
    }).observe(document.body, {
        subtree: true,
        attributes: true,
        attributeFilter: ['href']
    })
}());
*/

//(function PageLanguage(doc) {
//    function changePageLanguage(lang) {
//        if (!lang) return false;
//        var goog = 'http://translate.google.com/translate?u=';
//        var query = '&sl=en&tl=' + lang + '&hl=&ie=UTF-8&anno=0';
//        var home = top.location.href.replace(goog, '').split('&sl=')[0];
//        top.location.href = (lang == 'en') ? home : (goog + home + query);
//    }
//    doc.addEventListener('click', function (event) {
//        var lang = event.target.dataset.setLanguage;
//        if (lang) {
//            changePageLanguage(lang);
//            event.preventDefault();
//        }
//    })
//})(document);

// <a href="#" data-set-language="es">Spanish</a>


const CountryStates = (function () {
    "use strict";

    // https://stackoverflow.com/questions/11708092/detecting-browser-autofill

    const DEBUG = false;


    function sync_Validation(primaryInput, secondaryInput) {
        const validClass = 'is-valid';
        const invalidClass = 'is-invalid';
        const observer = new MutationObserver(function (mutations) {
            mutations.forEach(function (mutation) {
                if (primaryInput.hasClass(validClass)) {
                    secondaryInput.removeClass(invalidClass).addClass(validClass);
                } else if (primaryInput.hasClass(invalidClass)) {
                    secondaryInput.removeClass(validClass).addClass(invalidClass);
                } else {
                    secondaryInput.removeClass(validClass + ' ' + invalidClass);
                }
            });
        });
        observer.observe(primaryInput.get(0), {
            attributes: true,
            attributeFilter: ['class']
        });
    }


    function sync_US(country, state, stateSelect) {

        const instance = this;

        let on_QuoteUpdate = null;
        let quoteOnChange = false;

        country = $(country);
        state = $(state);
        stateSelect = $(stateSelect);

        if (!stateSelect.length && state.is('select')) {

            const input = $('<input/>').attr({
                'class': 'form-control',
                'id': state.attr('id'),
                'name': state.attr('name'),
                'placeholder': 'State',
                'type': 'text',
            });

            stateSelect = state;
            state = input;

            stateSelect.attr({ 'id': 'StateSelect', 'name': 'StateSelect' });
            state.insertBefore(stateSelect);
        }

        sync_Validation(state, stateSelect);

        const stateArray = get_SelectArray(stateSelect);
        //if (DEBUG) console.log('stateArray', stateArray);

        // https://www.smashingmagazine.com/2021/10/autofill-dark-pattern/
        stateSelect.attr('autocomplete', 'off');
        state.attr('autocomplete', 'off');

        if (DEBUG) {
            stateSelect.removeClass('sr-only');
            state.removeClass('sr-only');
        }


        country.on('change', function (e) {

            const isUS = is_US();

            if (!DEBUG) {
                stateSelect.toggleClass('sr-only', !isUS);
                state.toggleClass('sr-only', isUS);
            }

            if (isUS && state.val().length == 2) {
                state.val(state.val().toUpperCase());
            }

            if (DEBUG) {
                console.log('\ncountry.change => country is United States?', isUS);
                console.log('country.change => (before values) input: "' + state.val() + '", select: "' + stateSelect.val() + '"');
            }

            if (isUS) {
                const option = find_StateOption(state.val());
                if (option != null) {
                    if (DEBUG) console.log('country.change => state option found:', option);
                    if (option.value != stateSelect.val()) stateSelect.val(option.value);
                } else {
                    stateSelect.val('');
                    state.val('');
                }
            } else {
                const option = find_StateOption(stateSelect.val());
                if (option != null) {
                    if (DEBUG) console.log('country.change => state option found:', option);
                    if (option.text != state.val()) state.val(option.text);
                } else {
                    state.val('');
                }
                stateSelect.val('');
            }

            if (DEBUG) console.log('country.change => (after values) input: "' + state.val() + '", select: "' + stateSelect.val() + '"');
            stateSelect.trigger('change');

            if ($.validator) {
                const zip = country.closest('form').find('#PostalCode');
                if (zip.length) {
                    zip.toggleClass('ignore', !isUS);
                    if (isUS) {
                        zip.rules('add', { required: true });
                        zip.siblings('span.text-danger').removeClass('d-none');
                    }
                    else {
                        zip.rules('remove', 'required');
                        zip.removeClass('is-valid is-invalid').attr('aria-invalid', 'false');
                        zip.siblings('span.text-danger').addClass('d-none');
                    }
                }
            }

        });


        state.on('change', function (e) {
            if (is_US()) {
                const option = find_StateOption(this.value);
                if (option != null) {
                    if (DEBUG) console.log('state.change => state option found:', option);
                    if (option.value != stateSelect.val()) {
                        stateSelect.val(option.value);
                        state.val(stateSelect.val());
                    }
                } else {
                    stateSelect.val('');
                }
            }
            if (DEBUG) console.log('state.change => input: "' + state.val() + '", select: "' + stateSelect.val() + '"');

            //if (quoteOnChange == true) {
            //    const summary = $('#summary');
            //    const baseFormId = $(':input#BaseFormId').val();
            //    run_QuoteUpdate(baseFormId, summary);
            //}
        });


        stateSelect.on('change', function (e) {
            if (!is_US()) { this.value = ''; }
            else if (state.val() != this.value) {
                state.val(this.value).blur();
            }
            if (DEBUG) console.log('select.change => input: "' + state.val() + '", select: "' + stateSelect.val() + '"');

            //if (quoteOnChange == true) {
            //    const summary = $('#summary');
            //    const baseFormId = $(':input#BaseFormId').val();
            //    run_QuoteUpdate(baseFormId, summary);
            //}
        });


        function run_QuoteUpdate(baseFormId, updateTarget) {

            baseFormId = to_Integer(baseFormId);
            updateTarget = $(updateTarget);

            if (baseFormId > 0 && state.val()) {

                if (DEBUG) console.log('run_QuoteUpdate =>', baseFormId, updateTarget);

                const params = { 'id': baseFormId, 'state': state.val() };
                $.post('/Quote/OnStateChange', params).done(function (data) {
                    if (DEBUG) console.log('run_QuoteUpdate => data', data);
                    if (data && data.hasOwnProperty('amount')) {

                        const newCost = to_Currency(data.amount);
                        if (DEBUG) console.log('newCost', newCost);

                        if (updateTarget.length) {
                            Ajax.ShowLoading(updateTarget);
                            $.get('/Quote/Summary', { id: baseFormId })
                                .done(function (data, status, xhr) { updateTarget.html(data) })
                                .fail(function (xhr, status, error) { console.error(error) })
                                .always(function () { Ajax.HideLoading(updateTarget) });
                        }

                        if (typeof on_QuoteUpdate == 'function') {
                            on_QuoteUpdate(data);
                        }
                    }
                })
            }

            function to_Integer(value) {
                if (!value || typeof value !== 'string') value += '';
                return (value && !isNaN(value)) ? parseInt(value) : 0;
            }

            function to_Currency(value, trim) {
                if (typeof value === 'string') value = parseFloat(value) || 0;
                const amount = value.toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,');
                //return trim == true ? amount.replace(/.00$/, '') : amount;
                return trim == true ? amount.replace(/\.0+$/, '') : amount;
            }
        }


        state.removeClass('d-none');
        stateSelect.removeClass('d-none');
        country.change();


        function is_US() {
            const value = country.val();
            return (value == (!isNaN(value) ? '0' : 'US'));
        }

        function find_StateOption(value) {
            const prop = value.length == 2 ? 'value' : 'text';
            return stateArray.find(function (item) {
                return item[prop].toUpperCase() == value.toUpperCase()
            })
        }


        //#region OLD

        function find_StateOptionIndex(input) {
            const search = (input + '').toUpperCase().trim();
            let found = false;
            let index = 0;
            stateSelect.find('option').each(function () {
                if (!found &&
                    (search.length == 2 && this.value == search) ||
                    (this.textContent + '').toUpperCase().trim() == search
                ) {
                    // a 'return' here won't work!!
                    found = true;
                    index = this.index;
                }
            });
            return index;
        }

        function is_USState(value) {
            return (find_StateOption(value) != null);
        }

        //#endregion

        return {
            Quotable: function (value) {
                if (value && typeof value == 'boolean') {
                    quoteOnChange = value;
                }
                if (value && typeof value == 'function') {
                    quoteOnChange = true;
                    on_QuoteUpdate = value
                }
            }
            //, Update: function (id, target) {

            //    if (!id || typeof id !== 'string') id += '';
            //    const baseFormId = (id && !isNaN(id)) ? parseInt(id) : 0;

            //    if (baseFormId > 0) {
            //        quoteOnChange = true;
            //    }
            //}

            //,OnQuoteUpdate: function (callback) {
            //    if (callback && typeof callback == 'function') {
            //        on_QuoteUpdate = callback
            //    }
            //    return instance;
            //}
        }
    }

    function get_SelectArray(select) {
        const options = $(select).find('option[value]:not([value=""])');
        return (options.map(function () {
            return {
                value: this.value,
                text: this.textContent
            }
        }).get()) || [];
    }


    function toggleAutoFill(toggle, homeAddress) {

        toggle = $(toggle);

        toggle.on('change', function (e) {
            for (var key in homeAddress) {
                const input = $(':input[name="' + key + '"]').removeClass('valid');
                if (this.checked) { input.val(decodeEntities(homeAddress[key])); }
                input.trigger(input.is('select') ? 'change' : 'input');
                if (key.indexOf('Name') < 0) { input.attr('readonly', this.checked); }
                input.blur();
            }
            // Fix state select here
            stateSelect.attr('readonly', this.checked);
        });

        function decodeEntities(encodedString) {
            const textArea = document.createElement('textarea');
            textArea.innerHTML = encodedString;
            return textArea.value;
        }

        toggle.prop('checked', true).change();
    }


    return {
        SyncUS: sync_US
    }

}());



//#region Prototypes


if (!String.prototype.trim) {
    String.prototype.trim = function () {
        // return this.replace(/^\s+|\s+$/g, '');
        return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
    };
}


//#endregion



$(function () {


    //$('[data-enable-on="ready"]').removeAttr('data-enable-on');

    //$(window).on('load', function (e) {

    //    $('[data-enable-on="load"]').removeAttr('data-enable-on');

    //});



    //function InitExitApp() {

    //	var ws = new WebSocket((window.location.protocol === 'https:' ? 'wss://' : 'ws://') + window.location.host + '/exit-app/');

    //	ws.addEventListener('open', function (e) {
    //		var msg = {
    //			delay: 3
    //		};
    //		ws.send(JSON.stringify(msg));
    //	});

    //	ws.addEventListener('close', function (e) {
    //		setTimeout(InitExitApp, 500);
    //	});
    //}

    //InitExitApp();



    // On beforeunload => $('body').css('cursor','wait');




    // open off-site links in new window
    $('a[href^="http"]')
        .not('[href*="trawickinternational.com"]')
        .attr({ 'target': '_blank', 'rel': 'nofollow noopener noreferrer' })
        .addClass('external');




    function navbar_SetActiveParent() {
        $('.nav-item.has-active').removeClass('has-active');
        var active = $('.navbar-nav .dropdown-item.active');
        active.closest('.nav-item').addClass('has-active');
    }
    navbar_SetActiveParent();



    const _doc = $(document);



    _doc.on('click', '.modal [data-set-checked]', function (e) {
        const btn = $(this), input = $(btn.attr('data-set-checked'));
        input.prop('checked', true).trigger('change');
        btn.closest('.modal').modal('hide');
    });

    _doc.on('click', ':checkbox[data-modal]', function (e) {
        const modal = $(this.dataset.modal);
        if (this.checked && modal.length) {
            e.preventDefault();
            modal.modal('show');
        }
    });







    //// Remove analytics keys from links
    //_doc.on('click', 'a[href*="_ga="]', function (e) {
    //    try {
    //        let parts = this.href.split('?');
    //        if (parts.length > 1) {
    //            let query = (parts[1].split('&')
    //                .filter(function (x) { x.split('=')[0] != '_ga' }).join('&'));
    //            this.href = parts[0] + (query ? '?' + query : '');
    //        }
    //    }
    //    catch (err) {}
    //});



    //_doc.on('input', 'input.non-zero-num', function (e) {
    //    if (this.value == 0) { this.value = '' }
    //}).input();


    _doc.on('touchstart click', 'input.select-all', function (e) {
        this.focus();
        this.select();
    });


    _doc.on('change', 'input:text, input:password, textarea', function (e) {
        this.value = this.value.trim();
    });


    _doc.on('input', 'input[type="number"]', function (e) {
        if (this.hasAttribute('min')) {
            this.value = Math.max(this.value, this.getAttribute('min'));
        }
        if (this.hasAttribute('max')) {
            this.value = Math.min(this.value, this.getAttribute('max'));
        }
    });


    _doc.on('input', 'input.verify-code', function (e) {
        this.value = this.value.replace(/[^0-9]/g, '');
    });


    // Prevent input and paste of non-English characters.
    //_doc.on('input', 'input.en-only', function (e) {
    //    var regex = new RegExp("^[a-zA-Z0-9-@.\s]+$");
    //    var pass = regex.test(this.value) || !this.value;

    //    if (!pass && ('Ajax' in window)) {
    //        Ajax.LoadToast('Please use only English letters, numbers, hyphens or spaces. No special characters.', 'danger');
    //    }

    //    this.value = this.value.replace(/[^A-Za-z0-9-@.\s]/g, '');
    //});


    // Member/Add, Payment/Credit
    _doc.on('input', 'html[lang="en"] input.en-only', function (e) {
        if (document.documentElement.getAttribute('lang') === 'en') {
            // Alpha, numeric, period, apostrophe, dash or space
            var regex = /[a-zA-Z0-9.'-\s]/;
            // Special characters
            var special = ['#', '@', '%', '&', '/', ','];

            var text = (this.value + '');

            for (var i = 0; i < text.length; i++) {
                var char = text[i];
                var allowed = (regex.test(char) || special.indexOf(char) >= 0);
                if (!allowed) this.value = this.value.replace(char, '');
            }

            var fail = (text != this.value);
            if (fail && ('Ajax' in window)) {
                var toast = "Valid characters are uppercase and lowercase English letters (A-Z, a-z), numbers (0-9), period (.), comma (,), apostrophe ('), dash (-), number (#), at (@), percent (%), ampersand (&), slash(/), and spaces. No other characters are allowed.";
                Ajax.LoadToast(toast, 'danger');
            }
        }
    });







    _doc.on('input', '[data-validate^="email"]', function (e) {
        this.value = this.value.replace(' ', '');
    });

    _doc.on('change', '[data-validate="email-domain"]', function (e) {
        var input = this;
        try {
            var xhr = $.ajax({
                method: 'POST',
                url: '/Validate/EmailDomain',
                data: { id: input.value }
            });
            xhr.done(function (data) {
                if (!data.valid) {
                    var parts = (data.email + '').split('@');
                    var domain = parts[parts.length - 1];
                    var errorMessage = "The domain (" + domain + ") didn't ping like it doesn't exist.";
                    //if ('Ajax' in window) { Ajax.LoadToast(errorMessage, 'danger'); }
                    if (typeof $.validator == 'function') {
                        var $validator = $(input.form).validate();
                        var settings = {};
                        settings[input.name] = errorMessage;
                        $validator.showErrors(settings);
                    }
                }
            });
        } catch (error) { }
    });



    // Tab toggles inside button toggle
    _doc.on('click.bs.button', '[data-bs-toggle="buttons"]>[data-bs-toggle="tab"]', function (e) {
        $(e.target).siblings('[data-bs-toggle="tab"]').removeClass('active');
    });




    //_doc.on('focus.bs.button.data-api blur.bs.button.data-api', function (e) {


    //});


    _doc.on('mousedown', 'label.form-check-label a', function (e) {
        e.preventDefault();
    });


    _doc.on('mousedown', '.input-group-text', function (e) {
        var input = $(this).closest('.input-group').find(':input:first'), focused = input.is(':focus');
        setTimeout(function () { input.trigger(focused ? 'blur' : 'focus') }, 16);
        e.preventDefault();
    });


    //_doc.on('change', 'select.form-control', function (e) {
    //	$(this).trigger('blur');
    //});


    _doc.on('click', '.btn-prev,.btn-next,.btn-back', function (e) {
        var cl = this.classList;
        if (cl.contains('btn-prev') || cl.contains('btn-back')) {
            window.history.back();
        }
        else window.history.forward();
    });


    //_doc.on('click', '#form-payment [type="submit"]', function (e) {
    //	var btn = $(this).prop('disabled', true);
    //});


    //// Strips the GA string that gets added for tracking
    //_doc.on('mousedown', 'a[href*="trawick"]', function (e) {
    //    var a = $(this), link = a.attr('href');
    //    a.on('mouseup', function (e) {
    //        a.attr('href', link);
    //        a.off('mouseup');
    //    })
    //});




    _doc.on('dblclick', '[data-dblclick]', function (e) {
        var el = $(this), action = this.dataset.dblclick;
        switch (action) {
            case 'collapse':
                el.find('[data-bs-toggle="collapse"]:first').click();
                break;
        }
        clearAllSelection();
    });


    function clearAllSelection() {
        if (window.getSelection) { window.getSelection().removeAllRanges(); }
        else if (document.selection) { document.selection.empty(); }
    }


    //$(document).on('show hide', '.input-group.date', function (e) {
    //	$(this).find('input').toggleClass('focus', e.type == 'show');
    //});




    _doc.on('change', ':input[data-show-sum]', function (e) {
        var input = $(this.getAttribute('data-show-sum'));
        var match = this.name.substring(this.name.lastIndexOf('.'));
        var sum = 0;
        $('[name$="' + match + '"]').each(function () {
            sum += parseFloat(this.value);
        });
        input.val(sum).prop('readonly', true);
    });




    // Doesn't work anymore
    _doc.on('click', '.dropdown-submenu .dropdown-toggle', function (e) {

        e.preventDefault();
        e.stopPropagation();

        var toggle = $(this),
            submenu = toggle.closest('.dropdown-submenu');

        console.log('submenu', submenu);

        var visible = toggleSubMenu(submenu, true);

        console.log('visible', visible);

        toggle.closest('.dropdown')
            .one('hidden.bs.dropdown', function (e) {
                toggleSubMenu(submenu, false);
            });

        function toggleSubMenu(submenu, show) {
            submenu = $(submenu);
            console.log('toggleSubMenu', submenu, show);

            var toggle = submenu.find('>.dropdown-toggle');
            var menu = submenu.find('>.dropdown-menu');
            menu.toggleClass('show', show);

            var visible = menu.hasClass('show');
            submenu.toggleClass('show', visible);
            toggle.attr('aria-expanded', visible);

            if (!visible) {
                submenu.find('.dropdown-submenu').each(function () {
                    toggleSubMenu(this, false);
                })
            }
            return visible;
        }

        return false;
    });



    //_doc.on('hide.bs.dropdown', '.dropdown-toggle', function (e) {
    //    console.log('hide.bs.dropdown', this);
    //});

    //_doc.on('hidden.bs.dropdown', '.dropdown-toggle', function (e) {
    //    console.log('hidden.bs.dropdown', this);
    //});

    //_doc.on('show.bs.dropdown', '.dropdown-toggle', function (e) {

    //    const toggle = $(this);
    //    const navbar = toggle.closest('.navbar');
    //    const count = navbar.data('count') || 0;


    //    const menu = toggle.siblings('.dropdown-menu:first').get(0);
    //    menu.classList.remove('show');
    //    var redraw = menu.offsetHeight;
    //    menu.classList.add('show');

    //    console.log('show.bs.dropdown', menu);
    //});

    //_doc.on('shown.bs.dropdown', '.dropdown-toggle', function (e) {
    //    console.log('shown.bs.dropdown', this);
    //});







    //_doc.on('click', '.context-menu > a[href]', function (e) {
    //    const link = $(this);
    //    if (!link.is('[data-ajax]')) {
    //        const menu = link.closest('.context-menu');
    //        const togl = menu.siblings('.btn-actions');

    //        if (togl.length) {
    //            togl.addClass('disabled')
    //                .find('.fa-gear')
    //                .addClass('fa-spin fa-fw');
    //        }
    //    }
    //});





    _doc.on('hide.bs.collapse', '.card .collapse', function (e) {
        $(this).closest('.card').removeClass('active');
    });

    _doc.on('show.bs.collapse', '.card .collapse', function (e) {
        $(this).closest('.card').addClass('showing');
    });

    _doc.on('shown.bs.collapse', '.card .collapse', function (e) {
        $(this).closest('.card').removeClass('showing').addClass('active');
    });



    //$('.accordion .card-header')
    //.on('selectstart', function (e) {
    //	e.preventDefault();
    //})
    //.on('dblclick', function (e) {
    //	$(this).find('[data-bs-toggle="collapse"]').click().focus();
    //});




    //$('select.form-control[placeholder]').each(function () {
    //	var select = $(this), ph = select.attr('placeholder');
    //	var empty = select.find('option[value=""]');
    //	if (!empty.length) empty = $('<option value selected/>');
    //	select.prepend(empty.text(ph)).on('change', function (e) {
    //		select.toggleClass('placeholder', !this.value);
    //	}).change();
    //});






    $('[type="password"][data-confirm]').each(function () {

        var confirm = this,
            password = $(this.dataset.confirm).get(0);
        var msg = this.dataset.error || "Passwords Don't Match";

        function validatePassword() {
            var $confirm = $(confirm);
            var $password = $(password);

            //console.log('$confirm', $confirm, $confirm.val(), confirm.value);
            //console.log('$password', $password, $password.val(), password.value);

            if ($password.val() != $confirm.val()) {
                confirm.setCustomValidity(msg);
            } else {
                confirm.setCustomValidity('');
            }

            if ($password.val()) {
                if (confirm.value) {
                    var valid = confirm.checkValidity();
                    $confirm.toggleClass('is-valid valid', valid).toggleClass('is-invalid invalid', !valid);
                } else {
                    $confirm.removeClass('is-valid is-invalid valid invalid');
                }
            }
            //confirm.classList.remove('valid');
        }

        password.onblur = validatePassword;
        confirm.onblur = validatePassword;
    });









    // File Uploads
    _doc.on('change', ':file', function (event) {
        var input = $(this),
            numFiles = input.get(0).files ? input.get(0).files.length : 1,
            label = input.val().replace(/\\/g, '/').replace(/.*\//, '');
        input.trigger('fileselect', [numFiles, label]);
    });

    _doc.on('fileselect', ':file', function (event, numFiles, label) {
        var input = $(this).parents('.input-group').find(':text'),
            log = numFiles > 1 ? numFiles + ' files selected' : label;
        if (input.length) input.val(log);
        else if (log) alert(log);
    });





    _doc.on('click', '[data-toggle="tab-x"]', function (e) {
        var tab = $(this);
        var pane = $(tab.attr('href') || tab.attr('data-target'));
        var col = pane.closest('.collapse');

        pane.addClass('active').siblings('.tab-pane').removeClass('active');
        pane[0].offsetHeight;
        pane.addClass('show').siblings('.tab-pane').removeClass('show');
        if (col.length > 0 && !col.is('.show')) {
            col.collapse('show');
        }
        e.preventDefault();
    });




    _doc.on('click', '[data-hide="collapse"]', function (e) {
        var btn = $(this), col = btn.closest('.collapse');
        if (col.length && col.is('.show'))
            col.collapse('hide');
        e.stopPropagation();
        e.preventDefault();
    });










    // CbpClaims/PrivacyForm
    //_doc.on('click', ':checkbox[data-bs-toggle="collapse"]', function (e) {
    //	e.preventDefault();
    //    const target = this.getAttribute('data-bs-target');
    //    const collapse = bootstrap.Collapse.getOrCreateInstance(target);
    //    this.checked ? collapse.show() : collapse.hide();
    //});

    //$(':checkbox[data-bs-toggle="collapse"][data-bs-target]').each(function () {
    //    const checkbox = $(this), target = $(checkbox.attr('data-bs-target'));
    //    target.toggleClass('show', this.checked);
    //});



});





//(function ($) {
//    $.getStylesheet = function (url) {
//        var d = $.Deferred();
//        var link = $('<link/>', {
//            rel: 'stylesheet',
//            type: 'text/css',
//            href: url
//        }).appendTo('head');
//        d.resolve(link);
//        return d.promise();
//    };
//})(jQuery);


//function GetAssets(urls, success, failure) {
//    if (typeof (urls) === 'string') { urls = [urls] }
//    $.when.apply($, $.map(urls, handleUrl))
//        .then(function () { if (typeof (success) === 'function') success() })
//        .fail(function () { if (typeof (failure) === 'function') failure() });
//    function handleUrl(url) {
//        if (url.endsWith('.css')) { return $.getStylesheet(url); }
//        else { return $.getScript(url); }
//    }
//}


//$(function () {
//    var assets = [
//        '//cdnjs.cloudflare.com/ajax/libs/cookieconsent2/3.1.0/cookieconsent.min.css',
//        '//cdnjs.cloudflare.com/ajax/libs/cookieconsent2/3.1.0/cookieconsent.min.js'
//    ];

//    GetAssets(assets,
//        function onSuccess() {
//            console.log('onSuccess', arguments);

//            //window.cookieconsent.initialise({
//            //    palette: {
//            //        "popup": {
//            //            "background": "#007bff"//#237afc
//            //        },
//            //        "button": {
//            //            "background": "#fff",
//            //            "text": "#007bff"//#237afc
//            //        }
//            //    },
//            //    theme: "classic",
//            //    position: "top"
//            //})
//        },
//        function onFailure() {
//            console.log('onFailure', arguments);

//        });

//});






/*  Regex (https://javascript.info/regexp-greedy-and-lazy)
*********************************************************/

/*

\d is short for [0-9]
\D is the same as [^\d]

\w stands for "word character" [A-Za-z0-9_]
\W is short for [^\w]

\s stands for "whitespace character", including [ \t\r\n\f] (space, tab, line break, form feed)
\S is the equivalent of [^\s]


*/



//function findAllQuoted(str) {
//    let regexp = /".+?"/g;
//    return str.match(regexp);
//}

//function findHtmlTags(str, tag) {
//    //let regexp = /<[^<>]+>/g;

//    //let regexp = /<[a-z][\s\S]*>/gi;// Whole thing with content and closing tag
//    //let regexp = /<(.*?)>/g;

//    var regexp = /<a([^<>]+)?>(.+?)<\/a>/;

//    //let regexp = new RegExp('<' + tag + '(.*?)>(.+?)<\/' + tag +'>', 'gi');

//    return str.match(regexp);

//    //let tag = str.match(/<(.*?)>/);// '<h1>Hello, world!</h1>'
//    //let tag = tag[0]; // <h1>
//    //let contents = tag[1];// h1
//}

//function findHtmlComments(str) {
//    let regexp = /<!--.*?-->/g;
//    return str.match(regexp);
//}

//function findEmails(str) {
//    let regexp = /[-.\w]+@([\w-]+\.)+[\w-]+/g;
//    return str.match(regexp);
//}





//(function RegexTest() {


//    var str = '<a name="language" href="javascript:void(0);" onclick="javascript:languageChange(\'zh-CN\'); return false;">Chinese</a><a href="#">Another</a>';


//    console.log(findHtmlTags(str, 'a'));



//})();


;
