/* Minification of JavaScript failed:
(1109,57-58): run-time error JS1195: Expected expression: >
(1109,167-168): run-time error JS1004: Expected ';': )
(1110,64-65): run-time error JS1195: Expected expression: >
(1110,76-77): run-time error JS1004: Expected ';': )
(1126,17-18): run-time error JS1002: Syntax error: }
(1133,44-51): run-time error JS1197: Too many errors. The file might not be a JavaScript file: product
 */
var mpFrigidaire = (function () {
    var ScriptLoaded = $.Deferred(),
        TrackingReady = $.Deferred(),
        IsLoggedIn = false,
        GUID = "NA",
        isMixpanel = null;

    function init() {
        isMixpanelEnabled = (typeof mixpanel !== "undefined") && (typeof mixpanel.track !== "undefined"), //Does the mixpanel library exist? added second check because optimizely could be on (which defines mixpanel, ugh)
        Setup();
        GlobalProperties();
        Events();
    }

    function GetLastViewedData(prop) {
        // Usage: Get last page title or page type:
        // "Last Content Title Viewed": mpFrigidaire.GetLastViewedData("Last Content Title Viewed"),
        // "Last Page Type Viewed": mpFrigidaire.GetLastViewedData("Last Page Type Viewed")
        if (($.cookie('pageproperties') === undefined) || (!isMixpanelEnabled)) return;
        var pageproperties = $.cookie('pageproperties'),
            pagepropertiesST = JSON.parse(pageproperties);

        return pagepropertiesST[prop];
    }

    function SetLastViewedData() {
        // Stores current and prior page data for page title and page type.        
        var currentPage = mpGlobalProperties["Page Title"],
            currentPageType = mpGlobalProperties["Page Type"];

        // Page History
        if ($.cookie('pageproperties') != null) { //$.cookie('pageproperties') !== null || $.cookie('pageproperties') !== undefined
            var pageproperties = $.cookie('pageproperties'),
                pagepropertiesST = JSON.parse(pageproperties),
                lastPage = pagepropertiesST["Future Content Title Viewed"],
                lastPageType = pagepropertiesST["Future Page Type Viewed"];

            var pagepropertiesST = {
                "Last Content Title Viewed": lastPage,
                "Future Content Title Viewed": currentPage,
                "Last Page Type Viewed": lastPageType,
                "Future Page Type Viewed": currentPageType
            };

            var pagepropertiesST = JSON.stringify(pagepropertiesST);

            $.cookie('pageproperties', pagepropertiesST, { path: '/' });

            //console.log("Last Content Title Viewed: ", lastPage);
            //console.log("Last Page Type Viewed: ", lastPageType);
            //console.log("Current Content Title Viewed: ", currentPage);
            //console.log("Current Page Type Viewed: ", currentPageType);
        }
            // No Page History Exists
        else {
            var pageproperties = {
                "Last Content Title Viewed": "NA",
                "Last Page Type Viewed": "NA",
                "Future Content Title Viewed": currentPage,
                "Future Page Type Viewed": currentPageType
            };

            var pagepropertiesST = JSON.stringify(pageproperties);

            $.cookie('pageproperties', pagepropertiesST, { path: '/' });
        }

    }

    function Setup() {
        //console.log('isMixpanelEnabled:', isMixpanelEnabled);
        if (!isMixpanelEnabled) {
            ScriptLoaded.reject();
            TrackingReady.reject();
        }
    }

    function GlobalProperties() {
        mpGlobalProperties = (typeof mpGlobalProperties === "undefined" ? {} : mpGlobalProperties); //if mixpanel global properties (set in the head) is undefined, then assign it to an empty object so it doesnt error out
    }

    function Events() {

        $(document).on('mpLogin', function (e, guid, status) {
            if (!isMixpanelEnabled) return;
            //console.log('guid:', guid);

            function firstTimeCheck() {
                if (!($.cookie('mp-user'))) {
                    $.cookie('mp-user', 'known'); //creating a session cookie so we don't fire people setting and identify in subsequent page loads.
                    mixpanel.people.set({
                        "User ID": mpFrigidaire.GUID
                    });
                    mixpanel.identify(mpFrigidaire.GUID);
                }
            }

            function setDefaults() {
                //console.log('mpGlobalProperties', mpGlobalProperties);
                mpFrigidaire.increment("Total Number of Pages Viewed");
                mpFrigidaire.track('Page viewed', mpGlobalProperties);
                SetLastViewedData();
                mpFrigidaire.TrackingReady.resolve();
                if (!!document.querySelectorAll('[data-mixpanel-event]').length) {
                    mixpanel.time_event('Content Engagement');
                }
            }

            //if user has a GUID:
            if ((guid !== null) && (typeof guid !== 'undefined')) {
                mpFrigidaire.GUID = guid;
                mpFrigidaire.IsLoggedIn = true;

                //console.log('%c Logged In GUID %o', 'background:green;color:yellow', mpFrigidaire.GUID);

                if (status === true) { //then they are new
                    //hit an api to change the status from new user (true) to new user (false)
                    //console.log('%c New Mixpanel User %o', 'background:green;color:yellow');
                    $.ajax({
                        method: 'POST',
                        url: "/api/userapi/aliasuserwithmixpanel",
                        data: { UserGuid: mpFrigidaire.GUID, ShouldAlias: true },
                        success: function (data) {
                            if (data.ShouldAlias) {
                                //console.log('%c New Mixpanel User Success, Aliasing now... %o', 'background:green;color:yellow', data);
                                //if the user just registered (this must only happen once per user!)...
                                mixpanel.alias(mpFrigidaire.GUID);
                            }
                        },
                        complete: function (data) {
                            firstTimeCheck();
                            setDefaults();
                        }
                    });

                    //user has been aliased in the past
                } else {
                    //they already have been aliased, so let's identify them with their guid
                    firstTimeCheck();
                    setDefaults();
                }

                //user doesn't have a GUID and is therefore anonymous:
            } else {
                mpFrigidaire.GUID = mixpanel.get_distinct_id();
                mpFrigidaire.IsLoggedIn = false;
                //console.log('%c Logged Out GUID %o', 'background:yellow;color:black', mpFrigidaire.GUID);
                //mixpanel.identify(mpFrigidaire.GUID);
                setDefaults();
            }

        });

        $(document).off('click.mp-event', '[data-mixpanel-event]').on('click.mp-event', '[data-mixpanel-event]', function (e) {            
            if (!isMixpanelEnabled) return;
            var $this = $(this),
                mpEvent = $this.data('mixpanel-event'),
                mpPropertiesNew = $this.data('mixpanel-properties'),
                merged = mergeJSON(mpGlobalProperties, mpPropertiesNew);
            mpFrigidaire.increment("Total Number of "+ mpEvent +"s");
            track(mpEvent, merged);
        });

        $(document).off('mp-tracking-people').on('mp-tracking-people', function (e) {
            if (!isMixpanelEnabled || !mpFrigidaire.IsLoggedIn) return;

            if (typeof e.peopleproperties != "undefined") {
                mixpanel.people.set(e.peopleproperties);
            }
            mixpanel.identify(mpFrigidaire.GUID);
        });

        $(document).off('mp-tracking-people-increment').on('mp-tracking-people-increment', function (e) {
            if (!isMixpanelEnabled) return;

            if (typeof e.peopleproperties != "undefined") {
                mixpanel.people.increment(e.peopleproperties);
            }
        });

        $(document).off('mp-tracking-charge').on('mp-tracking-charge', function (e) {
            if (!isMixpanelEnabled) return;

            if (typeof e.properties != "undefined") {
                mixpanel.people.track_charge(e.properties);
            }
        });

        $(document).off('mp-tracking-forms').on('mp-tracking-forms', function (e) {
            if (!isMixpanelEnabled) return;

            if (typeof e.selector != "undefined") {
                if (e.callback) {
                    mixpanel.track_forms(e.selector, e.evt, e.callback);
                } else {
                    mixpanel.track_forms(e.selector, e.evt);
                }
            }
        });

        $(document).off('mp-tracking').on('mp-tracking', function (e) {
            if (e.callback) {
                mixpanel.track(e.evt, e.properties, e.callback);
            } else {
                mixpanel.track(e.evt, e.properties);
            }
        });
        
    }

    function track(evt, properties, callback) {
        if (isMixpanelEnabled) {
            $(document).trigger({ type: 'mp-tracking', evt: evt, properties: properties, callback: callback });
        } else {
            if (callback) callback();
        }
    }

    function people(peopleproperties) {
        if (!isMixpanelEnabled) return;
        $(document).trigger({ type: 'mp-tracking-people', peopleproperties: peopleproperties });
    }

    function peopleincrement(peopleproperties) {
        if (!isMixpanelEnabled) return;
        $(document).trigger({ type: 'mp-tracking-people-increment', peopleproperties: peopleproperties });
    }

    function charge(properties) {
        if (!isMixpanelEnabled) return;
        $(document).trigger({ type: 'mp-tracking-charge', properties: properties });
    }

    function trackforms(selector, evt, callback) {
        if (!isMixpanelEnabled) return;
        $(document).trigger({ type: 'mp-tracking-forms', selector: selector, evt: evt, callback: callback });
    }

    //mixpanel define the incrementing function:
    function increment(property) {
        if (!isMixpanelEnabled) return;

        value = mixpanel.get_property(property);
        update = {}
        if (value && typeof (value) == 'number') {
            update[property] = value + 1;
        } else {
            update[property] = 1
        }

        mixpanel.register(update);
        //console.log('increment update:', update);
        mixpanel.people.increment(property);
    };

    function mergeJSON(obj1, obj2) {
        var finalobj = {};
        for (var _obj in obj1) finalobj[_obj] = obj1[_obj];
        for (var _obj in obj2) finalobj[_obj] = obj2[_obj];
        return finalobj;
    }

    return {
        init: init,
        IsLoggedIn: IsLoggedIn,
        GUID: GUID,
        GlobalProperties: GlobalProperties,
        track: track,
        people: people,
        peopleincrement: peopleincrement,
        charge: charge,
        increment: increment,
        trackforms: trackforms,
        ScriptLoaded: ScriptLoaded,
        TrackingReady: TrackingReady,
        GetLastViewedData: GetLastViewedData
    }

})(mpFrigidaire);

