/* Minification failed. Returning unminified contents.
(2943,42-50): run-time error JS1004: Expected ';': function
(2944,32-37): run-time error JS1004: Expected ';': fetch
(2956,51-59): run-time error JS1193: Expected ',' or ')': response
(2956,66-67): run-time error JS1004: Expected ';': )
(2965,35-36): run-time error JS1014: Invalid character: `
(2965,65-66): run-time error JS1004: Expected ';': {
(2965,103-104): run-time error JS1014: Invalid character: `
(2965,104-105): run-time error JS1195: Expected expression: ?
(2965,154-155): run-time error JS1014: Invalid character: `
(2965,156-157): run-time error JS1195: Expected expression: :
(2965,161-162): run-time error JS1014: Invalid character: `
 */
/* global jQuery */

var perkspot = perkspot || {};

// Polyfill for console.log.
(function (global) {
    'use strict';
    global.console = global.console || {};
    var con = global.console;
    var prop, method;
    var empty = {};
    var dummy = function () { };
    var properties = 'memory'.split(',');
    var methods = ('assert,clear,count,debug,dir,dirxml,error,exception,group,' +
       'groupCollapsed,groupEnd,info,log,markTimeline,profile,profiles,profileEnd,' +
       'show,table,time,timeEnd,timeline,timelineEnd,timeStamp,trace,warn').split(',');
    while (prop = properties.pop()) if (!con[prop]) con[prop] = empty;
    while (method = methods.pop()) if (!con[method]) con[method] = dummy;
})(typeof window === 'undefined' ? this : window);

// The following Polyfill is required for IE 11.
if (Number.parseFloat === undefined) {
    Number.parseFloat = parseFloat;
}

perkspot.utils = (function ($) {
    var self = {};

    self.pageNotificationTO = null;

    /* Prototype Additions */
    if (!String.prototype.trim) {
        (function () {
            // Make sure we trim BOM and NBSP
            var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;
            String.prototype.trim = function () {
                return this.replace(rtrim, '');
            };
        })();
    }

    // #region String Utils
    // Trim string to a specified length and apply a suffix.
    self.trim = function (value, maxLength, suffix) {
        var result = value;
        suffix = (!self.isNullEmptyOrWhitespace(suffix) ? suffix : '...');

        if (!self.isNullEmptyOrWhitespace(result) && result.length > maxLength) {
            result = value.substring(0, maxLength).trim() + suffix;
        }

        return result;
    };
    // Check if a string is undefined, null, empty or just consists of whitespace.
    self.isNullEmptyOrWhitespace = function (value) {
        var result = false;

        if (typeof (value) === 'undefined' || value === null || value.toString().trim() === '') {
            result = true;
        }

        return result;
    };
    self.hasValue = function (value) {
        return !self.isNullEmptyOrWhitespace(value);
    };
    self.toTitleCaseSimple = function (value) {
        var result = value;

        if (!self.isNullEmptyOrWhitespace(value)) {
            result = result.replace(/\w\S*/g, function (txt) { return txt.charAt(0).toUpperCase() + txt.substr(1); });
        }

        return result;
    }
    self.toTitleCase = function (value) {
        var result = value;

        if (!self.isNullEmptyOrWhitespace(value)) {
            result = result.replace(/\w\S*/g, function (txt) { return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); });
        }

        return result;
    }

    self.truncateText = function (element, height) {
        element.dotdotdot({ watch: 'window', height: height });
    }

    // #endregion

    /* Type Converters */
    self.toBoolean = function (value) {
        var result = false;

        if (typeof value !== 'undefined' && value !== null && (value === true || value === 'true' || value === 1 || value === '1')) {
            result = true;
        }

        return result;
    };

    // #region URL Hash Helpers
    self.setUrlHash = function (url) {
        window.location.hash = url;
    };
    self.setUrlHashFromJson = function (object) {
        window.location.hash = JSON.stringify(object);
    };
    self.getUrlHash = function () {
        return window.location.hash.replace(/%22/g, '"').replace('#', '');
    };
    self.getUrlHashAsJson = function () {
        try {
            return $.parseJSON(window.location.hash.replace(/%22/g, '"').replace('#', ''));
        }
        catch (ex) {
            self.log('Handled exception while parsing JSON in getUrlHashAsJson().')
            return null;
        }
    };
    /*
     * Get the value of a hash fragment when the hash is of JSON format.
     */
    self.getUrlHashFragment = function (fragmentName) {
        var result = null;
        var hash = decodeURI(self.getUrlHash());

        if (hash.length > 0) {
            var jsonHash = jQuery.parseJSON(hash);
            result = jsonHash[fragmentName];
            // DEBUG:
            //console.log(fragmentName + ' = ' + hash[fragmentName]);
        }

        return result;
    };
    /*
     * Get the value of a hash fragment when the hash is of a key/value pair format.
     * (e.g. querystring style).
     */
    self.getUrlHashFragmentKeyValue = function (fragmentName) {
        var result = null;

        if (self.getUrlHash().length > 0) {
            var arrPairs = self.getUrlHash().split('&');

            var arrResult = $.grep(arrPairs, function (obj, i) {
                return (obj.indexOf(fragmentName) > -1 ? true : false);
            });

            if (arrResult.length > 0) {
                result = arrResult[0].split('=')[1];
            }
        }

        return result;
    };

    self.setUrlHashFragment = function (key, value) {
        var hash = {};

        if (self.getUrlHash().length > 0) {
            try {
                hash = $.parseJSON(self.getUrlHash());
            }
            catch (ex) {
                self.log('Handled exception while parsing JSON in setUrlHashFragment().')
            }
        }

        hash[key] = value;

        self.setUrlHash(JSON.stringify(hash));
    };

    self.logUrlHash = function (e) {
        self.log(self.getUrlHash(), 'debug');
    };

    // #endregion

    // #region QueryString Helpers

    self.getQsByKey = function (key) {
        var qs = self.parseQueryString(),
            result = null;

        if (!self.isNullEmptyOrWhitespace(qs[key])) { result = qs[key]; }
        else if (!self.isNullEmptyOrWhitespace(qs[key.toLowerCase()])) { result = qs[key.toLowerCase()]; }

        if (result) { result = decodeURIComponent(result) }

        return result;
    };

    self.parseQueryString = function () {
        var queryString = window.location.search.replace('?', '');
        var params = {}, queries, temp, i, l;

        // Split into key/value pairs
        queries = queryString.split("&");

        // Convert the array of strings into an object
        for (i = 0, l = queries.length; i < l; i++) {
            temp = queries[i].split('=');
            params[temp[0]] = temp[1];
        }

        return params;
    };

    // #endregion

    /* Simple Notifications */
    // Configuration for "noty".
    $.noty.defaults = {
        layout: 'center',
        theme: 'relax',//'defaultTheme', // or 'relax'
        type: 'alert',
        text: '', // can be html or string
        dismissQueue: true, // If you want to use queue feature set this true
        template: '<div class="noty_message"><span class="noty_text"></span><div class="noty_close"></div></div>',
        animation: {
            open: { height: 'toggle' }, // or Animate.css class names like: 'animated bounceInLeft'
            close: { height: 'toggle' }, // or Animate.css class names like: 'animated bounceOutLeft'
            easing: 'swing',
            speed: 500 // opening & closing animation speed
        },
        timeout: 5000, // delay for closing event. Set false for sticky notifications
        force: false, // adds notification to the beginning of queue when set to true
        modal: false,
        maxVisible: 5, // you can set max visible notification for dismissQueue true option,
        killer: false, // for close all notifications before show
        closeWith: ['click'], // ['click', 'button', 'hover', 'backdrop'] // backdrop click will close all notifications
        callback: {
            onShow: function () { },
            afterShow: function () { },
            onClose: function () { },
            afterClose: function () { },
            onCloseClick: function () { },
        },
        buttons: false // an array of buttons
    };
    self.notify = function (params) {
        var type = 'information';

        switch (params.type) {
            case 'bs-success':
                type = 'bs-success';
                break;
            case 'i':
            case 'information':
                type = 'information';
                break;
            case 'w':
            case 'warning':
                type = 'warning';
                break;
            case 'e':
            case 'error':
                type = 'error';
                break;
        }

        var n = noty(
            {
                text: params.message,
                type: type,
                layout: params.layout || 'center',
                timeout: params.timeout || false,
                animation: { open: params.open || 'animated flipInX', close: 'animated flipOutX' }
            });
    }

    /* Simple Logging */
    self.log = function (message, logLevel) {
        var logToConsole = false;

        if (typeof (window.environmentName) !== 'undefined' &&
            typeof (console) !== 'undefined' &&
            (window.environmentName === 'qa' || window.environmentName === 'dev' || window.environmentName === 'local')) {
            logToConsole = true;
        }

        if (typeof(logLevel) !== 'undefined' && logLevel != null) {
            switch (logLevel) {
                case 'alert':
                    alert(message);
                    break;
                case 'error':
                    throw new Error(message);
                default:
                    logToConsole ? console.log(message) : null;
                    break;
            }
        } else {
            logToConsole ? console.log(message) : null;
        }
    }

    /* Image URL Helpers */
    self.getMerchantLogoUrl = function (imageName) {
        var result = null;

        if (imageName !== null) {
            if (imageName.indexOf(window.v2Suffix) > -1) {
                result = window.cdnPath + window.cdnPathMerchantImages + imageName.replace(window.v2Suffix, '');
            } else {
                result = window.legacyPath + window.legacyPathMerchantImages + imageName;
            }
        }

        return result;
    }

    /* Attribute Helpers */
    self.getAttributeByName = function (list, name) {
        var result = null,
            attribute = null;

        attribute = $.grep(list, function (e) { return e.name === name; })[0];

        if (typeof attribute !== 'undefined' && attribute !== null) {
            if (attribute.value !== null) {
                if (attribute.value.toString().toLowerCase() === 'true' ||
                    attribute.value == '1') {
                    // Parse to boolean true.
                    result = true;
                } else if (attribute.value.toString().toLowerCase() === 'false' ||
                           attribute.value == '0') {
                    // Parse to boolean false.
                    result = false;
                } else {
                    result = attribute.value;
                }   // TODO: Parse for numeric values vs strings.
            }
        }

        return result;
    }

    // This function uses regex to parse the url query parameters and pull out the one we're interested in.  Borrowed from:
    // https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript
    // The accepted answer here has two solutions, one supported by modern browsers (way simpler), and an older one that is supported in all browsers.
    // This is the latter version because we still need to support IE11.
    self.getUrlParameter = function getParameterByName(name, url) {
        if (!url) url = window.location.href;
        name = name.replace(/[\[\]]/g, '\\$&');
        var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'),
            results = regex.exec(url);
        if (!results) return null;
        if (!results[2]) return '';
        return decodeURIComponent(results[2].replace(/\+/g, ' '));
    }

    /* Web API Helpers */
    self.asyncGet = function (url, params) {
        return $.getJSON(
                url,
                params
            );
    };

    self.asyncCreate = function (url, data) {
        return $.ajax(
            url,
            {
                type: 'POST',
                contentType: 'application/json',
                data: data,
                headers: {
                    'RequestVerificationToken': perkspot.global.getAntiForgeryToken()
                }
            });
    };

    self.asyncUpdate = function (url, data) {
        return $.ajax(
            url,
            {
                type: 'PUT',
                contentType: 'application/json',
                data: data,
                headers: {
                    'RequestVerificationToken': perkspot.global.getAntiForgeryToken()
                }
            });
    };

    self.caseInsensitiveSort = function (a, b) {
        a = a.toLowerCase();
        b = b.toLowerCase();

        if (a < b) { return -1; }
        if (a > b) { return 1; }

        return 0;
    };

    /* Sets the attributes of an offer's <a> tag */
    self.setOfferAttr = function (openNewWindow, relativeUrl, epId, section, recommendationGroupId, offerId) {
        if (typeof epId === 'undefined') { epId = null; }
        if (typeof section === 'undefined') { section = null; }
        if (typeof recommendationGroupId === 'undefined') { recommendationGroupId = null; }
        if (typeof offerId === 'undefined') { recommendationGroupId = null; }


        var epidParam = 'epid=' + epId;
        var sectionParam = 'section=' + section;
        var recommendationGroupIdParam = 'recommendationGroupId=' + recommendationGroupId;
        var offerIdParam = 'recommendedOfferId=' + offerId;

        var hasParam = false;

        if (epId || section || recommendationGroupId || offerId) {
            if (relativeUrl.includes('?')) {
                hasParam = true;
            } else {
                relativeUrl = relativeUrl + '?';
            }

            if (epId && !hasParam) {
                relativeUrl = relativeUrl + epidParam;
                hasParam = true;
            } else if (epId && hasParam) {
                relativeUrl = relativeUrl + '&' + epidParam;
            }

            if (section && !hasParam) {
                relativeUrl = relativeUrl + sectionParam;
                hasParam = true;
            } else if (section && hasParam) {
                relativeUrl = relativeUrl + '&' + sectionParam;
            }

            if (recommendationGroupId && !hasParam) {
                relativeUrl = relativeUrl + recommendationGroupIdParam;
                hasParam = true;
            } else if (recommendationGroupId && hasParam) {
                relativeUrl = relativeUrl + '&' + recommendationGroupIdParam;
            }

            if (offerId && !hasParam) {
                relativeUrl = relativeUrl + offerIdParam;
                hasParam = true;
            } else if (offerId && hasParam) {
                relativeUrl = relativeUrl + '&' + offerIdParam;
            }
        }

        var attr;

        if (openNewWindow) {
            attr = {
                'href': relativeUrl,
                'target': '_blank'
            };
        }
        else {
            attr = {
                'href': relativeUrl
            };
        }

        return attr;
    };

    /* Scrubs text for URL; javascript implementation of Discounts.Web.Helpers.UrlExtensions.ScrubforUrl */
    self.scrubTextForUrl = function (value) {
        var scrubValue = value;

        if (scrubValue) {
            scrubValue = scrubValue.trim();
            scrubValue = scrubValue.replace("%", "-percent");
            scrubValue = scrubValue.replace(/[\W_]+/g, "-");
            scrubValue = scrubValue.replace("-{2,}", "-");

            if (scrubValue.length > 25) {
                scrubValue = scrubValue.substring(0, 25);
            }
            if (scrubValue[0] == "-" && scrubValue.length > 1) {
                scrubValue = scrubValue.substring(1, scrubValue.length - 1);
            }
            if (scrubValue[scrubValue.length - 1] == "-") {
                scrubValue = scrubValue.substring(0, scrubValue.length - 1);
            }

            scrubValue = scrubValue.toLowerCase();
        }

        return scrubValue;
    };

    // Returns a function, that, as long as it continues to be invoked, will not
    // be triggered. The function will be called after it stops being called for
    // N milliseconds. If `immediate` is passed, trigger the function on the
    // leading edge, instead of the trailing.
    // Adapted from Underscore.js's implementation (https://github.com/jashkenas/underscore)
    self.debounce = function (func, wait, immediate) {
        var timeout;
        return function () {
            var context = this, args = arguments;
            var later = function () {
                timeout = null;
                if (!immediate) func.apply(context, args);
            };
            var callNow = immediate && !timeout;
            clearTimeout(timeout);
            timeout = setTimeout(later, wait);
            if (callNow) func.apply(context, args);
        };
    };

    // Takes a simple 10-digit phone number string (without any dashes, parentheses, etc.) and returns it as
    // (xxx) xxx-xxxx.
    self.formatPhoneNumber = function (phoneNumberString) {
        var cleaned = ('' + phoneNumberString).replace(/\D/g, '');

        var match = cleaned.match(/^(\d{3})(\d{3})(\d{4})$/);
        if (match) {
            return '(' + match[1] + ') ' + match[2] + '-' + match[3];
        }

        return null;
    };

    self.formatDateTime = function (dateTime, format) {
        var momentDateTime = moment.parseZone(dateTime);
        return moment(momentDateTime).format(format);
    };

    self.replaceLineBreaks = function (value, trim) {
        if (!self.isNullEmptyOrWhitespace(value)) {
            if (trim) {
                // Removing \n and \r characters at the end of string.
                value = value.replace(/(?!n|r)[\\n|r]+$/g, '');
            }

            return value.replace(/(\\r)?\\n/g, '<br />');
        }

        return '';
    };

    self.formatPhoneNumber = function (phoneNumber) {
        return phoneNumber.replace(/\D/g, '').replace(/(\d{3})(\d{3})(\d{4})/, '($1) $2-$3');
    }

    // https://datatracker.ietf.org/doc/html/rfc5322
    // https://emailregex.com/
    self.isEmail = function (email) {
        if (!self.hasValue(email)) {
            return false;
        }

        var scrubbedEmail = email.trim().toLowerCase();
        const regex = new RegExp(/^((")(.+?@)|(([0-9a-z_]((\.(?!\.))|[-!#\$%&'\*\+\/=\?\^`\{\}\|~\w])*)(?:[0-9a-z_])@))((\[\]\")*(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-z][-\w]*[0-9a-z]*\.)+[a-z0-9][\-a-z0-9]{0,22}[a-z0-9]))$/);
        return regex.test(scrubbedEmail);
    }

    return self;
}(jQuery));
//# sourceMappingURL=perkspot.utils.js.map
;
var perkspot = perkspot || {};

perkspot.global = function () {
    var self = {},
        areMerchantsLoaded = false,
        areCategoriesLoaded = false,
        isFooterLoaded = false;

    // #region KO View Models

    var headerViewModel = function () {
        this.merchants = ko.observableArray();
        this.primaryCategories = ko.observableArray();
        this.secondaryCategories = ko.observableArray();

        this.getPrimaryCategories = function (startIndex, endIndex) {
            if (this.primaryCategories().length < (endIndex - 1)) { endIndex = (this.primaryCategories().length - 1); }

            return this.primaryCategories().slice(startIndex, endIndex + 1)
        }
        this.getSecondaryCategories = function (startIndex, endIndex) {
            if (this.secondaryCategories().length < (endIndex - 1)) { endIndex = (this.secondaryCategories().length - 1); }

            return this.secondaryCategories().slice(startIndex, endIndex + 1)
        }


        this.rewardsCreditAvailableBudget = ko.observable();
        this.cartProductCount = ko.observable(0);
        this.currentUserAvailableCredit = ko.observable(0);
        this.isSoftAuth = ko.observable(true);
        this.loadExplicitInterests = function () {
            self.loadExplicitInterests();
        }
        this.isUserBalanceLoading = ko.observable(true);
    };

    var footerViewModel = function () {
        var self = this;

        self.merchants = ko.observableArray();
        self.categories = ko.observableArray();
        self.showDisclaimer = ko.observable();
        self.disclaimer = ko.observable();
        self.showPrivacyBanner = ko.observable();
        self.privacyPolicyUpdatedDate = ko.observable();
        self.communityNameAndDescriptor = ko.observable();

        self.getCategories = function (startIndex, endIndex) {
            if (self.categories().length < (endIndex - 1)) { endIndex = (self.categories().length - 1); }

            return self.categories().slice(startIndex, endIndex + 1)
        }
        self.getMerchants = function (startIndex, endIndex) {
            if (self.merchants().length < (endIndex - 1)) { endIndex = (self.merchants().length - 1); }

            return self.merchants().slice(startIndex, endIndex + 1)
        }
    };
    // #endregion

    self.headerVm = new headerViewModel();
    self.footerVm = new footerViewModel();

    // #region API Endpoints Reference

    self.apiEndPoints = {
        shop: {
            cart: {
                addProductToCart:         '/api/shop/cart/products/{productId}?quantity={quantity}',
                updateProductQuantity:    '/api/shop/cart/products/{productId}?quantity={quantity}',
                deleteProductFromCart:    '/api/shop/cart/products/{productId}?planId={planId}&userContactId={userContactId}&orderProductId={orderProductId}',
                addPlanToCart:            '/api/shop/cart/products/{productId}?quantity=1&planId={planId}&userContactId={userContactId}&isExisting={isExisting}',
                deleteTicketFromCart:     '/api/v1/exclusive-tickets/reserve/{ticketEventReservationId}',
                applyPointOrCreditAmount: '/api/shop/cart/applyPointOrCreditAmount?amount={amount}'
            },
            config: {
                get:                    '/api/shop/config',
                isSplitPayEnabled:      '/api/shop/splitpay',
                useRewardPoints:        '/api/shop/userewardpoints'
            },
            orders: {
                getCurrent:             '/api/shop/orders/current',
                validateCurrentOrder:   '/api/shop/orders/validateCurrentOrder',
                submit:                 '/api/shop/order?action=submit&userContactId={contactId}&paymentMethodId={paymentMethodId}&paymentMethodTypeId={paymentMethodTypeId}&deviceData={deviceData}&cvvNonce={cvvNonce}',
                getPointsEarnings:      '/api/shop/calculatePointsEarned'
            },
            giftCards: {
                getGiftCardsForCash:                '/api/shop/cash/giftcards',
                getGiftCardsForCredits:             '/api/shop/credits/giftcards',
                getGiftCardDetailsForCash:          '/api/shop/cash/giftcards/{giftcardId}',
                getGiftCardDetailsForCredits:       '/api/shop/credits/giftcards/{giftcardId}',
                redeem:                             '/api/shop/giftcards/redeem/{productRedemptionId}',

            },
            products: {
                getByProductId:         '/api/shop/products/{productId}',
                getMovieTickets:        '/api/shop/products/movietickets'
            },
            shopAttributes: {
                get:                    '/api/shop/metadata/shopattributes'
            },
            travel: {
                flights:                '/api/travel/search/flights',
                cars:                   '/api/travel/search/cars',
                hotels:                 '/api/travel/search/hotels',
                hotelHotDeals:          '/api/travel/getHotelDeals'
            },
            credits: {
                get:                    'api/credits',
                rewardCurrency:         '/api/credits/rewardcurrency'
            }
        },
        users: {
            language: {
                get:                    '/api/users/language',
            },
            contacts: {
                get:                    '/api/users/contacts',
                insert:                 '/api/users/contacts',
                update:                 '/api/users/contacts/{contactId}',
                remove:                 '/api/users/contacts/{contactId}'
            },
            paymentMethods: {
                get:                    '/api/v2/users/paymentmethods',
                insert:                 '/api/v3/users/paymentmethods',
                remove:                 '/api/v2/users/paymentmethods/{paymentMethodId}'
            },
            interests: {
                get:                    '/api/users/interests',
                insert:                 '/api/users/interests/{id}',
                remove:                 '/api/users/interests/{id}'
            },
            emailPreferences: {
                get:                    '/api/users/preferences/email',
                insert:                 '/api/users/preferences/email'
            },
            communicationPreferences: {
                getAudienceSubscriptions:            'api/communicationPreferences/subscriptions',
                insertAudienceSubscriptions:         'api/communicationPreferences/subscriptions',
                getAudienceCategories:               'api/communicationPreferences/categories',
                insertAudienceCategorySubscriptions: 'api/communicationPreferences/categories'
            },
            search: {
                autocomplete:           '/api/users/search/autocomplete'
            },
            onboarding: {
                video:                  'api/users/onboarding/video'
            }
        },
        offers: {
            codes: {
                get:                    '/api/offers/{id}/code'
            }
        },
        recognition: {
            getTypes:                   '/api/recognition/types',
            insert:                     '/api/recognition',
            getCreditAmountOptions:     '/api/recognition/communityamounts',
            getAmountOptions:           '/api/recognition/amount-options',
            getSubOrgs:                 '/api/recognition/suborgs',
            getSubOrgWhiteLabel:        '/api/recognition/community-sub-org-white-label',
            getMaxNumberOfRecognitions: '/api/recognition/maxrecipients',
            getRrFlagsAndConversion:    '/api/recognition/recognition-flags-and-conversion'
        },
        referrals: {
            post:                       '/api/userReferral',
            getByUserId:                '/api/userReferrals/{referrerUserId}',
            countRemaining:             '/api/userReferrals/{referrerUserId}/remaining',
            delete:                     '/api/userReferrals/{referralCodeId}'
        },
        locations: {
            logClick:                       '/api/geo/click'
        },
        offerfeedback: {
            submit:                     '/api/feedback',
            getModalOptions:            '/api/feedback/modalOptions'
        },
        autobuying: {
            getOffer:                   '/api/autobuyingoffer?communityId={communityId}&make={make}&autoBuyingTypeId={autoBuyingTypeId}'
        },
        rewards: {
            history:                    'api/rewards/history'
        },
        globalSettings: {
            globalSetting: 'api/globalsetting/{code}'
        },
        activity: {
            log: '/api/activity/log'
        }
    };

    self.routes = {
        shop: {
            giftCards: {
                redeemInterstitial: '/shop/giftcards/redeem?orderId={orderId}&orderProductId={orderProductId}&productRedemptionId={productRedemptionId}',
                redeemError: '/shop/giftcards/redeem/error',
                redeemRedirect: '/shop/orders/{orderId}/orderproducts/{orderProductId}/{productRedemptionId}/printredirect'
            }
        }
    };

    self.passwordRequirements = {
        regex: /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,24}$/,
        message: 'Password is required and must be between 8-24 characters long and contain at least one lowercase letter, one uppercase letter and one number.',
    }

    self.getAntiForgeryToken = function () {
        return $('#__AntiForgeryForm input[name=__RequestVerificationToken]').val();
    };

    // #endregion
    self.isNewSearchHeaderEnabled = ko.observable(false);
    self.init = function (isRewarder, usePoints, isNewSearchHeaderEnabled) {
        var selectedIcon = 'fa-chevron-down',
            initialIcon = 'fa-chevron-right',
            expandedClass = 'expanded',
            searchTooltipTimeout = null,
            perkSpotCommunityId = 924;
        self.isNewSearchHeaderEnabled(isNewSearchHeaderEnabled);
        // Init KO view models.
        if (document.getElementById('perk-nav-container')) {
            ko.applyBindings(self.headerVm, document.getElementById('perk-nav-container'));
        }

        ko.applyBindings(self.headerVm, document.getElementById('modal-categories'));
        ko.applyBindings(self.headerVm, document.getElementById('modal-myaccount'));
        ko.applyBindings(self.headerVm, document.getElementById('modal-myaccount-sm'));
        if(!isNewSearchHeaderEnabled) {
            ko.applyBindings(self.headerVm, document.getElementById('perknav-utility'));
        }
        ko.applyBindings(self.footerVm, document.getElementById('footer'));

        // Moved fat-menu initialization to server-side to avoid a client side "flash"
        // of the menu if it's closed.
        initSiteNotice();
        self.initCustomBanner();
        self.loadCartQuantity();
        if (usePoints)
            self.loadCurrentUserAvailablePoint();
        else
            self.loadCurrentUserAvailableCredit();

        if (isRewarder) {
            self.loadCurrentUserAvailableBudget();
        }

        // Lazy load any image with the class "lozad"
        var observer = lozad();
        observer.observe();

        if ($('.overflow-container').hasClass('perk-nav') && !isNewSearchHeaderEnabled) {
            perkspot.global.loadHeaderContent('categories');
        }
        $('.load-nav').on('click', function (e) {
            e.preventDefault();
            if (!isNewSearchHeaderEnabled) {
                perkspot.global.loadHeaderContent('categories');
            }
        });

        // Configure event handlers.
        // Header/Menus:
        $('#category-menu-close').on('click', function (e) {
            e.preventDefault();
            $('#category-menu').slideToggle();

            $('#category-menu-nav').parent().removeClass(expandedClass);
            $('#category-menu-nav i').removeClass(selectedIcon).addClass(initialIcon);
            $('#store-menu-nav i').removeClass(selectedIcon).addClass(initialIcon);

            setFatMenuState(false);
        });
        $('#category-menu-nav').on('click', function (e) {
            if ($(window).width() >= 975) {
                e.preventDefault();
            }

            $('#category-menu').slideToggle();
            $('#store-menu').slideUp();

            var el = $('#category-menu-nav i');

            if (el.hasClass(selectedIcon)) {
                el.removeClass(selectedIcon).addClass(initialIcon);
                $('#category-menu-nav').parent().removeClass(expandedClass);

                setFatMenuState(false);
            }
            else {
                el.removeClass(initialIcon).addClass(selectedIcon);
                $('#category-menu-nav').parent().addClass(expandedClass);
                $('#store-menu-nav i').removeClass(selectedIcon)
                                      .addClass(initialIcon);
                $('#store-menu-nav').parent().removeClass(expandedClass);

                if (!isNewSearchHeaderEnabled) {
                    perkspot.global.loadHeaderContent('categories');
                }

                setFatMenuState(true);
            }
        });
        $('#store-menu-close').on('click', function (e) {
            e.preventDefault();
            $('#store-menu').slideToggle();

            $('#store-menu-nav').parent().removeClass(expandedClass);
            $('#store-menu-nav i').removeClass(selectedIcon).addClass(initialIcon);
            $('#category-menu-nav i').removeClass(selectedIcon).addClass(initialIcon);

            setFatMenuState(false);
        });
        $('#store-menu-nav').on('click', function (e) {
            if ($(window).width() >= 975) {
                e.preventDefault();
            }

            $('#store-menu').slideToggle();
            $('#category-menu').slideUp();

            var el = $('#store-menu-nav i');

            if (el.hasClass(selectedIcon)) {
                el.removeClass(selectedIcon).addClass(initialIcon);
                $('#store-menu-nav').parent().removeClass(expandedClass);

                setFatMenuState(false);
            }
            else {
                el.removeClass(initialIcon).addClass(selectedIcon);
                $('#store-menu-nav').parent().addClass(expandedClass);
                $('#category-menu-nav i').removeClass(selectedIcon)
                                         .addClass(initialIcon);
                $('#category-menu-nav').parent().removeClass(expandedClass);

                perkspot.global.loadHeaderContent('merchants');

                setFatMenuState(true);
            }
        });

        /* Cookie Consent Box */
        $('#accept-cookies').on('click', function (e) {
            var url = '/api/users/cookies/consent?consent=true';
            $.ajax({
                type: 'POST',
                url: url,
                headers: {
                    'RequestVerificationToken': perkspot.global.getAntiForgeryToken()
                }
            })
                .done(function (d) {
                    $('#cookie-accept-popup').hide();
                })
                .error(function (d) {
                    console.log(d);
                });
        });

        /* Async Content Init */
        var footerWaypoint = new Waypoint({
            element: document.getElementById('footer-waypoint'),
            handler: function () {
                loadFooterContent();
            },
            offset: 'bottom-in-view',
            context: document.body
        });

        /* Search */
        $('.tabbed-nav a').click(function (e) {
            e.preventDefault();
            var navHeight = $( '.tabbed-nav' ).height();
            $('html, body').scrollTo('#' + this.className, 300, {
                offset: -navHeight
            });
        });

        // Enable store menu tooltips.
        $('#store-menu .selector').tooltip({});

        $(document).on('click', '#store-menu .selector', function (e) {
            e.preventDefault();

            $('#store-menu .selector').removeClass('selected');
            $(this).addClass('selected');

            setMerchantListView($(this).data('letter'));
        });

        function setMerchantListView(selector) {
            selector = (selector == '#') ? 'numeric' : selector;

            // Hide all visible store letters.
            $('.stores').removeClass('selected');
            // Show the selected store letter.
            $('.letter-' + selector).addClass('selected');
        }

        // Global "Back to Top" handler.
        $('.back-to-top a').click(function (e) {
            e.preventDefault();
            $('html, body').animate({ scrollTop: 0 }, 500);
            $('#skip a').focus({ preventScroll: true });
            return false;
        })

        /* Admin Utility Init */
        $('#admin-nav-toggle').on('click', function (e) {
            e.preventDefault();
            self.toggleAdminNav();
        });

        $('#admin-change-community').on('click', function (e) {
            e.preventDefault();

            $.when(function () {
                return $.ajax({
                    method: 'POST',
                    url: '/api/users/admin/change-community/' + $('#NewCommunityId').val(),
                    headers: {
                        'RequestVerificationToken': perkspot.global.getAntiForgeryToken()
                    }
                });
            }())
            .then(function (r) {
                location.reload(true);
            });
        });

        $('#admin-change-community-to-perkspot').on('click', function (e) {
            e.preventDefault();

            $.when(function () {
                return $.ajax({
                    method: 'POST',
                    url: '/api/users/admin/change-community/' + perkSpotCommunityId,
                    headers: {
                        'RequestVerificationToken': perkspot.global.getAntiForgeryToken()
                    }
                });
                }())
                .then(function (r) {
                    location.reload(true);
                });
        });

        $('#admin-copy-email-link').on('click', function (e) {
            e.preventDefault();

            var el = document.createElement('textarea');
            el.value = $('#SelectedEmailLink').val();
            el.setAttribute('readonly', '');
            el.style = { position: 'absolute', left: '-9999px' };
            document.body.appendChild(el);
            el.select();
            document.execCommand('copy');
            document.body.removeChild(el);
        });

        $('#admin-navigate-email-link').on('click', function (e) {
            e.preventDefault();

            window.open($('#SelectedEmailLink').val(), '_blank');
        });

        /**
         * Called when the user clicks on a community in the Change Community modal.
         */
        var changeCommunityLoading = false;

        $('.change-community-selection').on('click', function (e) {
            if (changeCommunityLoading) {
                return;
            }

            e.preventDefault();

            changeCommunityLoading = true;
            $('.change-community-selection').css({'cursor' : 'wait'});
            $('.loading-mask').fadeIn();
            var apiUrl = '/api/users/change-community/' + $(this).data('id');
            $.when(function () {
                return $.ajax({
                    method: 'POST',
                    url: apiUrl,
                    headers: {
                        'RequestVerificationToken': perkspot.global.getAntiForgeryToken()
                    }
                });
            }())
            .always(function (r) {
                // Always refresh the page because even on exception, the exceptions seem to be occurring after the community was changed.
                if (window.location.href.indexOf('/filter/') > -1) {
                    window.location.href = '/';
                } else {
                    location.reload(true);
                }
            });
        });

        //Handles Enter key press
        $('.change-community-selection').keypress(function (e) {
            if (e.which == 13) { //Enter key pressed
                $('.change-community-selection').click(); //Trigger search button click event
            }
        });

        self.initAccountViewModel = function () {
            self.AccountViewModel = new AccountViewModel();
            self.AccountViewModel.init();
            self.AccountViewModel.isLoggedIn(true);
            self.AccountViewModel.loadMetadata();
            self.AccountViewModel.loadUser();
            self.AccountViewModel.initCustomValidation();
            ko.applyBindings(self.AccountViewModel, document.getElementById('privacy-policy'));
        };

        // Configure send-referral button and form validation
        var loadingMask = $('.loading-mask');
        $('#send-referral-button').on('click', function (e) {
            e.preventDefault();

            $('#send-referral-button').prop('disabled', true);
            var referralTypeId = $('#select-referral-type option:selected').val();
            var referralEmailAddress = $('#send-referral-email').val();
            var sendReferralForm = $('#send-referral');
            if (sendReferralForm.parsley().validate()) {
                var referralData = {
                    referredEmail: referralEmailAddress,
                    referralTypeId: referralTypeId,
                    referredFirstName: "",
                    referredLastName: ""
                };
                $.when(function () {
                    loadingMask.fadeIn();
                    $.ajax(
                        {
                            type: 'POST',
                            url: self.apiEndPoints.referrals.post,
                            data: JSON.stringify(referralData),
                            headers: {
                                'RequestVerificationToken': perkspot.global.getAntiForgeryToken()
                            },
                            contentType: 'application/json',
                            success: function (response) {
                                // Close Send Referral Modal without closing the background overlay
                                perkspot.perxui.closeModal('sendreferral', 'fadeOut', false, false);
                                // Open "Thank You" modal
                                perkspot.perxui.activateModal('referralthankyou');
                                // Clear form field
                                sendReferralForm.find('#send-referral-email').val('');
                                sendReferralForm.find('#select-referral-type').prop('selectedIndex', 0);
                            },
                            error: function (response) {
                                perkspot.utils.notify({ message: 'Something went wrong. Please make sure you entered a valid email and try again.', type: 's', layout: 'topCenter', timeout: 5000 });
                                // Close Send Referral Modal and close the background overlay
                                perkspot.perxui.closeModal('sendreferral', 'fadeOut', true, false);
                            },
                            complete: function (response) {
                                $('#send-referral-button').prop('disabled', false);
                            }
                        });
                }()).always(function () {loadingMask.fadeOut();});
            } else {
                $('#send-referral-button').prop('disabled', false);
            }
        });
    };

    // #region Interests
    function selectInterests(state) {
        return state.modals.isInterestsChanged;
    }

    function handleChange() {
        let reloadInterests = selectInterests(window.stateStore.getState());
        if (reloadInterests) {
            $('#recommended-offers').fadeOut();
            $('#load-recommended-offers').show();

            $.ajax({
                url: '/Discounts/RecommendedOffers',
                type: 'GET',
                success: function (data) {
                    $('#load-recommended-offers').fadeOut();
                    $('#recommended-offers-container').html(data);
                    $('#recommended-offers').fadeIn();
                },
            });
        }
    }

    const unsubscribe = window.stateStore.subscribe(handleChange);
    self.loadExplicitInterests = function () {
        window.stateStore.dispatch({ "type": "modals/showUserInterests", payload: true });
    };

    // Expose interests modal to other non-knockout-bound components
    window.perkspot = window.perkspot || {};
    window.perkspot.interests = window.perkspot.interests || {};
    window.perkspot.interests.loadExplicitInterests = function () {
        self.loadExplicitInterests();
    }

    self.isInterestsModalSuppressed = function () {
        var cookie = $.cookie('ExplicitInterestCapture');
        if (cookie !== undefined) {
            return JSON.parse(cookie).isPostponed;
        } else {
            return false;
        }
    };

    // #endregion

    // #region Email Preferences
    // TODO - remove this function with the Subscription Manager flag
    self.loadEmailPreferencesForDisplay = function () {
        $.when(function () {
            return $.get(perkspot.global.apiEndPoints.users.emailPreferences.get + '?isDisplay=true');
        }())
        .then(function (r) {
            if (r.data) {
                $('#emailOptInCheckbox').prop('checked', (r.data.optInEmail));
                $('#newsletterOptInCheckbox').prop('checked', (r.data.optInNewsletter));
            }
        });
    };

    // TODO - remove this function with the Subscription Manager flag
    self.upsertEmailPreferences = function () {
        var emailOptIn = $('#emailOptInCheckbox').is(':checked');
        var newsletterOptIn = $('#newsletterOptInCheckbox').is(':checked');
        $.when(function () {
            return $.ajax({
                type: 'POST',
                url: perkspot.global.apiEndPoints.users.emailPreferences.insert,
                data: {
                    optInNewsletter: newsletterOptIn,
                    optInEmail: emailOptIn
                },
                headers: {
                    'RequestVerificationToken': perkspot.global.getAntiForgeryToken()
                }
            });
        }())
        .then(function (resp) {

        })
        .always(function () {
        });
    };
    // #endregion

    //#region Popover Methods

    /**
     * Initializes the popover when it's contained in a modal.
     * @param event The onclick event.
     */
    self.initPopoverInModal = function (event) {

        if (event.type === 'keyup' && event.keyCode !== 32) {
            // Only display it on space bar key ups.
            return;
        }

        // Don't let the body get this mouse click or the keystroke which will hide the popover just created.
        event.stopPropagation();

        var target = $(event.target);

        if (!$.data(target.get(0))['bs.popover']) {
            // The popover hasn't been created, create it now.

            // Clone content because when the popover is hidden, Bootstrap deletes the entire popover div.
            var content = $(target.data('popover-content')).clone(true).removeClass('hide');

            target.popover({
                container: 'body',
                html: true,
                title: 'CVV',
                trigger: 'click',
                content: function () {
                    return content;
                }
            }).click(function (e) {
                e.preventDefault();
            });

            var targetId = $(target).attr('id');

            // Close on any keypress.
            $(document).keyup(function (e) {

                // Get the popover container selector.
                var popoverId = $('#' + targetId).data('popover-content');
                if ($('.popover ' + popoverId).length) {
                    // The popover is visible, hide it.
                    $('#' + targetId).popover('hide');
                }
            });

            wasCvvHelpInitialized = true;
            setTimeout(function () {
                // Due to a bug in Bootstrap, have to make the popover go on top of the modal.
                // Let a cycle go through so that the surrounding DIV with the popover class can be added.
                $('.popover').zIndex(2001);
            }, 10);

            // It will initially be closed so have to manually show it. From now on, the popover will take care of itself.
            target.popover('show');
        } else if (event.type === 'keyup' && event.keyCode === 32) {
            // The popover has already been initialized but it target has the focus and the space bar was pressed,
            // toggle its visibility.
            target.popover('toggle');
        }
    };

    //#endregion

    // #region Fat Menu Utilities

    /* Fat Menu/Quick Browse Helpers */
    function getFatMenuState() {
        var cookie = $.cookie('fat-menu');

        try {
            if (cookie !== undefined) {
                return JSON.parse(cookie).isExpanded;
            }
        } catch (e) {

        }

        return true;
    }

    function setFatMenuState(isExpanded) {
        try {
            $.cookie('fat-menu', JSON.stringify({ isExpanded: isExpanded }), { expires: 365, path: '/' });
        } catch (e) {

        }
    }

    self.setPerkNavState = function(isClosed) {
        try
        {
            var currentDate = new Date();
            currentDate.setTime(currentDate.getTime() + 1 * 3600 * 1000);
            $.cookie('psc-perk-nav', JSON.stringify({ isClosed: isClosed }), { expires: currentDate, path: '/' });
        } catch (e) {
            console.log(e);
        }
    }

    self.loadMerchants = function () {
        if (!areMerchantsLoaded) {
            $.ajax({
                type: 'GET',
                url: '/merchants/list'
            })
            .done(function (data) {
                areMerchantsLoaded = true;

                var elMerchantList = $('.merchant-list');
                elMerchantList.fadeOut(function () {
                    elMerchantList.html(data);
                    elMerchantList.slideToggle();
                });
            })
            .fail(function () {

            });
        }
    }

    // #endregion

    // #region Async Content

    self.loadHeaderContent = function (type) {
        // this doesnt need to load if new header is present

        if (type === 'categories' && !areCategoriesLoaded) {
            //perkspot.utils.log('Loading Header Content - Categories...', 'debug');

            $.when(function () {
                areCategoriesLoaded = true;
                return $.getJSON('/api/content/header/categories');
            }())
            .then(function (resp) {
                try {
                    $.each(resp.data.primaryCategories,
                        function (index, value) {
                            value.cssClass = ('perx-' + value.displayName.toLowerCase().replace(' & ', '-').replace(' ', '-').replace('&', ''));
                    });

                    self.headerVm.primaryCategories(resp.data.primaryCategories);
                    self.headerVm.secondaryCategories(resp.data.secondaryCategories);
                    //$('#header-menu .categories.loader').slideUp();
                    //$('#top-menu-category-container').slideDown();
                    //$('.my-spot.perk-nav-section').addClass('fadeIn');                        // New header menu
                    //$('.perk-nav-head-container').addClass('nav-open');

                } catch (ex) { }
            });

        } else if (type === 'merchants' && !areMerchantsLoaded) {
            //perkspot.utils.log('Loading Header Content - Merchants...', 'debug');

            areMerchantsLoaded = true;
        }
    }

    function loadFooterContent() {
        if (!isFooterLoaded) {
            //perkspot.utils.log('Loading Footer Content...', 'debug');

            $.when(function () {
                isFooterLoaded = true;
                return $.getJSON('/api/content/footer');
            }())
            .then(function (resp) {
                try {
                    self.footerVm.categories(resp.data.categories);
                    self.footerVm.merchants(resp.data.merchants);
                    self.footerVm.showDisclaimer(resp.data.showDisclaimer);
                    self.footerVm.disclaimer(resp.data.disclaimer);
                    self.footerVm.showPrivacyBanner(resp.data.showPrivacyBanner);
                    self.footerVm.privacyPolicyUpdatedDate(resp.data.privacyPolicyUpdatedDate);
                    self.footerVm.communityNameAndDescriptor(resp.data.communityNameAndDescriptor);

                    //$('#footer .loader').fadeOut();
                    $('#footer-container').fadeIn();

                } catch (ex) { }
            });
        }
    }

    // #endregion

    // #region To Organize


    /* What's New Helpers */
    function initSiteNotice() {
        setTimeout(function () {
            if (isSiteNoticeVisible()) {
                $('#site-notice').css('display', 'flex');
                $('#site-notice .close-notice').on('click', function (e) {
                    e.preventDefault();
                    hideSiteNotice();
                });
            }
        }, 2000);
    }

    function isSiteNoticeVisible() {
        var cookie = $.cookie('psc-sitenotice'),
            isVisible = true;

        try {
            if (cookie !== undefined) {
                var _wasHidden = JSON.parse(cookie).wasHidden;

                if (_wasHidden) { isVisible = false; }
            }
        } catch (e) {
            isVisible = false;
        }

        return isVisible;
    }

    function hideSiteNotice() {
        console.log('hidebanner');
        $('#site-notice').css('display', 'none');

        try {
            $.cookie('psc-sitenotice', JSON.stringify({wasHidden: true }), { expires : 7, path: '/' });
        } catch (e) {

        }
    }

    function isCustomBannerVisible() {
        var cookie = $.cookie('psc-banner'),
            isVisible = true;

        try {
            if (cookie !== undefined) {
                var _wasHidden = JSON.parse(cookie).wasHidden;

                if (_wasHidden) { isVisible = false; }
            }
        } catch (e) {
            isVisible = false;
        }

        return isVisible;
    }

    self.loadCartQuantity = function() {
        $.when(function () {
            return $.getJSON('/api/shop/cart/products/quantity')
        }())
            .then(function (r) {
                if (perkspot.utils.hasValue(r.data.productQuantity) && r.data.productQuantity > 0) {
                    $('.cart-inventory .value').html(r.data.productQuantity);
                    $('.cart-inventory').fadeIn();
                }
                self.headerVm.cartProductCount(r.data.productQuantity);
                addToCartState();
        });
    };

    addToCartState = function () {
        if (self.isNewSearchHeaderEnabled()) {
            window.stateStore.dispatch({ "type": "cart/loaded", "payload":  self.headerVm.cartProductCount() });
        }
    }

    self.loadCurrentUserAvailableCredit = function () {
        $.when(function () {
            return $.getJSON('/api/credits');
        }())
        .then(function (r) {
            if (perkspot.utils.hasValue(r.data.userBalance)) {
                self.headerVm.currentUserAvailableCredit(r.data.userBalance);
                self.headerVm.isSoftAuth(r.data.softAuth);
                self.headerVm.isUserBalanceLoading(false);
            }
        });
    };

    self.loadCurrentUserAvailablePoint = function () {
        $.when(function () {
            return $.getJSON('/api/points');
        }())
            .then(function (r) {
                if (perkspot.utils.hasValue(r.data.userBalance)) {
                    self.headerVm.currentUserAvailableCredit(r.data.userBalance);
                    self.headerVm.isSoftAuth(r.data.softAuth);
                    self.headerVm.isUserBalanceLoading(false);
                }
            });
    };

    self.loadCurrentUserAvailableBudget = function () {
        $.when(function() {
                return $.getJSON('/api/credits/rewardscreditbudget?subOrgId=null');
            }())
            .then(function(r) {
                if (perkspot.utils.hasValue(r.data) && r.data > 0) {
                    self.headerVm.rewardsCreditAvailableBudget(r.data);
                } else {
                    self.headerVm.rewardsCreditAvailableBudget(0);
                }
            });
    };

    self.showOptIn = function () {
        $('#modal-optIn').modal('show');
        //perkspot.perxui.activateModal('int-location');


    }
    self.hideOptIn = function () {
        //perkspot.perxui.closeModal('int-location');
        $('#modal-optIn').modal('hide');
    }

    self.showConfirmDeactivate = function () {
        $('#modal-optout-confirm').modal('show');
    }
    self.hideConfirmDeactivate = function () {
        $('#modal-optout-confirm').modal('hide');
    }
    self.toggleAdminNav = function () {
        $('#nav-admin').slideToggle();
    }

    // #endregion

    // #region Terms of Use

    self.showTermsOfUse = function () {
        $('#modal-terms').modal('show');
        }
    self.hideTermsOfUse = function () {
        $('#modal-terms').modal('hide');
    }

    // #endregion

    // #region RR Terms of Use
    self.showRewardsTermsOfUse = function () {
        $('#modal-rr-terms').modal('show');
    }
    self.hideRewardsTermsOfUse = function () {
        $('#modal-rr-terms').modal('hide');
    }

    // #endregion

    /* Global Enums */
    self.asyncResult = {
        SUCCESS: 0,
        FAILURE: 1,
        WARNING: 2
    };

    /** The PerkSpot.ProductTypes. */
    self.productTypes = {
        ticket: 1,
        wellness: 2,
        wellnessProrate: 3,
        wellnessEnrollment: 4,
        giftCard: 5,
        travelHotel: 6,
        snackVoucher: 7,
        exclusiveTicket: 8,
        wholesaleClubVoucher: 9
    }

    /** The PerkSpot.OrderStatus. */
    self.orderStatus = {
        open: 1,
        complete: 2,
        awaitingPayment: 3,
        awaitingFulfillment: 4,
        awaitingReview: 5,
        cancelled: 6,
        refunded: 7,
        openRecurring: 8,
        completeRecurring: 9,
        disputed: 10,
        giveaway: 11,
        partiallyRefunded: 12,
        incompleteFulfillment: 13
    }

    self.onAjaxResponse = function (resultId, successCallback, warningCallback, failureCallback) {
        switch (resultId) {
            case perkspot.global.asyncResult.SUCCESS:
                if (successCallback !== null && typeof successCallback === 'function') { successCallback(); }
                break;
            case perkspot.global.asyncResult.WARNING:
                if (warningCallback !== null && typeof warningCallback === 'function') { warningCallback(); }
                break;
            case perkspot.global.asyncResult.FAILURE:
                if (failureCallback !== null && typeof failureCallback === 'function') { failureCallback(); }
                break;
        }
    };

    self.initCustomBanner = function () {
        setTimeout(function () {
            if (isCustomBannerVisible()) {
                $('#community-custom-banner').slideDown(100);
                $('#community-custom-banner .action-close').on('click', function (e) {
                    e.preventDefault();
                    self.hideCustomBanner();
                });
            }
        }, 2000);
    };

    self.hideCustomBanner = function () {
        $('#community-custom-banner').slideUp(100);
        try {
            $.cookie('psc-banner', JSON.stringify({ wasHidden: true }), { expires: 365, path: '/' });
        } catch (e) {

        }
    };

    // builds a URL for an external site, with optional arguments to build a query string.
    self.buildUrl = function (targetUrl, args) {
        args = args || null;
        var url = '';

        if (args !== null) {
            url = targetUrl + $.param(args);
        } else {
            url = targetUrl;
        }

        return url;
    };

    // Compiled from multiple sources at https://stackoverflow.com/questions/5999118/how-can-i-add-or-update-a-query-string-parameter.
    // New browser features (UrlSearchParams) would cover this scenario if we didn't need to support IE11 (not supported).
    self.upsertUrlQueryParam = function (uri, key, value) {
        // remove the hash part before operating on the uri
        var i = uri.indexOf('#');
        var hash = i === -1 ? '' : uri.substr(i);
        uri = i === -1 ? uri : uri.substr(0, i);

        var re = new RegExp("([?&])" + key + "=.*?(&|$)", "i");
        var separator = uri.indexOf('?') !== -1 ? "&" : "?";

        if (value === null) {
            // remove key-value pair if value is specifically null
            uri = uri.replace(new RegExp("([?&]?)" + key + "=[^&]*", "i"), '');
            if (uri.slice(-1) === '?') {
                uri = uri.slice(0, -1);
            }
            // replace first occurrence of & by ? if no ? is present
            if (uri.indexOf('?') === -1) uri = uri.replace(/&/, '?');
        } else if (uri.match(re)) {
            uri = uri.replace(re, '$1' + key + "=" + value + '$2');
        } else {
            uri = uri + separator + key + "=" + value;
        }
        return uri + hash;
    };

    return self;
}();

//# sourceMappingURL=perkspot.js.map
;
var perkspot = perkspot || {};

perkspot.perxui = function () {
    var self = {};

    var offerFeedbackModal = function () {
        var self = this;
        self.selectedOfferFeedbackType = ko.observable();
        self.offerFeedbackModalInfoText = ko.observable();
        self.isOfferFeedbackModalTextRequired = ko.observable();
        self.offerFeedbackModalPlaceholderText = ko.observable();
        self.offerFeedbackModalKeyup = ko.observable();
        self.offerFeedbackModalOptions = ko.observableArray();
        self.offerFeedbackModalTitle = ko.observable();
        self.offerFeedbackModalTypeId = ko.observable();
        self.isOptionSelected = ko.observable();
        self.isLoaded = ko.observable();
        self.offerId = ko.observable();
        self.merchantId = ko.observable();
        self.merchantName = ko.observable();
    }

    self.loadFeedbackModal = function (offerId, merchantId, merchantName) {
        self.offerFeedbackVM.offerId(offerId);
        self.offerFeedbackVM.merchantName(merchantName);
        self.offerFeedbackVM.merchantId(merchantId);

        if (self.offerFeedbackVM.isLoaded()) {
            self.activateModal('report-offer-one');
            return;
        }

        $.when(function () {
            return $.ajax({ type: 'GET', url: perkspot.global.apiEndPoints.offerfeedback.getModalOptions });
        }())
        .then(function (resp) {
            self.offerFeedbackVM.offerFeedbackModalOptions(resp);
            self.offerFeedbackVM.isLoaded(true);
            ko.applyBindings(self.offerFeedbackVM, document.getElementById('modal-report-offer-one'));
            self.activateModal('report-offer-one');
        });
    }

    self.init = function () {
        // Functions for animations
        // Essentially these let you add an animation class, let it run, then remove the class at the end.
        $.fn.extend({
            animateCss: function (animationName) {
                var animationEnd = 'webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend';
                this.addClass('animated ' + animationName).one(animationEnd, function () {
                    $(this).removeClass('animated ' + animationName);
                });
            }
        });

        //This shows/hides the arrow on the quick links menu, prompting users to scroll.
        $(document).ready(function () {
            $(".quick-links-container").on("scroll", function () {
                var cur = $(this).scrollLeft();
                if (cur == 0) {
                    $('.quick-links-list').addClass('scrolled-right').removeClass('scrolled-left');
                }
                else {
                    var max = $(this)[0].scrollWidth - $(this).parent().width();
                    if (cur == max) {
                        $('.quick-links-list').addClass('scrolled-left').removeClass('scrolled-right');
                    } else {
                        $('.quick-links-list').addClass('scrolled-right');
                    }
                }
            });
            $(".quick-links-container").trigger("scroll");
        });

        $.fn.extend({
            animateCssStart: function (animationName) {
                var animationEnd = 'webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend';
                this.addClass('animated ' + animationName).one(animationEnd, function () {
                    $(this).removeClass('animated ' + animationName);
                    $(this).addClass('open');
                });
            }
        });

        $.fn.extend({
            animateCssEnd: function (animationName) {
                var animationEnd = 'webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend';
                this.addClass('animated ' + animationName).one(animationEnd, function () {
                    $(this).removeClass('open');
                    $(this).removeClass('animated ' + animationName);
                });
            }
        });

        // This lets you show/hide recognition activity on the My Rewards page.
        $(document).on('click', '.show-hide', function (e) {
            e.preventDefault();
            $(this).parent('.activity').toggleClass('expanded');
        });

        // Allows for modals with variable, generated names.
        $(document).on('click', '.variable-modal', function (e) {
            // Gets the class of the modal's anchor tag, which should be directly after the .variable-modal element
            var thisModal = $(this).next().attr('class');
            // Removes "modal-" from the class of the modal's anchor tag
            thisModal = thisModal.replace('modal-', '');
            // Creates the modal using the class
            perkModal(thisModal, 'slideInDown', 'fadeOut', false, false, true, true, false);
            // Opens the modal.
            perkspot.perxui.activateModal(thisModal);
        });
        //Handles Enter key press
        $('.variable-modal').keypress(function (e) {
            if (e.which == 13) { //Enter key pressed
                $(this).click(); //Trigger search button click event
            }
        });

        // Modals
        perkModal('myhome', 'slideInUp', 'fadeOut', false, false, true, true, true);
        perkModal('categories', 'slideInUp', 'fadeOut', false, false, true, true, true);
        perkModal('recognition', 'slideInUp', 'fadeOut', true, false, true, true, true);
        perkModal('myaccount', 'slideInUp', 'fadeOut', true, false, true, true, true);
        perkModal('myfeed', 'slideInUp', 'fadeOut', true, false, true, true, true);
        perkModal('travelwidget', 'slideInUp', 'fadeOut', true, false, true, true, true);
        perkModal('search', 'slideInUp', 'fadeOut', true, false, true, true, true);
        perkModal('myaccount-sm', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('sorting', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('refine', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('cat-sorting', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('cat-filter', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('details', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('change-community', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('welcome', 'slideInUp', 'slideOutLeft', true, true, true, false, false);
        perkModal('interests', 'slideInRight', 'fadeOut', true, true, true, true, false);
        perkModal('utility', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('admin', 'slideInDown', 'slideOutUp', false, false, true, true, false);
        perkModal('promo-code', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('merchant', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('add-to-cart', 'slideInDown', 'fadeOut', false, false, false, true, false);
        perkModal('partner-information', 'slideInDown', 'fadeOut', false, true, true, true, false);
        perkModal('zip-code-prompt', 'slideInDown', 'fadeOut', true, true, true, true, false);
        perkModal('email-preferences', 'slideInDown', 'fadeOut', true, true, true, true, false);
        perkModal('add-to-community', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('ticket-terms', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('not-recommended', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('not-recommended-selected-ticket', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('product-terms', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('savings-breakdown', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('giftcards-intro1', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('giftcards-intro2', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('giftcards-intro3', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('giftcards-intro4', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('giftcard-store-filters', 'slideInUp', 'slideOutDown', false, false, true, true, false);
        perkModal('giftcard-store-giftcard-details', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('giftcard-store-sort', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('tickets-activities', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('tickets-locations', 'slideInDown', 'fadeOut', false, false, true, true, false);

        perkModal('report-offer-one', 'slideInUp', 'slideOutLeft', true, true, true, false, false);
        perkModal('report-offer-two', 'slideInRight', 'slideOutLeft', false, true, true, false, false);

        perkModal('aboutperkspot', 'slideInDown', 'fadeOut', false, false, true, true, false);

        perkModal('small-example', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('medium-example', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('multistep-example-one', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('multistep-example-two', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('inline-example', 'slideInUp', 'fadeOut', true, false, true, true, true);

        perkModal('addupdate-contact', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('communication-preferences', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('communication-preferences-unsubscribe', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('addupdate-payment', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('subscription-payment', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('subscription-cancel', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('charge-history', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('int-location', 'slideInDown', 'slideOutUp', false, false, true, true, false);
        perkModal('updatepassword-success', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('failure', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('updateaccount-success', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('invalid-postal-code', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('invalid-current-password', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('duplicateemail', 'slideInDown', 'fadeOut', false, false, true, true, false);

        perkModal('whatsnew', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('giftcardscallout', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('sendreferral', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('referralthankyou', 'slideInDown', 'fadeOut', false, false, true, true, false);

        perkModal('rewardslearnmore', 'slideInDown', 'fadeOut', false, false, true, true, false);

        perkModal('register-login', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('register-preregistered', 'slideInDown', 'fadeOut', false, false, true, true, false);

        perkModal('order-loading', 'slideInDown', 'fadeOut', true, false, true, false, false);
        perkModal('recognition-confirm', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('recognition-success', 'slideInDown', 'fadeOut', false, false, true, true, false);

        perkModal('weekly-perks-selector', 'slideInDown', 'fadeOut', false, false, true, true, false);
        perkModal('premium-perks', 'slideInDown', 'fadeOut', false, false, true, true, false);

        perkModal('missing-email', 'slideInDown', 'fadeOut', false, false, true, true, false);

        var isEmptyFeedback = false;
        var additionalInfo = $("#additionalinfo");

        self.clearFeedbackVars = function () {
            additionalInfo.css("border", "0px");
            $("#empty-feedback-error").text("");
        }

        // PerkModals and Options
        function perkModal(modalName, openTransition, closeTransition, disableOverlayClose, logActivity, preventDefault, closeOverlay, altOverlay) {
            //Opens the Modal and Overlay
            $(document).on('click', '.modal-' + modalName, function (e) {
                if (isEmptyFeedback) { return; }

                if (preventDefault) { e.preventDefault(); }
                // mark the main page as hidden
                $('#mainPage').attr('aria-hidden', 'true');

                // Opens the modal itself
                $('#modal-' + modalName).animateCssStart(openTransition);

                // Checks to see if this modal has an alt overlay and opens it
                if (!$('.modal-overlay').hasClass('open')) {
                    if (altOverlay) {
                        if ($('#modal-' + modalName).hasClass('overlay-opaque-sm')) {
                            $('.modal-overlay').addClass('alt-overlay opaque-sm').animateCssStart('fadeIn');
                        } else if ($('#modal-' + modalName).hasClass('overlay-opaque')) {
                            $('.modal-overlay').addClass('alt-overlay opaque').animateCssStart('fadeIn');
                        } else {
                            $('.modal-overlay').addClass('alt-overlay').animateCssStart('fadeIn-alt');
                        }
                    } else {
                        $('.modal-overlay').animateCssStart('fadeIn');
                    }
                }

                // mark the modal window as visible
                $('#modal-' + modalName).attr('aria-hidden', 'false');

                // Tries to make the page stick at the spot where the modal is
                if ($(this).hasClass('goToNext')) {
                    var scrollFromTop = 0;
                } else {
                    var scrollFromTop = $(window).scrollTop();
                }

                var top = $('body').css('top');
                if (top == '0px') {
                    $('body').css('top', -scrollFromTop).addClass('noscroll');
                }

                // Find all of the focusable items
                var focusableItems = $('#modal-' + modalName).find(':focusable');

                // Put focus on the modal itself
                if (modalName === "search") {
                    //iOS Keyboard hack
                    var modalSearchInput = $('#modal-search #search-query');
                    $(modalSearchInput).focus();
                    $(modalSearchInput).click(function () {
                        $("html, body").animate({ scrollTop: 0 }, "fast");
                        return false;
                    });
                    $(modalSearchInput).click();
                } else {
                    $('#modal-' + modalName).focus();
                }


                // Keypress tracking for tabbing
                if (!$('.modal-overlay').hasClass('open')) {
                    $(document).keydown(function (e) {
                        // tab keypress
                        if (e.which == 9) {
                            // changing focus forward and back is done by tabbing and shift-tabbing through focusable items (handled by the browser)
                            // the following code is here to trap focus within the modal, so if you reach the end of the modal you go back to the top and vice versa.

                            // get currently focused item
                            var focusedItem = $(':focus');

                            // get the number of focusable items
                            var numberOfFocusableItems = focusableItems.length

                            // get the index of the currently focused item
                            var focusedItemIndex = focusableItems.index(focusedItem);

                            if (e.shiftKey) {
                                //back tab
                                // if focused on first item and user preses back-tab, go to the last focusable item
                                if (focusedItemIndex == 0) {
                                    focusableItems.get(numberOfFocusableItems - 1).focus();
                                    e.preventDefault();
                                }
                            } else {
                                //forward tab
                                // if focused on the last item and user preses tab, go to the first focusable item
                                if (focusedItemIndex == numberOfFocusableItems - 1) {
                                    focusableItems.get(0).focus();
                                    e.preventDefault();
                                }
                            }
                        }
                    });
                };

                // Logging
                if (logActivity) {
                    self.logModalActivity(modalName, 49, 'click-open-modal');
                }
            });

            // Allows you to close the modal by clicking the overlay, unless disableOverlayClose is set to "true"
            if (!disableOverlayClose) {
                $('#modal-' + modalName).click(function (e) {
                    if (e.target != this)
                        return;

                    // Closes the modal
                    self.closeModal(modalName, closeTransition, closeOverlay, altOverlay);

                    // Logging
                    if (logActivity) {
                        self.logModalActivity(modalName, 50, 'dismiss-overlay');
                    }
                });
            };

            // Close Button
            $('#modal-' + modalName + ' .close, #modal-' + modalName + ' .closeModal').click(function (e) {
                e.preventDefault();

                // Logging
                if (logActivity) {
                    self.logModalActivity(modalName, 50, 'dismiss-x');
                }
                // Closes the modal
                self.closeModal(modalName, closeTransition, true, altOverlay);
            });

            // "OK" Button
            $('#modal-' + modalName + ' .close-ok, #modal-' + modalName + ' .closeModal-ok').click(function (e) {
                e.preventDefault();

                if (logActivity) {
                    self.logModalActivity(modalName, 50, 'dismiss-ok');
                }

                // Closes the modal
                self.closeModal(modalName, closeTransition, closeOverlay, altOverlay);
            });

            // Offer feedback modal fields
            self.offerFeedbackVM = new offerFeedbackModal();

            $('.report-offer-options li').keypress(function (e) {
                const ENTER_KEYCODE = 13;
                var keycode = (e.keyCode ? e.keyCode : e.which)
                if (keycode == ENTER_KEYCODE) {
                    $(this).find('input').prop('checked', true);
                    $(this).find('input').trigger('click');
                }
            });

            self.populateOfferFeedback = function (offerFeedbackType) {
                self.clearFeedbackVars();
                self.offerFeedbackVM.selectedOfferFeedbackType(offerFeedbackType);
                self.offerFeedbackVM.isOptionSelected(true);
                self.offerFeedbackVM.offerFeedbackModalTitle(offerFeedbackType.title);
                self.offerFeedbackVM.offerFeedbackModalInfoText(offerFeedbackType.additionalInfoText);
                self.offerFeedbackVM.isOfferFeedbackModalTextRequired(offerFeedbackType.isTextRequired);
                self.offerFeedbackVM.offerFeedbackModalPlaceholderText(offerFeedbackType.placeholderText);
                self.offerFeedbackVM.offerFeedbackModalKeyup(offerFeedbackType.keyupEvent);
                self.offerFeedbackVM.offerFeedbackModalTypeId(offerFeedbackType.offerFeedbackTypeId);
            };

            $('.resetOfferFeedbackModal').click(function (e) {
                self.resetFeedbackModal();
            })

            // Next Modal
            $('#modal-' + modalName + ' .goToNext').click(function (e) {
                goToNextModal(e);
            });

            // Next Modal Offer Feedback
            $('#modal-' + modalName + ' .goToNextFeedback').click(function (e) {
                //Textarea is empty = highlight textarea and show error message
                if (additionalInfo) {
                    if (self.offerFeedbackVM.isOfferFeedbackModalTextRequired() && !$.trim(additionalInfo.val())) {
                        additionalInfo.css("border", "2px solid red");
                        $("#empty-feedback-error").text("Please provide us a little bit more information about your issue").css("color", "red");
                        isEmptyFeedback = true;
                        return;
                    }
                }

                $.when(function () {
                    return $.ajax(
                        {
                            type: 'POST',
                            url: perkspot.global.apiEndPoints.offerfeedback.submit,
                            data:
                            {
                                offerId: self.offerFeedbackVM.offerId(),
                                userFeedback: additionalInfo.val(),
                                merchantId: self.offerFeedbackVM.merchantId(),
                                merchantName: self.offerFeedbackVM.merchantName(),
                                pageURL: window.location.href,
                                offerFeedbackTypeId: self.offerFeedbackVM.offerFeedbackModalTypeId(),
                                offerFeedbackTypeTitle: self.offerFeedbackVM.offerFeedbackModalTitle()
                            },
                            headers: {
                                'RequestVerificationToken': perkspot.global.getAntiForgeryToken()
                            }
                        });
                }())
                    .then(function (resp) {
                        $('input:radio[name=report-offer-radio]:checked').prop('checked', false);
                        self.offerFeedbackVM.selectedOfferFeedbackType(null);
                    });
                goToNextModal(e);
            });

            function goToNextModal(e) {
                e.preventDefault();
                if (logActivity) {
                    self.logModalActivity(modalName, 50, 'dismiss-next');
                }
                // Closes this modal
                self.closeModal(modalName, closeTransition, false, altOverlay);
            }

            // Close on ESC Keypress
            $(document).keyup(function (e) {
                if ($('#modal-' + modalName).hasClass('open')) {
                    if (e.which == 27) {
                        self.closeModal(modalName, closeTransition, closeOverlay, altOverlay);
                        if (!closeOverlay) {
                            $('.modal-overlay').animateCssEnd('fadeOut');
                        }
                    }
                };
            });

            self.resetFeedbackModal = function () {
                $('input:radio[name=report-offer-radio]:checked').prop('checked', false);
                self.offerFeedbackVM.selectedOfferFeedbackType(null);
                self.offerFeedbackVM.offerFeedbackModalInfoText(null);
                self.offerFeedbackVM.isOfferFeedbackModalTextRequired(false);
                self.offerFeedbackVM.offerFeedbackModalPlaceholderText(null);
                self.offerFeedbackVM.offerFeedbackModalKeyup(null);
                self.offerFeedbackVM.isOptionSelected(false);
                self.clearFeedbackVars();
            }

            // Close Modal Function
            self.closeModal = function (modalName, closeTransition, closeOverlay, altOverlay) {
                // Cleaning any possible residue from empty feedback error
                isEmptyFeedback = false;
                additionalInfo.val('');
                self.resetFeedbackModal();

                // Closes the modal contents
                $('#modal-' + modalName).animateCssEnd(closeTransition);

                // Checks to see if the overlay should close as well
                if (closeOverlay || closeOverlay == null) {
                    // Checks to see if it's an alt overlay and closes it if it is
                    var modalOverlay = $('.modal-overlay');
                    if (altOverlay) {
                        $(modalOverlay).animateCssEnd('fadeOut-alt');
                        setTimeout(function () {
                            $(modalOverlay).removeClass('alt-overlay');
                            $(modalOverlay).removeClass('opaque');
                            $(modalOverlay).removeClass('opaque-sm');
                        }, 300);
                    } else {
                        // If it isn't an alt overlay, closes the normal overlay
                        $(modalOverlay).animateCssEnd('fadeOut');
                        $(modalOverlay).removeClass('opaque');
                        $(modalOverlay).removeClass('opaque-sm');
                    }
                };

                // Attmepts to keep the user in their spot when the modal closes
                var scrollPosition = (Math.abs(parseInt($("body").css('top'))));
                $('body').removeClass('noscroll');
                $('body').css('top', 'auto');
                $('html, body').animate({ scrollTop: scrollPosition }, 1);


                // mark the modal window as hidden
                $('#modal-' + modalName).attr('aria-hidden', 'true');
                // mark the main page as visible
                $('#mainPage').attr('aria-hidden', 'false');

                $('body').off('focusin', '#mainPage');

                //Focus on the element that initally triggered the modal, unless it's the My Feeds button because that's ugly
                if (modalName == 'myfeed') {
                    $('#content').focus();
                } else {
                    $('.modal-' + modalName).focus();
                }

                $('#modal-' + modalName).trigger('closed');
            };
        }

        // Hack fix to make sure the second step offer reporting modal closes when you click the overlay
        $('#modal-report-offer-two').click(function (e) {
            if (e.target != this)
                return;
            $('.modal-overlay').animateCssEnd('fadeOut');
        });

        // Shortens the Desktop navigation for people with short screens
        $(window).on("load resize", function () {
            var navHeight = $(window).height();
            if (navHeight <= 780) {
                if ((!$('.overflow-container').hasClass('short-nav'))) {
                    $('.overflow-container').addClass('short-nav');
                } else { };
            } else {
                if (($('.overflow-container').hasClass('short-nav'))) {
                    $('.overflow-container').removeClass('short-nav');
                } else { };
            };
        });

        //Always close the Quick Links when the Travel Widget is present.

        if ($("#travel-widget-panel").length != 0) {
            $('.quick-links-container').removeClass('open');
            $('.quick-links-button').removeClass('active');
            $('.page-title-container').css('display', 'none');
        }

        // PerkNav

        perkNav('my-home');
        perkNav('categories');
        perkNav('recognition');

        function perkNav(navSectionName) {
            $(document).on('click', '.perk-nav-' + navSectionName, function (e) {
                e.preventDefault();
                // If the navigation isn't currently animating...
                if (!$('.perk-nav-section').hasClass('animated')) {
                    // If the nav link you clicked is currently active, close the nav
                    if ($(this).hasClass('active')) {
                        $('.perk-nav-section.' + navSectionName).animateCssEnd('fadeOut');
                        $('.perk-nav-body').removeClass('open');
                        // Remove the active class on the button you clicked
                        $(this).removeClass('active');

                        perkspot.global.setPerkNavState(true);
                        // if the nav link you clicked isn't currently active, switch close the currently open nav, open the one you clicked and add an active class to the button you clicked.
                    } else {
                        // Add the "open" class to the nav menu
                        $('.perk-nav-body').attr('class', 'perk-nav-body open');
                        // remove the active class from the buttons
                        $('.perk-nav-primary-buttons a').removeClass('active');
                        // add the active class to the button you clicked
                        $('.perk-nav-' + navSectionName).addClass('active');

                        // If the nav section you clicked is currently open, or currently in the process of animating, close it
                        if ($('.perk-nav-section.' + navSectionName).hasClass('open') || $('.perk-nav-section.' + navSectionName).hasClass('animated')) {
                            $('.perk-nav-section.' + navSectionName).animateCssEnd('fadeOut');
                            // If any of the nav sections are open, close them before opening the item you clicked
                        } else if ($('.perk-nav-section').hasClass('open')) {
                            var animationEnd = 'webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend';
                            // Find the open nav and fade it out. once the animation completes, remove the open class and the animation classes
                            $('.perk-nav-section.open').addClass('animated fadeOut').one(animationEnd, function () {
                                $(this).removeClass('open');
                                $(this).removeClass('animated fadeOut');
                                // Once the open nav has been closed, open the nav section you selected
                                $('.perk-nav-section.' + navSectionName).addClass('animated fadeIn').one(animationEnd, function () {
                                    $('.perk-nav-section.' + navSectionName).removeClass('animated fadeIn');
                                    $('.perk-nav-section.' + navSectionName).addClass('open');
                                });
                            });
                            // If the nav is currently closed, just open the nav section you clicked.
                        } else {
                            $('.perk-nav-section.' + navSectionName).animateCssStart('fadeIn');
                        };
                        perkspot.global.setPerkNavState(false);
                    };
                };
            })
        };

        var toggleNavButton = $('#toggle-nav-button');
        var mobileNavBody = $('.mobile-nav-body');
        var mobileNavContainer = $('.mobile-nav-container');

        $(document).on('click', '#toggle-nav-button', function (e) {
            e.preventDefault();
            // If the navigation isn't currently animating...
            if (!$(mobileNavBody).hasClass('animated')) {
                // If the nav link you clicked is currently active, close the nav
                if ($(toggleNavButton).hasClass('active')) {
                    mobileNavBody.addClass('animated fadeOut').one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function () {
                        mobileNavBody.removeClass('open');
                        mobileNavBody.removeClass('animated fadeOut');

                    });
                    // Remove the active class on the button you clicked
                    $(toggleNavButton).removeClass('active');
                    // Remove the active class on the container {
                    mobileNavContainer.removeClass('revealed');
                } else {
                    // Add the "open" class to the mobile menu
                    $(mobileNavBody).animateCssStart('fadeIn');
                    $(mobileNavBody).addClass('open');
                    // add the active class to the button you clicked
                    $(toggleNavButton).addClass('active');
                    // Add the active class on the container {
                    mobileNavContainer.addClass('revealed');
                };
            };
            // hide nav if window is above 768px wide

        });

        // If you're on the Cart or merchant profile page, start the perkNav closed regardless of user cookie

        closePerkNavDefault('cart');
        closePerkNavDefault('merchant-profile');

        function closePerkNavDefault(pageClass) {
            if ($('html').hasClass(pageClass)) {
                $('.perk-nav-body').removeClass('open');
                $('.perk-nav-primary-buttons a').removeClass('active');
                $('.perk-nav-section').removeClass('open');
            };
        }

        if ($('html').hasClass('merchant-profile')) {
            $('.perk-nav-body').removeClass('open');
            $('.perk-nav-primary-buttons a').removeClass('active');
            $('.perk-nav-section').removeClass('open');
        };

        $(document).on('click', '.login-nav', function (e) {
            e.preventDefault();
            // Checks to see if you clicked the "Go to Sign In" link
            var animationSpeed = 100
            var headerOffset = 100
            if ($(this).hasClass('goto-signin')) {
                //If so, animate scroll with offset
                $('html, body').animate({
                    scrollTop: $(this.hash).offset().top - headerOffset
                }, animationSpeed);
                // And then focus on the username input
                $("#Username").focus();
            } else {
                // If not, animate scroll with no offset
                headerOffset = 300
                $('html, body').animate({
                    scrollTop: $(this.hash).offset().top - headerOffset
                }, animationSpeed);
                // and then focus on the button
                $(this.hash + ' .button').focus();
            }
            // Make the section you land on bounce briefly to call your attention
            $(this.hash).animateCss('bounce');
        });


        // On the interests modal, show the rest of the categories when you click the show all button.
        $(document).on('click', '.show-all-trigger', function (e) {
            $('.interests-list').addClass('show-all-interests');
            $('.show-all-trigger').toggleClass('invisible');

            try {
                ga('send', 'event', 'modal', 'show-all', 'interests');
            } catch (ex) {
            }
        });

        //Search

        // When you click a "goto-search" button, search opens up.
        $(document).on('click', '.goto-search', function (e) {
            e.preventDefault();
            $('html, body').scrollTo($('#perknav-utility'), 0, {
                onAfter: function () {
                    $(".mobile-utilities #search-query").click();
                    $(".search-overlay").addClass('fadeIn');
                    $(".mobile-utilities #search-query").focus();
                }
            });
        });
        // Handles Enter key press
        $('.goto-search').keypress(function (e) {
            if (e.which == 13) { //Enter key pressed
                $('.goto-search').click(); //Trigger search button click event
            }
        });

        // Handles Enter key press for styled checkbox lists which appear on many pages.
        $('.checkbox-list li label, .terms-agreement label').keypress(function (e) {
            if (e.which == 13) { //Enter key pressed
                $(this).find('input[type="checkbox"]').click();
            }
        });

        $('.picker-list [tabindex=0]').keypress(function (e) {
            if (e.which == 13) { //Enter key pressed
                $(this).click();
            }
        });

        // Open the overlay and focus the search when you click the search input
        $(document).on('focus click', '.header-search #search-query, .header-search .focus-search', function (e) {
            $('.search-overlay').addClass('fadeIn');
            $('.mobile-utilities').addClass('search-open');
            $('.brand-container').addClass('search-open');
            $('.search-overlay').click(function (e) {
                $('.mobile-utilities').removeClass('search-open');
                $('.brand-container').removeClass('search-open');
                $('.search-overlay').removeClass('fadeIn').addClass('fadeOut').one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend',
                    function () {
                        $(this).removeClass('fadeOut');
                    });
                $(this).removeClass('.fadeOut');
            });
        });

        $(document).on('blur', '.header-search #search-query, .header-search .focus-search', function (e) {
            $('.mobile-utilities').removeClass('search-open');
            $('.brand-container').removeClass('search-open');
            $('.search-overlay').removeClass('fadeIn').addClass('fadeOut').one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend',
                function () {
                    $(this).removeClass('fadeOut');
                });
            $(this).removeClass('.fadeOut');
        });



        // Scroll back to the top of the list when paginating
        $(document).on('click', '.pagination-bottom .pagination-link', function (e) {
            e.preventDefault();
            $('html, body').animate({
                scrollTop: $('#results-top').offset().top
            }, 200);
        });

        // Scroll back to the top of the list selecting a City on Tickets and Attractions
        $(document).on('click', '.checkbox-subcategory-label', function () {
            $('html, body').animate({ scrollTop: 40 }, 'fast');
        });

        // Scroll back to the top of the movie tickets widget when selecting a ticket.
        $(document).on('click', '.theater-ticket .button, .search-results-body .closeModal', function (e) {
            e.preventDefault();
            $('html, body').animate({
                scrollTop: $('#movie-tickets-widget-body').offset().top
            }, 200);
        });

        // Show/hide the contents of a shop item description on click
        $(document).on('click', '.expandable', function (e) {
            e.preventDefault();
            $(this).toggleClass('closed');
        });

        // Open search when you click the modal-search button
        $('.modal-search').click(function () {
            $('#modal-search').one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend',
                function () {
                    var modalSearchInput = $('#modal-search #search-query');
                    $(modalSearchInput).click();
                    $(modalSearchInput).focus();
                });
        });

        $('#new-quick-search').click(function() {
            var newSearchInput = $('#new-quick-search-input');
            newSearchInput.focus();
        });

        //Truncation with dotdotdot js function
        function truncate(classtail, height) {
            $('.truncate-' + classtail).dotdotdot({
                watch: "window",
                height: height
            });
        }

        //calls the truncate function immediate when page loads and not only on resize
        truncate('cat-features', 75);

        // Checks if page nav exists, if so creates sticky nav.
        $(document).ready(function () {
            var doesPageNavExist = $('.page-nav-container').length;
            if (doesPageNavExist != 0) {
                new Waypoint.Sticky({
                    element: $('.page-nav-container')[0]
                })
            };
        });


        // JQuery Media Queries
        $(document).ready(genaralUseMediaQueries);
        $(window).on("resize", genaralUseMediaQueries);

        function genaralUseMediaQueries () {
            // General Use JS Media Queries
            var windowHeight = $(window).height();
            var windowWidth = $(window).width();

            // Hero Offers formatting
            $('li.full-size .hero-title').removeClass('truncate-recommended-four').addClass('truncate-featured-top');

            if (windowWidth <= 991) {
                truncate('featured-top', 66);
            }
            else {
                truncate('featured-top', 66);
            };

            truncate('recommended-four', 66);

            // Truncation function
            function truncate(classtail, height) {
                $('.truncate-' + classtail).dotdotdot({
                    watch: "window",
                    height: height
                });
            }

            if (windowWidth <= 767) {
                // Set up in case i need it
            };

            if (windowWidth > 767) {
                $('.perkmodal-mobile-only.open .close').click();
                $('.mobile-nav-container').removeClass('revealed');
                $('.mobile-nav-body').removeClass('open');
                truncate('catspons', 62);
                truncate('cat-features', 75);
            };

            if (windowWidth > 1200) {
                truncate('catspons', 105);
            } else {
            };

            // Mapped Checkout Functions, primarily to make the back button work
            $('.step-2 .map-checkout-back').unbind('click');
            $('.step-3 .map-checkout-back').unbind('click');

            // Mapped Checkout for Gyms
            if (windowWidth > 1200) {
                if ($('.step-2').hasClass('slideInRight')) {
                    $('.step-2').removeClass('slideInRight');
                    $('.step-1').addClass('slideInLeft');
                }
                mapCheckoutBack('.step-2 .map-checkout-back', '.map-checkout.step-1', 'slideOutLeft', '', 'slideInLeft', '')
                mapCheckoutBack('.step-2 .map-checkout-back', '.map-checkout.step-2', 'slideInLeft', 'slideInRight', 'slideOutRight', 'slideOutRight')
                mapCheckoutBack('.step-3 .map-checkout-back', '.map-checkout.step-3', 'slideInRight', 'slideInLeft', 'slideOutRight', 'slideOutRight')
                mapCheckoutBack('.step-3 .map-checkout-back', '.map-checkout.step-1', 'slideOutLeft', '', 'slideInLeft', '')
            } else {
                mapCheckoutBack('.step-2 .map-checkout-back', '.map-checkout.step-2', 'slideInRight', 'slideInLeft', 'slideOutRight', 'slideOutRight')
                mapCheckoutBack('.step-2 .map-checkout-back', '.map-checkout.step-1', 'slideOutLeft', '', 'slideInLeft', '')
                mapCheckoutBack('.step-3 .map-checkout-back', '.map-checkout.step-3', 'slideInRight', 'slideInLeft', 'slideOutRight', 'slideOutRight')
                mapCheckoutBack('.step-3 .map-checkout-back', '.map-checkout.step-2', 'slideOutLeft', '', 'slideInLeft', '')
            }

            function mapCheckoutBack(step, frame, remove1, remove2, add, finalRemove) {
                $(step).click(function (e) {
                    e.preventDefault();
                    $(frame).removeClass(remove1).removeClass(remove2).addClass(add).one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend',
                        function () {
                            $(this).removeClass(finalRemove);
                        });
                });
            }
        };
    }

    // First Visit Customizations



    $(document).on('ready', function (e) {
        e.preventDefault();
        var firstVisitMobile = $('.myfeed-cta-container .info .info-first-visit');
        var firstVisitDesktop = $('h1.myfeed-title-first-visit span.new-callout');
        if ($('.homepage').hasClass('first-visit')) {
            $(firstVisitMobile).css('display', 'inline-block').animateCssEnd('bounceInRight');
            $(firstVisitDesktop).css('display', 'inline-block').animateCssEnd('bounce');
         };
    });

    // Checkout Stuff
    $(document).on('click', '.cancel-addupdate', function (e) {
        e.preventDefault();
        $('#addupdate-contact').animateCssEnd('fadeOut');
    });

    $(document).on('click', '.cancel-addupdate-payment', function (e) {
        e.preventDefault();
        $('#addupdate-payment').animateCssEnd('fadeOut');
    });

    $(function () {
        $("#round-departing, #round-returning, #oneway-departing, #pick-up-date, #drop-off-date").datepicker({
            minDate: new Date(),
            maxDate: "+18m"
        });
    });

    function scrollIntoViewIfNeeded($target) {
        if ($target.position()) {
            if ($target.position().top < jQuery(window).scrollTop()) {
                //scroll up
                $('html,body').animate({ scrollTop: $target.position().top });
            }
            else if ($target.position().top + $target.height() >
                $(window).scrollTop() + (
                    window.innerHeight || document.documentElement.clientHeight
                )) {
                //scroll down
                $('html,body').animate({
                    scrollTop: $target.position().top -
                        (window.innerHeight || document.documentElement.clientHeight)
                        + $target.height() + 15
                }
                );
            }
        }
    }

    // Inline Alerts
    self.perkTipClick = function (clickTarget, messageOne, messageTwo, width) {
        $(document).on('click', '.perktipclick-' + clickTarget, function (e) {
            e.preventDefault();

            // Avoid Falling behind edges
            var offset = $(this).offset();
            var offsetright = Math.abs($(window).width() - (offset.left + $(this).outerWidth(true)));
            var offsetleft = $(this).offset().left;
            var buttonWidth = $(this).outerWidth();

            if (offsetleft > (width / 2) && offsetright > (width / 2)) {
                var perkTipPositionLeft = (0 - (width / 2)) + (buttonWidth / 2);
            } else if (offsetleft < (width / 2) && offsetright > (width / 2)) {
                var perkTipPositionLeft = 0;
            } else if (offsetleft < (width / 2) && offsetright < (width / 2)) {
                var perkTipPositionLeft = (0 - (width / 2)) + (buttonWidth / 2);
            } else {
                var perkTipPositionLeft = (0 - width) + buttonWidth;
            };

            // Work the magic
            if ($(this).hasClass('activated')) {
                $(this)
                    .append("<span class='perktip-alert alert-off'>" + messageTwo + "</span>")
                    .find("span.alert-off").css({
                        'width': width + "px",
                        'left': perkTipPositionLeft + "px",
                        'bottom': ($(this).outerHeight() + 5) + "px",
                        'z-index': "200"
                    })
                    .removeClass('activated')
                    .one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend',
                        function () {
                            $('span.alert-off').remove();
                        });
            } else {
                $(this)
                    .append("<span class='perktip-alert alert-on'>" + messageOne + "</span>")
                    .find("span.alert-on").css({
                        'width': width + "px",
                        'left': perkTipPositionLeft + "px",
                        'bottom': ($(this).outerHeight() + 5) + "px",
                        'z-index': "200"
                    })
                    .addClass('activated')
                    .one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend',
                        function () {
                            $('span.alert-on').remove();
                        });
            };
        });
        $(document).on('keypress', '.perktipclick-' + clickTarget, function (e) {
            if (e.which == 13) {
                $(this).click();
            }
        });
    }




    // Lets you activate the modal through js. ex: perkspot.perxui.activateModal('add-to-cart');
    self.activateModal = function (modalName) {
        $('.modal-' + modalName).trigger('click');
    };

    // Lets you move from one modal to another for multi-step modals
    self.nextModal = function (modalName, closeTransition, closeOverlay, altOverlay) {
        // Close the modal that is currently open
        self.closeModal(modalName, closeTransition, closeOverlay, altOverlay);

        // Wait for the first modal to close, then open the next one
        setTimeout(function () {
            $('#modal-' + modalName + ' .goToNext').trigger('click');
        }, 200);
    };


    // Function for Truncating text blocks.
    self.truncateText = function (truncElement, truncHeight) {

        // Checks to see if the text is going to be truncated. If not, hide the "read more" link since it's unnecessary.
        if ($(truncElement).height() >= truncHeight) {
            $(truncElement).find("a.read-more").removeClass('hidden');
        } else {
            $(truncElement).find("a.read-more").addClass('hidden');
        }

        // Run the .dotdotdot() command with options.
        $(truncElement).dotdotdot({
            ellipsis: '... ',
            wrap: 'word',
            after: "a.read-more",
            watch: true,
            height: truncHeight,
            callback: function (isTruncated, orgContent) {
                var self = $(this);
                self.find(".read-more").click(function () {
                    toggleRead($(this));
                });

                //if no more text to show hide read more link
                if (!isTruncated) {
                    self.find(truncElement + ' a.read-more').css("display", "none");
                }

            }
        });

        // This is the JS that handles the "read more/show less" links on the offers. I took it from a stackoverflow comment - it seams to work but does have some isses
        function toggleRead(caller) {
            var callerText = $(caller).text();
            var parent = $(caller).closest(truncElement);
            var isTruncated = $(parent).triggerHandler("isTruncated");
            if (isTruncated) {
                // Remove ellipsis
                $(parent).trigger("destroy.dot");
                // Update text - have to be clever about it, since destroy overwrites after element text values apparently
                $(parent).find("a.read-more").html("[Show Less]");
                // Re-add click function since I guess destroy also removes this
                $(parent).find("a.read-more").click(function () {
                    toggleRead(this);
                });
            } else {

                // Update text
                $(parent).find("a.read-more").html("[Read more]");

                // Re-add ellipsis
                $(parent).dotdotdot({
                    ellipsis: '... ',
                    wrap: 'word',
                    after: "a.read-more",
                    watch: true,
                    height: truncHeight
                });
            }
        }
    }

    // Logging
    self.logModalActivity = function (modalName, activityTypeId, notes) {
        var activityTypeName = 'unknown';

        // Set metadata with: modal name and notes.
        var metadata =
        {
            modal: modalName,
            notes: notes
        };

        // Set synthetic activity type name for Google Analytics events.
        switch (activityTypeId) {
            case 49:
                activityTypeName = 'open';
                break;
            case 50:
                activityTypeName = 'close';
                break;
        }
        activityTypeName = (notes != null ? activityTypeName + '-' + notes : activityTypeName);

        try {
            ga('send', 'event', 'modal', activityTypeName, 'interests', activityTypeId);
        } catch (ex) { }

        $.ajax(
            {
                type: 'POST',
                url: '/api/activity/log',
                contentType: 'application/json',
                data: JSON.stringify(
                    {
                        urlReferrer: window.location.href,
                        url: window.location.href,
                        activityType: activityTypeId,
                        sourceEntityType: null,
                        sourceEntityId: null,
                        targetEntityType: 20,
                        targetEntityId: null,
                        externalId: null,
                        metadata: metadata
                    }
                ),
                headers: {
                    'RequestVerificationToken': perkspot.global.getAntiForgeryToken()
                }
            });
    };

    return self;
}();
//# sourceMappingURL=perkspot.perxui.js.map
;
/// <reference path="~/Scripts/perkspot.js" />

perkspot.login = function () {
    var self = {};
    self.vm = null;
    self.init = function (isMagicLinkEnabled, areCredentialsInvalid, communityId) {

        self.vm = new loginViewModel(isMagicLinkEnabled, areCredentialsInvalid, communityId);
        var node = document.getElementById('login-page');
        ko.cleanNode(node);
        ko.applyBindings(self.vm, node);

        // Configure form validation.
        $('#sign-in').validate({
            // errorContainer: $('#sign-in-error'),
            rules: {
                Username: {
                    required: true,
                    email: true
                },
                Password: 'required'
            },
            messages: {
                Username: '<i class="fa fa-exclamation-circle"></i> Email address is required.',
                Password: '<i class="fa fa-exclamation-circle"></i> Password is required.'
            },
            errorElement: 'div',
            errorLabelContainer: '.login-errors'
        });

        // Configure validation trigger.
        $('#sign-in-submit').on('click', function (e) {
            e.preventDefault();

            if ($('#sign-in').valid()) {
                $('#sign-in').submit();
            }
        });

        self.validateEmail = function (email) {

            if (!perkspot.utils.isNullEmptyOrWhitespace(email) && !self.vm.isMagicLinkEnabled()) {
                $.when(function () {
                    let redirectUrl = window.location.pathname.replace("login", "").replace(/\//g, "");
                    return perkspot.utils.asyncCreate('/api/nli/validate-email-login', JSON.stringify({
                        communityId: self.vm.communityId(),
                        email: email,
                        redirectUrl: redirectUrl
                    }));
                }())
                    .then(function (resp) {
                        self.vm.loginEmailValidityMessage(resp.resultMessage);

                        //Password field will be disabled, so clear input as well
                        if (resp.resultMessage != null) {
                            self.vm.password("");
                        }
                    });
            }
        };

        self.vm.email.subscribe(function (value) {
            self.validateEmail(value);
        });

        $('#sign-in-sso').on('click', function (e) {
            e.preventDefault();

            var redirectUrl = window.location.pathname.replace("login", "").replace(/\//g, "");
            window.location.href = '/auth/sp-signin?redirectUrl=' + redirectUrl;
        });

        if (self.vm.areCredentialsInvalid()) {
            $('#sign-in-auth-error').show();
        }
    };

    return self;
}();

var loginViewModel = function (isMagicLinkEnabled, areCredentialsInvalid, communityId) {
    var self = this;

    self.isMagicLinkEnabled = ko.observable(isMagicLinkEnabled);
    self.areCredentialsInvalid = ko.observable(areCredentialsInvalid);
    self.communityId = ko.observable(communityId);
    self.email = ko.observable();
    self.loginEmailValidityMessage = ko.observable();
    self.password = ko.observable();
    self.showPasswordEnabled = ko.observable(false);
    self.errorMessage = ko.observable();

    self.toggleShowPassword = function (ele) {
        let showPasswordEnabled = self.showPasswordEnabled();
        self.showPasswordEnabled(!showPasswordEnabled);

        let input = $(ele).prev();

        if (!showPasswordEnabled) {
            input.attr('type', 'password');
        } else {
            input.attr('type', 'text');
        }
    };

    self.toggleShowPasswordOnEnter = function (ele, event) {
        const ENTER_KEYCODE = 13;
        if (event.keyCode == ENTER_KEYCODE) {
            self.toggleShowPassword(ele);
        }
    };

    self.handleGoogleOneTapLogin = async function(googlePayload) {
        const response = await fetch("/api/nli/google-1-tap", {
            method: 'POST',
            headers: {
                "Content-Type": "application/json"
            },
            body: JSON.stringify({
                GoogleToken: googlePayload.credential
            })
        });

        const ACCOUNT_NOT_FOUND_RESULT_ID = 1;
        if (response.ok) {
            const responseBody = JSON.parse(await response.text())

            // This is a hack for returning a "Not Found" status code.
            // PSC intercepts 404 responses and writes the "Oops" page into the response with a 200 instead.
            // To get around that, we need to return a 2xx code and indicate in the response that the user was not found.
            if (responseBody.resultId === ACCOUNT_NOT_FOUND_RESULT_ID) {
                self.errorMessage("Sorry, we couldn't log you in. This Google account isn't associated with any existing PerkSpot account. Please try another login method or create a new account.")
            } else {
                const urlSearchParams = new URLSearchParams(window.location.search);
                window.location = `/login/google-1-tap/complete${urlSearchParams.has('redirectUrl') ? `?redirectUrl=${urlSearchParams.get('redirectUrl')}` : ''}`
            }
        } else {
            self.errorMessage("Google login is temporarily unavailable. Please continue with one of the log in options below or try again later.")
        }
    }
};
//# sourceMappingURL=perkspot.public.login.js.map
;
/// <reference path="~/Scripts/perkspot.js" />

perkspot.forgotpasswordrequest = function () {
    var self = {};

    self.init = function () {
        if (window.location.href.indexOf('notregistered') > -1) {
            $('#alert-notregistered').show();
        }

        // Configure form validation.
        $('#forgot-password').validate({
            errorContainer: $('#forgot-password-error'),
            rules: {
                Email: {
                    required: true,
                    email: true
                }
            },
            messages: {
                Email: '<i class="fa fa-exclamation-circle"></i> Email address is required.'
            }
        });

        // Configure validation trigger.
        $('#forgot-password-submit').on('click', function (e) {
            e.preventDefault();

            if ($('#forgot-password').valid()) {
                $('#forgot-password').submit();
            }
        });
    };

    return self;
}();
//# sourceMappingURL=perkspot.public.forgotpasswordrequest.js.map
;
/// <reference path="~/Scripts/perkspot.js" />

perkspot.forgotpasswordreset = function () {
    var self = {};

    self.viewModel = null;

    self.init = function () {
        self.viewModel = new passwordResetViewModel();
        ko.applyBindings(self.viewModel, document.getElementById('password-reset-pickup'));
        self.viewModel.init();
    };

    return self;
}();

var passwordResetViewModel = function () {
    var self = this;

    self.isSubmitting = ko.observable(false);

    self.init = function () {

        // Password requirements validation
        $.validator.addMethod(
            'passwordRequirements',
            function (value) {
                var regex = perkspot.global.passwordRequirements.regex
                return regex.test(value);
            });

        // Configure form validation.
        $('#reset-password').validate({
            errorContainer: $('#reset-password-error'),
            rules: {
                NewPassword: {
                    required: true,
                    passwordRequirements: true
                },
                NewPasswordConfirm: {
                    equalTo: "#NewPassword"
                }
            },
            messages: {
                NewPassword: '<i class="fa fa-exclamation-circle"></i> ' + perkspot.global.passwordRequirements.message,
                NewPasswordConfirm: '<i class="fa fa-exclamation-circle"></i> Passwords must match.'
            },
            errorPlacement: function ($error, $element) {
                var name = $element.attr("name");
                $("#error" + name).append($error);
            }
        });

        // Configure validation trigger.
        $('#reset-password-submit').on('click', function (e) {
            e.preventDefault();
            if (!self.isSubmitting()) {
                if ($('#reset-password').valid()) {
                    self.isSubmitting(true);
                    $('#reset-password').submit();
                }
            }
        });


        $('.password-toggle').on('click', function (e) {
            e.preventDefault();

            var inputPassword = $(e.currentTarget.parentElement).find('input')[0];
            var iconElement = $($(e.currentTarget).find('i')[0]);

            if (inputPassword.type === "password") {
                inputPassword.type = "text";
                iconElement.toggleClass("fa-eye fa-eye-slash");
            } else {
                inputPassword.type = "password";
                iconElement.toggleClass("fa-eye fa-eye-slash");
            }
        });
    }
}
//# sourceMappingURL=perkspot.public.forgotpasswordreset.js.map
;