$(function () {
    mpFrigidaire.init();
});
/*! jQuery Validation Plugin - v1.11.1 - 3/22/2013\n* https://github.com/jzaefferer/jquery-validation
* Copyright (c) 2013 Jörn Zaefferer; Licensed MIT */(function(t){t.extend(t.fn,{validate:function(e){if(!this.length)return e&&e.debug&&window.console&&console.warn("Nothing selected, can't validate, returning nothing."),void 0;var i=t.data(this[0],"validator");return i?i:(this.attr("novalidate","novalidate"),i=new t.validator(e,this[0]),t.data(this[0],"validator",i),i.settings.onsubmit&&(this.validateDelegate(":submit","click",function(e){i.settings.submitHandler&&(i.submitButton=e.target),t(e.target).hasClass("cancel")&&(i.cancelSubmit=!0),void 0!==t(e.target).attr("formnovalidate")&&(i.cancelSubmit=!0)}),this.submit(function(e){function s(){var s;return i.settings.submitHandler?(i.submitButton&&(s=t("<input type='hidden'/>").attr("name",i.submitButton.name).val(t(i.submitButton).val()).appendTo(i.currentForm)),i.settings.submitHandler.call(i,i.currentForm,e),i.submitButton&&s.remove(),!1):!0}return i.settings.debug&&e.preventDefault(),i.cancelSubmit?(i.cancelSubmit=!1,s()):i.form()?i.pendingRequest?(i.formSubmitted=!0,!1):s():(i.focusInvalid(),!1)})),i)},valid:function(){if(t(this[0]).is("form"))return this.validate().form();var e=!0,i=t(this[0].form).validate();return this.each(function(){e=e&&i.element(this)}),e},removeAttrs:function(e){var i={},s=this;return t.each(e.split(/\s/),function(t,e){i[e]=s.attr(e),s.removeAttr(e)}),i},rules:function(e,i){var s=this[0];if(e){var r=t.data(s.form,"validator").settings,n=r.rules,a=t.validator.staticRules(s);switch(e){case"add":t.extend(a,t.validator.normalizeRule(i)),delete a.messages,n[s.name]=a,i.messages&&(r.messages[s.name]=t.extend(r.messages[s.name],i.messages));break;case"remove":if(!i)return delete n[s.name],a;var u={};return t.each(i.split(/\s/),function(t,e){u[e]=a[e],delete a[e]}),u}}var o=t.validator.normalizeRules(t.extend({},t.validator.classRules(s),t.validator.attributeRules(s),t.validator.dataRules(s),t.validator.staticRules(s)),s);if(o.required){var l=o.required;delete o.required,o=t.extend({required:l},o)}return o}}),t.extend(t.expr[":"],{blank:function(e){return!t.trim(""+t(e).val())},filled:function(e){return!!t.trim(""+t(e).val())},unchecked:function(e){return!t(e).prop("checked")}}),t.validator=function(e,i){this.settings=t.extend(!0,{},t.validator.defaults,e),this.currentForm=i,this.init()},t.validator.format=function(e,i){return 1===arguments.length?function(){var i=t.makeArray(arguments);return i.unshift(e),t.validator.format.apply(this,i)}:(arguments.length>2&&i.constructor!==Array&&(i=t.makeArray(arguments).slice(1)),i.constructor!==Array&&(i=[i]),t.each(i,function(t,i){e=e.replace(RegExp("\\{"+t+"\\}","g"),function(){return i})}),e)},t.extend(t.validator,{defaults:{messages:{},groups:{},rules:{},errorClass:"error",validClass:"valid",errorElement:"label",focusInvalid:!0,errorContainer:t([]),errorLabelContainer:t([]),onsubmit:!0,ignore:":hidden",ignoreTitle:!1,onfocusin:function(t){this.lastActive=t,this.settings.focusCleanup&&!this.blockFocusCleanup&&(this.settings.unhighlight&&this.settings.unhighlight.call(this,t,this.settings.errorClass,this.settings.validClass),this.addWrapper(this.errorsFor(t)).hide())},onfocusout:function(t){this.checkable(t)||!(t.name in this.submitted)&&this.optional(t)||this.element(t)},onkeyup:function(t,e){(9!==e.which||""!==this.elementValue(t))&&(t.name in this.submitted||t===this.lastElement)&&this.element(t)},onclick:function(t){t.name in this.submitted?this.element(t):t.parentNode.name in this.submitted&&this.element(t.parentNode)},highlight:function(e,i,s){"radio"===e.type?this.findByName(e.name).addClass(i).removeClass(s):t(e).addClass(i).removeClass(s)},unhighlight:function(e,i,s){"radio"===e.type?this.findByName(e.name).removeClass(i).addClass(s):t(e).removeClass(i).addClass(s)}},setDefaults:function(e){t.extend(t.validator.defaults,e)},messages:{required:"This field is required.",remote:"Please fix this field.",email:"Please enter a valid email address.",url:"Please enter a valid URL.",date:"Please enter a valid date.",dateISO:"Please enter a valid date (ISO).",number:"Please enter a valid number.",digits:"Please enter only digits.",creditcard:"Please enter a valid credit card number.",equalTo:"Please enter the same value again.",maxlength:t.validator.format("Please enter no more than {0} characters."),minlength:t.validator.format("Please enter at least {0} characters."),rangelength:t.validator.format("Please enter a value between {0} and {1} characters long."),range:t.validator.format("Please enter a value between {0} and {1}."),max:t.validator.format("Please enter a value less than or equal to {0}."),min:t.validator.format("Please enter a value greater than or equal to {0}.")},autoCreateRanges:!1,prototype:{init:function(){function e(e){var i=t.data(this[0].form,"validator"),s="on"+e.type.replace(/^validate/,"");i.settings[s]&&i.settings[s].call(i,this[0],e)}this.labelContainer=t(this.settings.errorLabelContainer),this.errorContext=this.labelContainer.length&&this.labelContainer||t(this.currentForm),this.containers=t(this.settings.errorContainer).add(this.settings.errorLabelContainer),this.submitted={},this.valueCache={},this.pendingRequest=0,this.pending={},this.invalid={},this.reset();var i=this.groups={};t.each(this.settings.groups,function(e,s){"string"==typeof s&&(s=s.split(/\s/)),t.each(s,function(t,s){i[s]=e})});var s=this.settings.rules;t.each(s,function(e,i){s[e]=t.validator.normalizeRule(i)}),t(this.currentForm).validateDelegate(":text, [type='password'], [type='file'], select, textarea, [type='number'], [type='search'] ,[type='tel'], [type='url'], [type='email'], [type='datetime'], [type='date'], [type='month'], [type='week'], [type='time'], [type='datetime-local'], [type='range'], [type='color'] ","focusin focusout keyup",e).validateDelegate("[type='radio'], [type='checkbox'], select, option","click",e),this.settings.invalidHandler&&t(this.currentForm).bind("invalid-form.validate",this.settings.invalidHandler)},form:function(){return this.checkForm(),t.extend(this.submitted,this.errorMap),this.invalid=t.extend({},this.errorMap),this.valid()||t(this.currentForm).triggerHandler("invalid-form",[this]),this.showErrors(),this.valid()},checkForm:function(){this.prepareForm();for(var t=0,e=this.currentElements=this.elements();e[t];t++)this.check(e[t]);return this.valid()},element:function(e){e=this.validationTargetFor(this.clean(e)),this.lastElement=e,this.prepareElement(e),this.currentElements=t(e);var i=this.check(e)!==!1;return i?delete this.invalid[e.name]:this.invalid[e.name]=!0,this.numberOfInvalids()||(this.toHide=this.toHide.add(this.containers)),this.showErrors(),i},showErrors:function(e){if(e){t.extend(this.errorMap,e),this.errorList=[];for(var i in e)this.errorList.push({message:e[i],element:this.findByName(i)[0]});this.successList=t.grep(this.successList,function(t){return!(t.name in e)})}this.settings.showErrors?this.settings.showErrors.call(this,this.errorMap,this.errorList):this.defaultShowErrors()},resetForm:function(){t.fn.resetForm&&t(this.currentForm).resetForm(),this.submitted={},this.lastElement=null,this.prepareForm(),this.hideErrors(),this.elements().removeClass(this.settings.errorClass).removeData("previousValue")},numberOfInvalids:function(){return this.objectLength(this.invalid)},objectLength:function(t){var e=0;for(var i in t)e++;return e},hideErrors:function(){this.addWrapper(this.toHide).hide()},valid:function(){return 0===this.size()},size:function(){return this.errorList.length},focusInvalid:function(){if(this.settings.focusInvalid)try{t(this.findLastActive()||this.errorList.length&&this.errorList[0].element||[]).filter(":visible").focus().trigger("focusin")}catch(e){}},findLastActive:function(){var e=this.lastActive;return e&&1===t.grep(this.errorList,function(t){return t.element.name===e.name}).length&&e},elements:function(){var e=this,i={};return t(this.currentForm).find("input, select, textarea").not(":submit, :reset, :image, [disabled]").not(this.settings.ignore).filter(function(){return!this.name&&e.settings.debug&&window.console&&console.error("%o has no name assigned",this),this.name in i||!e.objectLength(t(this).rules())?!1:(i[this.name]=!0,!0)})},clean:function(e){return t(e)[0]},errors:function(){var e=this.settings.errorClass.replace(" ",".");return t(this.settings.errorElement+"."+e,this.errorContext)},reset:function(){this.successList=[],this.errorList=[],this.errorMap={},this.toShow=t([]),this.toHide=t([]),this.currentElements=t([])},prepareForm:function(){this.reset(),this.toHide=this.errors().add(this.containers)},prepareElement:function(t){this.reset(),this.toHide=this.errorsFor(t)},elementValue:function(e){var i=t(e).attr("type"),s=t(e).val();return"radio"===i||"checkbox"===i?t("input[name='"+t(e).attr("name")+"']:checked").val():"string"==typeof s?s.replace(/\r/g,""):s},check:function(e){e=this.validationTargetFor(this.clean(e));var i,s=t(e).rules(),r=!1,n=this.elementValue(e);for(var a in s){var u={method:a,parameters:s[a]};try{if(i=t.validator.methods[a].call(this,n,e,u.parameters),"dependency-mismatch"===i){r=!0;continue}if(r=!1,"pending"===i)return this.toHide=this.toHide.not(this.errorsFor(e)),void 0;if(!i)return this.formatAndAdd(e,u),!1}catch(o){throw this.settings.debug&&window.console&&console.log("Exception occurred when checking element "+e.id+", check the '"+u.method+"' method.",o),o}}return r?void 0:(this.objectLength(s)&&this.successList.push(e),!0)},customDataMessage:function(e,i){return t(e).data("msg-"+i.toLowerCase())||e.attributes&&t(e).attr("data-msg-"+i.toLowerCase())},customMessage:function(t,e){var i=this.settings.messages[t];return i&&(i.constructor===String?i:i[e])},findDefined:function(){for(var t=0;arguments.length>t;t++)if(void 0!==arguments[t])return arguments[t];return void 0},defaultMessage:function(e,i){return this.findDefined(this.customMessage(e.name,i),this.customDataMessage(e,i),!this.settings.ignoreTitle&&e.title||void 0,t.validator.messages[i],"<strong>Warning: No message defined for "+e.name+"</strong>")},formatAndAdd:function(e,i){var s=this.defaultMessage(e,i.method),r=/\$?\{(\d+)\}/g;"function"==typeof s?s=s.call(this,i.parameters,e):r.test(s)&&(s=t.validator.format(s.replace(r,"{$1}"),i.parameters)),this.errorList.push({message:s,element:e}),this.errorMap[e.name]=s,this.submitted[e.name]=s},addWrapper:function(t){return this.settings.wrapper&&(t=t.add(t.parent(this.settings.wrapper))),t},defaultShowErrors:function(){var t,e;for(t=0;this.errorList[t];t++){var i=this.errorList[t];this.settings.highlight&&this.settings.highlight.call(this,i.element,this.settings.errorClass,this.settings.validClass),this.showLabel(i.element,i.message)}if(this.errorList.length&&(this.toShow=this.toShow.add(this.containers)),this.settings.success)for(t=0;this.successList[t];t++)this.showLabel(this.successList[t]);if(this.settings.unhighlight)for(t=0,e=this.validElements();e[t];t++)this.settings.unhighlight.call(this,e[t],this.settings.errorClass,this.settings.validClass);this.toHide=this.toHide.not(this.toShow),this.hideErrors(),this.addWrapper(this.toShow).show()},validElements:function(){return this.currentElements.not(this.invalidElements())},invalidElements:function(){return t(this.errorList).map(function(){return this.element})},showLabel:function(e,i){var s=this.errorsFor(e);s.length?(s.removeClass(this.settings.validClass).addClass(this.settings.errorClass),s.html(i)):(s=t("<"+this.settings.errorElement+">").attr("for",this.idOrName(e)).addClass(this.settings.errorClass).html(i||""),this.settings.wrapper&&(s=s.hide().show().wrap("<"+this.settings.wrapper+"/>").parent()),this.labelContainer.append(s).length||(this.settings.errorPlacement?this.settings.errorPlacement(s,t(e)):s.insertAfter(e))),!i&&this.settings.success&&(s.text(""),"string"==typeof this.settings.success?s.addClass(this.settings.success):this.settings.success(s,e)),this.toShow=this.toShow.add(s)},errorsFor:function(e){var i=this.idOrName(e);return this.errors().filter(function(){return t(this).attr("for")===i})},idOrName:function(t){return this.groups[t.name]||(this.checkable(t)?t.name:t.id||t.name)},validationTargetFor:function(t){return this.checkable(t)&&(t=this.findByName(t.name).not(this.settings.ignore)[0]),t},checkable:function(t){return/radio|checkbox/i.test(t.type)},findByName:function(e){return t(this.currentForm).find("[name='"+e+"']")},getLength:function(e,i){switch(i.nodeName.toLowerCase()){case"select":return t("option:selected",i).length;case"input":if(this.checkable(i))return this.findByName(i.name).filter(":checked").length}return e.length},depend:function(t,e){return this.dependTypes[typeof t]?this.dependTypes[typeof t](t,e):!0},dependTypes:{"boolean":function(t){return t},string:function(e,i){return!!t(e,i.form).length},"function":function(t,e){return t(e)}},optional:function(e){var i=this.elementValue(e);return!t.validator.methods.required.call(this,i,e)&&"dependency-mismatch"},startRequest:function(t){this.pending[t.name]||(this.pendingRequest++,this.pending[t.name]=!0)},stopRequest:function(e,i){this.pendingRequest--,0>this.pendingRequest&&(this.pendingRequest=0),delete this.pending[e.name],i&&0===this.pendingRequest&&this.formSubmitted&&this.form()?(t(this.currentForm).submit(),this.formSubmitted=!1):!i&&0===this.pendingRequest&&this.formSubmitted&&(t(this.currentForm).triggerHandler("invalid-form",[this]),this.formSubmitted=!1)},previousValue:function(e){return t.data(e,"previousValue")||t.data(e,"previousValue",{old:null,valid:!0,message:this.defaultMessage(e,"remote")})}},classRuleSettings:{required:{required:!0},email:{email:!0},url:{url:!0},date:{date:!0},dateISO:{dateISO:!0},number:{number:!0},digits:{digits:!0},creditcard:{creditcard:!0}},addClassRules:function(e,i){e.constructor===String?this.classRuleSettings[e]=i:t.extend(this.classRuleSettings,e)},classRules:function(e){var i={},s=t(e).attr("class");return s&&t.each(s.split(" "),function(){this in t.validator.classRuleSettings&&t.extend(i,t.validator.classRuleSettings[this])}),i},attributeRules:function(e){var i={},s=t(e),r=s[0].getAttribute("type");for(var n in t.validator.methods){var a;"required"===n?(a=s.get(0).getAttribute(n),""===a&&(a=!0),a=!!a):a=s.attr(n),/min|max/.test(n)&&(null===r||/number|range|text/.test(r))&&(a=Number(a)),a?i[n]=a:r===n&&"range"!==r&&(i[n]=!0)}return i.maxlength&&/-1|2147483647|524288/.test(i.maxlength)&&delete i.maxlength,i},dataRules:function(e){var i,s,r={},n=t(e);for(i in t.validator.methods)s=n.data("rule-"+i.toLowerCase()),void 0!==s&&(r[i]=s);return r},staticRules:function(e){var i={},s=t.data(e.form,"validator");return s.settings.rules&&(i=t.validator.normalizeRule(s.settings.rules[e.name])||{}),i},normalizeRules:function(e,i){return t.each(e,function(s,r){if(r===!1)return delete e[s],void 0;if(r.param||r.depends){var n=!0;switch(typeof r.depends){case"string":n=!!t(r.depends,i.form).length;break;case"function":n=r.depends.call(i,i)}n?e[s]=void 0!==r.param?r.param:!0:delete e[s]}}),t.each(e,function(s,r){e[s]=t.isFunction(r)?r(i):r}),t.each(["minlength","maxlength"],function(){e[this]&&(e[this]=Number(e[this]))}),t.each(["rangelength","range"],function(){var i;e[this]&&(t.isArray(e[this])?e[this]=[Number(e[this][0]),Number(e[this][1])]:"string"==typeof e[this]&&(i=e[this].split(/[\s,]+/),e[this]=[Number(i[0]),Number(i[1])]))}),t.validator.autoCreateRanges&&(e.min&&e.max&&(e.range=[e.min,e.max],delete e.min,delete e.max),e.minlength&&e.maxlength&&(e.rangelength=[e.minlength,e.maxlength],delete e.minlength,delete e.maxlength)),e},normalizeRule:function(e){if("string"==typeof e){var i={};t.each(e.split(/\s/),function(){i[this]=!0}),e=i}return e},addMethod:function(e,i,s){t.validator.methods[e]=i,t.validator.messages[e]=void 0!==s?s:t.validator.messages[e],3>i.length&&t.validator.addClassRules(e,t.validator.normalizeRule(e))},methods:{required:function(e,i,s){if(!this.depend(s,i))return"dependency-mismatch";if("select"===i.nodeName.toLowerCase()){var r=t(i).val();return r&&r.length>0}return this.checkable(i)?this.getLength(e,i)>0:t.trim(e).length>0},email:function(t,e){return this.optional(e)||/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i.test(t)},url:function(t,e){return this.optional(e)||/^(https?|s?ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(t)},date:function(t,e){return this.optional(e)||!/Invalid|NaN/.test(""+new Date(t))},dateISO:function(t,e){return this.optional(e)||/^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/.test(t)},number:function(t,e){return this.optional(e)||/^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(t)},digits:function(t,e){return this.optional(e)||/^\d+$/.test(t)},creditcard:function(t,e){if(this.optional(e))return"dependency-mismatch";if(/[^0-9 \-]+/.test(t))return!1;var i=0,s=0,r=!1;t=t.replace(/\D/g,"");for(var n=t.length-1;n>=0;n--){var a=t.charAt(n);s=parseInt(a,10),r&&(s*=2)>9&&(s-=9),i+=s,r=!r}return 0===i%10},minlength:function(e,i,s){var r=t.isArray(e)?e.length:this.getLength(t.trim(e),i);return this.optional(i)||r>=s},maxlength:function(e,i,s){var r=t.isArray(e)?e.length:this.getLength(t.trim(e),i);return this.optional(i)||s>=r},rangelength:function(e,i,s){var r=t.isArray(e)?e.length:this.getLength(t.trim(e),i);return this.optional(i)||r>=s[0]&&s[1]>=r},min:function(t,e,i){return this.optional(e)||t>=i},max:function(t,e,i){return this.optional(e)||i>=t},range:function(t,e,i){return this.optional(e)||t>=i[0]&&i[1]>=t},equalTo:function(e,i,s){var r=t(s);return this.settings.onfocusout&&r.unbind(".validate-equalTo").bind("blur.validate-equalTo",function(){t(i).valid()}),e===r.val()},remote:function(e,i,s){if(this.optional(i))return"dependency-mismatch";var r=this.previousValue(i);if(this.settings.messages[i.name]||(this.settings.messages[i.name]={}),r.originalMessage=this.settings.messages[i.name].remote,this.settings.messages[i.name].remote=r.message,s="string"==typeof s&&{url:s}||s,r.old===e)return r.valid;r.old=e;var n=this;this.startRequest(i);var a={};return a[i.name]=e,t.ajax(t.extend(!0,{url:s,mode:"abort",port:"validate"+i.name,dataType:"json",data:a,success:function(s){n.settings.messages[i.name].remote=r.originalMessage;var a=s===!0||"true"===s;if(a){var u=n.formSubmitted;n.prepareElement(i),n.formSubmitted=u,n.successList.push(i),delete n.invalid[i.name],n.showErrors()}else{var o={},l=s||n.defaultMessage(i,"remote");o[i.name]=r.message=t.isFunction(l)?l(e):l,n.invalid[i.name]=!0,n.showErrors(o)}r.valid=a,n.stopRequest(i,a)}},s)),"pending"}}}),t.format=t.validator.format})(jQuery),function(t){var e={};if(t.ajaxPrefilter)t.ajaxPrefilter(function(t,i,s){var r=t.port;"abort"===t.mode&&(e[r]&&e[r].abort(),e[r]=s)});else{var i=t.ajax;t.ajax=function(s){var r=("mode"in s?s:t.ajaxSettings).mode,n=("port"in s?s:t.ajaxSettings).port;return"abort"===r?(e[n]&&e[n].abort(),e[n]=i.apply(this,arguments),e[n]):i.apply(this,arguments)}}}(jQuery),function(t){t.extend(t.fn,{validateDelegate:function(e,i,s){return this.bind(i,function(i){var r=t(i.target);return r.is(e)?s.apply(r,arguments):void 0})}})}(jQuery);
//Unobtrusive validation support library for jQuery and jQuery Validate
//jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: false
//global document: false, jQuery: false

(function ($) {
    var $jQval = $.validator,
        adapters,
        data_validation = "unobtrusiveValidation";

    function setValidationValues(options, ruleName, value) {
        options.rules[ruleName] = value;
        if (options.message) {
            options.messages[ruleName] = options.message;
        }
    }

    function splitAndTrim(value) {
        return value.replace(/^\s+|\s+$/g, "").split(/\s*,\s*/g);
    }

    function escapeAttributeValue(value) {
        // As mentioned on http://api.jquery.com/category/selectors/
        return value.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g, "\\$1");
    }

    function getModelPrefix(fieldName) {
        return fieldName.substr(0, fieldName.lastIndexOf(".") + 1);
    }

    function appendModelPrefix(value, prefix) {
        if (value.indexOf("*.") === 0) {
            value = value.replace("*.", prefix);
        }
        return value;
    }

    function onError(error, inputElement) {  // 'this' is the form element
        var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"),
            replaceAttrValue = container.attr("data-valmsg-replace"),
            replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null;

        container.removeClass("field-validation-valid").addClass("field-validation-error");
        error.data("unobtrusiveContainer", container);

        if (replace) {
            container.empty();
            error.removeClass("input-validation-error").appendTo(container);
        }
        else {
            error.hide();
        }
    }

    function onErrors(event, validator) {  // 'this' is the form element
        var container = $(this).find("[data-valmsg-summary=true]"),
            list = container.find("ul");

        if (list && list.length && validator.errorList.length) {
            list.empty();
            container.addClass("validation-summary-errors").removeClass("validation-summary-valid");

            $.each(validator.errorList, function () {
                $("<li />").html(this.message).appendTo(list);
            });
        }
    }

    function onSuccess(error) {  // 'this' is the form element
        var container = error.data("unobtrusiveContainer"),
            replaceAttrValue = container.attr("data-valmsg-replace"),
            replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) : null;

        if (container) {
            container.addClass("field-validation-valid").removeClass("field-validation-error");
            error.removeData("unobtrusiveContainer");

            if (replace) {
                container.empty();
            }
        }
    }

    function onReset(event) {  // 'this' is the form element
        var $form = $(this);
        $form.data("validator").resetForm();
        $form.find(".validation-summary-errors")
            .addClass("validation-summary-valid")
            .removeClass("validation-summary-errors");
        $form.find(".field-validation-error")
            .addClass("field-validation-valid")
            .removeClass("field-validation-error")
            .removeData("unobtrusiveContainer")
            .find(">*")  // If we were using valmsg-replace, get the underlying error
                .removeData("unobtrusiveContainer");
    }

    function validationInfo(form) {
        var $form = $(form),
            result = $form.data(data_validation),
            onResetProxy = $.proxy(onReset, form);

        if (!result) {
            result = {
                options: {  // options structure passed to jQuery Validate's validate() method
                    errorClass: "input-validation-error",
                    errorElement: "span",
                    errorPlacement: $.proxy(onError, form),
                    invalidHandler: $.proxy(onErrors, form),
                    messages: {},
                    rules: {},
                    success: $.proxy(onSuccess, form)
                },
                attachValidation: function () {
                    $form
                        .unbind("reset." + data_validation, onResetProxy)
                        .bind("reset." + data_validation, onResetProxy)
                        .validate(this.options);
                },
                validate: function () {  // a validation function that is called by unobtrusive Ajax
                    $form.validate();
                    return $form.valid();
                }
            };
            $form.data(data_validation, result);
        }

        return result;
    }

    $jQval.unobtrusive = {
        adapters: [],

        parseElement: function (element, skipAttach) {
            /// <summary>
            /// Parses a single HTML element for unobtrusive validation attributes.
            /// </summary>
            /// <param name="element" domElement="true">The HTML element to be parsed.</param>
            /// <param name="skipAttach" type="Boolean">[Optional] true to skip attaching the
            /// validation to the form. If parsing just this single element, you should specify true.
            /// If parsing several elements, you should specify false, and manually attach the validation
            /// to the form when you are finished. The default is false.</param>
            var $element = $(element),
                form = $element.parents("form")[0],
                valInfo, rules, messages;

            if (!form) {  // Cannot do client-side validation without a form
                return;
            }

            valInfo = validationInfo(form);
            valInfo.options.rules[element.name] = rules = {};
            valInfo.options.messages[element.name] = messages = {};

            $.each(this.adapters, function () {
                var prefix = "data-val-" + this.name,
                    message = $element.attr(prefix),
                    paramValues = {};

                if (message !== undefined) {  // Compare against undefined, because an empty message is legal (and falsy)
                    prefix += "-";

                    $.each(this.params, function () {
                        paramValues[this] = $element.attr(prefix + this);
                    });

                    this.adapt({
                        element: element,
                        form: form,
                        message: message,
                        params: paramValues,
                        rules: rules,
                        messages: messages
                    });
                }
            });

            $.extend(rules, { "__dummy__": true });

            if (!skipAttach) {
                valInfo.attachValidation();
            }
        },

        parse: function (selector) {
            /// <summary>
            /// Parses all the HTML elements in the specified selector. It looks for input elements decorated
            /// with the [data-val=true] attribute value and enables validation according to the data-val-*
            /// attribute values.
            /// </summary>
            /// <param name="selector" type="String">Any valid jQuery selector.</param>
            var $forms = $(selector)
                .parents("form")
                .andSelf()
                .add($(selector).find("form"))
                .filter("form");

            $(selector).find(":input[data-val=true]").each(function () {
                $jQval.unobtrusive.parseElement(this, true);
            });

            $forms.each(function () {
                var info = validationInfo(this);
                if (info) {
                    info.attachValidation();
                }
            });
        }
    };

    adapters = $jQval.unobtrusive.adapters;

    adapters.add = function (adapterName, params, fn) {
        /// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation.</summary>
        /// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
        /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
        /// <param name="params" type="Array" optional="true">[Optional] An array of parameter names (strings) that will
        /// be extracted from the data-val-nnnn-mmmm HTML attributes (where nnnn is the adapter name, and
        /// mmmm is the parameter name).</param>
        /// <param name="fn" type="Function">The function to call, which adapts the values from the HTML
        /// attributes into jQuery Validate rules and/or messages.</param>
        /// <returns type="jQuery.validator.unobtrusive.adapters" />
        if (!fn) {  // Called with no params, just a function
            fn = params;
            params = [];
        }
        this.push({ name: adapterName, params: params, adapt: fn });
        return this;
    };

    adapters.addBool = function (adapterName, ruleName) {
        /// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
        /// the jQuery Validate validation rule has no parameter values.</summary>
        /// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
        /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
        /// <param name="ruleName" type="String" optional="true">[Optional] The name of the jQuery Validate rule. If not provided, the value
        /// of adapterName will be used instead.</param>
        /// <returns type="jQuery.validator.unobtrusive.adapters" />
        return this.add(adapterName, function (options) {
            setValidationValues(options, ruleName || adapterName, true);
        });
    };

    adapters.addMinMax = function (adapterName, minRuleName, maxRuleName, minMaxRuleName, minAttribute, maxAttribute) {
        /// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
        /// the jQuery Validate validation has three potential rules (one for min-only, one for max-only, and
        /// one for min-and-max). The HTML parameters are expected to be named -min and -max.</summary>
        /// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
        /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
        /// <param name="minRuleName" type="String">The name of the jQuery Validate rule to be used when you only
        /// have a minimum value.</param>
        /// <param name="maxRuleName" type="String">The name of the jQuery Validate rule to be used when you only
        /// have a maximum value.</param>
        /// <param name="minMaxRuleName" type="String">The name of the jQuery Validate rule to be used when you
        /// have both a minimum and maximum value.</param>
        /// <param name="minAttribute" type="String" optional="true">[Optional] The name of the HTML attribute that
        /// contains the minimum value. The default is "min".</param>
        /// <param name="maxAttribute" type="String" optional="true">[Optional] The name of the HTML attribute that
        /// contains the maximum value. The default is "max".</param>
        /// <returns type="jQuery.validator.unobtrusive.adapters" />
        return this.add(adapterName, [minAttribute || "min", maxAttribute || "max"], function (options) {
            var min = options.params.min,
                max = options.params.max;

            if (min && max) {
                setValidationValues(options, minMaxRuleName, [min, max]);
            }
            else if (min) {
                setValidationValues(options, minRuleName, min);
            }
            else if (max) {
                setValidationValues(options, maxRuleName, max);
            }
        });
    };

    adapters.addSingleVal = function (adapterName, attribute, ruleName) {
        /// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
        /// the jQuery Validate validation rule has a single value.</summary>
        /// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
        /// in the data-val-nnnn HTML attribute(where nnnn is the adapter name).</param>
        /// <param name="attribute" type="String">[Optional] The name of the HTML attribute that contains the value.
        /// The default is "val".</param>
        /// <param name="ruleName" type="String" optional="true">[Optional] The name of the jQuery Validate rule. If not provided, the value
        /// of adapterName will be used instead.</param>
        /// <returns type="jQuery.validator.unobtrusive.adapters" />
        return this.add(adapterName, [attribute || "val"], function (options) {
            setValidationValues(options, ruleName || adapterName, options.params[attribute]);
        });
    };

    $jQval.addMethod("__dummy__", function (value, element, params) {
        return true;
    });

    $jQval.addMethod("regex", function (value, element, params) {
        var match;
        if (this.optional(element)) {
            return true;
        }

        match = new RegExp(params).exec(value);
        return (match && (match.index === 0) && (match[0].length === value.length));
    });

    $jQval.addMethod("nonalphamin", function (value, element, nonalphamin) {
        var match;
        if (nonalphamin) {
            match = value.match(/\W/g);
            match = match && match.length >= nonalphamin;
        }
        return match;
    });

    adapters.addSingleVal("accept", "exts").addSingleVal("regex", "pattern");
    adapters.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url");
    adapters.addMinMax("length", "minlength", "maxlength", "rangelength").addMinMax("range", "min", "max", "range");
    adapters.add("equalto", ["other"], function (options) {
        var prefix = getModelPrefix(options.element.name),
            other = options.params.other,
            fullOtherName = appendModelPrefix(other, prefix),
            element = $(options.form).find(":input[name='" + escapeAttributeValue(fullOtherName) + "']")[0];

        setValidationValues(options, "equalTo", element);
    });
    adapters.add("required", function (options) {
        // jQuery Validate equates "required" with "mandatory" for checkbox elements
        if (options.element.tagName.toUpperCase() !== "INPUT" || options.element.type.toUpperCase() !== "CHECKBOX") {
            setValidationValues(options, "required", true);
        }
    });
    adapters.add("remote", ["url", "type", "additionalfields"], function (options) {
        var value = {
            url: options.params.url,
            type: options.params.type || "GET",
            data: {}
        },
            prefix = getModelPrefix(options.element.name);

        $.each(splitAndTrim(options.params.additionalfields || options.element.name), function (i, fieldName) {
            var paramName = appendModelPrefix(fieldName, prefix);
            value.data[paramName] = function () {
                return $(options.form).find(":input[name='" + escapeAttributeValue(paramName) + "']").val();
            };
        });

        setValidationValues(options, "remote", value);
    });
    adapters.add("password", ["min", "nonalphamin", "regex"], function (options) {
        if (options.params.min) {
            setValidationValues(options, "minlength", options.params.min);
        }
        if (options.params.nonalphamin) {
            setValidationValues(options, "nonalphamin", options.params.nonalphamin);
        }
        if (options.params.regex) {
            setValidationValues(options, "regex", options.params.regex);
        }
    });

    $(function () {
        $jQval.unobtrusive.parse(document);
    });
} (jQuery));
!function (t, e) { "object" == typeof exports && "undefined" != typeof module ? module.exports = e() : "function" == typeof define && define.amd ? define(e) : t.ES6Promise = e() }(this, function () { "use strict"; function t(t) { var e = typeof t; return null !== t && ("object" === e || "function" === e) } function e(t) { return "function" == typeof t } function n(t) { B = t } function r(t) { G = t } function o() { return function () { return process.nextTick(a) } } function i() { return "undefined" != typeof z ? function () { z(a) } : c() } function s() { var t = 0, e = new J(a), n = document.createTextNode(""); return e.observe(n, { characterData: !0 }), function () { n.data = t = ++t % 2 } } function u() { var t = new MessageChannel; return t.port1.onmessage = a, function () { return t.port2.postMessage(0) } } function c() { var t = setTimeout; return function () { return t(a, 1) } } function a() { for (var t = 0; t < W; t += 2) { var e = V[t], n = V[t + 1]; e(n), V[t] = void 0, V[t + 1] = void 0 } W = 0 } function f() { try { var t = Function("return this")().require("vertx"); return z = t.runOnLoop || t.runOnContext, i() } catch (e) { return c() } } function l(t, e) { var n = this, r = new this.constructor(p); void 0 === r[Z] && O(r); var o = n._state; if (o) { var i = arguments[o - 1]; G(function () { return P(o, r, i, n._result) }) } else E(n, r, t, e); return r } function h(t) { var e = this; if (t && "object" == typeof t && t.constructor === e) return t; var n = new e(p); return g(n, t), n } function p() { } function v() { return new TypeError("You cannot resolve a promise with itself") } function d() { return new TypeError("A promises callback cannot return that same promise.") } function _(t) { try { return t.then } catch (e) { return nt.error = e, nt } } function y(t, e, n, r) { try { t.call(e, n, r) } catch (o) { return o } } function m(t, e, n) { G(function (t) { var r = !1, o = y(n, e, function (n) { r || (r = !0, e !== n ? g(t, n) : S(t, n)) }, function (e) { r || (r = !0, j(t, e)) }, "Settle: " + (t._label || " unknown promise")); !r && o && (r = !0, j(t, o)) }, t) } function b(t, e) { e._state === tt ? S(t, e._result) : e._state === et ? j(t, e._result) : E(e, void 0, function (e) { return g(t, e) }, function (e) { return j(t, e) }) } function w(t, n, r) { n.constructor === t.constructor && r === l && n.constructor.resolve === h ? b(t, n) : r === nt ? (j(t, nt.error), nt.error = null) : void 0 === r ? S(t, n) : e(r) ? m(t, n, r) : S(t, n) } function g(e, n) { e === n ? j(e, v()) : t(n) ? w(e, n, _(n)) : S(e, n) } function A(t) { t._onerror && t._onerror(t._result), T(t) } function S(t, e) { t._state === $ && (t._result = e, t._state = tt, 0 !== t._subscribers.length && G(T, t)) } function j(t, e) { t._state === $ && (t._state = et, t._result = e, G(A, t)) } function E(t, e, n, r) { var o = t._subscribers, i = o.length; t._onerror = null, o[i] = e, o[i + tt] = n, o[i + et] = r, 0 === i && t._state && G(T, t) } function T(t) { var e = t._subscribers, n = t._state; if (0 !== e.length) { for (var r = void 0, o = void 0, i = t._result, s = 0; s < e.length; s += 3)r = e[s], o = e[s + n], r ? P(n, r, o, i) : o(i); t._subscribers.length = 0 } } function M(t, e) { try { return t(e) } catch (n) { return nt.error = n, nt } } function P(t, n, r, o) { var i = e(r), s = void 0, u = void 0, c = void 0, a = void 0; if (i) { if (s = M(r, o), s === nt ? (a = !0, u = s.error, s.error = null) : c = !0, n === s) return void j(n, d()) } else s = o, c = !0; n._state !== $ || (i && c ? g(n, s) : a ? j(n, u) : t === tt ? S(n, s) : t === et && j(n, s)) } function x(t, e) { try { e(function (e) { g(t, e) }, function (e) { j(t, e) }) } catch (n) { j(t, n) } } function C() { return rt++ } function O(t) { t[Z] = rt++ , t._state = void 0, t._result = void 0, t._subscribers = [] } function k() { return new Error("Array Methods must be provided an Array") } function F(t) { return new ot(this, t).promise } function Y(t) { var e = this; return new e(U(t) ? function (n, r) { for (var o = t.length, i = 0; i < o; i++)e.resolve(t[i]).then(n, r) } : function (t, e) { return e(new TypeError("You must pass an array to race.")) }) } function q(t) { var e = this, n = new e(p); return j(n, t), n } function D() { throw new TypeError("You must pass a resolver function as the first argument to the promise constructor") } function K() { throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.") } function L() { var t = void 0; if ("undefined" != typeof global) t = global; else if ("undefined" != typeof self) t = self; else try { t = Function("return this")() } catch (e) { throw new Error("polyfill failed because global object is unavailable in this environment") } var n = t.Promise; if (n) { var r = null; try { r = Object.prototype.toString.call(n.resolve()) } catch (e) { } if ("[object Promise]" === r && !n.cast) return } t.Promise = it } var N = void 0; N = Array.isArray ? Array.isArray : function (t) { return "[object Array]" === Object.prototype.toString.call(t) }; var U = N, W = 0, z = void 0, B = void 0, G = function (t, e) { V[W] = t, V[W + 1] = e, W += 2, 2 === W && (B ? B(a) : X()) }, H = "undefined" != typeof window ? window : void 0, I = H || {}, J = I.MutationObserver || I.WebKitMutationObserver, Q = "undefined" == typeof self && "undefined" != typeof process && "[object process]" === {}.toString.call(process), R = "undefined" != typeof Uint8ClampedArray && "undefined" != typeof importScripts && "undefined" != typeof MessageChannel, V = new Array(1e3), X = void 0; X = Q ? o() : J ? s() : R ? u() : void 0 === H && "function" == typeof require ? f() : c(); var Z = Math.random().toString(36).substring(2), $ = void 0, tt = 1, et = 2, nt = { error: null }, rt = 0, ot = function () { function t(t, e) { this._instanceConstructor = t, this.promise = new t(p), this.promise[Z] || O(this.promise), U(e) ? (this.length = e.length, this._remaining = e.length, this._result = new Array(this.length), 0 === this.length ? S(this.promise, this._result) : (this.length = this.length || 0, this._enumerate(e), 0 === this._remaining && S(this.promise, this._result))) : j(this.promise, k()) } return t.prototype._enumerate = function (t) { for (var e = 0; this._state === $ && e < t.length; e++)this._eachEntry(t[e], e) }, t.prototype._eachEntry = function (t, e) { var n = this._instanceConstructor, r = n.resolve; if (r === h) { var o = _(t); if (o === l && t._state !== $) this._settledAt(t._state, e, t._result); else if ("function" != typeof o) this._remaining-- , this._result[e] = t; else if (n === it) { var i = new n(p); w(i, t, o), this._willSettleAt(i, e) } else this._willSettleAt(new n(function (e) { return e(t) }), e) } else this._willSettleAt(r(t), e) }, t.prototype._settledAt = function (t, e, n) { var r = this.promise; r._state === $ && (this._remaining-- , t === et ? j(r, n) : this._result[e] = n), 0 === this._remaining && S(r, this._result) }, t.prototype._willSettleAt = function (t, e) { var n = this; E(t, void 0, function (t) { return n._settledAt(tt, e, t) }, function (t) { return n._settledAt(et, e, t) }) }, t }(), it = function () { function t(e) { this[Z] = C(), this._result = this._state = void 0, this._subscribers = [], p !== e && ("function" != typeof e && D(), this instanceof t ? x(this, e) : K()) } return t.prototype["catch"] = function (t) { return this.then(null, t) }, t.prototype["finally"] = function (t) { var e = this, n = e.constructor; return e.then(function (e) { return n.resolve(t()).then(function () { return e }) }, function (e) { return n.resolve(t()).then(function () { throw e }) }) }, t }(); return it.prototype.then = l, it.all = F, it.race = Y, it.resolve = h, it.reject = q, it._setScheduler = n, it._setAsap = r, it._asap = G, it.polyfill = L, it.Promise = it, it.polyfill(), it });
var dataLayerService = {
    fixedNavHeight: 0,
    windowHeight: 0,

    init: function () {
        // Make sure data layer is defined
        window.dataLayer = window.dataLayer || [];

        // Push mpGlobalProperties to dataLayer
        window.dataLayer.push({ event: 'pageInfo', 'pageInfo': mpGlobalProperties });

        this.fixedNavHeight = $("#menuFrigidaireFixedTop").outerHeight();
        this.windowHeight = $(window).height();
        var $this = this;
        $(window).on('resize', function () {
            $this.windowHeight = $(window).height();
        });

        // skus already saved to data layer
        this.savedSkus = [];

        // Take in impressions on page load
        this.findVisibleImpressions();
        
        // Events that only are checked/fire on page load
        if ($("input[name='isHybris']").val() !== "true") {
            this.getDetailImpression();
        }
        this.getPurchaseEvent();

        // Bind data layer events
        this.bindEvents();
    },

    selectors: {
        productImpressions: '[data-component-type=product-card]:visible',
        productImpressionsSlickActive: '[data-component-type=product-card-accessories].slick-active',
        detailImpression: '[data-component-type=product-details]',
        productClickFilters: [
            '.friModalSize'
        ],
        productClicks: [
            '[data-component-type=product-card]:visible a',
            '[data-component-type=product-link]:visible a'
        ],
        productClickSelectors: function () {
            var productClickSelectors = [];
            $.each(this.productClicks, function (idx, selector) {
                productClickSelectors.push(selector + ':not("' + dataLayerService.selectors.productClickFilters.join(",") + '")');
            });
            return productClickSelectors;
        }
    },

    bindEvents: function () {
        var scrollTimeout = null;
        $(window).scroll(function () {
            if (scrollTimeout) {
                clearTimeout(scrollTimeout);
            }
            scrollTimeout = setTimeout(function () { dataLayerService.findVisibleImpressions(); dataLayerService.findVisibleImpressionsSlickActive(); }, 200);
        });

        $('[data-color-chip]').click(function () {
            setTimeout(function() {
                dataLayerService.findVisibleImpressions();
            },500);
           
        });

        $('#pl').on('filtering-done', function () {
            dataLayerService.findVisibleImpressions();
        });

        $('#RelatedAccessories').click(function () {
            dataLayerService.findVisibleImpressions();
        });

        $('.pdp-relatedproducts__nav').click(function () {
            dataLayerService.findVisibleImpressionsSlickActive();
        });

        $(document).on('click', dataLayerService.selectors.productClickSelectors().join(','), function (e) {
            e.preventDefault();
            var productId = $(this).closest('[data-product-id]').data('product-id');
            var parentSelectors = '[data-component-type=product-card]:visible, [data-component-type=product-link]:visible, [data-component-type=product-card-accessories].slick-active'
            var closestParent = $(this).closest(parentSelectors);
            var idx = $(parentSelectors).index(closestParent);
            var list = $(this).closest('[data-section-type]').data('section-type') || mpGlobalProperties["Page Type"];

            if ($(this).attr('href') && $(this).attr('href').indexOf(productId) > -1) {
                // some elements that generate product click events
                // have the json already on the page, others do not (like links in the cart)
                var cachedEventJson = dataLayerService.parseEventJsonFromScript($("script.product-click-json", closestParent));
                var href = $(this).attr('href');

                function onSuccess(eventJson, list, position) {
                    if (eventJson && eventJson.ecommerce && eventJson.ecommerce.click) {
                        (eventJson.ecommerce.click.actionField || {}).list = list;
                        (eventJson.ecommerce.click.products[0] || {}).position = position;
                        console.log('Push product click event: ', eventJson);
                        window.dataLayer.push(eventJson);
                    }
                }

                function onComplete(productLinkHref) {
                    window.open(productLinkHref, '_parent');
                }

                if (cachedEventJson !== null) {
                    onSuccess(cachedEventJson, list);
                    onComplete(href);
                }
                else {
                    dataLayerService.dataLayerApi.getProductClick(productId, list, idx, href, onSuccess, onComplete);
                }
            } else {
                window.open(this.href, '_parent');
            }
        });

        $(document).on('showAutocomplete', function () {
            dataLayerService.findVisibleImpressions();
        });

        $(document).on('addToCart', function (event, sku, quantity, section) {
            var list = section || mpGlobalProperties["Page Type"];
            dataLayerService.dataLayerApi.getAddToCart(sku, quantity, list);
        });

        $(document).on('esaLandingPage', function (event, esaSelectedProduct) {
            dataLayerService.dataLayerApi.getEsaLandingPage(esaSelectedProduct);
        });

        $(document).on('addToEsaCart', function (event, section, esaCartLines) {
            var list = section || mpGlobalProperties["Page Type"];
            dataLayerService.dataLayerApi.getAddToEsaCart(esaCartLines, list);
        });

        $(document).on('removeFromCart', function (event, sku, quantity, section) {
            var list = section || mpGlobalProperties["Page Type"];
            dataLayerService.dataLayerApi.getRemoveFromCart(sku, quantity, list);
        });

        $(document).on('removeFromEsaCart', function (event, section, lineItem) {
            var list = section || mpGlobalProperties["Page Type"];
            dataLayerService.dataLayerApi.getRemoveFromEsaCart(lineItem, list);
        });

        $(document).on('viewEsaCart', function (event, section, lineItem) {
            var list = section || mpGlobalProperties["Page Type"];
            dataLayerService.dataLayerApi.viewEsaCart(lineItem, list);
        });

        $(document).on('checkoutStep', function (event, step, option) {
            if (step > 1) {
                var dataLayerObj = {
                    event: 'eec.checkout',
                    ecommerce: {
                        checkout: {
                            actionField: { step: step }
                        }
                    }
                };

                if (option) {
                    dataLayerObj.ecommerce.checkout.actionField.option = option;
                }

                console.log('Push checkout step: ', dataLayerObj);
                window.dataLayer.push(dataLayerObj);
            } else {
                dataLayerService.dataLayerApi.getCheckoutData(option);
            }
        });


        $(document).on('checkoutStepOption', function (event, step, option) {
            if (step === 1) {
                var dataLayerObj = {
                    event: 'eec.checkoutOption',
                    ecommerce: {
                        checkout: {
                            actionField: { step: step }
                        }
                    }
                };

                if (option) {
                    dataLayerObj.ecommerce.checkout.actionField.option = option;
                }

                console.log('Push checkoutOption step: ', dataLayerObj);
                window.dataLayer.push(dataLayerObj);
            } 
        });
    },

    parseEventJsonFromScript: function ($script) {
        var innerHtml = ($script.html() || "").replace(/\s+/, "");
        return innerHtml !== "" ? JSON.parse(innerHtml) : null;
    },

    getDetailImpression: function () {
        $(this.selectors.detailImpression).each(function () {
            var eventJson = dataLayerService.parseEventJsonFromScript($("script.product-detail-impression-json", this));

            if (eventJson !== null) {
                var list = $(this).closest('[data-section-type]').data('section-type') || null;

                if (eventJson
                    && list
                    && eventJson.ecommerce
                    && eventJson.ecommerce.detail
                    && eventJson.ecommerce.detail.actionField) {
                    eventJson.ecommerce.detail.actionField.list = list;
                }

                console.log('Push product detail impressions event: ', eventJson);
                window.dataLayer.push(eventJson);
            } else {
                console.error('No product detail impression JSON found.');
            }
        });
    },

    getPurchaseEvent: function () {
        var $wrapper = $('.orderConfirmationPageWrapper');
        if ($wrapper.length && !$wrapper.data("viewed")) {
            this.dataLayerApi.getOrderConfirmation($wrapper.data('order-group-id'), $wrapper.data('esa-order-group-id'));
        }
    },

    findVisibleImpressionsSlickActive: function () {
        var visibleImpressions = [];

        $(this.selectors.productImpressionsSlickActive).each(function (idx) {
            var positionVar = $(this).data('slick-index');
            // If the item is on the page, but not visible in the window, ignore it
            if (dataLayerService.isEleInWindow(this)) {
                var sku = (($(this).data('product-id') || $(this).find('[data-product-id]').data('product-id')) || '').toString();

                // Ignore already saved skus
                if (sku && dataLayerService.savedSkus.indexOf(sku) < 0) {
                    var list = $(this).closest('[data-section-type]').data('section-type') || mpGlobalProperties["Page Type"];
                    visibleImpressions.push({ el: this, id: sku, position: positionVar, list: list });
                }
            }
        });

        if (visibleImpressions.length) {
            var eventJson = null;

            $.each(visibleImpressions, function () {
                var json = dataLayerService.parseEventJsonFromScript($("script.product-impression-json", this.el));
                if (eventJson == null) {
                    eventJson = json;
                }
                else {
                    eventJson.ecommerce.impressions = eventJson.ecommerce.impressions.concat(json.ecommerce.impressions);
                }
            });

            if (eventJson == null) {
                console.log("No event json found.");
                return;
            }

            var dataLayerObj = dataLayerService.setImpressionData(visibleImpressions, eventJson);
            console.log('Push product impressions event: ', dataLayerObj);
            window.dataLayer.push(dataLayerObj);
            // Quicker to search through than the entire data layer object for duplicates
            dataLayerService.savedSkus = dataLayerService.savedSkus.concat(visibleImpressions.map(function (impression) { return impression.id; }));
        }
    },

    findVisibleImpressions: function () {
        var visibleImpressions = [];
        
        $(this.selectors.productImpressions).each(function (idx) {
            // If the item is on the page, but not visible in the window, ignore it
            if (dataLayerService.isEleInWindow(this)) {
                var sku = (($(this).data('product-id') || $(this).find('[data-product-id]').data('product-id')) || '').toString();

                // Ignore already saved skus
                if (sku && dataLayerService.savedSkus.indexOf(sku) < 0) {
                    var list = $(this).closest('[data-section-type]').data('section-type') || mpGlobalProperties["Page Type"];
                    visibleImpressions.push({ el: this, id: sku, position: idx, list: list });
                }
            }
        });

        if (visibleImpressions.length) {
            var eventJson = null;

            $.each(visibleImpressions, function () {
                var json = dataLayerService.parseEventJsonFromScript($("script.product-impression-json", this.el));
                if (eventJson == null) {
                    eventJson = json;
                }
                else {
                    eventJson.ecommerce.impressions = eventJson.ecommerce.impressions.concat(json.ecommerce.impressions);
                }
            });

            if (eventJson == null) {
                console.log("No event json found.");
                return;
            }

            var dataLayerObj = dataLayerService.setImpressionData(visibleImpressions, eventJson);
            console.log('Push product impressions event: ', dataLayerObj);
            window.dataLayer.push(dataLayerObj);
            // Quicker to search through than the entire data layer object for duplicates
            dataLayerService.savedSkus = dataLayerService.savedSkus.concat(visibleImpressions.map(function (impression) { return impression.id; }));
        }
    },

    isEleInWindow: function (ele) {
        var buffer = 20;

        var windowTop = $(window).scrollTop() + this.fixedNavHeight;
        var windowBottom = windowTop + this.windowHeight;

        windowTop += buffer;
        windowBottom -= buffer;

        var elementTop = $(ele).offset().top;
        var elementBottom = elementTop + $(ele).innerHeight();

        var elementHeight = elementBottom - elementTop;
        var windowHeight = windowBottom - windowTop;
        var elementFitsInWindow = windowHeight > elementHeight;

        var elementMidpoint = elementTop + (elementHeight / 2);

        // if the element fits in the window, then we only find impressions when they
        // are fully in the window.
        // otherwise, we find elements that are partially shown
        return elementFitsInWindow
            ? elementTop >= windowTop && elementBottom <= windowBottom
            : elementMidpoint > windowTop && elementMidpoint < windowBottom;
    },

    setImpressionData: function (impressions, data) {
        var completedImpressions = [];
        $.each(impressions, function (index, impression) {
            $.each(data.ecommerce.impressions, function (idx, returnedImpression) {
                if (impression.id === returnedImpression.id) {
                    completedImpressions.push($.extend({}, data.ecommerce.impressions[idx], impression));
                }
            });
        });
        data.ecommerce.impressions = completedImpressions;
        return data;
    },

    buildQueryUrl: function (event) {
        if (frigidaire.lang().toLowerCase() === 'fr-ca') {
            return '/fr-ca/apiv2/datalayer/' + event;
        }
        return '/apiv2/datalayer/' + event;
    },

    dataLayerApi: {
        getProductClick: function (sku, list, position, href, onSuccess, onComplete) {
            $.ajax({
                url: dataLayerService.buildQueryUrl('productclickevent'),
                data: {
                    sku: sku
                },
                timeout: 3000,
                headers: {
                    'accept-language': frigidaire.lang(),
                    'Content-Type': 'application/json'
                },
                success: function (response) {
                    if (response.success) {
                        onSuccess(response.data, list, position);
                    } else {
                        console.error('Get product click failure: ', response.error.message);
                    }
                },
                error: function (err) {
                    console.error('Get product click failure: ', err);
                },
                complete: function () {
                    onComplete(href);
                }
            });
        },

        getAddToCart: function (sku, quantity, list) {
            $.ajax({
                url: dataLayerService.buildQueryUrl('addtocartevent'),
                data: {
                    sku: sku
                },
                headers: {
                    'accept-language': frigidaire.lang(),
                    'Content-Type': 'application/json'
                },
                success: function (response) {
                    if (response.success) {
                        response.data.ecommerce.add.actionField.list = list;
                        response.data.ecommerce.add.products[0].quantity = quantity;
                        console.log('Push add to cart event: ', response.data);
                        window.dataLayer.push(response.data);
                    } else {
                        console.error('Get add to cart failure: ', response.error.message);
                    }
                },
                error: function (err) {
                    console.error('Get add to cart failure: ', err);
                }
            });
        },


        getAddToEsaCart: function (esaCartLines, list) {
            var jsonEvent = {
                "event": "eec.addToCart",
                "ecommerce":
                {
                    "add":
                    {
                        "actionField": { "list": list },
                        "products": []
                    }
                }
            }

            var $this = this;
            $.each(esaCartLines, function (index, esaCartLine) {
                var esaItem = $this.getAnalyticsProduct(esaCartLine);
                esaItem.position = index;

                jsonEvent.ecommerce.add.products.push(esaItem);
            });

            window.dataLayer.push(jsonEvent);
        },

        getAnalyticsProduct: function (esaCartLine) {
            var yearLength = 1;
            var esaItem = {};

            if (esaCartLine == null)
                return esaItem;

            var price = esaCartLine.salePrice;
            var quantity = esaCartLine.quantity;

            if (esaCartLine.subscriptionInterval > 0) {
                yearLength = (esaCartLine.subscriptionInterval / 12);
            }
            else {
                var termsItems = esaCartLine.terms;
                if (typeof (termsItems) != 'undefined' && termsItems != null) {
                    var terms = termsItems.sort((a, b) => (a.termLengthInMonths > b.termLengthInMonths) ? 1 : ((b.termLengthInMonths > a.termLengthInMonths) ? -1 : 0))
                    var selectedFilters = termsItems.filter(p => p.selected);
                    var currentFilter = 0;

                    if (selectedFilters != null && selectedFilters.length > 0) {
                        currentFilter = selectedFilters[0];
                    }

                    if (currentFilter == null && terms != null && terms.length > 0) {
                        currentFilter = terms[0];
                    }

                    if (currentFilter != null) {
                        price = currentFilter.netPrice;
                        yearLength = currentFilter.termLengthInMonths / 12;
                        quantity = 1;
                    }
                }
            }

            esaItem.name = esaCartLine.productDescription + " " + yearLength + " Year";
            esaItem.id = "ESA_F_" + yearLength + "YR";
            esaItem.price = price;
            esaItem.brand = esaCartLine.collection;
            esaItem.category = esaCartLine.product + '/' + esaCartLine.productDescription;
            esaItem.variant = '';
            esaItem.quantity = quantity;

            return esaItem;
        },

        getRemoveFromCart: function (sku, quantity, list) {
            $.ajax({
                url: dataLayerService.buildQueryUrl('removefromcartevent'),
                data: {
                    sku: sku
                },
                headers: {
                    'accept-language': frigidaire.lang(),
                    'Content-Type': 'application/json'
                },
                success: function (response) {
                    if (response.success) {
                        response.data.ecommerce.remove.actionField.list = list;
                        response.data.ecommerce.remove.products[0].quantity = quantity;
                        console.log('Push remove from cart event: ', response.data);
                        window.dataLayer.push(response.data);
                    } else {
                        console.error('Get remove from cart failure: ', response.error.message);
                    }
                },
                error: function (err) {
                    console.error('Get remove from cart failure: ', err);
                }
            });
        },

        getEsaLandingPage: function (esaSelectedProduct) {
            var jsonEvent = {
                "eventCategory": "owner_support_esa",
                "eventAction": "click_quote",
                "eventLabel": esaSelectedProduct.productDescription + '|' + esaSelectedProduct.purchaseDate,
                "eventValue": ''
            }

            window.dataLayer.push(jsonEvent);
        },

        viewEsaCart: function (cart) {
            var jsonEvent = {
                "event": "eec.impression",
                "ecommerce":
                {
                    'impressions': []
                }
            };

            $this = this;

            $.each(cart, function (index, esaCartLine) {
                var esaItem = $this.getAnalyticsProduct(esaCartLine);
                esaItem.position = index;

                jsonEvent.ecommerce.impressions.push(esaItem);
            });

            window.dataLayer.push(jsonEvent);
        },

        getRemoveFromEsaCart: function (lineItem, list) {
            var jsonEvent = {
                "event": "eec.removeFromCart",
                "ecommerce":
                {
                    "remove":
                    {
                        "actionField": { "list": list },
                        "products": []
                    }
                }
            };

            var esaItem = this.getAnalyticsProduct(lineItem);

            jsonEvent.ecommerce.remove.products.push(esaItem);

            window.dataLayer.push(jsonEvent);
        },

        getCheckoutData: function (option) {
            $.ajax({
                url: dataLayerService.buildQueryUrl('checkoutstartevent'),
                headers: {
                    'accept-language': frigidaire.lang(),
                    'Content-Type': 'application/json'
                },
                success: function (response) {
                    if (response.success) {
                        if (option) {
                            response.data.ecommerce.checkout.actionField.option = option;
                        }
                        console.log('Push checkout start event: ', response.data);
                        window.dataLayer.push(response.data);
                    } else {
                        console.error('Get checkout start failure: ', response.error.message);
                    }
                },
                error: function (err) {
                    console.error('Get checkout start failure: ', err);
                }
            });
        },

        getOrderConfirmation: function (orderGroupId, esaOrderGroupId) {
            $.ajax({
                url: dataLayerService.buildQueryUrl('purchaseevent'),
                data: {
                    orderGroupId: orderGroupId,
                    esaOrderGroupId: esaOrderGroupId
                },
                headers: {
                    'accept-language': frigidaire.lang(),
                    'Content-Type': 'application/json'
                },
                success: function (response) {
                    if (response.success) {
                        console.log('Push order confirmation event: ', response.data);
                        window.dataLayer.push(response.data);
                    } else {
                        console.error('Get order confirmation failure: ', response.error.message);
                    }
                },
                error: function (err) {
                    console.error('Get order confirmation failure: ', err);
                }
            });
        }
    }
};


$(document).ready(function () {
    dataLayerService.init();
});

$(window).on('load', function () {
    dataLayerService.findVisibleImpressionsSlickActive();
});
(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
        typeof define === 'function' && define.amd ? define(['exports'], factory) :
            (factory((global.SpriteSpin = {})));
}(this, (function (exports) {
    'use strict';

    var Api = /** @class */ (function () {
        function Api(data) {
            this.data = data;
        }
        return Api;
    }());
    /**
     * Helper method that allows to extend the api with more methods.
     * Receives an object with named functions that are extensions to the API.
     */
    function extendApi(methods) {
        var api = Api.prototype;
        for (var key in methods) {
            if (methods.hasOwnProperty(key)) {
                if (api[key]) {
                    throw new Error('API method is already defined: ' + key);
                }
                else {
                    api[key] = methods[key];
                }
            }
        }
        return api;
    }

    var $$1 = window.jQuery || window.$;

    function getCursorPosition(event) {
        var touches = event.touches;
        var source = event;
        // jQuery Event normalization does not preserve the 'event.touches'
        // try to grab touches from the original event
        if (event.touches === undefined && event.originalEvent !== undefined) {
            touches = event.originalEvent.touches;
        }
        // get current touch or mouse position
        if (touches !== undefined && touches.length > 0) {
            source = touches[0];
        }
        return {
            x: source.clientX || 0,
            y: source.clientY || 0
        };
    }

    var canvas;
    var context;
    function detectionContext() {
        if (context) {
            return context;
        }
        if (!canvas) {
            canvas = document.createElement('canvas');
        }
        if (!canvas || !canvas.getContext) {
            return null;
        }
        context = canvas.getContext('2d');
        return context;
    }
    /**
     * Idea taken from https://github.com/stomita/ios-imagefile-megapixel
     * Detects whether the image has been sub sampled by the browser and does not have its original dimensions.
     * This method unfortunately does not work for images that have transparent background.
     */
    function detectSubsampling(img, width, height) {
        if (!detectionContext()) {
            return false;
        }
        // sub sampling happens on images above 1 megapixel
        if (width * height <= 1024 * 1024) {
            return false;
        }
        // set canvas to 1x1 pixel size and fill it with magenta color
        canvas.width = canvas.height = 1;
        context.fillStyle = '#FF00FF';
        context.fillRect(0, 0, 1, 1);
        // render the image with a negative offset to the left so that it would
        // fill the canvas pixel with the top right pixel of the image.
        context.drawImage(img, -width + 1, 0);
        // check color value to confirm image is covering edge pixel or not.
        // if color still magenta, the image is assumed to be sub sampled.
        try {
            var dat = context.getImageData(0, 0, 1, 1).data;
            return (dat[0] === 255) && (dat[1] === 0) && (dat[2] === 255);
        }
        catch (err) {
            // avoids cross origin exception for chrome when code runs without a server
            return false;
        }
    }

    /**
     *
     */
    function getOuterSize(data) {
        var width = Math.floor(data.width || data.frameWidth || data.target.innerWidth());
        var height = Math.floor(data.height || data.frameHeight || data.target.innerHeight());
        return {
            aspect: width / height,
            height: height,
            width: width
        };
    }
    function getComputedSize(data) {
        var size = getOuterSize(data);
        if (typeof window.getComputedStyle !== 'function') {
            return size;
        }
        var style = window.getComputedStyle(data.target[0]);
        if (!style.width) {
            return size;
        }
        size.width = Math.floor(Number(style.width.replace('px', '')));
        size.height = Math.floor(size.width / size.aspect);
        return size;
    }
    /**
     *
     */
    function getInnerSize(data) {
        var width = Math.floor(data.frameWidth || data.width || data.target.innerWidth());
        var height = Math.floor(data.frameHeight || data.height || data.target.innerHeight());
        return {
            aspect: width / height,
            height: height,
            width: width
        };
    }
    /**
     *
     */
    function getInnerLayout(mode, inner, outer) {
        // get mode
        var isFit = mode === 'fit';
        var isFill = mode === 'fill';
        var isMatch = mode === 'stretch';
        // resulting layout
        var layout = {
            width: '100%',
            height: '100%',
            top: 0,
            left: 0,
            bottom: 0,
            right: 0,
            position: 'absolute',
            overflow: 'hidden'
        };
        // no calculation here
        if (!mode || isMatch) {
            return layout;
        }
        // get size and aspect
        var aspectIsGreater = inner.aspect >= outer.aspect;
        // mode == original
        var width = inner.width;
        var height = inner.height;
        // keep aspect ratio but fit/fill into container
        if (isFit && aspectIsGreater || isFill && !aspectIsGreater) {
            width = outer.width;
            height = outer.width / inner.aspect;
        }
        if (isFill && aspectIsGreater || isFit && !aspectIsGreater) {
            height = outer.height;
            width = outer.height * inner.aspect;
        }
        // floor the numbers
        width = Math.floor(width);
        height = Math.floor(height);
        // position in center
        layout.width = width;
        layout.height = height;
        layout.top = Math.floor((outer.height - height) / 2);
        layout.left = Math.floor((outer.width - width) / 2);
        layout.right = layout.left;
        layout.bottom = layout.top;
        return layout;
    }

    var img;
    /**
     * gets the original width and height of an image element
     */
    function naturalSize(image) {
        // for browsers that support naturalWidth and naturalHeight properties
        if (image.naturalWidth) {
            return {
                height: image.naturalHeight,
                width: image.naturalWidth
            };
        }
        // browsers that do not support naturalWidth and naturalHeight properties have to fall back to the width and
        // height properties. However, the image might have a css style applied so width and height would return the
        // css size. To avoid thet create a new Image object that is free of css rules and grab width and height
        // properties
        //
        // assume that the src has already been downloaded, so no onload callback is needed.
        img = img || new Image();
        img.src = image.src;
        return {
            height: img.height,
            width: img.width
        };
    }

    /**
     * Measures the image frames that are used in the given data object
     */
    function measure(images, options) {
        if (images.length === 1) {
            return [measureSheet(images[0], options)];
        }
        else {
            return measureFrames(images, options);
        }
    }
    function measureSheet(image, options) {
        var result = { id: 0, sprites: [] };
        measureImage(image, options, result);
        var frames = options.frames;
        var framesX = Number(options.framesX) || frames;
        var framesY = Math.ceil(frames / framesX);
        var frameWidth = Math.floor(result.width / framesX);
        var frameHeight = Math.floor(result.height / framesY);
        var divisor = result.isSubsampled ? 2 : 1;
        for (var i = 0; i < frames; i++) {
            var x = (i % framesX) * frameWidth;
            var y = Math.floor(i / framesX) * frameHeight;
            result.sprites.push({
                id: i,
                x: x, y: y,
                width: frameWidth,
                height: frameHeight,
                sampledX: x / divisor,
                sampledY: y / divisor,
                sampledWidth: frameWidth / divisor,
                sampledHeight: frameHeight / divisor
            });
        }
        return result;
    }
    function measureFrames(images, options) {
        var result = [];
        for (var id = 0; id < images.length; id++) {
            // TODO: optimize
            // dont measure images with same size twice
            var sheet = measureSheet(images[id], { frames: 1, framesX: 1, detectSubsampling: options.detectSubsampling });
            sheet.id = id;
            result.push(sheet);
        }
        return result;
    }
    function measureImage(image, options, result) {
        var size = naturalSize(image);
        result.isSubsampled = options.detectSubsampling && detectSubsampling(image, size.width, size.height);
        result.width = size.width;
        result.height = size.height;
        result.sampledWidth = size.width / (result.isSubsampled ? 2 : 1);
        result.sampledHeight = size.height / (result.isSubsampled ? 2 : 1);
        return result;
    }
    function findSpecs(metrics, frames, frame, lane) {
        var spriteId = lane * frames + frame;
        var sheetId = 0;
        var sprite = null;
        var sheet = null;
        while (true) {
            sheet = metrics[sheetId];
            if (!sheet) {
                break;
            }
            if (spriteId >= sheet.sprites.length) {
                spriteId -= sheet.sprites.length;
                sheetId++;
                continue;
            }
            sprite = sheet.sprites[spriteId];
            break;
        }
        return { sprite: sprite, sheet: sheet };
    }

    function indexOf(element, arr) {
        for (var i = 0; i < arr.length; i++) {
            if (arr[i] === element) {
                return i;
            }
        }
    }
    function noop() {
        //
    }
    function preload(opts) {
        var src;
        var input = opts.source;
        src = typeof input === 'string' ? [input] : input;
        // const src: string[] =  ? [opts.source] : opts.source
        var images = [];
        var targetCount = (opts.preloadCount || src.length);
        var onInitiated = opts.initiated || noop;
        var onProgress = opts.progress || noop;
        var onComplete = opts.complete || noop;
        var count = 0;
        var completed = false;
        var firstLoaded = false;
        var tick = function () {
            count += 1;
            onProgress({
                index: indexOf(this, images),
                loaded: count,
                total: src.length,
                percent: Math.round((count / src.length) * 100)
            });
            firstLoaded = firstLoaded || (this === images[0]);
            if (firstLoaded && !completed && (count >= targetCount)) {
                completed = true;
                onComplete(images);
            }
        };
        for (var _i = 0, src_1 = src; _i < src_1.length; _i++) {
            var url = src_1[_i];
            var img = new Image();
            // push result
            images.push(img);
            // bind logic, dont care about abort/errors
            img.onload = img.onabort = img.onerror = tick;
            // begin load
            img.src = url;
        }
        onInitiated(images);
    }

    function padNumber(num, length, pad) {
        num = String(num);
        while (num.length < length) {
            num = String(pad) + num;
        }
        return num;
    }
    /**
     * Generates an array of source strings
     * - path is a source string where the frame number of the file name is exposed as '{frame}'
     * - start indicates the first frame number
     * - end indicates the last frame number
     * - digits is the number of digits used in the file name for the frame number
     * @example
     *      sourceArray('http://example.com/image_{frame}.jpg, { frame: [1, 3], digits: 2 })
     *      // -> [ 'http://example.com/image_01.jpg', 'http://example.com/image_02.jpg', 'http://example.com/image_03.jpg' ]
     */
    function sourceArray(path, opts) {
        var fStart = 0, fEnd = 0, lStart = 0, lEnd = 0;
        var digits = opts.digits || 2;
        if (opts.frame) {
            fStart = opts.frame[0];
            fEnd = opts.frame[1];
        }
        if (opts.lane) {
            lStart = opts.lane[0];
            lEnd = opts.lane[1];
        }
        var i, j, temp;
        var result = [];
        for (i = lStart; i <= lEnd; i += 1) {
            for (j = fStart; j <= fEnd; j += 1) {
                temp = path.replace('{lane}', padNumber(i, digits, 0));
                temp = temp.replace('{frame}', padNumber(j, digits, 0));
                result.push(temp);
            }
        }
        return result;
    }

    /**
     * The namespace that is used to bind functions to DOM events and store the data object
     */
    var namespace = 'spritespin';
    /**
     * Event names that are recognized by SpriteSpin. A module can implement any of these and they will be bound
     * to the target element on which the plugin is called.
     */
    var eventNames = [
        'mousedown',
        'mousemove',
        'mouseup',
        'mouseenter',
        'mouseover',
        'mouseleave',
        'dblclick',
        'mousewheel',
        'touchstart',
        'touchmove',
        'touchend',
        'touchcancel',
        'selectstart',
        'gesturestart',
        'gesturechange',
        'gestureend'
    ];
    /**
     *
     */
    var callbackNames = [
        'onInit',
        'onProgress',
        'onLoad',
        'onFrameChanged',
        'onFrame',
        'onDraw',
        'onComplete',
        'onDestroy'
    ];
    /**
     * Names of events for that the default behavior should be prevented.
     */
    var eventsToPrevent = [
        'dragstart'
    ];
    /**
     * Default set of SpriteSpin options. This also represents the majority of data attributes that are used during the
     * lifetime of a SpriteSpin instance. The data is stored inside the target DOM element on which the plugin is called.
     */
    var defaults = {
        source: undefined,
        width: undefined,
        height: undefined,
        frames: undefined,
        framesX: undefined,
        lanes: 1,
        sizeMode: undefined,
        renderer: 'canvas',
        lane: 0,
        frame: 0,
        frameTime: 40,
        animate: true,
        retainAnimate: false,
        reverse: false,
        loop: true,
        stopFrame: 0,
        wrap: true,
        wrapLane: false,
        sense: 1,
        senseLane: undefined,
        orientation: 'horizontal',
        detectSubsampling: true,
        preloadCount: undefined,
        responsive: undefined,
        plugins: [
            '360',
            'drag'
        ]
    };

    function noop$1() {
        // noop
    }
    function wrapConsole(type) {
        return console && console[type] ? function () {
            var args = [];
            for (var _i = 0; _i < arguments.length; _i++) {
                args[_i] = arguments[_i];
            }
            return console.log.apply(console, args);
        } : noop$1;
    }
    var log = wrapConsole('log');
    var warn = wrapConsole('warn');
    var error = wrapConsole('error');
    function toArray(value) {
        return Array.isArray(value) ? value : [value];
    }
    /**
     * clamps the given value by the given min and max values
     */
    function clamp(value, min, max) {
        return (value > max ? max : (value < min ? min : value));
    }
    /**
     *
     */
    function wrap(value, min, max, size) {
        while (value > max) {
            value -= size;
        }
        while (value < min) {
            value += size;
        }
        return value;
    }
    /**
     * prevents default action on the given event
     */
    function prevent(e) {
        e.preventDefault();
        return false;
    }
    /**
     * Binds on the given target and event the given function.
     * The SpriteSpin namespace is attached to the event name
     */
    function bind(target, event, func) {
        if (func) {
            target.bind(event + '.' + namespace, function (e) {
                func.apply(target, [e, target.spritespin('data')]);
            });
        }
    }
    /**
     * Unbinds all SpriteSpin events from given target element
     */
    function unbind(target) {
        target.unbind('.' + namespace);
    }
    /**
     * Checks if given object is a function
     */
    function isFunction(fn) {
        return typeof fn === 'function';
    }
    function pixelRatio(context) {
        var devicePixelRatio = window.devicePixelRatio || 1;
        var backingStoreRatio = context.webkitBackingStorePixelRatio ||
            context.mozBackingStorePixelRatio ||
            context.msBackingStorePixelRatio ||
            context.oBackingStorePixelRatio ||
            context.backingStorePixelRatio || 1;
        return devicePixelRatio / backingStoreRatio;
    }



    var _Utils = Object.freeze({
        $: $$1,
        getCursorPosition: getCursorPosition,
        detectSubsampling: detectSubsampling,
        getOuterSize: getOuterSize,
        getComputedSize: getComputedSize,
        getInnerSize: getInnerSize,
        getInnerLayout: getInnerLayout,
        measure: measure,
        findSpecs: findSpecs,
        naturalSize: naturalSize,
        preload: preload,
        sourceArray: sourceArray,
        noop: noop$1,
        log: log,
        warn: warn,
        error: error,
        toArray: toArray,
        clamp: clamp,
        wrap: wrap,
        prevent: prevent,
        bind: bind,
        unbind: unbind,
        isFunction: isFunction,
        pixelRatio: pixelRatio
    });

    /**
     * Applies css attributes to layout the SpriteSpin containers.
     */
    function applyLayout(data) {
        // disable selection
        data.target
            .attr('unselectable', 'on')
            .css({
                width: '',
                height: '',
                '-ms-user-select': 'none',
                '-moz-user-select': 'none',
                '-khtml-user-select': 'none',
                '-webkit-user-select': 'none',
                'user-select': 'none'
            });
        var size = data.responsive ? getComputedSize(data) : getOuterSize(data);
        var layout = getInnerLayout(data.sizeMode, getInnerSize(data), size);
        // apply layout on target
        data.target.css({
            width: size.width,
            height: size.height,
            position: 'relative',
            overflow: 'hidden'
        });
        // apply layout on stage
        data.stage.css(layout).hide();
        if (!data.canvas) {
            return;
        }
        // apply layout on canvas
        data.canvas.css(layout).hide();
        // apply pixel ratio on canvas
        data.canvasRatio = data.canvasRatio || pixelRatio(data.context);
        if (typeof layout.width === 'number' && typeof layout.height === 'number') {
            data.canvas[0].width = (layout.width * data.canvasRatio) || size.width;
            data.canvas[0].height = (layout.height * data.canvasRatio) || size.height;
        }
        else {
            data.canvas[0].width = (size.width * data.canvasRatio);
            data.canvas[0].height = (size.height * data.canvasRatio);
        }
        // width and height must be set before calling scale
        data.context.scale(data.canvasRatio, data.canvasRatio);
    }

    function getState(data, name) {
        data.state = data.state || {};
        data.state[name] = data.state[name] || {};
        return data.state[name];
    }
    function getPluginState(data, name) {
        var state = getState(data, 'plugin');
        state[name] = state[name] || {};
        return state[name];
    }
    function is(data, key) {
        return !!getState(data, 'flags')[key];
    }
    function flag(data, key, value) {
        getState(data, 'flags')[key] = !!value;
    }

    function getPlaybackState(data) {
        return getState(data, 'playback');
    }
    function updateLane(data, lane) {
        data.lane = data.wrapLane
            ? wrap(lane, 0, data.lanes - 1, data.lanes)
            : clamp(lane, 0, data.lanes - 1);
    }
    function updateAnimationFrame(data) {
        data.frame += (data.reverse ? -1 : 1);
        // wrap the frame value to fit in range [0, data.frames)
        data.frame = wrap(data.frame, 0, data.frames - 1, data.frames);
        // stop animation if loop is disabled and the stopFrame is reached
        if (!data.loop && (data.frame === data.stopFrame)) {
            stopAnimation(data);
        }
    }
    function updateInputFrame(data, frame) {
        data.frame = Number(frame);
        data.frame = data.wrap
            ? wrap(data.frame, 0, data.frames - 1, data.frames)
            : clamp(data.frame, 0, data.frames - 1);
    }
    function updateAnimation(data) {
        var state = getPlaybackState(data);
        if (state.handler) {
            updateBefore(data);
            updateAnimationFrame(data);
            updateAfter(data);
        }
    }
    function updateBefore(data) {
        var state = getPlaybackState(data);
        state.lastFrame = data.frame;
        state.lastLane = data.lane;
    }
    function updateAfter(data) {
        var state = getPlaybackState(data);
        if (state.lastFrame !== data.frame || state.lastLane !== data.lane) {
            data.target.trigger('onFrameChanged', data);
        }
        data.target.trigger('onFrame', data);
        data.target.trigger('onDraw', data);
    }
    /**
     * Updates the frame number of the SpriteSpin data. Performs an auto increment if no frame number is given.
     */
    function updateFrame(data, frame, lane) {
        updateBefore(data);
        if (frame != null) {
            updateInputFrame(data, frame);
        }
        if (lane != null) {
            updateLane(data, lane);
        }
        updateAfter(data);
    }
    /**
     * Stops the running animation on given SpriteSpin data.
     */
    function stopAnimation(data) {
        data.animate = false;
        var state = getPlaybackState(data);
        if (state.handler != null) {
            window.clearInterval(state.handler);
            state.handler = null;
        }
    }
    /**
     * Starts animation on given SpriteSpin data if animation is enabled.
     */
    function applyAnimation(data) {
        var state = getPlaybackState(data);
        if (state.handler && (!data.animate || state.frameTime !== data.frameTime)) {
            stopAnimation(data);
        }
        if (data.animate && !state.handler) {
            state.frameTime = data.frameTime;
            state.handler = window.setInterval(function () { return updateAnimation(data); }, state.frameTime);
        }
    }
    /**
     * Starts the animation playback
     */
    function startAnimation(data) {
        data.animate = true;
        applyAnimation(data);
    }

    var plugins = {};
    /**
     * Registers a module implementation as an available extension to SpriteSpin.
     * Use this to add custom Rendering or Updating modules that can be addressed with the 'module' option.
     */
    function registerPlugin(name, plugin) {
        if (plugins[name]) {
            error("Plugin name \"" + name + "\" is already taken");
            return;
        }
        plugin = plugin || {};
        plugins[name] = plugin;
        return plugin;
    }
    function registerModule(name, plugin) {
        warn('"registerModule" is deprecated, use "registerPlugin" instead');
        registerPlugin(name, plugin);
    }
    function getPlugin(name) {
        return plugins[name];
    }
    /**
     * Replaces module names on given SpriteSpin data and replaces them with actual implementations.
     */
    function applyPlugins(data) {
        fixPlugins(data);
        for (var i = 0; i < data.plugins.length; i += 1) {
            var name_1 = data.plugins[i];
            if (typeof name_1 !== 'string') {
                continue;
            }
            var plugin = getPlugin(name_1);
            if (!plugin) {
                error('No plugin found with name ' + name_1);
                continue;
            }
            data.plugins[i] = plugin;
        }
    }
    function fixPlugins(data) {
        // tslint:disable no-string-literal
        if (data['mods']) {
            warn('"mods" option is deprecated, use "plugins" instead');
            data.plugins = data['mods'];
            delete data['mods'];
        }
        if (data['behavior']) {
            warn('"behavior" option is deprecated, use "plugins" instead');
            data.plugins.push(data['behavior']);
            delete data['behavior'];
        }
        if (data['module']) {
            warn('"module" option is deprecated, use "plugins" instead');
            data.plugins.push(data['module']);
            delete data['module'];
        }
    }

    var $$2 = $$1;
    var counter = 0;
    /**
     * Collection of all SpriteSpin instances
     */
    var instances = {};
    function pushInstance(data) {
        counter += 1;
        data.id = String(counter);
        instances[data.id] = data;
    }
    function popInstance(data) {
        delete instances[data.id];
    }
    function eachInstance(cb) {
        for (var id in instances) {
            if (instances.hasOwnProperty(id)) {
                cb(instances[id]);
            }
        }
    }
    var lazyinit = function () {
        // replace function with a noop
        // this logic must run only once
        lazyinit = function () { };
        function onEvent(eventName, e) {
            eachInstance(function (data) {
                for (var _i = 0, _a = data.plugins; _i < _a.length; _i++) {
                    var module_1 = _a[_i];
                    if (typeof module_1[eventName] === 'function') {
                        module_1[eventName].apply(data.target, [e, data]);
                    }
                }
            });
        }
        function onResize() {
            eachInstance(function (data) {
                if (data.responsive) {
                    boot(data);
                }
            });
        }
        var _loop_1 = function (eventName) {
            $$2(window.document).bind(eventName + '.' + namespace, function (e) {
                onEvent('document' + eventName, e);
            });
        };
        for (var _i = 0, eventNames_1 = eventNames; _i < eventNames_1.length; _i++) {
            var eventName = eventNames_1[_i];
            _loop_1(eventName);
        }
        var resizeTimeout = null;
        $$2(window).on('resize', function () {
            window.clearTimeout(resizeTimeout);
            resizeTimeout = window.setTimeout(onResize, 100);
        });
    };
    /**
     * (re)binds all spritespin events on the target element
     */
    function applyEvents(data) {
        var target = data.target;
        // Clear all SpriteSpin events on the target element
        unbind(target);
        // disable all default browser behavior on the following events
        // mainly prevents image drag operation
        for (var _i = 0, eventsToPrevent_1 = eventsToPrevent; _i < eventsToPrevent_1.length; _i++) {
            var eName = eventsToPrevent_1[_i];
            bind(target, eName, prevent);
        }
        // Bind module functions to SpriteSpin events
        for (var _a = 0, _b = data.plugins; _a < _b.length; _a++) {
            var plugin = _b[_a];
            for (var _c = 0, eventNames_2 = eventNames; _c < eventNames_2.length; _c++) {
                var eName = eventNames_2[_c];
                bind(target, eName, plugin[eName]);
            }
            for (var _d = 0, callbackNames_1 = callbackNames; _d < callbackNames_1.length; _d++) {
                var eName = callbackNames_1[_d];
                bind(target, eName, plugin[eName]);
            }
        }
        // bind auto start function to load event.
        bind(target, 'onLoad', function (e, d) {
            applyAnimation(d);
        });
        // bind all user events that have been passed on initialization
        for (var _e = 0, callbackNames_2 = callbackNames; _e < callbackNames_2.length; _e++) {
            var eName = callbackNames_2[_e];
            bind(target, eName, data[eName]);
        }
    }
    function applyMetrics(data) {
        if (!data.images) {
            data.metrics = [];
        }
        data.metrics = measure(data.images, data);
        var spec = findSpecs(data.metrics, data.frames, 0, 0);
        if (spec.sprite) {
            // TODO: try to remove frameWidth/frameHeight
            data.frameWidth = spec.sprite.width;
            data.frameHeight = spec.sprite.height;
        }
    }
    /**
     * Runs the boot process. (re)initializes plugins, (re)initializes the layout, (re)binds events and loads source images.
     */
    function boot(data) {
        applyPlugins(data);
        applyEvents(data);
        applyLayout(data);
        data.source = toArray(data.source);
        data.loading = true;
        data.target.addClass('loading').trigger('onInit', data);
        preload({
            source: data.source,
            preloadCount: data.preloadCount,
            progress: function (progress) {
                data.progress = progress;
                data.target.trigger('onProgress', data);
            },
            complete: function (images) {
                data.images = images;
                data.loading = false;
                data.frames = data.frames || images.length;
                applyMetrics(data);
                applyLayout(data);
                data.stage.show();
                data.target
                    .removeClass('loading')
                    .trigger('onLoad', data)
                    .trigger('onFrame', data)
                    .trigger('onDraw', data)
                    .trigger('onComplete', data);
            }
        });
    }
    /**
     * Creates a new SpriteSpin instance
     */
    function create(options) {
        var _this = this;
        var target = options.target;
        // SpriteSpin is not initialized
        // Create default settings object and extend with given options
        var data = $$2.extend({}, defaults, options);
        // ensure source is set
        data.source = data.source || [];
        // ensure plugins are set
        data.plugins = data.plugins || [];
        // if image tags are contained inside this DOM element
        // use these images as the source files
        target.find('img').each(function () {
            if (!Array.isArray(data.source)) {
                data.source = [];
            }
            data.source.push($$2(_this).attr('src'));
        });
        // build inner html
        // <div>
        //   <div class='spritespin-stage'></div>
        //   <canvas class='spritespin-canvas'></canvas>
        // </div>
        target
            .empty()
            .addClass('spritespin-instance')
            .append("<div class='spritespin-stage'></div>");
        // add the canvas element if canvas rendering is enabled and supported
        if (data.renderer === 'canvas') {
            var canvas = document.createElement('canvas');
            if (!!(canvas.getContext && canvas.getContext('2d'))) {
                data.canvas = $$2(canvas).addClass('spritespin-canvas');
                data.context = canvas.getContext('2d');
                target.append(data.canvas);
                target.addClass('with-canvas');
            }
            else {
                // fallback to image rendering mode
                data.renderer = 'image';
            }
        }
        // setup references to DOM elements
        data.target = target;
        data.stage = target.find('.spritespin-stage');
        // store the data
        target.data(namespace, data);
        pushInstance(data);
        return data;
    }
    /**
     * Creates a new SpriteSpin instance, or updates it if it is already present
     */
    function createOrUpdate(options) {
        lazyinit();
        var data = options.target.data(namespace);
        if (!data) {
            data = create(options);
        }
        else {
            $$2.extend(data, options);
        }
        boot(data);
    }
    /**
     * Stops running animation, unbinds all events and deletes the data on the target element of the given data object.
     */
    function destroy(data) {
        popInstance(data);
        stopAnimation(data);
        data.target.trigger('onDestroy', data);
        unbind(data.target);
        data.target.removeData(namespace);
    }

    function getInputState(data) {
        return getState(data, 'input');
    }
    /**
     * Updates the input state of the SpriteSpin data using the given mouse or touch event.
     */
    function updateInput(e, data) {
        var cursor = getCursorPosition(e);
        var state = getInputState(data);
        // cache positions from previous frame
        state.oldX = state.currentX;
        state.oldY = state.currentY;
        state.currentX = cursor.x;
        state.currentY = cursor.y;
        // Fix old position.
        if (state.oldX === undefined || state.oldY === undefined) {
            state.oldX = state.currentX;
            state.oldY = state.currentY;
        }
        // Cache the initial click/touch position and store the frame number at which the click happened.
        // Useful for different behavior implementations. This must be restored when the click/touch is released.
        if (state.startX === undefined || state.startY === undefined) {
            state.startX = state.currentX;
            state.startY = state.currentY;
            state.clickframe = data.frame;
            state.clicklane = data.lane;
        }
        // Calculate the vector from start position to current pointer position.
        state.dX = state.currentX - state.startX;
        state.dY = state.currentY - state.startY;
        // Calculate the vector from last frame position to current pointer position.
        state.ddX = state.currentX - state.oldX;
        state.ddY = state.currentY - state.oldY;
        // Normalize vectors to range [-1:+1]
        state.ndX = state.dX / data.target.innerWidth();
        state.ndY = state.dY / data.target.innerHeight();
        state.nddX = state.ddX / data.target.innerWidth();
        state.nddY = state.ddY / data.target.innerHeight();
    }
    /**
     * Resets the input state of the SpriteSpin data.
     */
    function resetInput(data) {
        var input = getInputState(data);
        input.startX = input.startY = undefined;
        input.currentX = input.currentY = undefined;
        input.oldX = input.oldY = undefined;
        input.dX = input.dY = 0;
        input.ddX = input.ddY = 0;
        input.ndX = input.ndY = 0;
        input.nddX = input.nddY = 0;
    }

    function extension(obj, value) {
        var _this = this;
        if (obj === 'data') {
            return this.data(namespace);
        }
        if (obj === 'api') {
            var data = this.data(namespace);
            data.api = data.api || new Api(data);
            return data.api;
        }
        if (obj === 'destroy') {
            return $$1(this).each(function () {
                var data = $$1(_this).data(namespace);
                if (data) {
                    destroy(data);
                }
            });
        }
        if (arguments.length === 2 && typeof obj === 'string') {
            var tmp = {};
            tmp[obj] = value;
            obj = tmp;
        }
        if (typeof obj === 'object') {
            obj.target = obj.target || $$1(this);
            createOrUpdate(obj);
            return obj.target;
        }
        throw new Error('Invalid call to spritespin');
    }
    $$1.fn[namespace] = extension;

    // tslint:disable:object-literal-shorthand
    // tslint:disable:only-arrow-functions
    extendApi({
        // Gets a value indicating whether the animation is currently running.
        isPlaying: function () {
            return getPlaybackState(this.data).handler != null;
        },
        // Gets a value indicating whether the animation looping is enabled.
        isLooping: function () {
            return this.data.loop;
        },
        // Starts/Stops the animation playback
        toggleAnimation: function () {
            if (this.isPlaying()) {
                this.stopAnimation();
            }
            else {
                this.startAnimation();
            }
        },
        // Stops animation playback
        stopAnimation: function () {
            this.data.animate = false;
            stopAnimation(this.data);
        },
        // Starts animation playback
        startAnimation: function () {
            this.data.animate = true;
            applyAnimation(this.data);
        },
        // Sets a value indicating whether the animation should be looped or not.
        // This might start the animation (if the 'animate' data attribute is set to true)
        loop: function (value) {
            this.data.loop = value;
            applyAnimation(this.data);
            return this;
        },
        // Gets the current frame number
        currentFrame: function () {
            return this.data.frame;
        },
        // Updates SpriteSpin to the specified frame.
        updateFrame: function (frame) {
            updateFrame(this.data, frame);
            return this;
        },
        // Skips the given number of frames
        skipFrames: function (step) {
            var data = this.data;
            updateFrame(data, data.frame + (data.reverse ? -step : +step));
            return this;
        },
        // Updates SpriteSpin so that the next frame is shown
        nextFrame: function () {
            return this.skipFrames(1);
        },
        // Updates SpriteSpin so that the previous frame is shown
        prevFrame: function () {
            return this.skipFrames(-1);
        },
        // Starts the animations that will play until the given frame number is reached
        // options:
        //   force [boolean] starts the animation, even if current frame is the target frame
        //   nearest [boolean] animates to the direction with minimum distance to the target frame
        playTo: function (frame, options) {
            var data = this.data;
            options = options || {};
            if (!options.force && data.frame === frame) {
                return;
            }
            if (options.nearest) {
                // distance to the target frame
                var a = frame - data.frame;
                // distance to last frame and the to target frame
                var b = frame > data.frame ? a - data.frames : a + data.frames;
                // minimum distance
                var c = Math.abs(a) < Math.abs(b) ? a : b;
                data.reverse = c < 0;
            }
            data.animate = true;
            data.loop = false;
            data.stopFrame = frame;
            applyAnimation(data);
            return this;
        }
    });

    function pick(target, names) {
        for (var _i = 0, names_1 = names; _i < names_1.length; _i++) {
            var name_1 = names_1[_i];
            if (target[name_1] || name_1 in target) {
                return name_1;
            }
        }
        return names[0];
    }
    var browser = {
        requestFullscreen: pick(document.documentElement, [
            'requestFullscreen',
            'webkitRequestFullScreen',
            'mozRequestFullScreen',
            'msRequestFullscreen'
        ]),
        exitFullscreen: pick(document, [
            'exitFullscreen',
            'webkitExitFullscreen',
            'webkitCancelFullScreen',
            'mozCancelFullScreen',
            'msExitFullscreen'
        ]),
        fullscreenElement: pick(document, [
            'fullscreenElement',
            'webkitFullscreenElement',
            'webkitCurrentFullScreenElement',
            'mozFullScreenElement',
            'msFullscreenElement'
        ]),
        fullscreenEnabled: pick(document, [
            'fullscreenEnabled',
            'webkitFullscreenEnabled',
            'mozFullScreenEnabled',
            'msFullscreenEnabled'
        ]),
        fullscreenchange: pick(document, [
            'onfullscreenchange',
            'onwebkitfullscreenchange',
            'onmozfullscreenchange',
            'onMSFullscreenChange'
        ]).replace(/^on/, ''),
        fullscreenerror: pick(document, [
            'onfullscreenerror',
            'onwebkitfullscreenerror',
            'onmozfullscreenerror',
            'onMSFullscreenError'
        ]).replace(/^on/, '')
    };
    var changeEvent = browser.fullscreenchange + '.' + namespace + '-fullscreen';
    function unbindChangeEvent() {
        $$1(document).unbind(changeEvent);
    }
    function bindChangeEvent(callback) {
        unbindChangeEvent();
        $$1(document).bind(changeEvent, callback);
    }
    var orientationEvent = 'orientationchange.' + namespace + '-fullscreen';
    function unbindOrientationEvent() {
        $$1(window).unbind(orientationEvent);
    }
    function bindOrientationEvent(callback) {
        unbindOrientationEvent();
        $$1(window).bind(orientationEvent, callback);
    }
    function requestFullscreenNative(e) {
        e = e || document.documentElement;
        e[browser.requestFullscreen]();
    }
    function exitFullscreen() {
        return document[browser.exitFullscreen]();
    }
    function fullscreenEnabled() {
        return document[browser.fullscreenEnabled];
    }
    function fullscreenElement() {
        return document[browser.fullscreenElement];
    }
    function isFullscreen() {
        return !!fullscreenElement();
    }
    function toggleFullscreen(data, opts) {
        if (isFullscreen()) {
            this.apiRequestFullscreen(opts);
        }
        else {
            this.exitFullscreen();
        }
    }
    function requestFullscreen(data, opts) {
        opts = opts || {};
        var oWidth = data.width;
        var oHeight = data.height;
        var oSource = data.source;
        var oSize = data.sizeMode;
        var oResponsive = data.responsive;
        var enter = function () {
            data.width = window.screen.width;
            data.height = window.screen.height;
            data.source = (opts.source || oSource);
            data.sizeMode = opts.sizeMode || 'fit';
            data.responsive = false;
            boot(data);
        };
        var exit = function () {
            data.width = oWidth;
            data.height = oHeight;
            data.source = oSource;
            data.sizeMode = oSize;
            data.responsive = oResponsive;
            boot(data);
        };
        bindChangeEvent(function () {
            if (isFullscreen()) {
                enter();
                bindOrientationEvent(enter);
            }
            else {
                unbindChangeEvent();
                unbindOrientationEvent();
                exit();
            }
        });
        requestFullscreenNative(data.target[0]);
    }
    extendApi({
        fullscreenEnabled: fullscreenEnabled,
        fullscreenElement: fullscreenElement,
        exitFullscreen: exitFullscreen,
        toggleFullscreen: function (opts) {
            toggleFullscreen(this.data, opts);
        },
        requestFullscreen: function (opts) {
            requestFullscreen(this.data, opts);
        }
    });

    (function () {
        var NAME = 'click';
        function click(e, data) {
            if (data.loading || !data.stage.is(':visible')) {
                return;
            }
            updateInput(e, data);
            var input = getInputState(data);
            var half, pos;
            var target = data.target, offset = target.offset();
            if (data.orientation === 'horizontal') {
                half = target.innerWidth() / 2;
                pos = input.currentX - offset.left;
            }
            else {
                half = target.innerHeight() / 2;
                pos = input.currentY - offset.top;
            }
            updateFrame(data, data.frame + (pos > half ? 1 : -1));
        }
        registerPlugin(NAME, {
            name: NAME,
            mouseup: click,
            touchend: click
        });
    })();

    (function () {
        var NAME = 'drag';
        function getState$$1(data) {
            return getPluginState(data, NAME);
        }
        function getAxis(data) {
            if (typeof data.orientation === 'number') {
                return data.orientation * Math.PI / 180;
            }
            if (data.orientation === 'horizontal') {
                return 0;
            }
            return Math.PI / 2;
        }
        function dragStart(e, data) {
            var state = getState$$1(data);
            if (data.loading || is(data, 'dragging') || !data.stage.is(':visible')) {
                return;
            }
            // allow browser scroll only on double tap
            var now = new Date().getTime();
            if (state.startAt && (now - state.startAt > 200)) {
                e.preventDefault();
            }
            state.startAt = now;
            state.wasPlaying = !!getPlaybackState(data).handler;
            state.frame = data.frame || 0;
            state.lane = data.lane || 0;
            flag(data, 'dragging', true);
            updateInput(e, data);
        }
        function dragEnd(e, data) {
            if (is(data, 'dragging')) {
                flag(data, 'dragging', false);
                resetInput(data);
                if (data.retainAnimate && getState$$1(data).wasPlaying) {
                    startAnimation(data);
                }
            }
        }
        function drag(e, data) {
            var state = getState$$1(data);
            var input = getInputState(data);
            if (!is(data, 'dragging')) {
                return;
            }
            updateInput(e, data);
            var rad = getAxis(data);
            var sn = Math.sin(rad);
            var cs = Math.cos(rad);
            var x = ((input.nddX * cs - input.nddY * sn) * data.sense) || 0;
            var y = ((input.nddX * sn + input.nddY * cs) * (data.senseLane || data.sense)) || 0;
            // accumulate
            state.frame += data.frames * x;
            state.lane += data.lanes * y;
            // update spritespin
            var oldFrame = data.frame;
            var oldLane = data.lane;
            updateFrame(data, Math.floor(state.frame), Math.floor(state.lane));
            stopAnimation(data);
        }
        function mousemove(e, data) {
            dragStart(e, data);
            drag(e, data);
        }
        registerPlugin('drag', {
            name: 'drag',
            mousedown: dragStart,
            mousemove: drag,
            mouseup: dragEnd,
            documentmousemove: drag,
            documentmouseup: dragEnd,
            touchstart: dragStart,
            touchmove: drag,
            touchend: dragEnd,
            touchcancel: dragEnd
        });
        registerPlugin('move', {
            name: 'move',
            mousemove: mousemove,
            mouseleave: dragEnd,
            touchstart: dragStart,
            touchmove: drag,
            touchend: dragEnd,
            touchcancel: dragEnd
        });
    })();

    (function () {
        var NAME = 'hold';
        function getState$$1(data) {
            return getPluginState(data, NAME);
        }
        function rememberOptions(data) {
            var state = getState$$1(data);
            state.frameTime = data.frameTime;
            state.animate = data.animate;
            state.reverse = data.reverse;
        }
        function restoreOptions(data) {
            var state = getState$$1(data);
            data.frameTime = state.frameTime;
            data.animate = state.animate;
            data.reverse = state.reverse;
        }
        function start(e, data) {
            if (is(data, 'loading') || is(data, 'dragging') || !data.stage.is(':visible')) {
                return;
            }
            rememberOptions(data);
            updateInput(e, data);
            flag(data, 'dragging', true);
            data.animate = true;
            applyAnimation(data);
        }
        function stop(e, data) {
            flag(data, 'dragging', false);
            resetInput(data);
            stopAnimation(data);
            restoreOptions(data);
            applyAnimation(data);
        }
        function update(e, data) {
            if (!is(data, 'dragging')) {
                return;
            }
            updateInput(e, data);
            var input = getInputState(data);
            var half, delta;
            var target = data.target, offset = target.offset();
            if (data.orientation === 'horizontal') {
                half = target.innerWidth() / 2;
                delta = (input.currentX - offset.left - half) / half;
            }
            else {
                half = (data.height / 2);
                delta = (input.currentY - offset.top - half) / half;
            }
            data.reverse = delta < 0;
            delta = delta < 0 ? -delta : delta;
            data.frameTime = 80 * (1 - delta) + 20;
            if (((data.orientation === 'horizontal') && (input.dX < input.dY)) ||
                ((data.orientation === 'vertical') && (input.dX < input.dY))) {
                e.preventDefault();
            }
        }
        function onFrame(e, data) {
            data.animate = true;
            applyAnimation(data);
        }
        registerPlugin(NAME, {
            name: NAME,
            mousedown: start,
            mousemove: update,
            mouseup: stop,
            mouseleave: stop,
            touchstart: start,
            touchmove: update,
            touchend: stop,
            touchcancel: stop,
            onFrame: onFrame
        });
    })();

    (function () {
        var NAME = 'swipe';
        function getState$$1(data) {
            return getPluginState(data, NAME);
        }
        function getOption(data, name, fallback) {
            return data[name] || fallback;
        }
        function init(e, data) {
            var state = getState$$1(data);
            state.fling = getOption(data, 'swipeFling', 10);
            state.snap = getOption(data, 'swipeSnap', 0.50);
        }
        function start(e, data) {
            if (!data.loading && !is(data, 'dragging')) {
                updateInput(e, data);
                flag(data, 'dragging', true);
            }
        }
        function update(e, data) {
            if (!is(data, 'dragging')) {
                return;
            }
            updateInput(e, data);
            var frame = data.frame;
            var lane = data.lane;
            updateFrame(data, frame, lane);
        }
        function end(e, data) {
            if (!is(data, 'dragging')) {
                return;
            }
            flag(data, 'dragging', false);
            var state = getState$$1(data);
            var input = getInputState(data);
            var frame = data.frame;
            var lane = data.lane;
            var snap = state.snap;
            var fling = state.fling;
            var dS, dF;
            if (data.orientation === 'horizontal') {
                dS = input.ndX;
                dF = input.ddX;
            }
            else {
                dS = input.ndY;
                dF = input.ddY;
            }
            if (dS >= snap || dF >= fling) {
                frame = data.frame - 1;
            }
            else if (dS <= -snap || dF <= -fling) {
                frame = data.frame + 1;
            }
            resetInput(data);
            updateFrame(data, frame, lane);
            stopAnimation(data);
        }
        registerPlugin(NAME, {
            name: NAME,
            onLoad: init,
            mousedown: start,
            mousemove: update,
            mouseup: end,
            mouseleave: end,
            touchstart: start,
            touchmove: update,
            touchend: end,
            touchcancel: end
        });
    })();

    (function () {
        var NAME = '360';
        function onLoad(e, data) {
            data.stage.find('.spritespin-frames').detach();
            if (data.renderer === 'image') {
                $(data.images).addClass('spritespin-frames').appendTo(data.stage);
            }
        }
        function onDraw(e, data) {
            var specs = findSpecs(data.metrics, data.frames, data.frame, data.lane);
            var sheet = specs.sheet;
            var sprite = specs.sprite;
            if (!sheet || !sprite) {
                return;
            }
            var src = data.source[sheet.id];
            var image = data.images[sheet.id];
            if (data.renderer === 'canvas') {
                data.canvas.show();
                var w = data.canvas[0].width / data.canvasRatio;
                var h = data.canvas[0].height / data.canvasRatio;
                data.context.clearRect(0, 0, w, h);
                data.context.drawImage(image, sprite.sampledX, sprite.sampledY, sprite.sampledWidth, sprite.sampledHeight, 0, 0, w, h);
                return;
            }
            var scaleX = sprite.sampledWidth / data.stage.innerWidth();
            var scaleY = sprite.sampledHeight / data.stage.innerHeight();
            var top = Math.floor(-sprite.sampledX * scaleY);
            var left = Math.floor(-sprite.sampledY * scaleX);
            var width = Math.floor(sheet.sampledWidth * scaleX);
            var height = Math.floor(sheet.sampledHeight * scaleY);
            if (data.renderer === 'background') {
                data.stage.css({
                    'background-image': "url('" + src + "')",
                    'background-position': left + "px " + top + "px",
                    'background-repeat': 'no-repeat',
                    // set custom background size to enable responsive rendering
                    '-webkit-background-size': width + "px " + height + "px",
                    '-moz-background-size': width + "px " + height + "px",
                    '-o-background-size': width + "px " + height + "px",
                    'background-size': width + "px " + height + "px" /* Chrome, Firefox 4+, IE 9+, Opera, Safari 5+ */
                });
                return;
            }
            $(data.images).hide();
            $(image).show().css({
                position: 'absolute',
                top: top,
                left: left,
                'max-width': 'initial',
                width: width,
                height: height
            });
        }
        registerPlugin(NAME, {
            name: NAME,
            onLoad: onLoad,
            onDraw: onDraw
        });
    })();

    (function () {
        var NAME = 'blur';
        function getState$$1(data) {
            return getPluginState(data, NAME);
        }
        function getOption(data, name, fallback) {
            return data[name] || fallback;
        }
        function init(e, data) {
            var state = getState$$1(data);
            state.canvas = state.canvas || $$1("<canvas class='blur-layer'></canvas>");
            state.context = state.context || state.canvas[0].getContext('2d');
            state.steps = state.steps || [];
            state.fadeTime = Math.max(getOption(data, 'blurFadeTime', 200), 1);
            state.frameTime = Math.max(getOption(data, 'blurFrameTime', data.frameTime), 16);
            state.trackTime = null;
            state.cssBlur = !!getOption(data, 'blurCss', data.frameTime);
            var inner = getInnerSize(data);
            var outer = data.responsive ? getComputedSize(data) : getOuterSize(data);
            var css = getInnerLayout(data.sizeMode, inner, outer);
            state.canvas[0].width = data.width * data.canvasRatio;
            state.canvas[0].height = data.height * data.canvasRatio;
            state.canvas.css(css).show();
            state.context.scale(data.canvasRatio, data.canvasRatio);
            data.target.append(state.canvas);
        }
        function onFrame(e, data) {
            var state = getState$$1(data);
            trackFrame(data);
            if (state.timeout == null) {
                loop(data);
            }
        }
        function trackFrame(data) {
            var state = getState$$1(data);
            var ani = getPlaybackState(data);
            // distance between frames
            var d = Math.abs(data.frame - ani.lastFrame);
            // shortest distance
            d = d >= data.frames / 2 ? data.frames - d : d;
            state.steps.unshift({
                frame: data.frame,
                lane: data.lane,
                live: 1,
                step: state.frameTime / state.fadeTime,
                d: d,
                alpha: 0
            });
        }
        var toRemove = [];
        function removeOldFrames(frames) {
            toRemove.length = 0;
            for (var i = 0; i < frames.length; i += 1) {
                if (frames[i].alpha <= 0) {
                    toRemove.push(i);
                }
            }
            for (var _i = 0, toRemove_1 = toRemove; _i < toRemove_1.length; _i++) {
                var item = toRemove_1[_i];
                frames.splice(item, 1);
            }
        }
        function loop(data) {
            var state = getState$$1(data);
            state.timeout = window.setTimeout(function () { tick(data); }, state.frameTime);
        }
        function killLoop(data) {
            var state = getState$$1(data);
            window.clearTimeout(state.timeout);
            state.timeout = null;
        }
        function applyCssBlur(canvas, d) {
            var amount = Math.min(Math.max((d / 2) - 4, 0), 1.5);
            var blur = "blur(" + amount + "px)";
            canvas.css({
                '-webkit-filter': blur,
                filter: blur
            });
        }
        function drawFrame(data, state, step) {
            if (step.alpha <= 0) {
                return;
            }
            var specs = findSpecs(data.metrics, data.frames, data.frame, data.lane);
            var sheet = specs.sheet;
            var sprite = specs.sprite;
            if (!sheet || !sprite) {
                return;
            }
            var src = data.source[sheet.id];
            var image = data.images[sheet.id];
            if (image.complete === false) {
                return;
            }
            state.canvas.show();
            var w = state.canvas[0].width / data.canvasRatio;
            var h = state.canvas[0].height / data.canvasRatio;
            state.context.clearRect(0, 0, w, h);
            state.context.drawImage(image, sprite.sampledX, sprite.sampledY, sprite.sampledWidth, sprite.sampledHeight, 0, 0, w, h);
        }
        function tick(data) {
            var state = getState$$1(data);
            killLoop(data);
            if (!state.context) {
                return;
            }
            var d = 0;
            state.context.clearRect(0, 0, data.width, data.height);
            for (var _i = 0, _a = state.steps; _i < _a.length; _i++) {
                var step = _a[_i];
                step.live = Math.max(step.live - step.step, 0);
                step.alpha = Math.max(step.live - 0.25, 0);
                drawFrame(data, state, step);
                d += step.alpha + step.d;
            }
            if (state.cssBlur) {
                applyCssBlur(state.canvas, d);
            }
            removeOldFrames(state.steps);
            if (state.steps.length) {
                loop(data);
            }
        }
        registerPlugin(NAME, {
            name: NAME,
            onLoad: init,
            onFrameChanged: onFrame
        });
    })();

    (function () {
        var max = Math.max;
        var min = Math.min;
        var NAME = 'ease';
        function getState$$1(data) {
            return getPluginState(data, NAME);
        }
        function getOption(data, name, fallback) {
            return data[name] || fallback;
        }
        function init(e, data) {
            var state = getState$$1(data);
            state.maxSamples = max(getOption(data, 'easeMaxSamples', 5), 0);
            state.damping = max(min(getOption(data, 'easeDamping', 0.9), 0.999), 0);
            state.abortTime = max(getOption(data, 'easeAbortTime', 250), 16);
            state.updateTime = max(getOption(data, 'easeUpdateTime', data.frameTime), 16);
            state.samples = [];
            state.steps = [];
        }
        function update(e, data) {
            if (is(data, 'dragging')) {
                killLoop(data);
                sampleInput(data);
            }
        }
        function end(e, data) {
            var state = getState$$1(data);
            var samples = state.samples;
            var last;
            var lanes = 0;
            var frames = 0;
            var time = 0;
            for (var _i = 0, samples_1 = samples; _i < samples_1.length; _i++) {
                var sample = samples_1[_i];
                if (!last) {
                    last = sample;
                    continue;
                }
                var dt = sample.time - last.time;
                if (dt > state.abortTime) {
                    lanes = frames = time = 0;
                    return killLoop(data);
                }
                frames += sample.frame - last.frame;
                lanes += sample.lane - last.lane;
                time += dt;
                last = sample;
            }
            samples.length = 0;
            if (!time) {
                return;
            }
            state.lane = data.lane;
            state.lanes = 0;
            state.laneStep = lanes / time * state.updateTime;
            state.frame = data.frame;
            state.frames = 0;
            state.frameStep = frames / time * state.updateTime;
            loop(data);
        }
        function sampleInput(data) {
            var state = getState$$1(data);
            // add a new sample
            state.samples.push({
                time: new Date().getTime(),
                frame: data.frame,
                lane: data.lane
            });
            // drop old samples
            while (state.samples.length > state.maxSamples) {
                state.samples.shift();
            }
        }
        function killLoop(data) {
            var state = getState$$1(data);
            if (state.handler != null) {
                window.clearTimeout(state.handler);
                state.handler = null;
            }
        }
        function loop(data) {
            var state = getState$$1(data);
            state.handler = window.setTimeout(function () { tick(data); }, state.updateTime);
        }
        function tick(data) {
            var state = getState$$1(data);
            state.lanes += state.laneStep;
            state.frames += state.frameStep;
            state.laneStep *= state.damping;
            state.frameStep *= state.damping;
            var frame = Math.floor(state.frame + state.frames);
            var lane = Math.floor(state.lane + state.lanes);
            updateFrame(data, frame, lane);
            if (is(data, 'dragging')) {
                killLoop(data);
            }
            else if (Math.abs(state.frameStep) > 0.005 || Math.abs(state.laneStep) > 0.005) {
                loop(data);
            }
            else {
                killLoop(data);
            }
        }
        registerPlugin(NAME, {
            name: NAME,
            onLoad: init,
            mousemove: update,
            mouseup: end,
            mouseleave: end,
            touchmove: update,
            touchend: end,
            touchcancel: end
        });
    })();

    (function () {
        var NAME = 'gallery';
        function getState$$1(data) {
            return getPluginState(data, NAME);
        }
        function getOption(data, name, fallback) {
            return data[name] || fallback;
        }
        function load(e, data) {
            var state = getState$$1(data);
            state.images = [];
            state.offsets = [];
            state.frame = data.frame;
            state.speed = getOption(data, 'gallerySpeed', 500);
            state.opacity = getOption(data, 'galleryOpacity', 0.25);
            state.stage = getOption(data, 'galleryStage', $$1('<div></div>'));
            state.stage.empty().addClass('gallery-stage').prependTo(data.stage);
            var size = 0;
            for (var _i = 0, _a = data.images; _i < _a.length; _i++) {
                var image = _a[_i];
                var naturalSize$$1 = naturalSize(image);
                var scale = data.height / naturalSize$$1.height;
                var img = $$1(image);
                state.stage.append(img);
                state.images.push(img);
                state.offsets.push(-size + (data.width - image.width * scale) / 2);
                size += data.width;
                img.css({
                    'max-width': 'initial',
                    opacity: state.opacity,
                    width: data.width,
                    height: data.height
                });
            }
            var innerSize = getInnerSize(data);
            var outerSize = data.responsive ? getComputedSize(data) : getOuterSize(data);
            var layout = getInnerLayout(data.sizeMode, innerSize, outerSize);
            state.stage.css(layout).css({ width: size, left: state.offsets[state.frame] });
            state.images[state.frame].animate({ opacity: 1 }, { duration: state.speed });
        }
        function draw(e, data) {
            var state = getState$$1(data);
            var input = getInputState(data);
            var isDragging = is(data, 'dragging');
            if (state.frame !== data.frame && !isDragging) {
                state.stage.stop(true, false).animate({ left: state.offsets[data.frame] }, { duration: state.speed });
                state.images[state.frame].animate({ opacity: state.opacity }, { duration: state.speed });
                state.frame = data.frame;
                state.images[state.frame].animate({ opacity: 1 }, { duration: state.speed });
                state.stage.animate({ left: state.offsets[state.frame] });
            }
            else if (isDragging || state.dX !== input.dX) {
                state.dX = input.dX;
                state.ddX = input.ddX;
                state.stage.stop(true, true).css({ left: state.offsets[state.frame] + state.dX });
            }
        }
        registerPlugin(NAME, {
            name: NAME,
            onLoad: load,
            onDraw: draw
        });
    })();

    (function () {
        var NAME = 'panorama';
        function getState$$1(data) {
            return getPluginState(data, NAME);
        }
        function onLoad(e, data) {
            var state = getState$$1(data);
            var sprite = data.metrics[0];
            if (!sprite) {
                return;
            }
            if (data.orientation === 'horizontal') {
                state.scale = data.target.innerHeight() / sprite.sampledHeight;
                data.frames = sprite.sampledWidth;
            }
            else {
                state.scale = data.target.innerWidth() / sprite.sampledWidth;
                data.frames = sprite.sampledHeight;
            }
            var width = Math.floor(sprite.sampledWidth * state.scale);
            var height = Math.floor(sprite.sampledHeight * state.scale);
            data.stage.css({
                'background-image': "url(" + data.source[sprite.id] + ")",
                'background-repeat': 'repeat-both',
                // set custom background size to enable responsive rendering
                '-webkit-background-size': width + "px " + height + "px",
                '-moz-background-size': width + "px " + height + "px",
                '-o-background-size': width + "px " + height + "px",
                'background-size': width + "px " + height + "px" /* Chrome, Firefox 4+, IE 9+, Opera, Safari 5+ */
            });
        }
        function onDraw(e, data) {
            var state = getState$$1(data);
            var px = data.orientation === 'horizontal' ? 1 : 0;
            var py = px ? 0 : 1;
            var offset = data.frame % data.frames;
            var left = Math.round(px * offset * state.scale);
            var top = Math.round(py * offset * state.scale);
            data.stage.css({ 'background-position': left + "px " + top + "px" });
        }
        registerPlugin(NAME, {
            name: NAME,
            onLoad: onLoad,
            onDraw: onDraw
        });
    })();

    (function () {
        var NAME = 'zoom';
        function getState$$1(data) {
            return getPluginState(data, NAME);
        }
        function getOption(data, name, fallback) {
            return data[name] || fallback;
        }
        function onInit(e, data) {
            var state = getState$$1(data);
            state.source = getOption(data, 'zoomSource', data.source);
            state.doubleClickTime = getOption(data, 'zoomDoubleClickTime', 500);
            state.stage = state.stage || $$1("<div class='zoom-stage'></div>");
            state.stage.css({
                width: '100%',
                height: '100%',
                top: 0,
                left: 0,
                bottom: 0,
                right: 0,
                position: 'absolute'
            })
                .appendTo(data.target)
                .hide();
        }
        function onDestroy(e, data) {
            var state = getState$$1(data);
            if (state.stage) {
                state.stage.remove();
                delete state.stage;
            }
        }
        function updateInput$$1(e, data) {
            var state = getState$$1(data);
            if (!state.stage.is(':visible')) {
                return;
            }
            e.preventDefault();
            // hack into drag/move module and disable dragging
            // prevents frame change during zoom mode
            flag(data, 'dragging', false);
            // grab touch/cursor position
            var cursor = getCursorPosition(e);
            // normalize cursor position into [0:1] range
            var x = cursor.x / data.width;
            var y = cursor.y / data.height;
            if (state.oldX == null) {
                state.oldX = x;
                state.oldY = y;
            }
            if (state.currentX == null) {
                state.currentX = x;
                state.currentY = y;
            }
            // calculate move delta since last frame and remember current position
            var dx = x - state.oldX;
            var dy = y - state.oldY;
            state.oldX = x;
            state.oldY = y;
            // invert drag direction for touch events to enable 'natural' scrolling
            if (e.type.match(/touch/)) {
                dx = -dx;
                dy = -dy;
            }
            // accumulate display coordinates
            state.currentX = clamp(state.currentX + dx, 0, 1);
            state.currentY = clamp(state.currentY + dy, 0, 1);
            updateFrame(data, data.frame, data.lane);
        }
        function onClick(e, data) {
            e.preventDefault();
            var state = getState$$1(data);
            // simulate double click
            var clickTime = new Date().getTime();
            if (!state.clickTime) {
                // on first click
                state.clickTime = clickTime;
                return;
            }
            // on second click
            var timeDelta = clickTime - state.clickTime;
            if (timeDelta > state.doubleClickTime) {
                // took too long, back to first click
                state.clickTime = clickTime;
                return;
            }
            // on valid double click
            state.clickTime = undefined;
            if (toggleZoom(data)) {
                updateInput$$1(e, data);
            }
        }
        function onMove(e, data) {
            var state = getState$$1(data);
            if (state.stage.is(':visible')) {
                updateInput$$1(e, data);
            }
        }
        function onDraw(e, data) {
            var state = getState$$1(data);
            // calculate the frame index
            var index = data.lane * data.frames + data.frame;
            // get the zoom image. Use original frames as fallback. This won't work for spritesheets
            var source = state.source[index];
            var spec = findSpecs(data.metrics, data.frames, data.frame, data.lane);
            // get display position
            var x = state.currentX;
            var y = state.currentY;
            // fallback to centered position
            if (x == null) {
                x = state.currentX = 0.5;
                y = state.currentY = 0.5;
            }
            if (source) {
                // scale up from [0:1] to [0:100] range
                x = Math.floor(x * 100);
                y = Math.floor(y * 100);
                // update background image and position
                state.stage.css({
                    'background-repeat': 'no-repeat',
                    'background-image': "url('" + source + "')",
                    'background-position': x + "% " + y + "%"
                });
            }
            else if (spec.sheet && spec.sprite) {
                var sprite = spec.sprite;
                var sheet = spec.sheet;
                var src = data.source[sheet.id];
                var left = -Math.floor(sprite.sampledX + x * (sprite.sampledWidth - data.width));
                var top_1 = -Math.floor(sprite.sampledY + y * (sprite.sampledHeight - data.height));
                var width = sheet.sampledWidth;
                var height = sheet.sampledHeight;
                state.stage.css({
                    'background-image': "url('" + src + "')",
                    'background-position': left + "px " + top_1 + "px",
                    'background-repeat': 'no-repeat',
                    // set custom background size to enable responsive rendering
                    '-webkit-background-size': width + "px " + height + "px",
                    '-moz-background-size': width + "px " + height + "px",
                    '-o-background-size': width + "px " + height + "px",
                    'background-size': width + "px " + height + "px" /* Chrome, Firefox 4+, IE 9+, Opera, Safari 5+ */
                });
            }
        }
        function toggleZoom(data) {
            var state = getState$$1(data);
            if (!state.stage) {
                throw new Error('zoom module is not initialized or is not available.');
            }
            if (state.stage.is(':visible')) {
                state.stage.fadeOut();
                data.stage.fadeIn();
            }
            else {
                state.stage.fadeIn();
                data.stage.fadeOut();
                return true;
            }
            return false;
        }
        registerPlugin(NAME, {
            name: NAME,
            mousedown: onClick,
            touchstart: onClick,
            mousemove: onMove,
            touchmove: onMove,
            onInit: onInit,
            onDestroy: onDestroy,
            onDraw: onDraw
        });
        extendApi({
            toggleZoom: function () { toggleZoom(this.data); } // tslint:disable-line
        });
    })();

    var Utils = _Utils;

    exports.Utils = Utils;
    exports.sourceArray = sourceArray;
    exports.Api = Api;
    exports.extendApi = extendApi;
    exports.instances = instances;
    exports.applyEvents = applyEvents;
    exports.boot = boot;
    exports.create = create;
    exports.createOrUpdate = createOrUpdate;
    exports.destroy = destroy;
    exports.namespace = namespace;
    exports.eventNames = eventNames;
    exports.callbackNames = callbackNames;
    exports.eventsToPrevent = eventsToPrevent;
    exports.defaults = defaults;
    exports.getInputState = getInputState;
    exports.updateInput = updateInput;
    exports.resetInput = resetInput;
    exports.applyLayout = applyLayout;
    exports.getPlaybackState = getPlaybackState;
    exports.updateFrame = updateFrame;
    exports.stopAnimation = stopAnimation;
    exports.applyAnimation = applyAnimation;
    exports.startAnimation = startAnimation;
    exports.registerPlugin = registerPlugin;
    exports.registerModule = registerModule;
    exports.getPlugin = getPlugin;
    exports.applyPlugins = applyPlugins;
    exports.getState = getState;
    exports.getPluginState = getPluginState;
    exports.is = is;
    exports.flag = flag;

    Object.defineProperty(exports, '__esModule', { value: true });

})));
//# sourceMappingURL=spritespin.js.map
/*
 currency.js - v1.2.2
 http://scurker.github.io/currency.js

 Copyright (c) 2019 Jason Wilson
 Released under MIT license
*/
(function(d,c){"object"===typeof exports&&"undefined"!==typeof module?module.exports=c():"function"===typeof define&&define.amd?define(c):(d=d||self,d.currency=c())})(this,function(){function d(b,a){if(!(this instanceof d))return new d(b,a);a=Object.assign({},m,a);var f=Math.pow(10,a.precision);this.intValue=b=c(b,a);this.value=b/f;a.increment=a.increment||1/f;a.groups=a.useVedic?n:p;this.s=a;this.p=f}function c(b,a){var f=2<arguments.length&&void 0!==arguments[2]?arguments[2]:!0,c=a.decimal,g=a.errorOnInvalid;
var e=Math.pow(10,a.precision);var h="number"===typeof b;if(h||b instanceof d)e*=h?b:b.value;else if("string"===typeof b)g=new RegExp("[^-\\d"+c+"]","g"),c=new RegExp("\\"+c,"g"),e=(e*=b.replace(/\((.*)\)/,"-$1").replace(g,"").replace(c,"."))||0;else{if(g)throw Error("Invalid Input");e=0}e=e.toFixed(4);return f?Math.round(e):e}var m={symbol:"$",separator:",",decimal:".",formatWithSymbol:!1,errorOnInvalid:!1,precision:2,pattern:"!#",negativePattern:"-!#"},p=/(\d)(?=(\d{3})+\b)/g,n=/(\d)(?=(\d\d)+\d\b)/g;
d.prototype={add:function(b){var a=this.s,f=this.p;return d((this.intValue+c(b,a))/f,a)},subtract:function(b){var a=this.s,f=this.p;return d((this.intValue-c(b,a))/f,a)},multiply:function(b){var a=this.s;return d(this.intValue*b/Math.pow(10,a.precision),a)},divide:function(b){var a=this.s;return d(this.intValue/c(b,a,!1),a)},distribute:function(b){for(var a=this.intValue,f=this.p,c=this.s,g=[],e=Math[0<=a?"floor":"ceil"](a/b),h=Math.abs(a-e*b);0!==b;b--){var k=d(e/f,c);0<h--&&(k=0<=a?k.add(1/f):k.subtract(1/
f));g.push(k)}return g},dollars:function(){return~~this.value},cents:function(){return~~(this.intValue%this.p)},format:function(b){var a=this.s,c=a.pattern,d=a.negativePattern,g=a.formatWithSymbol,e=a.symbol,h=a.separator,k=a.decimal;a=a.groups;var l=(this+"").replace(/^-/,"").split("."),m=l[0];l=l[1];"undefined"===typeof b&&(b=g);return(0<=this.value?c:d).replace("!",b?e:"").replace("#","".concat(m.replace(a,"$1"+h)).concat(l?k+l:""))},toString:function(){var b=this.s,a=b.increment;return(Math.round(this.intValue/
this.p/a)*a).toFixed(b.precision)},toJSON:function(){return this.value}};return d});

