/* Minification failed. Returning unminified contents.
(96,63-64): run-time error JS1195: Expected expression: )
(96,66-67): run-time error JS1195: Expected expression: >
(98,106-107): run-time error JS1195: Expected expression: )
(98,109-110): run-time error JS1195: Expected expression: >
(100,22-23): run-time error JS1195: Expected expression: ,
(100,24-25): run-time error JS1010: Expected identifier: {
(100,38-39): run-time error JS1195: Expected expression: )
(101,18-19): run-time error JS1195: Expected expression: )
(104,38-39): run-time error JS1004: Expected ';': {
(437,70-71): run-time error JS1195: Expected expression: >
(439,83-84): run-time error JS1195: Expected expression: )
(439,86-87): run-time error JS1195: Expected expression: >
(443,18-19): run-time error JS1195: Expected expression: ,
(443,34-35): run-time error JS1195: Expected expression: )
(792,5-6): run-time error JS1002: Syntax error: }
(778,9,789,10): run-time error JS1018: 'return' statement outside of function: return {
            setFormTarget: setFormTarget,
            initEvents: initEvents,
            animateOfferCodes: animateOfferCodes,
            loadEventVideo: function () { loadVideo(); },
            ticketQuantityChanged: ticketQuantityChanged,
            doesQueryStringParamExist: doesQueryStringParamExist,
            loadTicketsContainer: loadTicketsContainer,
            loadTicketHistory: loadTicketHistory,
            showWaitlistPopup: showWaitlistPopup,
            closePopupWaitlist: closePopupWaitlist
        }
 */


(function ($) {
    // *******************************************************************************************
    //              feature tabs
    //              given a div with event ids from the marketing service
    //              extract event information for them and compose on
    //              screen in feature tab format
    // *******************************************************************************************

    $.formatFeatureTabs = function (element, options) {

        // plugin's default options
        var defaults = {
            reload : false
        }; // to avoid confusions, use "plugin" to reference the
        // current instance of the object
        var plugin = this;

        plugin.settings = {};
        var $element = $(element);    // reference to the actual DOM element

        // the "constructor" method that gets called when the object is created
        plugin.init = function () {

            // the plugin's final properties are the merged default and
            // user-provided options (if any)
            plugin.settings = $.extend({}, defaults, options);

            // code goes here
            
            var eventIds = $element.find('.event-ids').data('event-ids');
            var data = {
                eventIds: $.parseJSON('[' + eventIds + ']'),
                tabtype: "live"
            };
            $.get(config.contextPath + 'api/event/get-feature-tabs', $.param(data, true), function (result) {
                $element.html(result);
                $element.hoverInfoPanel();
            });
           
        };
        // public methods

        // private methods
        // call the "constructor" method
        plugin.init();

    }; // add the plugin to the jQuery.fn object
    $.fn.formatFeatureTabs = function (options) {
        // iterate through the DOM elements we are attaching the plugin to
        return this.each(function () {
            // if plugin has not already been attached to the element
            if (undefined == $(this).data('featuretabs')) {
                // create a new instance of the plugin
                // pass the DOM element and the user-provided options as arguments
                var plugin = new $.formatFeatureTabs(this, options);
                // in the jQuery version of the element
                // store a reference to the plugin object
                // you can later access the plugin and its methods and properties like
                // element.data('pluginName').publicMethod(arg1, arg2, ... argn) or
                // element.data('pluginName').settings.propertyName
                $(this).data('featuretabs', plugin);

            }
        });

    };
})(jQuery);;
$(document).ready(function () {
    moshtixEventCommon.initEvents({ onValidationError: onValidationError });
    moshtixEventCommon.animateOfferCodes();
    moshtixEventCommon.loadEventVideo();
    moshtixEventCommon.ticketQuantityChanged();


    moshtixEventCommon.loadTicketsContainer();
    
    function onValidationError(errorMessage)
    {
        commonModule.showErrorMessage("#event-tickets-messages", errorMessage);
    }
});
;
var moshtixEventCommon = moshtixEventCommon ||
    (function (window, document, undefined) {
        var eventSettings;
        var transactionFee = 0;
        var gatewayBuyNowPayLater = null;
        var intltelinput = null;

        function intialiseTicketRequestEvent() {
            // ticket request check how to modal
            const ticketRequestHowTo = document.getElementById('ticket-request-how-to');
            if (ticketRequestHowTo) {
                ticketRequestHowTo.addEventListener('click', () => {
                    document.getElementById('ticketRequestHowToModal').style.display = 'block';
                    document.getElementById('ticket-request-how-to-modal-ok').addEventListener('click', () => {
                        document.getElementById('ticketRequestHowToModal').style.display = 'none';
                    }, { once: true });
                });
            }
        }
        function initEvents(options) {

            // merge defaluts
            eventSettings = $.extend({
                onBuyTickets: $.noop,
                onValidationError: $.noop,
                onTicketsAdded: $.noop,
                hideOfferCodeInfo: false,
                formTarget: '_top'
            },
                options);

            $("body").on("click", "#event-buy-tickets", buyTickets);
            $("body").on("click", ".offercode-apply-button", applyOfferCode);
            $("body").on("click", ".remove-offer-code", removeOfferCode);
            $("body").on("keyup", "#event-offercode-textbox", applyOfferCodeEnterKey);
            $("body").on("keyup", ".offercode-apply-button", applyOfferCode);

            intialiseTicketRequestEvent();

            window.onhashchange = processHash;

            $(document).ready(function () {
                processHash();

                transactionFee = parseFloat($("#transaction-fee").val());

                showBuyNowPayLaterDefaultBanner();
            });

            function processHash() {
                var hash = window.location.hash;
                if (hash.indexOf("#group") !== -1) {
                    var groupId = hash.replace("#group", "");
                    var groupHeaderName = $('#display-group-name-' + groupId);
                    if (groupHeaderName.length > 0) {
                        var groupHeader = groupHeaderName.parent().parent();
                        var parentGroupHeader = groupHeader.parent().parent().parent().children('.event-display-group-header');
                        if (parentGroupHeader.length > 0) {
                            if (parentGroupHeader.parent().hasClass("collapsed-container")) {
                                parentGroupHeader.click();
                            }
                        }
                        groupHeader[0].scrollIntoView({
                            behavior: "smooth", // or "auto" or "instant"
                            block: "start" // or "end"
                        });
                        if (groupHeader.parent().hasClass("collapsed-container")) {
                            groupHeader.click();
                        }
                        groupHeader.fadeTo(300, 0.4).fadeTo(300, 1).fadeTo(300, 0.4).fadeTo(300, 1);
                    }
                }
            }

            $("#popup-button-confirm").click(function () {
                $("#event-tickets-form").submit();
            });

            $(".locked-padlock").click(function (element) {
                var lock = $(event.target);
                var groupId = lock.parent().parent().parent().data('display-group-id');
                window.location.hash = groupId;
                ticketTypeGroupModule.showDependencyDetails(groupId);
            });

            $(".unlocked-padlock").click(function (element) {
                var lock = $(event.target);
                var groupId = lock.parent().parent().parent().data('display-group-id');
                window.location.hash = groupId;
                ticketTypeGroupModule.showDependencyDetails(groupId);
            });

            $(document).keydown(function (event) {
                // don't want to stop a query from being run
                // if you find your form submit isn't working, this is probably why
                if ($(event.srcElement).attr('id') != 'query' && $(event.srcElement).attr('id') != 'waitlist-email') {

                    if (event.keyCode == 13) {
                        event.preventDefault();
                        return false;
                    }
                }
            });

            $("#waitlist-email").focusout(function () {
                var emailAddress = $('#waitlist-email').val();
                validateWaitlistEmail(emailAddress);
            });

            $('#waitlist-form').on('submit',
                function (event) {
                    event.preventDefault();
                    console.log('submit to the waitlist');
                    var emailAddress = $('#waitlist-email').val();
                    var mobileNumber= $('#waitlist-mobile').val();
                    if (validateWaitlistEmail(emailAddress) && (!mobileNumber || intltelinput.isValidNumber())) {
                        $('#waitlist-add').fadeOut(function () {
                            $('#waitlist-success').fadeIn().addClass('waitlist-success-visible');
                        });

                        var subscribeThirdParty = $('#third-party').find('input[type="checkbox"]').prop('checked');
                        var subscribeMoshtix = $('#moshtix-subscribe').find('input[type="checkbox"]').prop('checked');

                        $.ajax({
                            type: "POST",
                            data: {
                                fullName: $('#waitlist-fullname').val(),
                                emailAddress: emailAddress,
                                mobileNumber: $('#waitlist-mobile').val(),
                                id: $('#waitlist-eventId').val(),
                                sendThirdPartyOffers: subscribeThirdParty,
                                sendMoshtixSpecialOffers: subscribeMoshtix
                            },
                            success: function () {
                                $.ajax({
                                    type: "POST",
                                    url: "/v2/waitlistuser/updateusercookies"
                                });
                            },
                            url: "/v2/marketing/waitlist/add"
                        });
                    }
                });
        }

        function validateWaitlistEmail(emailAddress) {
            if (!commonValidation.validateEmail(emailAddress)) {
                $("#emailWarning").css('visibility', 'visible');
                $("#waitlist-email-validation").text("Please check your details are correct");
                return false;
            }
            else {
                $("#emailWarning").css('visibility', 'hidden');
                return true;
            }
        }

        function showWaitlistPopup() {
            $("#waitlist-modal").show();
            $("#overlay-waitlist").show();
            initWaitlistMobileValidation();
        }

        function closePopupWaitlist() {
            $("#waitlist-modal").hide();
            $("#overlay-waitlist").hide();
        }

        function initWaitlistMobileValidation() {
            if ($("#waitlist-mobile").length) {
                // initialise country selector for phone validation
                var input = document.querySelector("#waitlist-mobile");
                intltelinput = commonModule.initMobileDefault(input);
                $("#waitlist-mobile").focusout(function () {
                    var mobileValid = intltelinput.isValidNumber();
                    var mobileNumber = $('#waitlist-mobile').val();

                    if (!mobileValid && mobileNumber) {
                        // show mobile validation error
                        var validationError = intltelinput.getValidationError();
                        var errorString = commonModule.phoneNumberErrors[validationError] || "Please check your details are correct";
                        $("#mobileWarning").css('visibility', 'visible');
                        $("#waitlist-mobile-validation").text(errorString);
                    } else {
                        // clear mobile validation error is fixed
                        $("#mobileWarning").css('visibility', 'hidden');
                        $("#waitlist-mobile-validation").text("");
                    }
                });

                if ($("#waitlist-mobile").val().length) {
                    // user is logged in so we need to trigger that the country has changed on the phone validation plugin
                    const event = new CustomEvent("countrychange", {});
                    document.querySelector("#waitlist-mobile").dispatchEvent(event);
                    // recheck where the user is and default country to that if user is logged in
                    var countryIso2 = 'au';
                    if (Intl) {
                        // get timezone from browser
                        var userTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
                        // map timezone to country
                        var userCountry = timezoneToCountry[userTimeZone];
                        // map country to iso 2 code or default to au if not available
                        countryIso2 = countryMapping[userCountry].toLowerCase() || "au";
                    }
                    intltelinput.setCountry(countryIso2);
                }
            }
        }

        var urlParams = {};
        (function () {
            var match,
                pl = /\+/g, // Regex for replacing addition symbol with a space
                search = /([^&=]+)=?([^&]*)/g,
                decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); },
                query = window.location.search.substring(1);

            while (match = search.exec(query))
                urlParams[decode(match[1])] = decode(match[2]);
        })();

        function doesQueryStringParamExist(param) {
            return urlParams[param] != null;
        }

        function loadVideo() {
            commonModule.loadVideo();
        }

        function removeOfferCode() {
            checkOfferCode("");
        }

        function applyOfferCodeEnterKey(event) {

            if (event.keyCode && event.keyCode === 13) {
                event.preventDefault();
                applyOfferCode(event);
            }
        }

        function applyOfferCode(event) {
            event.preventDefault();

            var offerCode = $("#event-offercode-textbox").val();
            if (offerCode === "" || offerCode === "Enter offer code")
            //ie 9 and earlier can't deal with the place holder text
            {
                return;
            }

            checkOfferCode(offerCode);
        }

        function checkOfferCode(offerCode) {
            var vip = $("#event-vipview").val();
            var eventId = $("#event-eventid").val();
            var ref = $("#Referrer").val();
            var skin = $("#Skin").val();
            var collectorTicket = $('[id^=IsCollectorTicketSelected]').val() || false;
            var resaleAccessCode = $("#peertopeer-resale-access-code").val();

            var ticketsUrl = config.contextPath +
                "/home/GetTicketsForEventPage?id=" +
                eventId +
                "&vip=" +
                vip +
                "&offercode=" +
                offerCode +
                "&hideOfferCodeInfo=" +
                eventSettings.hideOfferCodeInfo +
                "&ref=" +
                ref +
                "&rac=" +
                resaleAccessCode +
                "&skin=" +
                skin +
                "&collectorTicket=" +
                collectorTicket;

            $.get(ticketsUrl).success(function (data) {
                $("#event-tickets-content").html(data);
                eventSettings.onTicketsAdded();
                ticketQuantityChanged();
                $("#event-tickets-content").trigger("eventTicketsContentRendered");
                animateOfferCodes();
                loadTicketsContainer();
                checkCollectorOnLoad();
            });
        }

        function checkCollectorOnLoad() {
            checkForCollectorTixOnLoad();
        }

        function buyTickets() {

            function continuePurchase() {
                $("#event-tickets-form").submit();
            }

            // Validate credits
            var hasRedeemedCredits = false;
            var creditsValidationMessage = creditsModule.validateCredits();
            if (creditsValidationMessage) {
                if (creditsValidationMessage === "success") {
                    hasRedeemedCredits = true;
                } else {
                    ticketTypeGroupModule.showValidationMessage(creditsValidationMessage, "credits");
                    return;
                }
            }

            // Check that some tickets have been selected.
            var peerToPeerResaleQuantity = 0;
            $('select[name^="peertopeer-resale-quantity"]').each(function () {
                peerToPeerResaleQuantity += parseInt($(this).val());
            });

            // Check that some tickets have been selected.
            var ticketsQuantity = 0;
            $('select[name^="lQuantity"]').each(function () {
                ticketsQuantity += parseInt($(this).val());
            });

            if (ticketsQuantity > 0) {
                if (!validateOfferCodeTicketLimit()) {
                    eventSettings.onValidationError("Too many tickets selected. Offer code has a ticket limit of " +
                        parseInt($("#offer-code-ticket-limit").val()) +
                        " tickets.");
                    return;
                }
            } else {
                if (!hasRedeemedCredits && peerToPeerResaleQuantity <= 0) {
                    eventSettings.onValidationError("Please select the number of tickets you wish to purchase");
                    return;
                }
            }

            // Validate packages
            var packagesValidationMessage = packageModule.validatePackages();
            if (packagesValidationMessage) {
                ticketTypeGroupModule.showValidationMessage(packagesValidationMessage, "package");

                return;
            }

            // clear any validation messages
            const el = document.getElementById('event-tickets-messages');
            if (el) {
                el.remove();
            }
            const showTicketRequestModal = (modelId, modalButtonId) => {
                document.getElementById(modelId).style.display = 'block';
                document.getElementById(modalButtonId).addEventListener('click', () => {
                    document.getElementById(modelId).style.display = 'none';

                    continuePurchase();
                }, { once: true });
            }

            // ticket request check to display modal to user
            const ticketRequestInput = document.getElementById('ticket-request');
            if (ticketRequestInput && ticketRequestInput.value === 'true') {
                const ticketRequestReserveFundsInput = document.getElementById('ticket-request-reserve-funds');
                const isReserveFunds = ticketRequestReserveFundsInput && ticketRequestReserveFundsInput.value === 'true';
                const modalId = isReserveFunds ? 'ticketRequestReserveFundsModal' : 'ticketRequestModal';
                const modalButtonId = isReserveFunds ? 'ticket-request-reserve-funds-modal-ok' : 'ticket-request-modal-ok';
                showTicketRequestModal(modalId, modalButtonId);
            } else {
                continuePurchase();
            }
        }

        function loadTicketsContainer() {
            var peerToPeerResaleOptions = $("#peertopeer-resale-options");

            if (peerToPeerResaleOptions.length > 0) {
                peerToPeerResaleOptions.fadeIn("slow");
            }

            // reset zippay
            $('.zippay-banner-small-info-text').text('');
            $('.ticket-type-quantity > select').change(function () {
                $(window).trigger('eventPageBasketChanged');
            })
        }

        function validateOfferCodeTicketLimit() {
            var $offerCodeExists = $('#offer-code-ticket-limit');
            var offercodeExists = $offerCodeExists.length;
            var offercodeTicketLimit = parseInt($offerCodeExists.val());
            var ticketsUsed = 0;
            var result = false;
            if (offercodeExists) {
                // iterate through each ticket type looking for ticket types that have offer code applied to them
                $('select[name^="lQuantity"]').each(function (index, aSelect) {
                    var hasOfferCodeApplied = $(this).parent('td').attr('data-offercode-applied-to-ticket') === 'True';
                    if (hasOfferCodeApplied) {
                        var selectedValue = parseInt($(aSelect).val());
                        ticketsUsed += selectedValue;
                    }
                });

                if (ticketsUsed > offercodeTicketLimit) {
                    result = false;
                } else {
                    result = true;
                }
            } else {
                // not offer code to validate
                result = true;
            }
            return result;
        }

        function animateOfferCodes() {
            $(".event-offercodeapplied").removeClass("offercode-initial");
        }

        function setFormTarget(target) {
            $('#event-tickets-form').attr('target', target);
        }

        function loadTicketHistory(forPhoneBooking) {
            try {
                var purchaseHistory = commonModule.getPurchaseHistory(forPhoneBooking);

                if (!purchaseHistory || !purchaseHistory.events) {
                    return;
                }

                // get event
                var eventId = $("#event-eventid").val();
                var event = purchaseHistory.events[eventId];
                if (!event) {
                    return;
                }

                // get ticket types
                var ticketTypes = event.TicketTypes;
                if (!ticketTypes) {
                    return;
                }

                ticketTypes.forEach(populateTicketTypeWithHistory);
            } catch (ex) {
                console.error(ex);
                console.log("Error loading Moshtix purchase history");
            }
        }

        function populateTicketTypeWithHistory(ticketType) {
            // set historical quantity on quantity
            var elem = $('.ticket-type-quantity.col-quantity-' + ticketType.TicketTypeId);
            elem.data("historical-quantity", ticketType.Quantity);
        }


        function ticketQuantityChanged() {
            loadTicketHistory();
            recalculateAllowedQuantityValues();
            recalculateGroupTotals();
            checkGroupDependencies();

            $('select[name^="lQuantity"]').change(function () {
                recalculateAllowedQuantityValues();
                recalculateGroupTotals();
                checkGroupDependencies();
            });
        }

        $('select[name^="lQuantity"]').change(function () {
            recalculateAllowedQuantityValues();
            recalculateGroupTotals();
            checkGroupDependencies();
            handleBuyNowPayLaterMessage();
        });

        function showBuyNowPayLaterDefaultBanner() {
            var showBanner = false;

            if (gatewayBuyNowPayLater) {
                $(".ticket-type-total span").each(function () {
                    var amount = $(this).text();
                    amount = amount.replace(/[^0-9.-]+/g, ""); //Removing currency symbol
                    amount = parseFloat(amount);

                    if ((amount + transactionFee) >= 20) {
                        //At least one ticket + trans fee is >= $20 therefore show default banner
                        showBanner = true;
                        return false; //break
                    }
                });
            }

            if (showBanner) {
                $("#" + gatewayBuyNowPayLater + "-promo-default").show();
                $("#" + gatewayBuyNowPayLater + "-promo").hide();
                $("#" + gatewayBuyNowPayLater + "-banner").show();
            } else {
                $("#" + gatewayBuyNowPayLater + "-banner").hide();
            }
        }

        function handleBuyNowPayLaterMessage() {
            if (gatewayBuyNowPayLater) {
                var totalTicketsAmount = 0;
                $(".ticket-type-costs-and-quantity").each(function () {
                    var amount = $(this).find(".ticket-type-total span").text();
                    amount = amount.replace(/[^0-9.-]+/g, ""); //Removing currency symbol
                    amount = parseFloat(amount);

                    var quantity = parseInt($(this).find('select[name^="lQuantity"]').val());

                    totalTicketsAmount += amount * quantity;
                });

                var totalAmount = totalTicketsAmount + transactionFee;
                if (totalAmount >= 20) {
                    var weeklyAmount = (totalAmount / 10).toFixed(2);

                    $("#" + gatewayBuyNowPayLater + "-promo-default").hide();
                    $("#" + gatewayBuyNowPayLater + "-promo").show();
                    $("#" + gatewayBuyNowPayLater + "-weekly-amount").text(weeklyAmount);
                    $("#" + gatewayBuyNowPayLater + "-banner").show();
                } else {
                    showBuyNowPayLaterDefaultBanner();
                }
            }
        }

        function checkGroupDependencies() {
            var groups = $('.with-dependencies');
            for (var i = 0; i < groups.length; i++) {
                var display = true;
                var requirementsMet = false;
                var usingHistorical = false;
                var group = $(groups[i]);
                var dependencies = group.attr('data-dependencies').split('|');
                for (var j = 0; j < dependencies.length; j++) {
                    //get dependency group
                    var dependentDisplayGroupId = dependencies[j];
                    var groupHeader = $('.col-display-group-quantity-' + dependentDisplayGroupId).parent();
                    //does it have tickets selected
                    var ticketsTotal = groupHeader.attr('data-quantity');
                    if (ticketsTotal > 0) {
                        requirementsMet = true;
                    }
                    //does it include historical purchases
                    var ticketsHistorical = groupHeader.attr('data-quantity-historical');
                    if (ticketsHistorical > 0) {
                        usingHistorical = true;
                    }
                }
                if (!requirementsMet) {
                    display = false;
                }
                if (display) {
                    unlockGroup(group, usingHistorical);
                } else {
                    lockGroup(group);
                }
            }
            refreshGroupQuantities();
        }

        var assetsUrl = "/v2/assets/img/common/";

        function lockGroup(group) {
            var id = group.data("display-group-id");
            group.addClass("hidden-container");
            group.removeClass("unlocked-container");

            var quantitySelector = group.find('select[name^="lQuantity"]');
            quantitySelector.val(0);
            quantitySelector.prop("disabled", true);
            quantitySelector.parent().click(function () {
                if (quantitySelector.prop("disabled") === true && ticketTypeGroupModule) {
                    ticketTypeGroupModule.showDependencyDetails(id);
                }
            });

            var lockedImg = group.find(".display-group-lock-icon .locked-padlock");
            var unlockedImg = group.find(".display-group-lock-icon .unlocked-padlock");
            if (lockedImg.prop("src").indexOf("Padlock_Icon_Lock_Black_Static") === -1) {
                lockedImg.prop("src", assetsUrl + "Padlock_Icon_Lock_Black_Static.gif?a=");
            }
            unlockedImg.prop("src", "");
            lockedImg.show();
            unlockedImg.hide();

            group.find('.dependency-log-in').show();
            group.find('.already-purchased').hide();
        }

        function unlockGroup(group, usingHistorical) {
            group.addClass("unlocked-container");
            group.removeClass("hidden-container");
            group.find('select[name^="lQuantity"]').prop("disabled", false);

            var lockedImg = group.find(".display-group-lock-icon .locked-padlock");
            var unlockedImg = group.find(".display-group-lock-icon .unlocked-padlock");
            lockedImg.prop("src", "");

            if (unlockedImg.prop("src").indexOf("Padlock_Icon_Unlock_Black") === -1) {
                unlockedImg.prop("src", assetsUrl + "Padlock_Icon_Unlock_Black.gif?a=");
            }
            lockedImg.hide();
            unlockedImg.show();

            if (usingHistorical) {
                group.find('.dependency-log-in').hide();
                group.find('.already-purchased').show();
            }
        }

        function refreshGroupQuantities() {
            $('.display-group-quantity-label').each(
                function (index, element) {
                    var container = $(element).closest('.event-display-group-container,.event-child-display-group');
                    var ticketTypeCount = container.find('li.event-ticket-type').length;
                    var labelText = "See " + ticketTypeCount + " ticket";
                    labelText = ticketTypeCount == 1 ? labelText : labelText + "s";
                    $(element).text(labelText);
                    if (ticketTypeCount === 0) {
                        if (container.hasClass('hidden-initial')) {
                            container.slideUp();
                        } else {
                            container.hide();
                        }
                    }
                    else if (ticketTypeCount > 0 && !container.hasClass('hidden-container')) {
                        container.slideDown();
                        container.removeClass('hidden-initial');
                    }
                });
        }

        function recalculateGroupTotals() {
            $('.event-display-group-header').each(recalculateGroupTotal);
        }

        function recalculateGroupTotal(index, element) {

            var selected = $(element).next('.event-ticket-type-list').find('select[name^="lQuantity"]')
                .map(function (i, select) { return parseInt($(select).val()) }).get()
                .reduce(function (total, add) { return total + add; }, 0);
            var historical = $(element).next('.event-ticket-type-list').find('.ticket-type-quantity')
                .map(function (i, ticketType) {
                    return parseInt($(ticketType).data("historical-quantity"))
                }).get()
                .reduce(function (totalH, add) {
                    return totalH + add;
                }, 0);
            var total = selected + historical;
            if (total !== 0) {
                $(element).attr('data-quantity', total);
                $(element).attr('data-quantity-selected', selected);
                $(element).attr('data-quantity-historical', historical);
                $(element).find('.display-group-quantity-label').attr('data-quantity', total);
            } else {
                $(element).removeAttr('data-quantity');
                $(element).find('.display-group-quantity-label').removeAttr('data-quantity');
            }
        }

        function recalculateAllowedQuantityValues() {
            var maxPerOrder = parseInt($('#MaxTotalTicketsPerSale').val());
            var currentTicketsSelected = 0;
            $('select[name^="lQuantity"]').each(function () {
                currentTicketsSelected += parseInt($(this).val());
            });
            var remainingTicketsForOrder = maxPerOrder - currentTicketsSelected;

            $('select[name^="lQuantity"]').each(function (index, aSelect) {
                var selectedValue = parseInt($(aSelect).val());
                var ticketsRemainingAndIncluded = remainingTicketsForOrder + selectedValue; // add in the tickets selected from this tickettype
                var maxForTicketType = parseInt($(this).parent().attr('data-ticket-max-available-for-transaction'));
                var maxAllowed = Math.min(ticketsRemainingAndIncluded, maxForTicketType);

                var selectOptions = $(aSelect).find('option');
                for (var selectIndex = 1; selectIndex < selectOptions.length; selectIndex++) {
                    var jOption = $(selectOptions).eq(selectIndex);
                    if (jOption.val() > maxAllowed) {
                        jOption.prop('disabled', true);
                    } else {
                        jOption.prop('disabled', false);
                    }
                }
            });
        }

        return {
            setFormTarget: setFormTarget,
            initEvents: initEvents,
            animateOfferCodes: animateOfferCodes,
            loadEventVideo: function () { loadVideo(); },
            ticketQuantityChanged: ticketQuantityChanged,
            doesQueryStringParamExist: doesQueryStringParamExist,
            loadTicketsContainer: loadTicketsContainer,
            loadTicketHistory: loadTicketHistory,
            showWaitlistPopup: showWaitlistPopup,
            closePopupWaitlist: closePopupWaitlist
        };

        // ReSharper disable ThisInGlobalContext
    })(this, this.document);
// ReSharper restore ThisInGlobalContext;
var ticketTypeGroupModule = ticketTypeGroupModule || (function () {

    function showTicketTypeDetails(ticketTypeId) {
        var title = $("#ticket-type-name-" + ticketTypeId).html() + " Details";
        var content = $("#ticket-type-details-text-" + ticketTypeId).html();
        commonModule.showPopupOk(title, content);
    }

    function showDependencyDetails(groupId) {
        history.replaceState(undefined, undefined, "#" + groupId);
        var title = "Unlocking Tickets";
        var content = $("#dependency-details-text-" + groupId).html();
        commonModule.showPopupOk(title, content, "Close");
        var encodedUrl = encodeURIComponent(window.location.pathname + window.location.search);
        var linkWithReturn = $(".dependency-log-in a").prop("href") + "&ReturnUrl=" + encodedUrl;
        $(".dependency-log-in a").prop("href", linkWithReturn);
    }

    function hideDependencyDetails(groupId) {
        history.replaceState(undefined, undefined, "#group" + groupId);
        window.dispatchEvent(new HashChangeEvent("hashchange")); // make sure the scroll works
        commonModule.closePopup();
    }

    function showGroupSelectionStatus(groupId, entityType) {
        var currentTicketsSelected = 0;
        var selectionGroupId = entityType + "-group-quantity-selection-" + groupId + "-";
        $("select[name^=" + selectionGroupId + "]").each(function () {
            currentTicketsSelected += parseInt($(this).val());
        });

        var groupQuantity = $("#" + entityType + "-group-quantity-effective-" + groupId).val();
        var remainingTicketsForOrder = groupQuantity - currentTicketsSelected;

        var choiceElementBaseId = "#" + entityType + "-group-" + groupId + "-text-choice-";
        var choiceMade = $(choiceElementBaseId + "made");
        var choiceRemaining = $(choiceElementBaseId + "remaining");
        var choiceWarning = $(choiceElementBaseId + "warning");

        choiceMade.hide();
        choiceRemaining.hide();
        choiceWarning.hide();

        var groupSelectionStatus = $('div[id^="' + entityType + '-group-selection-status-"][id$="' + groupId + '"]');

        if (remainingTicketsForOrder === 0) {
            groupSelectionStatus.text("1");
            choiceMade.show();
        } else if (remainingTicketsForOrder > 0) {
            groupSelectionStatus.text("2");
            choiceRemaining.text((remainingTicketsForOrder > 1 ? remainingTicketsForOrder + " choices" : "1 choice") + " remaining");
            choiceRemaining.show();
        } else if (remainingTicketsForOrder < 0) {
            groupSelectionStatus.text("-1");
            choiceWarning.children("span").text("Choose " + (remainingTicketsForOrder < -1 ? Math.abs(remainingTicketsForOrder) + " less options" : "1 less option"));
            choiceWarning.show();
        }
    }

    function showValidationMessage(validationMessage, entityType) {
        var messageInfo = validationMessage.split("-");
        var messageType = messageInfo[0];
        var messageContent = validationMessage.replace(messageType + "-", "");

        var entityDescription = "";
        switch (entityType) {
            case "credits":
                entityDescription = "tickets' claim";
                break;
            case "package":
                entityDescription = "package options";
                break;
        }

        if (messageType === "error") {
            commonModule.showErrorMessage("#event-tickets-messages", messageContent);
        } else if (messageType === "warning") {
            $("#tickettype-group-selection-warning-list").html(messageContent);
            var popupTitle = "Remaining " + entityDescription;
            var popupContent = $("#tickettype-group-selection-warning-message").html();
            commonModule.showPopupOptions(popupTitle, popupContent, "Checkout");
        } else {
            commonModule.showErrorMessage("#event-tickets-messages", "Error validating " + entityDescription + " selection. Please refresh the page and try again.");
        }
    }

    function showTicketOptionsTerms() {
        var title = "Ticket options";
        var content = $("#tickettype-group-options-terms").html();
        commonModule.showPopupOk(title, content);
    }

    return {
        showTicketTypeDetails: showTicketTypeDetails,
        showDependencyDetails: showDependencyDetails,
        hideDependencyDetails: hideDependencyDetails,
        showTicketOptionsTerms: showTicketOptionsTerms,
        showGroupSelectionStatus: showGroupSelectionStatus,
        showValidationMessage: showValidationMessage
    };
})();;
var creditsModule = creditsModule || (function () {

    $(document).ready(function () {
        loadCreditsContainer();
    });

    function loadCreditsContainer() {
        var creditsOptions = $("#credits-options");

        if (creditsOptions.length > 0) {
            // Check if all groups have options available for selection.
            // Here we are not checking for "sold out" scenario rather if we have groups with ticket types attached to them.
            // This is because we might have sold packages with no option available yet.
            var creditsHaveGroupsWithAvailableOptions = false;
            $('[id*="credits-group-has-options-"]').each(function () {
                if ($(this).val().toUpperCase() === "TRUE") {
                    creditsHaveGroupsWithAvailableOptions = true;
                }
            });

            // Display the user credits panel
            if (creditsHaveGroupsWithAvailableOptions) {
                resetCreditsSelectionQuantities();
                creditsOptions.fadeIn("slow");
            }
        }
    }

    function resetCreditsSelectionQuantities() {

        // Iterate through all ticket types within groups of the same package and reset all drop downs values
        $('input[name^="credits-group-quantity-effective-"]').each(function () {
            var groupId = $(this).attr("name").split("-").pop();
            var groupQuantity = parseInt($(this).val());

            // Update options available text
            $("#credits-group-text-quantity-" + groupId).text(groupQuantity > 1 ? "up to " + groupQuantity : "1");

            // Update selection status text
            var choiceElementBaseId = "#credits-group-" + groupId + "-text-choice-";
            var choiceMade = $(choiceElementBaseId + "made");
            var choiceRemaining = $(choiceElementBaseId + "remaining");
            var choiceWarning = $(choiceElementBaseId + "warning");

            choiceMade.hide();
            choiceWarning.hide();

            choiceRemaining.text((groupQuantity > 1 ? groupQuantity + " choices" : "1 choice") + " remaining");
            choiceRemaining.show();

            // Iterate through each ticket type dropdown and set the quantity available for selection
            $('select[name^="credits-group-quantity-selection-' + groupId + '-"]').each(function () {
                // This value considers the limit set up on the ticket type, the available inventory and the resale inventory
                var maxQuantityAvailable = parseInt($(this).data("max-quantity-available"));

                // This value is the max selection limit per ticket type
                var maxQuantityOptions = parseInt($(this).data("max-quantity-options"));

                if (maxQuantityOptions > 0) {
                    // Safety check: make sure the limit on the ticket type is not higher than the group quantity. If so, it's a configuration mistake so we need to rectify it.
                    maxQuantityOptions = maxQuantityOptions > groupQuantity ? groupQuantity : maxQuantityOptions;
                } else {
                    // No limit set up on the ticket type, so we are going to use the group one
                    maxQuantityOptions = groupQuantity;
                }
                
                // Make sure we never increase the options more than what we have available for each specific ticket type
                var appliedQuantity = maxQuantityOptions > maxQuantityAvailable ? maxQuantityAvailable : maxQuantityOptions;

                $(this).children("option:not(:first)").remove();
                for (var i = 1; i <= appliedQuantity; ++i) {
                    $(this).append($("<option>", { value: i, text: i }));
                }
            });

            // Open the user credits groups container
            showCreditsContainer();
        });
    }

    function toggleCreditsContainer() {
        var button = $(".credits-title-bar");
        var defaultText = "show";
        $(".credits-container").slideToggle("slow", function () {
            var text = button.children("span").text();
            if (text === defaultText) {
                button.children("span").text("hide");
                button.children("div").children("img").attr("src", "/v2/Assets/img/common/icon_up_expand.png");
            } else {
                button.children("span").text(defaultText);
                button.children("div").children("img").attr("src", "/v2/Assets/img/common/icon_down_expand.png");
            }
        });
    }

    function showCreditsContainer() {
        $(".credits-container").slideDown("slow", function () {
            var button = $(".credits-title-bar");
            button.children("span").text("hide");
            button.children("div").children("img").attr("src", "/v2/Assets/img/common/icon_up_expand.png");
        });
    }

    function validateCredits() {
        var invalidGroupsId = [];
        var incompleteGroupsId = [];
        var creditsRedeemedFully = false;

        $('div[class="credits-group-selection-status"]').each(function () {
            var groupId = parseInt($(this).data("group-id"));
            var groupStatus = parseInt($(this).text());
            
            /* groupStatus: 0 = default, 1 = complete, 2 = incomplete, -1 = error */

            if (groupStatus === -1) {
                invalidGroupsId.push(groupId);
                showCreditsContainer();
            } else if (groupStatus === 2) {
                var ticketsSelected = 0;
                var selectionGroupId = "credits-group-quantity-selection-" + groupId + "-";
                $("select[name^=" + selectionGroupId + "]").each(function () {
                    ticketsSelected += parseInt($(this).val());
                });

                if (ticketsSelected > 0) {
                    incompleteGroupsId.push(groupId);
                }
                
            } else if (groupStatus === 1) {
                creditsRedeemedFully = true;
            }
        });

        var errorMessage = "error-";

        // We need to show the error/warning message in order of priority, and one message type only,
        // therefore we process errors first and exit once a message type has been found.
        if (invalidGroupsId.length > 0) {
            if (invalidGroupsId.length === 1) {
                errorMessage += "One of your claims has exeeded the amount allowed for its specific group. Please reduce the amount selected.";
            } else {
                errorMessage += "More than one of your claims has exceeded the amount allowed for its specific group. Please reduce the amount selected.";
            }

            return errorMessage;

        } else if (incompleteGroupsId.length > 0) {
            //return "warning-" + message;
            return "success"; //We are not planning to show anything yet in case the user selects only few of his entitlements. Else, uncomment and update the above code. 

        } else if (creditsRedeemedFully) {
            return "success";
        }

        return "";
    }

    return {
        loadCreditsContainer: loadCreditsContainer,
        toggleCreditsContainer: toggleCreditsContainer,
        validateCredits: validateCredits
    };
})();;
var peerToPeerResaleModule = peerToPeerResaleModule || (function () {

    $(document).ready(function () {
        loadTicketsContainer();
    });

    function loadTicketsContainer() {
        var peerToPeerResaleOptions = $("#peertopeer-resale-options");

        if (peerToPeerResaleOptions.length > 0) {
            peerToPeerResaleOptions.fadeIn("slow");
        }
    }

    function toggleTicketsContainer() {
        var button = $(".peertopeer-resale-title-bar");
        var defaultText = "show";
        $(".peertopeer-resale-container").slideToggle("slow", function () {
            var text = button.children("span").text();
            if (text === defaultText) {
                button.children("span").text("hide");
                button.children("div").children("img").attr("src", "/v2/Assets/img/common/icon_up_expand.png");
            } else {
                button.children("span").text(defaultText);
                button.children("div").children("img").attr("src", "/v2/Assets/img/common/icon_down_expand.png");
            }
        });
    }

    return {
        loadTicketsContainer: loadTicketsContainer,
        toggleTicketsContainer: toggleTicketsContainer
    };
})();;
var packageModule = packageModule || (function () {
    var singleQuoteLeftHtml = "&#8216;";
    var singleQuoteRightHtml = "&#8217;";
    var dashHtml = "&#8211;";
    var breakTagHtml = "<br />";
    var boldOpenTagHtml = "<strong>";
    var boldCloseTagHtml = "</strong>";

    function resetPackageStatus(packageId, status) {
        // Iterate through all groups within a package and reset all statuses to 0 (0 = default, 1 = complete, 2 = incomplete, -1 = error)
        $('div[id^="package-group-selection-status-' + packageId + '-"]').each(function () {
            $(this).text(status);
        });
    }

    function resetPackageSelectionQuantities(packageId, selectedQuantity) {
        resetPackageStatus(packageId, 2); // Set status to 2 (incomplete) as the user has selected a quantity for the package

        // Iterate through all ticket types within groups of the same package and reset all drop downs values
        $('input[name^="package-group-quantity-default-' + packageId + '-"]').each(function () {
            var groupId = $(this).attr("name").split("-").pop();
            var groupQuantity = parseInt($(this).val());

            var effectiveGroupQuantity = groupQuantity * selectedQuantity;

            // Update options available text
            $("#package-group-quantity-effective-" + groupId).val(effectiveGroupQuantity);
            $("#package-group-text-quantity-" + groupId).text(effectiveGroupQuantity > 1 ? "up to " + effectiveGroupQuantity : "1");

            // Update selection status text
            var choiceElementBaseId = "#package-group-" + groupId + "-text-choice-";
            var choiceMade = $(choiceElementBaseId + "made");
            var choiceRemaining = $(choiceElementBaseId + "remaining");
            var choiceWarning = $(choiceElementBaseId + "warning");

            choiceMade.hide();
            choiceWarning.hide();

            choiceRemaining.text((effectiveGroupQuantity > 1 ? effectiveGroupQuantity + " choices" : "1 choice") + " remaining");
            choiceRemaining.show();

            // Iterate through each ticket type dropdown and set the quantity available for selection
            $('select[name^="package-group-quantity-selection-' + groupId + '-"]').each(function () {
                // This value considers the limit set up on the ticket type, the available inventory and the resale inventory
                var maxQuantityAvailable = parseInt($(this).data("max-quantity-available"));

                // This value is the max selection limit per ticket type
                var maxQuantityOptions = parseInt($(this).data("max-quantity-options"));

                if (maxQuantityOptions > 0) {
                    // Safety check: make sure the limit on the ticket type is not higher than the group quantity. If so, it's a package configuration mistake so we need to rectify it.
                    maxQuantityOptions = maxQuantityOptions > groupQuantity ? groupQuantity : maxQuantityOptions;
                } else {
                    // No limit set up on the ticket type, so we are going to use the group one
                    maxQuantityOptions = groupQuantity;
                }

                // Calculate the selectable quantity per ticket type
                var effectiveTicketTypeQuantity = maxQuantityOptions * selectedQuantity;

                // Make sure we never increase the options more than what we have available for each specific ticket type
                var appliedQuantity = effectiveTicketTypeQuantity > maxQuantityAvailable ? maxQuantityAvailable : effectiveTicketTypeQuantity;

                $(this).children("option:not(:first)").remove();
                for (var i = 1; i <= appliedQuantity; ++i) {
                    $(this).append($("<option>", { value: i, text: i }));
                }
            });

            // Open the package groups container
            $("#package-options-container-" + packageId).slideDown("slow", function () {
                var button = $(this).prev("div");
                button.children("span").text("Hide Options");
                button.children("img").attr("src", "/v2/Assets/img/common/icon_up_expand.png");
            });
        });
    }

    function showPackageOptionsMainContainer(elem, packageId, ticketTypeId) {
        var packageOptions = $("#package-options-" + packageId);

        var collectorTicketDeliveryDeadlinePassed = false;
        var collectorDeadline = $("#CollectorTicketDeadlinePassed-" + ticketTypeId);
        var isCollector = $(".is-collector-ticket-checked" + ticketTypeId);

        if (collectorDeadline.closest('.ticket-type-quantity').find('.select_medium').val() > 0 && collectorDeadline.val().toUpperCase() === "TRUE"
            && isCollector.val().toUpperCase() === "TRUE") {
            collectorTicketDeliveryDeadlinePassed = true;
        }

        if (collectorTicketDeliveryDeadlinePassed == true) {
            $("#collector-ticket-delivery-warning").css("display", "flex");
        }
        else {
            $("#collector-ticket-delivery-warning").css("display", "none");
        }

        if (packageOptions.length > 0) {
            // Check if all groups have options available for selection.
            // Here we are not checking for "sold out" scenario rather if we have groups with ticket types attached to them.
            // This is because we might want to sell packages with no option available yet, but allow users to come back and redeem the credits generated.
            var packageHaveGroupsWithAvailableOptions = false;
            $('[id*="package-group-has-options-' + packageId + '"]').each(function () {
                if ($(this).val().toUpperCase() === "TRUE") {
                    packageHaveGroupsWithAvailableOptions = true;
                }
            });

            // Display/hide the options panel
            if (packageHaveGroupsWithAvailableOptions) {
                var selectedQuantity = $(elem).val(); // Quantity of packages selected
                if (selectedQuantity > 0) {
                    resetPackageSelectionQuantities(packageId, selectedQuantity);
                    packageOptions.fadeIn("slow");
                } else {
                    resetPackageStatus(packageId, 0); // Set status to 0 (default) as the user has selected no quantity for the package
                    packageOptions.fadeOut("slow");
                }
            }
        }
    }

    function togglePackageOptionsContainer(packageId) {
        var button = $("#package-options-button-configure-" + packageId);
        var defaultText = "Configure Options";
        $("#package-options-container-" + packageId).slideToggle("slow", function () {
            var text = button.children("span").text();
            if (text === defaultText) {
                button.children("span").text("Hide Options");
                button.children("img").attr("src", "/v2/Assets/img/common/icon_up_expand.png");
            } else {
                button.children("span").text(defaultText);
                button.children("img").attr("src", "/v2/Assets/img/common/icon_down_expand.png");
            }
        });
    }

    function getPackagesNamesString(packagesNames) {
        var packagesNamesString = "";
        var packagesNamesLength = packagesNames.length;

        // Concatenate packages names
        for (var i = 0; i < packagesNamesLength; i++) {
            packagesNamesString += singleQuoteLeftHtml + packagesNames[i] + singleQuoteRightHtml;
            if (packagesNamesLength > 1) {
                packagesNamesString += packagesNamesLength === (i + 2) ? " and " : (packagesNamesLength === (i + 1) ? "" : ", ");
            }
        }

        return packagesNamesString;
    }

    function getPackagesNamesHtml(packagesNames) {
        var packagesNamesHtml = "";
        var packagesNamesLength = packagesNames.length;

        // List packages names
        for (var i = 0; i < packagesNamesLength; i++) {
            packagesNamesHtml += dashHtml + " " + singleQuoteLeftHtml + packagesNames[i] + singleQuoteRightHtml + breakTagHtml;
        }

        return boldOpenTagHtml + packagesNamesHtml + boldCloseTagHtml;
    }

    function showPackageOptionsContainer(packageId) {
        $("#package-options-" + packageId).fadeIn("slow");
        var button = $("#package-options-button-configure-" + packageId);
        button.children("span").text("Hide Options");
        button.children("img").attr("src", "/v2/Assets/img/common/icon_up_expand.png");
        $("#package-options-container-" + packageId).fadeIn("slow");
    }

    function validatePackages() {
        var invalidPackagesNames = [];
        var incompletePackagesNames = [];
        var incompleteCanReturnPackagesNames = [];
        var packagesIds = [];

        $('div[class="package-group-selection-status"]').each(function () {
            var packageTicketTypeId = parseInt($(this).data("ticket-type-id"));

            if (!packagesIds.includes(packageTicketTypeId)) {
                var issueFound = false;
                var packageId = $("#package-id-" + packageTicketTypeId).val();
                var packageName = $("#ticket-type-name-" + packageTicketTypeId).text();
                var packageTicketTypeSelectedQuantity = parseInt($('*[data-select-ticket-type-id="' + packageTicketTypeId + '"]').val());
                var groupStatus = parseInt($(this).text());

                /* groupStatus: 0 = default, 1 = complete, 2 = incomplete, -1 = error */

                if (packageTicketTypeSelectedQuantity > 0 && groupStatus === 0) {
                    issueFound = true;

                    // This can happen when a user navigates back to the event page from the payment page as the DOM elements lose any changes made via JS
                    incompletePackagesNames.push(packageName);

                    // Reset the package groups dropdowns as the DOM has lost the changes made via JS
                    resetPackageSelectionQuantities(packageId, packageTicketTypeSelectedQuantity);
                    showPackageOptionsContainer(packageId);
                } else if (groupStatus === -1) {
                    issueFound = true;
                    invalidPackagesNames.push(packageName);
                    showPackageOptionsContainer(packageId);
                } else if (packageTicketTypeSelectedQuantity > 0 && groupStatus === 2) {
                    issueFound = true;
                    var canReturn = $(this).data("allow-option-selection-later").toUpperCase() === "TRUE";
                    if (canReturn) {
                        incompleteCanReturnPackagesNames.push(packageName);
                    } else {
                        incompletePackagesNames.push(packageName);
                        showPackageOptionsContainer(packageId);
                    }
                }

                if (issueFound) {
                    // If we find an issue related to a group within a package, we want to skip validating the remaining groups within the same package to avoid a repetitive notification message
                    packagesIds.push(packageTicketTypeId);
                }
            }
        });
        
        var invalidPackagesNamesLength = invalidPackagesNames.length;
        var incompletePackagesNamesLength = incompletePackagesNames.length;
        var incompleteCanReturnPackagesNamesLength = incompleteCanReturnPackagesNames.length;
        var packagesNames = "";
        var errorMessage = "error-";
        
        // We need to show the error/warning message in order of priority, and one message type only,
        // therefore we process errors first and exit once a message type has been found.
        if (invalidPackagesNamesLength > 0) {
            packagesNames = getPackagesNamesString(invalidPackagesNames);

            if (invalidPackagesNamesLength === 1) {
                errorMessage += "The " + packagesNames + " ticket type has too many choices selected. Please reduce the amount selected.";
            } else {
                errorMessage += "The " + packagesNames + " ticket types have too many choices selected. Please reduce the amount selected.";
            }

            return errorMessage;

        } else if (incompletePackagesNamesLength > 0) {
            packagesNames = getPackagesNamesString(incompletePackagesNames);
            
            if (incompletePackagesNamesLength === 1) {
                errorMessage += "The " + packagesNames + " ticket type still has options that need to be configured.";
            } else {
                errorMessage += "The " + packagesNames + " ticket types still have options that need to be configured.";
            }

            return errorMessage;

        } else if (incompleteCanReturnPackagesNamesLength > 0) {
            packagesNames = getPackagesNamesHtml(incompleteCanReturnPackagesNames);

            return "warning-" + packagesNames;
        }
        
        return "";
    }

    return {
        showPackageOptionsMainContainer: showPackageOptionsMainContainer,
        togglePackageOptionsContainer: togglePackageOptionsContainer,
        validatePackages: validatePackages
    };
})();;


(function ($) {
    // *******************************************************************************************
    //              gallery event info plugin. apply to html generated from gallery partial view
    // *******************************************************************************************

    $.galleryeventinfo = function (element, options) {

        // plugin's default options
        var defaults = {
            onComplete: jQuery.noop
        }; // to avoid confusions, use "plugin" to reference the
        // current instance of the object
        var plugin = this;

        plugin.settings = {};
        var $element = $(element);    // reference to the actual DOM element

        // the "constructor" method that gets called when the object is created
        plugin.init = function () {

            // the plugin's final properties are the merged default and
            // user-provided options (if any)
            plugin.settings = $.extend({}, defaults, options);

            // load the event information from the event service for the displayed items
            var galleryLinks = $element.find('.mediagalleryoverlay');
            var eventIds = '';
            galleryLinks.each(function (index, iteratorElement) {
                var $iteratorElement = $(iteratorElement);
                eventIds = (eventIds + ',' + $iteratorElement.data('event-id'));
            });
            eventIds = eventIds.substring(1).substring(0, eventIds.length - 1); // remove first and last comma
            var data = {
                ids: $.parseJSON('[' + eventIds + ']')
            };

            $.getJSON(config.contextPath + 'api/event/get-gallery-events', $.param(data, true), function (result) {
                var $result = $(result);
                $result.each(function (index, iteratorElement) {
                    var $aHref = $element.find('#event-id-' + iteratorElement.EventId);
                    $aHref.find('.hoverinfo_date').html(iteratorElement.Date);
                    $aHref.find('.hoverinfo_description').html(iteratorElement.Venue);
                    var galleryName = $aHref.find('.hoverinfo_title').html();
                    var galleryId = $aHref.data('gallery-id');
                    // set the href
                    $aHref.attr('href', config.contextPath + 'gallery/photos/'
                        + iteratorElement.Year + '/' + iteratorElement.Month + '/'
                        + iteratorElement.Day + '/' + galleryName.slugify() + '/'
                        + iteratorElement.Venue.slugify() + '/' + galleryId);
                });

                plugin.settings.onComplete();
            });

        }; // public methods

        // private methods
        // call the "constructor" method
        plugin.init();

    }; // add the plugin to the jQuery.fn object
    $.fn.galleryeventinfo = function (options) {
        // iterate through the DOM elements we are attaching the plugin to
        return this.each(function () {
            // if plugin has not already been attached to the element
            if (undefined == $(this).data('galleryeventinfo')) {
                // create a new instance of the plugin
                // pass the DOM element and the user-provided options as arguments
                var plugin = new $.galleryeventinfo(this, options);
                // in the jQuery version of the element
                // store a reference to the plugin object
                // you can later access the plugin and its methods and properties like
                // element.data('pluginName').publicMethod(arg1, arg2, ... argn) or
                // element.data('pluginName').settings.propertyName
                $(this).data('galleryeventinfo', plugin);

            }
        });
        


    };
    
    // *******************************************************************************************
    //              feature photos plugin. apply to html generated by featured photos partial view
    // *******************************************************************************************

    $.galleryfeaturephoto = function (element, options) {

        // plugin's default options
        var defaults = {
            onComplete : jQuery.noop
        }; // to avoid confusions, use "plugin" to reference the
        // current instance of the object
        var plugin = this;

        plugin.settings = {};
        var $element = $(element);    // reference to the actual DOM element
        var $infoElement = $element.next(); // next div is the information div

        // the "constructor" method that gets called when the object is created
        plugin.init = function () {

            // the plugin's final properties are the merged default and
            // user-provided options (if any)
            plugin.settings = $.extend({}, defaults, options);

            // load the event information from the event service for the displayed items
            var $galleryLink = $element.find('.mediagalleryoverlay:first'); // events are the same
            var eventId = $galleryLink.data('event-id');
            if (eventId !== undefined) {
                var data = {
                    ids: $.parseJSON('[' + eventId + ']')
                };

                $.getJSON(config.contextPath + 'api/event/get-gallery-events', $.param(data, true), function (result) {
                    var $result = $(result);
                    var galleryName = $infoElement.find('#gallery_name').html();


                    $result.each(function (index, iteratorElement) {
                        // set the article date
                        $infoElement.find('#article_date').html(iteratorElement.Date);
                        $infoElement.find('#article_venue').html(iteratorElement.Venue);

                        var $aHrefs = $element.find('a'); // get all the links

                        $aHrefs.each(function (aIndex, aElement) {
                            var $aElement = $(aElement);
                            var galleryId = $aElement.data('gallery-id');
                            var ordinal = $aElement.data('ordinal');
                            $aElement.attr('href', config.contextPath + 'gallery/photos/'
                                + iteratorElement.Year + '/' + iteratorElement.Month + '/'
                                + iteratorElement.Day + '/' + galleryName.slugify() + '/'
                                + iteratorElement.Venue.slugify() + '/' + galleryId + '#' + ordinal);
                        });

                        plugin.settings.onComplete();
                    });
                });
            }

        }; // public methods

        // private methods
        // call the "constructor" method
        plugin.init();

    }; // add the plugin to the jQuery.fn object
    $.fn.galleryfeaturephoto = function (options) {
        // iterate through the DOM elements we are attaching the plugin to
        return this.each(function () {
            // if plugin has not already been attached to the element
            if (undefined == $(this).data('galleryfeaturephoto')) {
                // create a new instance of the plugin
                // pass the DOM element and the user-provided options as arguments
                var plugin = new $.galleryfeaturephoto(this, options);
                // in the jQuery version of the element
                // store a reference to the plugin object
                // you can later access the plugin and its methods and properties like
                // element.data('pluginName').publicMethod(arg1, arg2, ... argn) or
                // element.data('pluginName').settings.propertyName
                $(this).data('galleryfeaturephoto', plugin);

            }
        });



    };
})(jQuery);;
/*
 * International Telephone Input v18.1.3
 * https://github.com/jackocnr/intl-tel-input.git
 * Licensed under the MIT license
 */

// wrap in UMD
(function(factory) {
    if (typeof module === "object" && module.exports) module.exports = factory(); else window.intlTelInput = factory();
})(function(undefined) {
    "use strict";
    return function() {
        // Array of country objects for the flag dropdown.
        // Here is the criteria for the plugin to support a given country/territory
        // - It has an iso2 code: https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
        // - It has it's own country calling code (it is not a sub-region of another country): https://en.wikipedia.org/wiki/List_of_country_calling_codes
        // - It has a flag in the region-flags project: https://github.com/behdad/region-flags/tree/gh-pages/png
        // - It is supported by libphonenumber (it must be listed on this page): https://github.com/googlei18n/libphonenumber/blob/master/resources/ShortNumberMetadata.xml
        // Each country array has the following information:
        // [
        //    Country name,
        //    iso2 code,
        //    International dial code,
        //    Order (if >1 country with same dial code),
        //    Area codes
        // ]
        var allCountries = [ [ "Afghanistan (‫افغانستان‬‎)", "af", "93" ], [ "Albania (Shqipëri)", "al", "355" ], [ "Algeria (‫الجزائر‬‎)", "dz", "213" ], [ "American Samoa", "as", "1", 5, [ "684" ] ], [ "Andorra", "ad", "376" ], [ "Angola", "ao", "244" ], [ "Anguilla", "ai", "1", 6, [ "264" ] ], [ "Antigua and Barbuda", "ag", "1", 7, [ "268" ] ], [ "Argentina", "ar", "54" ], [ "Armenia (Հայաստան)", "am", "374" ], [ "Aruba", "aw", "297" ], [ "Ascension Island", "ac", "247" ], [ "Australia", "au", "61", 0 ], [ "Austria (Österreich)", "at", "43" ], [ "Azerbaijan (Azərbaycan)", "az", "994" ], [ "Bahamas", "bs", "1", 8, [ "242" ] ], [ "Bahrain (‫البحرين‬‎)", "bh", "973" ], [ "Bangladesh (বাংলাদেশ)", "bd", "880" ], [ "Barbados", "bb", "1", 9, [ "246" ] ], [ "Belarus (Беларусь)", "by", "375" ], [ "Belgium (België)", "be", "32" ], [ "Belize", "bz", "501" ], [ "Benin (Bénin)", "bj", "229" ], [ "Bermuda", "bm", "1", 10, [ "441" ] ], [ "Bhutan (འབྲུག)", "bt", "975" ], [ "Bolivia", "bo", "591" ], [ "Bosnia and Herzegovina (Босна и Херцеговина)", "ba", "387" ], [ "Botswana", "bw", "267" ], [ "Brazil (Brasil)", "br", "55" ], [ "British Indian Ocean Territory", "io", "246" ], [ "British Virgin Islands", "vg", "1", 11, [ "284" ] ], [ "Brunei", "bn", "673" ], [ "Bulgaria (България)", "bg", "359" ], [ "Burkina Faso", "bf", "226" ], [ "Burundi (Uburundi)", "bi", "257" ], [ "Cambodia (កម្ពុជា)", "kh", "855" ], [ "Cameroon (Cameroun)", "cm", "237" ], [ "Canada", "ca", "1", 1, [ "204", "226", "236", "249", "250", "263", "289", "306", "343", "354", "365", "367", "368", "382", "387", "403", "416", "418", "428", "431", "437", "438", "450", "584", "468", "474", "506", "514", "519", "548", "579", "581", "584", "587", "604", "613", "639", "647", "672", "683", "705", "709", "742", "753", "778", "780", "782", "807", "819", "825", "867", "873", "902", "905" ] ], [ "Cape Verde (Kabu Verdi)", "cv", "238" ], [ "Caribbean Netherlands", "bq", "599", 1, [ "3", "4", "7" ] ], [ "Cayman Islands", "ky", "1", 12, [ "345" ] ], [ "Central African Republic (République centrafricaine)", "cf", "236" ], [ "Chad (Tchad)", "td", "235" ], [ "Chile", "cl", "56" ], [ "China (中国)", "cn", "86" ], [ "Christmas Island", "cx", "61", 2, [ "89164" ] ], [ "Cocos (Keeling) Islands", "cc", "61", 1, [ "89162" ] ], [ "Colombia", "co", "57" ], [ "Comoros (‫جزر القمر‬‎)", "km", "269" ], [ "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)", "cd", "243" ], [ "Congo (Republic) (Congo-Brazzaville)", "cg", "242" ], [ "Cook Islands", "ck", "682" ], [ "Costa Rica", "cr", "506" ], [ "Côte d’Ivoire", "ci", "225" ], [ "Croatia (Hrvatska)", "hr", "385" ], [ "Cuba", "cu", "53" ], [ "Curaçao", "cw", "599", 0 ], [ "Cyprus (Κύπρος)", "cy", "357" ], [ "Czech Republic (Česká republika)", "cz", "420" ], [ "Denmark (Danmark)", "dk", "45" ], [ "Djibouti", "dj", "253" ], [ "Dominica", "dm", "1", 13, [ "767" ] ], [ "Dominican Republic (República Dominicana)", "do", "1", 2, [ "809", "829", "849" ] ], [ "Ecuador", "ec", "593" ], [ "Egypt (‫مصر‬‎)", "eg", "20" ], [ "El Salvador", "sv", "503" ], [ "Equatorial Guinea (Guinea Ecuatorial)", "gq", "240" ], [ "Eritrea", "er", "291" ], [ "Estonia (Eesti)", "ee", "372" ], [ "Eswatini", "sz", "268" ], [ "Ethiopia", "et", "251" ], [ "Falkland Islands (Islas Malvinas)", "fk", "500" ], [ "Faroe Islands (Føroyar)", "fo", "298" ], [ "Fiji", "fj", "679" ], [ "Finland (Suomi)", "fi", "358", 0 ], [ "France", "fr", "33" ], [ "French Guiana (Guyane française)", "gf", "594" ], [ "French Polynesia (Polynésie française)", "pf", "689" ], [ "Gabon", "ga", "241" ], [ "Gambia", "gm", "220" ], [ "Georgia (საქართველო)", "ge", "995" ], [ "Germany (Deutschland)", "de", "49" ], [ "Ghana (Gaana)", "gh", "233" ], [ "Gibraltar", "gi", "350" ], [ "Greece (Ελλάδα)", "gr", "30" ], [ "Greenland (Kalaallit Nunaat)", "gl", "299" ], [ "Grenada", "gd", "1", 14, [ "473" ] ], [ "Guadeloupe", "gp", "590", 0 ], [ "Guam", "gu", "1", 15, [ "671" ] ], [ "Guatemala", "gt", "502" ], [ "Guernsey", "gg", "44", 1, [ "1481", "7781", "7839", "7911" ] ], [ "Guinea (Guinée)", "gn", "224" ], [ "Guinea-Bissau (Guiné Bissau)", "gw", "245" ], [ "Guyana", "gy", "592" ], [ "Haiti", "ht", "509" ], [ "Honduras", "hn", "504" ], [ "Hong Kong (香港)", "hk", "852" ], [ "Hungary (Magyarország)", "hu", "36" ], [ "Iceland (Ísland)", "is", "354" ], [ "India (भारत)", "in", "91" ], [ "Indonesia", "id", "62" ], [ "Iran (‫ایران‬‎)", "ir", "98" ], [ "Iraq (‫العراق‬‎)", "iq", "964" ], [ "Ireland", "ie", "353" ], [ "Isle of Man", "im", "44", 2, [ "1624", "74576", "7524", "7924", "7624" ] ], [ "Israel (‫ישראל‬‎)", "il", "972" ], [ "Italy (Italia)", "it", "39", 0 ], [ "Jamaica", "jm", "1", 4, [ "876", "658" ] ], [ "Japan (日本)", "jp", "81" ], [ "Jersey", "je", "44", 3, [ "1534", "7509", "7700", "7797", "7829", "7937" ] ], [ "Jordan (‫الأردن‬‎)", "jo", "962" ], [ "Kazakhstan (Казахстан)", "kz", "7", 1, [ "33", "7" ] ], [ "Kenya", "ke", "254" ], [ "Kiribati", "ki", "686" ], [ "Kosovo", "xk", "383" ], [ "Kuwait (‫الكويت‬‎)", "kw", "965" ], [ "Kyrgyzstan (Кыргызстан)", "kg", "996" ], [ "Laos (ລາວ)", "la", "856" ], [ "Latvia (Latvija)", "lv", "371" ], [ "Lebanon (‫لبنان‬‎)", "lb", "961" ], [ "Lesotho", "ls", "266" ], [ "Liberia", "lr", "231" ], [ "Libya (‫ليبيا‬‎)", "ly", "218" ], [ "Liechtenstein", "li", "423" ], [ "Lithuania (Lietuva)", "lt", "370" ], [ "Luxembourg", "lu", "352" ], [ "Macau (澳門)", "mo", "853" ], [ "Madagascar (Madagasikara)", "mg", "261" ], [ "Malawi", "mw", "265" ], [ "Malaysia", "my", "60" ], [ "Maldives", "mv", "960" ], [ "Mali", "ml", "223" ], [ "Malta", "mt", "356" ], [ "Marshall Islands", "mh", "692" ], [ "Martinique", "mq", "596" ], [ "Mauritania (‫موريتانيا‬‎)", "mr", "222" ], [ "Mauritius (Moris)", "mu", "230" ], [ "Mayotte", "yt", "262", 1, [ "269", "639" ] ], [ "Mexico (México)", "mx", "52" ], [ "Micronesia", "fm", "691" ], [ "Moldova (Republica Moldova)", "md", "373" ], [ "Monaco", "mc", "377" ], [ "Mongolia (Монгол)", "mn", "976" ], [ "Montenegro (Crna Gora)", "me", "382" ], [ "Montserrat", "ms", "1", 16, [ "664" ] ], [ "Morocco (‫المغرب‬‎)", "ma", "212", 0 ], [ "Mozambique (Moçambique)", "mz", "258" ], [ "Myanmar (Burma) (မြန်မာ)", "mm", "95" ], [ "Namibia (Namibië)", "na", "264" ], [ "Nauru", "nr", "674" ], [ "Nepal (नेपाल)", "np", "977" ], [ "Netherlands (Nederland)", "nl", "31" ], [ "New Caledonia (Nouvelle-Calédonie)", "nc", "687" ], [ "New Zealand", "nz", "64" ], [ "Nicaragua", "ni", "505" ], [ "Niger (Nijar)", "ne", "227" ], [ "Nigeria", "ng", "234" ], [ "Niue", "nu", "683" ], [ "Norfolk Island", "nf", "672" ], [ "North Korea (조선 민주주의 인민 공화국)", "kp", "850" ], [ "North Macedonia (Северна Македонија)", "mk", "389" ], [ "Northern Mariana Islands", "mp", "1", 17, [ "670" ] ], [ "Norway (Norge)", "no", "47", 0 ], [ "Oman (‫عُمان‬‎)", "om", "968" ], [ "Pakistan (‫پاکستان‬‎)", "pk", "92" ], [ "Palau", "pw", "680" ], [ "Palestine (‫فلسطين‬‎)", "ps", "970" ], [ "Panama (Panamá)", "pa", "507" ], [ "Papua New Guinea", "pg", "675" ], [ "Paraguay", "py", "595" ], [ "Peru (Perú)", "pe", "51" ], [ "Philippines", "ph", "63" ], [ "Poland (Polska)", "pl", "48" ], [ "Portugal", "pt", "351" ], [ "Puerto Rico", "pr", "1", 3, [ "787", "939" ] ], [ "Qatar (‫قطر‬‎)", "qa", "974" ], [ "Réunion (La Réunion)", "re", "262", 0 ], [ "Romania (România)", "ro", "40" ], [ "Russia (Россия)", "ru", "7", 0 ], [ "Rwanda", "rw", "250" ], [ "Saint Barthélemy", "bl", "590", 1 ], [ "Saint Helena", "sh", "290" ], [ "Saint Kitts and Nevis", "kn", "1", 18, [ "869" ] ], [ "Saint Lucia", "lc", "1", 19, [ "758" ] ], [ "Saint Martin (Saint-Martin (partie française))", "mf", "590", 2 ], [ "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)", "pm", "508" ], [ "Saint Vincent and the Grenadines", "vc", "1", 20, [ "784" ] ], [ "Samoa", "ws", "685" ], [ "San Marino", "sm", "378" ], [ "São Tomé and Príncipe (São Tomé e Príncipe)", "st", "239" ], [ "Saudi Arabia (‫المملكة العربية السعودية‬‎)", "sa", "966" ], [ "Senegal (Sénégal)", "sn", "221" ], [ "Serbia (Србија)", "rs", "381" ], [ "Seychelles", "sc", "248" ], [ "Sierra Leone", "sl", "232" ], [ "Singapore", "sg", "65" ], [ "Sint Maarten", "sx", "1", 21, [ "721" ] ], [ "Slovakia (Slovensko)", "sk", "421" ], [ "Slovenia (Slovenija)", "si", "386" ], [ "Solomon Islands", "sb", "677" ], [ "Somalia (Soomaaliya)", "so", "252" ], [ "South Africa", "za", "27" ], [ "South Korea (대한민국)", "kr", "82" ], [ "South Sudan (‫جنوب السودان‬‎)", "ss", "211" ], [ "Spain (España)", "es", "34" ], [ "Sri Lanka (ශ්‍රී ලංකාව)", "lk", "94" ], [ "Sudan (‫السودان‬‎)", "sd", "249" ], [ "Suriname", "sr", "597" ], [ "Svalbard and Jan Mayen", "sj", "47", 1, [ "79" ] ], [ "Sweden (Sverige)", "se", "46" ], [ "Switzerland (Schweiz)", "ch", "41" ], [ "Syria (‫سوريا‬‎)", "sy", "963" ], [ "Taiwan (台灣)", "tw", "886" ], [ "Tajikistan", "tj", "992" ], [ "Tanzania", "tz", "255" ], [ "Thailand (ไทย)", "th", "66" ], [ "Timor-Leste", "tl", "670" ], [ "Togo", "tg", "228" ], [ "Tokelau", "tk", "690" ], [ "Tonga", "to", "676" ], [ "Trinidad and Tobago", "tt", "1", 22, [ "868" ] ], [ "Tunisia (‫تونس‬‎)", "tn", "216" ], [ "Turkey (Türkiye)", "tr", "90" ], [ "Turkmenistan", "tm", "993" ], [ "Turks and Caicos Islands", "tc", "1", 23, [ "649" ] ], [ "Tuvalu", "tv", "688" ], [ "U.S. Virgin Islands", "vi", "1", 24, [ "340" ] ], [ "Uganda", "ug", "256" ], [ "Ukraine (Україна)", "ua", "380" ], [ "United Arab Emirates (‫الإمارات العربية المتحدة‬‎)", "ae", "971" ], [ "United Kingdom", "gb", "44", 0 ], [ "United States", "us", "1", 0 ], [ "Uruguay", "uy", "598" ], [ "Uzbekistan (Oʻzbekiston)", "uz", "998" ], [ "Vanuatu", "vu", "678" ], [ "Vatican City (Città del Vaticano)", "va", "39", 1, [ "06698" ] ], [ "Venezuela", "ve", "58" ], [ "Vietnam (Việt Nam)", "vn", "84" ], [ "Wallis and Futuna (Wallis-et-Futuna)", "wf", "681" ], [ "Western Sahara (‫الصحراء الغربية‬‎)", "eh", "212", 1, [ "5288", "5289" ] ], [ "Yemen (‫اليمن‬‎)", "ye", "967" ], [ "Zambia", "zm", "260" ], [ "Zimbabwe", "zw", "263" ], [ "Åland Islands", "ax", "358", 1, [ "18" ] ] ];
        // loop over all of the countries above, restructuring the data to be objects with named keys
        for (var i = 0; i < allCountries.length; i++) {
            var c = allCountries[i];
            allCountries[i] = {
                name: c[0],
                iso2: c[1],
                dialCode: c[2],
                priority: c[3] || 0,
                areaCodes: c[4] || null
            };
        }
        "use strict";
        function _objectSpread(target) {
            for (var i = 1; i < arguments.length; i++) {
                var source = arguments[i] != null ? Object(arguments[i]) : {};
                var ownKeys = Object.keys(source);
                if (typeof Object.getOwnPropertySymbols === "function") {
                    ownKeys.push.apply(ownKeys, Object.getOwnPropertySymbols(source).filter(function(sym) {
                        return Object.getOwnPropertyDescriptor(source, sym).enumerable;
                    }));
                }
                ownKeys.forEach(function(key) {
                    _defineProperty(target, key, source[key]);
                });
            }
            return target;
        }
        function _defineProperty(obj, key, value) {
            key = _toPropertyKey(key);
            if (key in obj) {
                Object.defineProperty(obj, key, {
                    value: value,
                    enumerable: true,
                    configurable: true,
                    writable: true
                });
            } else {
                obj[key] = value;
            }
            return obj;
        }
        function _classCallCheck(instance, Constructor) {
            if (!(instance instanceof Constructor)) {
                throw new TypeError("Cannot call a class as a function");
            }
        }
        function _defineProperties(target, props) {
            for (var i = 0; i < props.length; i++) {
                var descriptor = props[i];
                descriptor.enumerable = descriptor.enumerable || false;
                descriptor.configurable = true;
                if ("value" in descriptor) descriptor.writable = true;
                Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor);
            }
        }
        function _createClass(Constructor, protoProps, staticProps) {
            if (protoProps) _defineProperties(Constructor.prototype, protoProps);
            if (staticProps) _defineProperties(Constructor, staticProps);
            Object.defineProperty(Constructor, "prototype", {
                writable: false
            });
            return Constructor;
        }
        function _toPropertyKey(arg) {
            var key = _toPrimitive(arg, "string");
            return typeof key === "symbol" ? key : String(key);
        }
        function _toPrimitive(input, hint) {
            if (typeof input !== "object" || input === null) return input;
            var prim = input[Symbol.toPrimitive];
            if (prim !== undefined) {
                var res = prim.call(input, hint || "default");
                if (typeof res !== "object") return res;
                throw new TypeError("@@toPrimitive must return a primitive value.");
            }
            return (hint === "string" ? String : Number)(input);
        }
        var intlTelInputGlobals = {
            getInstance: function getInstance(input) {
                var id = input.getAttribute("data-intl-tel-input-id");
                return window.intlTelInputGlobals.instances[id];
            },
            instances: {},
            // using a global like this allows us to mock it in the tests
            documentReady: function documentReady() {
                return document.readyState === "complete";
            }
        };
        if (typeof window === "object") {
            window.intlTelInputGlobals = intlTelInputGlobals;
        }
        // these vars persist through all instances of the plugin
        var id = 0;
        var defaults = {
            // whether or not to allow the dropdown
            allowDropdown: true,
            // auto insert dial code (A) on init, (B) on user selecting a country, (C) on calling setCountry
            // also listen for blur/submit and auto remove dial code if that's all there is
            autoInsertDialCode: false,
            // add a placeholder in the input with an example number for the selected country
            autoPlaceholder: "polite",
            // modify the parentClass
            customContainer: "",
            // modify the auto placeholder
            customPlaceholder: null,
            // append menu to specified element
            dropdownContainer: null,
            // don't display these countries
            excludeCountries: [],
            // format the input value during initialisation and on setNumber
            formatOnDisplay: true,
            // geoIp lookup function
            geoIpLookup: null,
            // inject a hidden input with this name, and on submit, populate it with the result of getNumber
            hiddenInput: "",
            // initial country
            initialCountry: "",
            // localized country names e.g. { 'de': 'Deutschland' }
            localizedCountries: null,
            // national vs international formatting for numbers e.g. placeholders and displaying existing numbers
            nationalMode: true,
            // display only these countries
            onlyCountries: [],
            // number type to use for placeholders
            placeholderNumberType: "MOBILE",
            // the countries at the top of the list. defaults to united states and united kingdom
            preferredCountries: [ "us", "gb" ],
            // display the country dial code next to the selected flag
            separateDialCode: false,
            // option to hide the flags - must be used with separateDialCode, or allowDropdown=false
            showFlags: true,
            // specify the path to the libphonenumber script to enable validation/formatting
            utilsScript: ""
        };
        // https://en.wikipedia.org/wiki/List_of_North_American_Numbering_Plan_area_codes#Non-geographic_area_codes
        var regionlessNanpNumbers = [ "800", "822", "833", "844", "855", "866", "877", "880", "881", "882", "883", "884", "885", "886", "887", "888", "889" ];
        // utility function to iterate over an object. can't use Object.entries or native forEach because
        // of IE11
        var forEachProp = function forEachProp(obj, callback) {
            var keys = Object.keys(obj);
            for (var i = 0; i < keys.length; i++) {
                callback(keys[i], obj[keys[i]]);
            }
        };
        // run a method on each instance of the plugin
        var forEachInstance = function forEachInstance(method) {
            forEachProp(window.intlTelInputGlobals.instances, function(key) {
                window.intlTelInputGlobals.instances[key][method]();
            });
        };
        // this is our plugin class that we will create an instance of
        // eslint-disable-next-line no-unused-vars
        var Iti = /*#__PURE__*/ function() {
            function Iti(input, options) {
                var _this = this;
                _classCallCheck(this, Iti);
                this.id = id++;
                this.telInput = input;
                this.activeItem = null;
                this.highlightedItem = null;
                // process specified options / defaults
                // alternative to Object.assign, which isn't supported by IE11
                var customOptions = options || {};
                this.options = {};
                forEachProp(defaults, function(key, value) {
                    _this.options[key] = customOptions.hasOwnProperty(key) ? customOptions[key] : value;
                });
                this.hadInitialPlaceholder = Boolean(input.getAttribute("placeholder"));
            }
            _createClass(Iti, [ {
                key: "_init",
                value: function _init() {
                    var _this2 = this;
                    // if in nationalMode, do not insert dial codes
                    if (this.options.nationalMode) {
                        this.options.autoInsertDialCode = false;
                    }
                    // if separateDialCode enabled, do not insert dial codes
                    if (this.options.separateDialCode) {
                        this.options.autoInsertDialCode = false;
                    }
                    // force showFlags=true if there's a dropdown and we're not displaying the dial code,
                    // as otherwise you just have a down arrow on it's own which doesn't make sense
                    var forceShowFlags = this.options.allowDropdown && !this.options.separateDialCode;
                    if (!this.options.showFlags && forceShowFlags) {
                        this.options.showFlags = true;
                    }
                    // we cannot just test screen size as some smartphones/website meta tags will report desktop
                    // resolutions
                    // Note: for some reason jasmine breaks if you put this in the main Plugin function with the
                    // rest of these declarations
                    // Note: to target Android Mobiles (and not Tablets), we must find 'Android' and 'Mobile'
                    this.isMobile = /Android.+Mobile|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
                    if (this.isMobile) {
                        // trigger the mobile dropdown css
                        document.body.classList.add("iti-mobile");
                        // on mobile, we want a full screen dropdown, so we must append it to the body
                        if (!this.options.dropdownContainer) {
                            this.options.dropdownContainer = document.body;
                        }
                    }
                    // these promises get resolved when their individual requests complete
                    // this way the dev can do something like iti.promise.then(...) to know when all requests are
                    // complete
                    if (typeof Promise !== "undefined") {
                        var autoCountryPromise = new Promise(function(resolve, reject) {
                            _this2.resolveAutoCountryPromise = resolve;
                            _this2.rejectAutoCountryPromise = reject;
                        });
                        var utilsScriptPromise = new Promise(function(resolve, reject) {
                            _this2.resolveUtilsScriptPromise = resolve;
                            _this2.rejectUtilsScriptPromise = reject;
                        });
                        this.promise = Promise.all([ autoCountryPromise, utilsScriptPromise ]);
                    } else {
                        // prevent errors when Promise doesn't exist
                        this.resolveAutoCountryPromise = this.rejectAutoCountryPromise = function() {};
                        this.resolveUtilsScriptPromise = this.rejectUtilsScriptPromise = function() {};
                    }
                    // in various situations there could be no country selected initially, but we need to be able
                    // to assume this variable exists
                    this.selectedCountryData = {};
                    // process all the data: onlyCountries, excludeCountries, preferredCountries etc
                    this._processCountryData();
                    // generate the markup
                    this._generateMarkup();
                    // set the initial state of the input value and the selected flag
                    this._setInitialState();
                    // start all of the event listeners: autoInsertDialCode, input keydown, selectedFlag click
                    this._initListeners();
                    // utils script, and auto country
                    this._initRequests();
                }
            }, {
                key: "_processCountryData",
                value: function _processCountryData() {
                    // process onlyCountries or excludeCountries array if present
                    this._processAllCountries();
                    // process the countryCodes map
                    this._processCountryCodes();
                    // process the preferredCountries
                    this._processPreferredCountries();
                    // translate countries according to localizedCountries option
                    if (this.options.localizedCountries) {
                        this._translateCountriesByLocale();
                    }
                    // sort countries by name
                    if (this.options.onlyCountries.length || this.options.localizedCountries) {
                        this.countries.sort(this._countryNameSort);
                    }
                }
            }, {
                key: "_addCountryCode",
                value: function _addCountryCode(iso2, countryCode, priority) {
                    if (countryCode.length > this.countryCodeMaxLen) {
                        this.countryCodeMaxLen = countryCode.length;
                    }
                    if (!this.countryCodes.hasOwnProperty(countryCode)) {
                        this.countryCodes[countryCode] = [];
                    }
                    // bail if we already have this country for this countryCode
                    for (var i = 0; i < this.countryCodes[countryCode].length; i++) {
                        if (this.countryCodes[countryCode][i] === iso2) {
                            return;
                        }
                    }
                    // check for undefined as 0 is falsy
                    var index = priority !== undefined ? priority : this.countryCodes[countryCode].length;
                    this.countryCodes[countryCode][index] = iso2;
                }
            }, {
                key: "_processAllCountries",
                value: function _processAllCountries() {
                    if (this.options.onlyCountries.length) {
                        var lowerCaseOnlyCountries = this.options.onlyCountries.map(function(country) {
                            return country.toLowerCase();
                        });
                        this.countries = allCountries.filter(function(country) {
                            return lowerCaseOnlyCountries.indexOf(country.iso2) > -1;
                        });
                    } else if (this.options.excludeCountries.length) {
                        var lowerCaseExcludeCountries = this.options.excludeCountries.map(function(country) {
                            return country.toLowerCase();
                        });
                        this.countries = allCountries.filter(function(country) {
                            return lowerCaseExcludeCountries.indexOf(country.iso2) === -1;
                        });
                    } else {
                        this.countries = allCountries;
                    }
                }
            }, {
                key: "_translateCountriesByLocale",
                value: function _translateCountriesByLocale() {
                    for (var i = 0; i < this.countries.length; i++) {
                        var iso = this.countries[i].iso2.toLowerCase();
                        if (this.options.localizedCountries.hasOwnProperty(iso)) {
                            this.countries[i].name = this.options.localizedCountries[iso];
                        }
                    }
                }
            }, {
                key: "_countryNameSort",
                value: function _countryNameSort(a, b) {
                    if (a.name < b.name) {
                        return -1;
                    }
                    if (a.name > b.name) {
                        return 1;
                    }
                    return 0;
                }
            }, {
                key: "_processCountryCodes",
                value: function _processCountryCodes() {
                    this.countryCodeMaxLen = 0;
                    // here we store just dial codes
                    this.dialCodes = {};
                    // here we store "country codes" (both dial codes and their area codes)
                    this.countryCodes = {};
                    // first: add dial codes
                    for (var i = 0; i < this.countries.length; i++) {
                        var c = this.countries[i];
                        if (!this.dialCodes[c.dialCode]) {
                            this.dialCodes[c.dialCode] = true;
                        }
                        this._addCountryCode(c.iso2, c.dialCode, c.priority);
                    }
                    // next: add area codes
                    // this is a second loop over countries, to make sure we have all of the "root" countries
                    // already in the map, so that we can access them, as each time we add an area code substring
                    // to the map, we also need to include the "root" country's code, as that also matches
                    for (var _i = 0; _i < this.countries.length; _i++) {
                        var _c = this.countries[_i];
                        // area codes
                        if (_c.areaCodes) {
                            var rootCountryCode = this.countryCodes[_c.dialCode][0];
                            // for each area code
                            for (var j = 0; j < _c.areaCodes.length; j++) {
                                var areaCode = _c.areaCodes[j];
                                // for each digit in the area code to add all partial matches as well
                                for (var k = 1; k < areaCode.length; k++) {
                                    var partialDialCode = _c.dialCode + areaCode.substr(0, k);
                                    // start with the root country, as that also matches this dial code
                                    this._addCountryCode(rootCountryCode, partialDialCode);
                                    this._addCountryCode(_c.iso2, partialDialCode);
                                }
                                // add the full area code
                                this._addCountryCode(_c.iso2, _c.dialCode + areaCode);
                            }
                        }
                    }
                }
            }, {
                key: "_processPreferredCountries",
                value: function _processPreferredCountries() {
                    this.preferredCountries = [];
                    for (var i = 0; i < this.options.preferredCountries.length; i++) {
                        var countryCode = this.options.preferredCountries[i].toLowerCase();
                        var countryData = this._getCountryData(countryCode, false, true);
                        if (countryData) {
                            this.preferredCountries.push(countryData);
                        }
                    }
                }
            }, {
                key: "_createEl",
                value: function _createEl(name, attrs, container) {
                    var el = document.createElement(name);
                    if (attrs) {
                        forEachProp(attrs, function(key, value) {
                            return el.setAttribute(key, value);
                        });
                    }
                    if (container) {
                        container.appendChild(el);
                    }
                    return el;
                }
            }, {
                key: "_generateMarkup",
                value: function _generateMarkup() {
                    // if autocomplete does not exist on the element and its form, then
                    // prevent autocomplete as there's no safe, cross-browser event we can react to, so it can
                    // easily put the plugin in an inconsistent state e.g. the wrong flag selected for the
                    // autocompleted number, which on submit could mean wrong number is saved
                    if (!this.telInput.hasAttribute("autocomplete") && !(this.telInput.form && this.telInput.form.hasAttribute("autocomplete"))) {
                        this.telInput.setAttribute("autocomplete", "off");
                    }
                    var _this$options = this.options, allowDropdown = _this$options.allowDropdown, separateDialCode = _this$options.separateDialCode, showFlags = _this$options.showFlags, customContainer = _this$options.customContainer, hiddenInput = _this$options.hiddenInput, dropdownContainer = _this$options.dropdownContainer;
                    // containers (mostly for positioning)
                    var parentClass = "iti";
                    if (allowDropdown) {
                        parentClass += " iti--allow-dropdown";
                    }
                    if (separateDialCode) {
                        parentClass += " iti--separate-dial-code";
                    }
                    if (showFlags) {
                        parentClass += " iti--show-flags";
                    }
                    if (customContainer) {
                        parentClass += " ".concat(customContainer);
                    }
                    var wrapper = this._createEl("div", {
                        "class": parentClass
                    });
                    this.telInput.parentNode.insertBefore(wrapper, this.telInput);
                    // only hide the flagsContainer if allowDropdown, showFlags and separateDialCode are all false
                    var showFlagsContainer = allowDropdown || showFlags || separateDialCode;
                    if (showFlagsContainer) {
                        this.flagsContainer = this._createEl("div", {
                            "class": "iti__flag-container"
                        }, wrapper);
                    }
                    wrapper.appendChild(this.telInput);
                    // selected flag (displayed to left of input)
                    // using Aria tags for "Select-Only Combobox Example"
                    // https://www.w3.org/WAI/ARIA/apg/patterns/combobox/examples/combobox-select-only/
                    if (showFlagsContainer) {
                        this.selectedFlag = this._createEl("div", _objectSpread({
                            "class": "iti__selected-flag"
                        }, allowDropdown && {
                            role: "combobox",
                            "aria-haspopup": "listbox",
                            "aria-controls": "iti-".concat(this.id, "__country-listbox"),
                            "aria-owns": "iti-".concat(this.id, "__country-listbox"),
                            "aria-expanded": "false",
                            "aria-label": "Telephone country code"
                        }), this.flagsContainer);
                    }
                    if (showFlags) {
                        this.selectedFlagInner = this._createEl("div", {
                            "class": "iti__flag"
                        }, this.selectedFlag);
                    }
                    if (this.selectedFlag && this.telInput.disabled) {
                        this.selectedFlag.setAttribute("aria-disabled", "true");
                    }
                    if (separateDialCode) {
                        this.selectedDialCode = this._createEl("div", {
                            "class": "iti__selected-dial-code"
                        }, this.selectedFlag);
                    }
                    if (allowDropdown) {
                        if (!this.telInput.disabled) {
                            // make element focusable and tab navigable
                            this.selectedFlag.setAttribute("tabindex", "0");
                        }
                        this.dropdownArrow = this._createEl("div", {
                            "class": "iti__arrow"
                        }, this.selectedFlag);
                        // country dropdown: preferred countries, then divider, then all countries
                        this.countryList = this._createEl("ul", {
                            "class": "iti__country-list iti__hide",
                            id: "iti-".concat(this.id, "__country-listbox"),
                            role: "listbox",
                            "aria-label": "List of countries"
                        });
                        if (this.preferredCountries.length) {
                            this._appendListItems(this.preferredCountries, "iti__preferred", true);
                            this._createEl("li", {
                                "class": "iti__divider",
                                role: "separator",
                                "aria-disabled": "true"
                            }, this.countryList);
                        }
                        this._appendListItems(this.countries, "iti__standard");
                        // create dropdownContainer markup
                        if (dropdownContainer) {
                            this.dropdown = this._createEl("div", {
                                "class": "iti iti--container"
                            });
                            this.dropdown.appendChild(this.countryList);
                        } else {
                            this.flagsContainer.appendChild(this.countryList);
                        }
                    }
                    if (hiddenInput) {
                        var hiddenInputName = hiddenInput;
                        var name = this.telInput.getAttribute("name");
                        if (name) {
                            var i = name.lastIndexOf("[");
                            // if input name contains square brackets, then give the hidden input the same name,
                            // replacing the contents of the last set of brackets with the given hiddenInput name
                            if (i !== -1) {
                                hiddenInputName = "".concat(name.substr(0, i), "[").concat(hiddenInputName, "]");
                            }
                        }
                        this.hiddenInput = this._createEl("input", {
                            type: "hidden",
                            name: hiddenInputName
                        });
                        wrapper.appendChild(this.hiddenInput);
                    }
                }
            }, {
                key: "_appendListItems",
                value: function _appendListItems(countries, className, preferred) {
                    // we create so many DOM elements, it is faster to build a temp string
                    // and then add everything to the DOM in one go at the end
                    var tmp = "";
                    // for each country
                    for (var i = 0; i < countries.length; i++) {
                        var c = countries[i];
                        var idSuffix = preferred ? "-preferred" : "";
                        // open the list item
                        tmp += "<li class='iti__country ".concat(className, "' tabIndex='-1' id='iti-").concat(this.id, "__item-").concat(c.iso2).concat(idSuffix, "' role='option' data-dial-code='").concat(c.dialCode, "' data-country-code='").concat(c.iso2, "' aria-selected='false'>");
                        // add the flag
                        if (this.options.showFlags) {
                            tmp += "<div class='iti__flag-box'><div class='iti__flag iti__".concat(c.iso2, "'></div></div>");
                        }
                        // and the country name and dial code
                        tmp += "<span class='iti__country-name'>".concat(c.name, "</span>");
                        tmp += "<span class='iti__dial-code'>+".concat(c.dialCode, "</span>");
                        // close the list item
                        tmp += "</li>";
                    }
                    this.countryList.insertAdjacentHTML("beforeend", tmp);
                }
            }, {
                key: "_setInitialState",
                value: function _setInitialState() {
                    // fix firefox bug: when first load page (with input with value set to number with intl dial
                    // code) and initialising plugin removes the dial code from the input, then refresh page,
                    // and we try to init plugin again but this time on number without dial code so get grey flag
                    var attributeValue = this.telInput.getAttribute("value");
                    var inputValue = this.telInput.value;
                    var useAttribute = attributeValue && attributeValue.charAt(0) === "+" && (!inputValue || inputValue.charAt(0) !== "+");
                    var val = useAttribute ? attributeValue : inputValue;
                    var dialCode = this._getDialCode(val);
                    var isRegionlessNanp = this._isRegionlessNanp(val);
                    var _this$options2 = this.options, initialCountry = _this$options2.initialCountry, autoInsertDialCode = _this$options2.autoInsertDialCode;
                    // if we already have a dial code, and it's not a regionlessNanp, we can go ahead and set the
                    // flag, else fall back to the default country
                    if (dialCode && !isRegionlessNanp) {
                        this._updateFlagFromNumber(val);
                    } else if (initialCountry !== "auto") {
                        // see if we should select a flag
                        if (initialCountry) {
                            this._setFlag(initialCountry.toLowerCase());
                        } else {
                            if (dialCode && isRegionlessNanp) {
                                // has intl dial code, is regionless nanp, and no initialCountry, so default to US
                                this._setFlag("us");
                            } else {
                                // no dial code and no initialCountry, so default to first in list
                                this.defaultCountry = this.preferredCountries.length ? this.preferredCountries[0].iso2 : this.countries[0].iso2;
                                if (!val) {
                                    this._setFlag(this.defaultCountry);
                                }
                            }
                        }
                        // if empty and autoInsertDialCode then insert the dial code
                        if (!val && autoInsertDialCode) {
                            this.telInput.value = "+".concat(this.selectedCountryData.dialCode);
                        }
                    }
                    // NOTE: if initialCountry is set to auto, that will be handled separately
                    // format - note this wont be run after _updateDialCode as that's only called if no val
                    if (val) {
                        this._updateValFromNumber(val);
                    }
                }
            }, {
                key: "_initListeners",
                value: function _initListeners() {
                    this._initKeyListeners();
                    if (this.options.autoInsertDialCode) {
                        this._initBlurListeners();
                    }
                    if (this.options.allowDropdown) {
                        this._initDropdownListeners();
                    }
                    if (this.hiddenInput) {
                        this._initHiddenInputListener();
                    }
                }
            }, {
                key: "_initHiddenInputListener",
                value: function _initHiddenInputListener() {
                    var _this3 = this;
                    this._handleHiddenInputSubmit = function() {
                        _this3.hiddenInput.value = _this3.getNumber();
                    };
                    if (this.telInput.form) {
                        this.telInput.form.addEventListener("submit", this._handleHiddenInputSubmit);
                    }
                }
            }, {
                key: "_getClosestLabel",
                value: function _getClosestLabel() {
                    var el = this.telInput;
                    while (el && el.tagName !== "LABEL") {
                        el = el.parentNode;
                    }
                    return el;
                }
            }, {
                key: "_initDropdownListeners",
                value: function _initDropdownListeners() {
                    var _this4 = this;
                    // hack for input nested inside label (which is valid markup): clicking the selected-flag to
                    // open the dropdown would then automatically trigger a 2nd click on the input which would
                    // close it again
                    this._handleLabelClick = function(e) {
                        // if the dropdown is closed, then focus the input, else ignore the click
                        if (_this4.countryList.classList.contains("iti__hide")) {
                            _this4.telInput.focus();
                        } else {
                            e.preventDefault();
                        }
                    };
                    var label = this._getClosestLabel();
                    if (label) {
                        label.addEventListener("click", this._handleLabelClick);
                    }
                    // toggle country dropdown on click
                    this._handleClickSelectedFlag = function() {
                        // only intercept this event if we're opening the dropdown
                        // else let it bubble up to the top ("click-off-to-close" listener)
                        // we cannot just stopPropagation as it may be needed to close another instance
                        if (_this4.countryList.classList.contains("iti__hide") && !_this4.telInput.disabled && !_this4.telInput.readOnly) {
                            _this4._showDropdown();
                        }
                    };
                    this.selectedFlag.addEventListener("click", this._handleClickSelectedFlag);
                    // open dropdown list if currently focused
                    this._handleFlagsContainerKeydown = function(e) {
                        var isDropdownHidden = _this4.countryList.classList.contains("iti__hide");
                        if (isDropdownHidden && [ "ArrowUp", "Up", "ArrowDown", "Down", " ", "Enter" ].indexOf(e.key) !== -1) {
                            // prevent form from being submitted if "ENTER" was pressed
                            e.preventDefault();
                            // prevent event from being handled again by document
                            e.stopPropagation();
                            _this4._showDropdown();
                        }
                        // allow navigation from dropdown to input on TAB
                        if (e.key === "Tab") {
                            _this4._closeDropdown();
                        }
                    };
                    this.flagsContainer.addEventListener("keydown", this._handleFlagsContainerKeydown);
                }
            }, {
                key: "_initRequests",
                value: function _initRequests() {
                    var _this5 = this;
                    // if the user has specified the path to the utils script, fetch it on window.load, else resolve
                    if (this.options.utilsScript && !window.intlTelInputUtils) {
                        // if the plugin is being initialised after the window.load event has already been fired
                        if (window.intlTelInputGlobals.documentReady()) {
                            window.intlTelInputGlobals.loadUtils(this.options.utilsScript);
                        } else {
                            // wait until the load event so we don't block any other requests e.g. the flags image
                            window.addEventListener("load", function() {
                                window.intlTelInputGlobals.loadUtils(_this5.options.utilsScript);
                            });
                        }
                    } else {
                        this.resolveUtilsScriptPromise();
                    }
                    if (this.options.initialCountry === "auto") {
                        this._loadAutoCountry();
                    } else {
                        this.resolveAutoCountryPromise();
                    }
                }
            }, {
                key: "_loadAutoCountry",
                value: function _loadAutoCountry() {
                    // 3 options:
                    // 1) already loaded (we're done)
                    // 2) not already started loading (start)
                    // 3) already started loading (do nothing - just wait for loading callback to fire)
                    if (window.intlTelInputGlobals.autoCountry) {
                        this.handleAutoCountry();
                    } else if (!window.intlTelInputGlobals.startedLoadingAutoCountry) {
                        // don't do this twice!
                        window.intlTelInputGlobals.startedLoadingAutoCountry = true;
                        if (typeof this.options.geoIpLookup === "function") {
                            this.options.geoIpLookup(function(countryCode) {
                                window.intlTelInputGlobals.autoCountry = countryCode.toLowerCase();
                                // tell all instances the auto country is ready
                                // TODO: this should just be the current instances
                                // UPDATE: use setTimeout in case their geoIpLookup function calls this callback straight
                                // away (e.g. if they have already done the geo ip lookup somewhere else). Using
                                // setTimeout means that the current thread of execution will finish before executing
                                // this, which allows the plugin to finish initialising.
                                setTimeout(function() {
                                    return forEachInstance("handleAutoCountry");
                                });
                            }, function() {
                                return forEachInstance("rejectAutoCountryPromise");
                            });
                        }
                    }
                }
            }, {
                key: "_initKeyListeners",
                value: function _initKeyListeners() {
                    var _this6 = this;
                    // update flag on keyup
                    this._handleKeyupEvent = function() {
                        if (_this6._updateFlagFromNumber(_this6.telInput.value)) {
                            _this6._triggerCountryChange();
                        }
                    };
                    this.telInput.addEventListener("keyup", this._handleKeyupEvent);
                    // update flag on cut/paste events (now supported in all major browsers)
                    this._handleClipboardEvent = function() {
                        // hack because "paste" event is fired before input is updated
                        setTimeout(_this6._handleKeyupEvent);
                    };
                    this.telInput.addEventListener("cut", this._handleClipboardEvent);
                    this.telInput.addEventListener("paste", this._handleClipboardEvent);
                }
            }, {
                key: "_cap",
                value: function _cap(number) {
                    var max = this.telInput.getAttribute("maxlength");
                    return max && number.length > max ? number.substr(0, max) : number;
                }
            }, {
                key: "_initBlurListeners",
                value: function _initBlurListeners() {
                    var _this7 = this;
                    // on blur or form submit: if just a dial code then remove it
                    this._handleSubmitOrBlurEvent = function() {
                        _this7._removeEmptyDialCode();
                    };
                    if (this.telInput.form) {
                        this.telInput.form.addEventListener("submit", this._handleSubmitOrBlurEvent);
                    }
                    this.telInput.addEventListener("blur", this._handleSubmitOrBlurEvent);
                }
            }, {
                key: "_removeEmptyDialCode",
                value: function _removeEmptyDialCode() {
                    if (this.telInput.value.charAt(0) === "+") {
                        var numeric = this._getNumeric(this.telInput.value);
                        // if just a plus, or if just a dial code
                        if (!numeric || this.selectedCountryData.dialCode === numeric) {
                            this.telInput.value = "";
                        }
                    }
                }
            }, {
                key: "_getNumeric",
                value: function _getNumeric(s) {
                    return s.replace(/\D/g, "");
                }
            }, {
                key: "_trigger",
                value: function _trigger(name) {
                    // have to use old school document.createEvent as IE11 doesn't support `new Event()` syntax
                    var e = document.createEvent("Event");
                    e.initEvent(name, true, true);
                    // can bubble, and is cancellable
                    this.telInput.dispatchEvent(e);
                }
            }, {
                key: "_showDropdown",
                value: function _showDropdown() {
                    this.countryList.classList.remove("iti__hide");
                    this.selectedFlag.setAttribute("aria-expanded", "true");
                    this._setDropdownPosition();
                    // update highlighting and scroll to active list item
                    if (this.activeItem) {
                        this._highlightListItem(this.activeItem, false);
                        this._scrollTo(this.activeItem, true);
                    }
                    // bind all the dropdown-related listeners: mouseover, click, click-off, keydown
                    this._bindDropdownListeners();
                    // update the arrow
                    this.dropdownArrow.classList.add("iti__arrow--up");
                    this._trigger("open:countrydropdown");
                }
            }, {
                key: "_toggleClass",
                value: function _toggleClass(el, className, shouldHaveClass) {
                    if (shouldHaveClass && !el.classList.contains(className)) {
                        el.classList.add(className);
                    } else if (!shouldHaveClass && el.classList.contains(className)) {
                        el.classList.remove(className);
                    }
                }
            }, {
                key: "_setDropdownPosition",
                value: function _setDropdownPosition() {
                    var _this8 = this;
                    if (this.options.dropdownContainer) {
                        this.options.dropdownContainer.appendChild(this.dropdown);
                    }
                    if (!this.isMobile) {
                        var pos = this.telInput.getBoundingClientRect();
                        // windowTop from https://stackoverflow.com/a/14384091/217866
                        var windowTop = window.pageYOffset || document.documentElement.scrollTop;
                        var inputTop = pos.top + windowTop;
                        var dropdownHeight = this.countryList.offsetHeight;
                        // dropdownFitsBelow = (dropdownBottom < windowBottom)
                        var dropdownFitsBelow = inputTop + this.telInput.offsetHeight + dropdownHeight < windowTop + window.innerHeight;
                        var dropdownFitsAbove = inputTop - dropdownHeight > windowTop;
                        // by default, the dropdown will be below the input. If we want to position it above the
                        // input, we add the dropup class.
                        this._toggleClass(this.countryList, "iti__country-list--dropup", !dropdownFitsBelow && dropdownFitsAbove);
                        // if dropdownContainer is enabled, calculate postion
                        if (this.options.dropdownContainer) {
                            // by default the dropdown will be directly over the input because it's not in the flow.
                            // If we want to position it below, we need to add some extra top value.
                            var extraTop = !dropdownFitsBelow && dropdownFitsAbove ? 0 : this.telInput.offsetHeight;
                            // calculate placement
                            this.dropdown.style.top = "".concat(inputTop + extraTop, "px");
                            this.dropdown.style.left = "".concat(pos.left + document.body.scrollLeft, "px");
                            // close menu on window scroll
                            this._handleWindowScroll = function() {
                                return _this8._closeDropdown();
                            };
                            window.addEventListener("scroll", this._handleWindowScroll);
                        }
                    }
                }
            }, {
                key: "_getClosestListItem",
                value: function _getClosestListItem(target) {
                    var el = target;
                    while (el && el !== this.countryList && !el.classList.contains("iti__country")) {
                        el = el.parentNode;
                    }
                    // if we reached the countryList element, then return null
                    return el === this.countryList ? null : el;
                }
            }, {
                key: "_bindDropdownListeners",
                value: function _bindDropdownListeners() {
                    var _this9 = this;
                    // when mouse over a list item, just highlight that one
                    // we add the class "highlight", so if they hit "enter" we know which one to select
                    this._handleMouseoverCountryList = function(e) {
                        // handle event delegation, as we're listening for this event on the countryList
                        var listItem = _this9._getClosestListItem(e.target);
                        if (listItem) {
                            _this9._highlightListItem(listItem, false);
                        }
                    };
                    this.countryList.addEventListener("mouseover", this._handleMouseoverCountryList);
                    // listen for country selection
                    this._handleClickCountryList = function(e) {
                        var listItem = _this9._getClosestListItem(e.target);
                        if (listItem) {
                            _this9._selectListItem(listItem);
                        }
                    };
                    this.countryList.addEventListener("click", this._handleClickCountryList);
                    // click off to close
                    // (except when this initial opening click is bubbling up)
                    // we cannot just stopPropagation as it may be needed to close another instance
                    var isOpening = true;
                    this._handleClickOffToClose = function() {
                        if (!isOpening) {
                            _this9._closeDropdown();
                        }
                        isOpening = false;
                    };
                    document.documentElement.addEventListener("click", this._handleClickOffToClose);
                    // listen for up/down scrolling, enter to select, or letters to jump to country name.
                    // use keydown as keypress doesn't fire for non-char keys and we want to catch if they
                    // just hit down and hold it to scroll down (no keyup event).
                    // listen on the document because that's where key events are triggered if no input has focus
                    var query = "";
                    var queryTimer = null;
                    this._handleKeydownOnDropdown = function(e) {
                        // prevent down key from scrolling the whole page,
                        // and enter key from submitting a form etc
                        e.preventDefault();
                        // up and down to navigate
                        if (e.key === "ArrowUp" || e.key === "Up" || e.key === "ArrowDown" || e.key === "Down") {
                            _this9._handleUpDownKey(e.key);
                        } else if (e.key === "Enter") {
                            _this9._handleEnterKey();
                        } else if (e.key === "Escape") {
                            _this9._closeDropdown();
                        } else if (/^[a-zA-ZÀ-ÿа-яА-Я ]$/.test(e.key)) {
                            // jump to countries that start with the query string
                            if (queryTimer) {
                                clearTimeout(queryTimer);
                            }
                            query += e.key.toLowerCase();
                            _this9._searchForCountry(query);
                            // if the timer hits 1 second, reset the query
                            queryTimer = setTimeout(function() {
                                query = "";
                            }, 1e3);
                        }
                    };
                    document.addEventListener("keydown", this._handleKeydownOnDropdown);
                }
            }, {
                key: "_handleUpDownKey",
                value: function _handleUpDownKey(key) {
                    var next = key === "ArrowUp" || key === "Up" ? this.highlightedItem.previousElementSibling : this.highlightedItem.nextElementSibling;
                    if (next) {
                        // skip the divider
                        if (next.classList.contains("iti__divider")) {
                            next = key === "ArrowUp" || key === "Up" ? next.previousElementSibling : next.nextElementSibling;
                        }
                        this._highlightListItem(next, true);
                    }
                }
            }, {
                key: "_handleEnterKey",
                value: function _handleEnterKey() {
                    if (this.highlightedItem) {
                        this._selectListItem(this.highlightedItem);
                    }
                }
            }, {
                key: "_searchForCountry",
                value: function _searchForCountry(query) {
                    for (var i = 0; i < this.countries.length; i++) {
                        if (this._startsWith(this.countries[i].name, query)) {
                            var listItem = this.countryList.querySelector("#iti-".concat(this.id, "__item-").concat(this.countries[i].iso2));
                            // update highlighting and scroll
                            this._highlightListItem(listItem, false);
                            this._scrollTo(listItem, true);
                            break;
                        }
                    }
                }
            }, {
                key: "_startsWith",
                value: function _startsWith(a, b) {
                    return a.substr(0, b.length).toLowerCase() === b;
                }
            }, {
                key: "_updateValFromNumber",
                value: function _updateValFromNumber(originalNumber) {
                    var number = originalNumber;
                    if (this.options.formatOnDisplay && window.intlTelInputUtils && this.selectedCountryData) {
                        var useNational = this.options.nationalMode || number.charAt(0) !== "+" && !this.options.separateDialCode;
                        var _intlTelInputUtils$nu = intlTelInputUtils.numberFormat, NATIONAL = _intlTelInputUtils$nu.NATIONAL, INTERNATIONAL = _intlTelInputUtils$nu.INTERNATIONAL;
                        var format = useNational ? NATIONAL : INTERNATIONAL;
                        number = intlTelInputUtils.formatNumber(number, this.selectedCountryData.iso2, format);
                    }
                    number = this._beforeSetNumber(number);
                    this.telInput.value = number;
                }
            }, {
                key: "_updateFlagFromNumber",
                value: function _updateFlagFromNumber(originalNumber) {
                    // if we already have US/Canada selected, make sure the number starts
                    // with a +1 so _getDialCode will be able to extract the area code
                    // update: if we dont yet have selectedCountryData, but we're here (trying to update the flag
                    // from the number), that means we're initialising the plugin with a number that already has a
                    // dial code, so fine to ignore this bit
                    var number = originalNumber;
                    var selectedDialCode = this.selectedCountryData.dialCode;
                    var isNanp = selectedDialCode === "1";
                    if (number && isNanp && number.charAt(0) !== "+") {
                        if (number.charAt(0) !== "1") {
                            number = "1".concat(number);
                        }
                        number = "+".concat(number);
                    }
                    // if separateDialCode enabled, then consider the selected dial code to be part of the number
                    if (this.options.separateDialCode && selectedDialCode && number.charAt(0) !== "+") {
                        number = "+".concat(selectedDialCode).concat(number);
                    }
                    // try and extract valid dial code from input
                    var dialCode = this._getDialCode(number, true);
                    var numeric = this._getNumeric(number);
                    var countryCode = null;
                    if (dialCode) {
                        var countryCodes = this.countryCodes[this._getNumeric(dialCode)];
                        // check if the right country is already selected. this should be false if the number is
                        // longer than the matched dial code because in this case we need to make sure that if
                        // there are multiple country matches, that the first one is selected (note: we could
                        // just check that here, but it requires the same loop that we already have later)
                        var alreadySelected = countryCodes.indexOf(this.selectedCountryData.iso2) !== -1 && numeric.length <= dialCode.length - 1;
                        var isRegionlessNanpNumber = selectedDialCode === "1" && this._isRegionlessNanp(numeric);
                        // only update the flag if:
                        // A) NOT (we currently have a NANP flag selected, and the number is a regionlessNanp)
                        // AND
                        // B) the right country is not already selected
                        if (!isRegionlessNanpNumber && !alreadySelected) {
                            // if using onlyCountries option, countryCodes[0] may be empty, so we must find the first
                            // non-empty index
                            for (var j = 0; j < countryCodes.length; j++) {
                                if (countryCodes[j]) {
                                    countryCode = countryCodes[j];
                                    break;
                                }
                            }
                        }
                    } else if (number.charAt(0) === "+" && numeric.length) {
                        // invalid dial code, so empty
                        // Note: use getNumeric here because the number has not been formatted yet, so could contain
                        // bad chars
                        countryCode = "";
                    } else if (!number || number === "+") {
                        // empty, or just a plus, so default
                        countryCode = this.defaultCountry;
                    }
                    if (countryCode !== null) {
                        return this._setFlag(countryCode);
                    }
                    return false;
                }
            }, {
                key: "_isRegionlessNanp",
                value: function _isRegionlessNanp(number) {
                    var numeric = this._getNumeric(number);
                    if (numeric.charAt(0) === "1") {
                        var areaCode = numeric.substr(1, 3);
                        return regionlessNanpNumbers.indexOf(areaCode) !== -1;
                    }
                    return false;
                }
            }, {
                key: "_highlightListItem",
                value: function _highlightListItem(listItem, shouldFocus) {
                    var prevItem = this.highlightedItem;
                    if (prevItem) {
                        prevItem.classList.remove("iti__highlight");
                    }
                    this.highlightedItem = listItem;
                    this.highlightedItem.classList.add("iti__highlight");
                    this.selectedFlag.setAttribute("aria-activedescendant", listItem.getAttribute("id"));
                    if (shouldFocus) {
                        this.highlightedItem.focus();
                    }
                }
            }, {
                key: "_getCountryData",
                value: function _getCountryData(countryCode, ignoreOnlyCountriesOption, allowFail) {
                    var countryList = ignoreOnlyCountriesOption ? allCountries : this.countries;
                    for (var i = 0; i < countryList.length; i++) {
                        if (countryList[i].iso2 === countryCode) {
                            return countryList[i];
                        }
                    }
                    if (allowFail) {
                        return null;
                    }
                    throw new Error("No country data for '".concat(countryCode, "'"));
                }
            }, {
                key: "_setFlag",
                value: function _setFlag(countryCode) {
                    var prevCountry = this.selectedCountryData.iso2 ? this.selectedCountryData : {};
                    // do this first as it will throw an error and stop if countryCode is invalid
                    this.selectedCountryData = countryCode ? this._getCountryData(countryCode, false, false) : {};
                    // update the defaultCountry - we only need the iso2 from now on, so just store that
                    if (this.selectedCountryData.iso2) {
                        this.defaultCountry = this.selectedCountryData.iso2;
                    }
                    if (this.options.showFlags) {
                        this.selectedFlagInner.setAttribute("class", "iti__flag iti__".concat(countryCode));
                    }
                    // update the selected country's title attribute
                    if (this.selectedFlag) {
                        var title = countryCode ? "".concat(this.selectedCountryData.name, ": +").concat(this.selectedCountryData.dialCode) : "Unknown";
                        this.selectedFlag.setAttribute("title", title);
                    }
                    if (this.options.separateDialCode) {
                        var dialCode = this.selectedCountryData.dialCode ? "+".concat(this.selectedCountryData.dialCode) : "";
                        this.selectedDialCode.innerHTML = dialCode;
                        // offsetWidth is zero if input is in a hidden container during initialisation
                        var selectedFlagWidth = this.selectedFlag.offsetWidth || this._getHiddenSelectedFlagWidth();
                        // add 6px of padding after the grey selected-dial-code box, as this is what we use in the css
                        this.telInput.style.paddingLeft = "".concat(selectedFlagWidth + 6, "px");
                    }
                    // and the input's placeholder
                    this._updatePlaceholder();
                    // update the active list item
                    if (this.options.allowDropdown) {
                        var prevItem = this.activeItem;
                        if (prevItem) {
                            prevItem.classList.remove("iti__active");
                            prevItem.setAttribute("aria-selected", "false");
                        }
                        if (countryCode) {
                            // check if there is a preferred item first, else fall back to standard
                            var nextItem = this.countryList.querySelector("#iti-".concat(this.id, "__item-").concat(countryCode, "-preferred")) || this.countryList.querySelector("#iti-".concat(this.id, "__item-").concat(countryCode));
                            nextItem.setAttribute("aria-selected", "true");
                            nextItem.classList.add("iti__active");
                            this.activeItem = nextItem;
                        }
                    }
                    // return if the flag has changed or not
                    return prevCountry.iso2 !== countryCode;
                }
            }, {
                key: "_getHiddenSelectedFlagWidth",
                value: function _getHiddenSelectedFlagWidth() {
                    // to get the right styling to apply, all we need is a shallow clone of the container,
                    // and then to inject a deep clone of the selectedFlag element
                    var containerClone = this.telInput.parentNode.cloneNode();
                    containerClone.style.visibility = "hidden";
                    document.body.appendChild(containerClone);
                    var flagsContainerClone = this.flagsContainer.cloneNode();
                    containerClone.appendChild(flagsContainerClone);
                    var selectedFlagClone = this.selectedFlag.cloneNode(true);
                    flagsContainerClone.appendChild(selectedFlagClone);
                    var width = selectedFlagClone.offsetWidth;
                    containerClone.parentNode.removeChild(containerClone);
                    return width;
                }
            }, {
                key: "_updatePlaceholder",
                value: function _updatePlaceholder() {
                    var shouldSetPlaceholder = this.options.autoPlaceholder === "aggressive" || !this.hadInitialPlaceholder && this.options.autoPlaceholder === "polite";
                    if (window.intlTelInputUtils && shouldSetPlaceholder) {
                        var numberType = intlTelInputUtils.numberType[this.options.placeholderNumberType];
                        var placeholder = this.selectedCountryData.iso2 ? intlTelInputUtils.getExampleNumber(this.selectedCountryData.iso2, this.options.nationalMode, numberType) : "";
                        placeholder = this._beforeSetNumber(placeholder);
                        if (typeof this.options.customPlaceholder === "function") {
                            placeholder = this.options.customPlaceholder(placeholder, this.selectedCountryData);
                        }
                        this.telInput.setAttribute("placeholder", placeholder);
                    }
                }
            }, {
                key: "_selectListItem",
                value: function _selectListItem(listItem) {
                    // update selected flag and active list item
                    var flagChanged = this._setFlag(listItem.getAttribute("data-country-code"));
                    this._closeDropdown();
                    this._updateDialCode(listItem.getAttribute("data-dial-code"));
                    // focus the input
                    this.telInput.focus();
                    // put cursor at end - this fix is required for FF and IE11 (with auto inserting dial code),
                    // who try to put the cursor at the beginning the first time
                    var len = this.telInput.value.length;
                    this.telInput.setSelectionRange(len, len);
                    if (flagChanged) {
                        this._triggerCountryChange();
                    }
                }
            }, {
                key: "_closeDropdown",
                value: function _closeDropdown() {
                    this.countryList.classList.add("iti__hide");
                    this.selectedFlag.setAttribute("aria-expanded", "false");
                    this.selectedFlag.removeAttribute("aria-activedescendant");
                    // update the arrow
                    this.dropdownArrow.classList.remove("iti__arrow--up");
                    // unbind key events
                    document.removeEventListener("keydown", this._handleKeydownOnDropdown);
                    document.documentElement.removeEventListener("click", this._handleClickOffToClose);
                    this.countryList.removeEventListener("mouseover", this._handleMouseoverCountryList);
                    this.countryList.removeEventListener("click", this._handleClickCountryList);
                    // remove menu from container
                    if (this.options.dropdownContainer) {
                        if (!this.isMobile) {
                            window.removeEventListener("scroll", this._handleWindowScroll);
                        }
                        if (this.dropdown.parentNode) {
                            this.dropdown.parentNode.removeChild(this.dropdown);
                        }
                    }
                    this._trigger("close:countrydropdown");
                }
            }, {
                key: "_scrollTo",
                value: function _scrollTo(element, middle) {
                    var container = this.countryList;
                    // windowTop from https://stackoverflow.com/a/14384091/217866
                    var windowTop = window.pageYOffset || document.documentElement.scrollTop;
                    var containerHeight = container.offsetHeight;
                    var containerTop = container.getBoundingClientRect().top + windowTop;
                    var containerBottom = containerTop + containerHeight;
                    var elementHeight = element.offsetHeight;
                    var elementTop = element.getBoundingClientRect().top + windowTop;
                    var elementBottom = elementTop + elementHeight;
                    var newScrollTop = elementTop - containerTop + container.scrollTop;
                    var middleOffset = containerHeight / 2 - elementHeight / 2;
                    if (elementTop < containerTop) {
                        // scroll up
                        if (middle) {
                            newScrollTop -= middleOffset;
                        }
                        container.scrollTop = newScrollTop;
                    } else if (elementBottom > containerBottom) {
                        // scroll down
                        if (middle) {
                            newScrollTop += middleOffset;
                        }
                        var heightDifference = containerHeight - elementHeight;
                        container.scrollTop = newScrollTop - heightDifference;
                    }
                }
            }, {
                key: "_updateDialCode",
                value: function _updateDialCode(newDialCodeBare) {
                    var inputVal = this.telInput.value;
                    // save having to pass this every time
                    var newDialCode = "+".concat(newDialCodeBare);
                    var newNumber;
                    if (inputVal.charAt(0) === "+") {
                        // there's a plus so we're dealing with a replacement
                        var prevDialCode = this._getDialCode(inputVal);
                        if (prevDialCode) {
                            // current number contains a valid dial code, so replace it
                            newNumber = inputVal.replace(prevDialCode, newDialCode);
                        } else {
                            // current number contains an invalid dial code, so ditch it
                            // (no way to determine where the invalid dial code ends and the rest of the number begins)
                            newNumber = newDialCode;
                        }
                        this.telInput.value = newNumber;
                    } else if (this.options.autoInsertDialCode) {
                        if (inputVal) {
                            // there is an existing value with no dial code: prefix the new dial code
                            newNumber = newDialCode + inputVal;
                        } else {
                            newNumber = newDialCode;
                        }
                        this.telInput.value = newNumber;
                    }
                }
            }, {
                key: "_getDialCode",
                value: function _getDialCode(number, includeAreaCode) {
                    var dialCode = "";
                    // only interested in international numbers (starting with a plus)
                    if (number.charAt(0) === "+") {
                        var numericChars = "";
                        // iterate over chars
                        for (var i = 0; i < number.length; i++) {
                            var c = number.charAt(i);
                            // if char is number (https://stackoverflow.com/a/8935649/217866)
                            if (!isNaN(parseInt(c, 10))) {
                                numericChars += c;
                                // if current numericChars make a valid dial code
                                if (includeAreaCode) {
                                    if (this.countryCodes[numericChars]) {
                                        // store the actual raw string (useful for matching later)
                                        dialCode = number.substr(0, i + 1);
                                    }
                                } else {
                                    if (this.dialCodes[numericChars]) {
                                        dialCode = number.substr(0, i + 1);
                                        // if we're just looking for a dial code, we can break as soon as we find one
                                        break;
                                    }
                                }
                                // stop searching as soon as we can - in this case when we hit max len
                                if (numericChars.length === this.countryCodeMaxLen) {
                                    break;
                                }
                            }
                        }
                    }
                    return dialCode;
                }
            }, {
                key: "_getFullNumber",
                value: function _getFullNumber() {
                    var val = this.telInput.value.trim();
                    var dialCode = this.selectedCountryData.dialCode;
                    var prefix;
                    var numericVal = this._getNumeric(val);
                    if (this.options.separateDialCode && val.charAt(0) !== "+" && dialCode && numericVal) {
                        // when using separateDialCode, it is visible so is effectively part of the typed number
                        prefix = "+".concat(dialCode);
                    } else {
                        prefix = "";
                    }
                    return prefix + val;
                }
            }, {
                key: "_beforeSetNumber",
                value: function _beforeSetNumber(originalNumber) {
                    var number = originalNumber;
                    if (this.options.separateDialCode) {
                        var dialCode = this._getDialCode(number);
                        // if there is a valid dial code
                        if (dialCode) {
                            // in case _getDialCode returned an area code as well
                            dialCode = "+".concat(this.selectedCountryData.dialCode);
                            // a lot of numbers will have a space separating the dial code and the main number, and
                            // some NANP numbers will have a hyphen e.g. +1 684-733-1234 - in both cases we want to get
                            // rid of it
                            // NOTE: don't just trim all non-numerics as may want to preserve an open parenthesis etc
                            var start = number[dialCode.length] === " " || number[dialCode.length] === "-" ? dialCode.length + 1 : dialCode.length;
                            number = number.substr(start);
                        }
                    }
                    return this._cap(number);
                }
            }, {
                key: "_triggerCountryChange",
                value: function _triggerCountryChange() {
                    this._trigger("countrychange");
                }
            }, {
                key: "handleAutoCountry",
                value: function handleAutoCountry() {
                    if (this.options.initialCountry === "auto") {
                        // we must set this even if there is an initial val in the input: in case the initial val is
                        // invalid and they delete it - they should see their auto country
                        this.defaultCountry = window.intlTelInputGlobals.autoCountry;
                        // if there's no initial value in the input, then update the flag
                        if (!this.telInput.value) {
                            this.setCountry(this.defaultCountry);
                        }
                        this.resolveAutoCountryPromise();
                    }
                }
            }, {
                key: "handleUtils",
                value: function handleUtils() {
                    // if the request was successful
                    if (window.intlTelInputUtils) {
                        // if there's an initial value in the input, then format it
                        if (this.telInput.value) {
                            this._updateValFromNumber(this.telInput.value);
                        }
                        this._updatePlaceholder();
                    }
                    this.resolveUtilsScriptPromise();
                }
            }, {
                key: "destroy",
                value: function destroy() {
                    var form = this.telInput.form;
                    if (this.options.allowDropdown) {
                        // make sure the dropdown is closed (and unbind listeners)
                        this._closeDropdown();
                        this.selectedFlag.removeEventListener("click", this._handleClickSelectedFlag);
                        this.flagsContainer.removeEventListener("keydown", this._handleFlagsContainerKeydown);
                        // label click hack
                        var label = this._getClosestLabel();
                        if (label) {
                            label.removeEventListener("click", this._handleLabelClick);
                        }
                    }
                    // unbind hiddenInput listeners
                    if (this.hiddenInput && form) {
                        form.removeEventListener("submit", this._handleHiddenInputSubmit);
                    }
                    // unbind autoInsertDialCode listeners
                    if (this.options.autoInsertDialCode) {
                        if (form) {
                            form.removeEventListener("submit", this._handleSubmitOrBlurEvent);
                        }
                        this.telInput.removeEventListener("blur", this._handleSubmitOrBlurEvent);
                    }
                    // unbind key events, and cut/paste events
                    this.telInput.removeEventListener("keyup", this._handleKeyupEvent);
                    this.telInput.removeEventListener("cut", this._handleClipboardEvent);
                    this.telInput.removeEventListener("paste", this._handleClipboardEvent);
                    // remove attribute of id instance: data-intl-tel-input-id
                    this.telInput.removeAttribute("data-intl-tel-input-id");
                    // remove markup (but leave the original input)
                    var wrapper = this.telInput.parentNode;
                    wrapper.parentNode.insertBefore(this.telInput, wrapper);
                    wrapper.parentNode.removeChild(wrapper);
                    delete window.intlTelInputGlobals.instances[this.id];
                }
            }, {
                key: "getExtension",
                value: function getExtension() {
                    if (window.intlTelInputUtils) {
                        return intlTelInputUtils.getExtension(this._getFullNumber(), this.selectedCountryData.iso2);
                    }
                    return "";
                }
            }, {
                key: "getNumber",
                value: function getNumber(format) {
                    if (window.intlTelInputUtils) {
                        var iso2 = this.selectedCountryData.iso2;
                        return intlTelInputUtils.formatNumber(this._getFullNumber(), iso2, format);
                    }
                    return "";
                }
            }, {
                key: "getNumberType",
                value: function getNumberType() {
                    if (window.intlTelInputUtils) {
                        return intlTelInputUtils.getNumberType(this._getFullNumber(), this.selectedCountryData.iso2);
                    }
                    return -99;
                }
            }, {
                key: "getSelectedCountryData",
                value: function getSelectedCountryData() {
                    return this.selectedCountryData;
                }
            }, {
                key: "getValidationError",
                value: function getValidationError() {
                    if (window.intlTelInputUtils) {
                        var iso2 = this.selectedCountryData.iso2;
                        return intlTelInputUtils.getValidationError(this._getFullNumber(), iso2);
                    }
                    return -99;
                }
            }, {
                key: "isValidNumber",
                value: function isValidNumber() {
                    var val = this._getFullNumber().trim();
                    return window.intlTelInputUtils ? intlTelInputUtils.isValidNumber(val, this.selectedCountryData.iso2) : null;
                }
            }, {
                key: "setCountry",
                value: function setCountry(originalCountryCode) {
                    var countryCode = originalCountryCode.toLowerCase();
                    // check if already selected
                    if (this.selectedCountryData.iso2 !== countryCode) {
                        this._setFlag(countryCode);
                        this._updateDialCode(this.selectedCountryData.dialCode);
                        this._triggerCountryChange();
                    }
                }
            }, {
                key: "setNumber",
                value: function setNumber(number) {
                    // we must update the flag first, which updates this.selectedCountryData, which is used for
                    // formatting the number before displaying it
                    var flagChanged = this._updateFlagFromNumber(number);
                    this._updateValFromNumber(number);
                    if (flagChanged) {
                        this._triggerCountryChange();
                    }
                }
            }, {
                key: "setPlaceholderNumberType",
                value: function setPlaceholderNumberType(type) {
                    this.options.placeholderNumberType = type;
                    this._updatePlaceholder();
                }
            } ]);
            return Iti;
        }();
        /********************
 *  STATIC METHODS
 ********************/
        // get the country data object
        intlTelInputGlobals.getCountryData = function() {
            return allCountries;
        };
        // inject a <script> element to load utils.js
        var injectScript = function injectScript(path, handleSuccess, handleFailure) {
            // inject a new script element into the page
            var script = document.createElement("script");
            script.onload = function() {
                forEachInstance("handleUtils");
                if (handleSuccess) {
                    handleSuccess();
                }
            };
            script.onerror = function() {
                forEachInstance("rejectUtilsScriptPromise");
                if (handleFailure) {
                    handleFailure();
                }
            };
            script.className = "iti-load-utils";
            script.async = true;
            script.src = path;
            document.body.appendChild(script);
        };
        // load the utils script
        intlTelInputGlobals.loadUtils = function(path) {
            // 2 options:
            // 1) not already started loading (start)
            // 2) already started loading (do nothing - just wait for the onload callback to fire, which will
            // trigger handleUtils on all instances, invoking their resolveUtilsScriptPromise functions)
            if (!window.intlTelInputUtils && !window.intlTelInputGlobals.startedLoadingUtilsScript) {
                // only do this once
                window.intlTelInputGlobals.startedLoadingUtilsScript = true;
                // if we have promises, then return a promise
                if (typeof Promise !== "undefined") {
                    return new Promise(function(resolve, reject) {
                        return injectScript(path, resolve, reject);
                    });
                }
                injectScript(path);
            }
            return null;
        };
        // default options
        intlTelInputGlobals.defaults = defaults;
        // version
        intlTelInputGlobals.version = "18.1.3";
        // convenience wrapper
        return function(input, options) {
            var iti = new Iti(input, options);
            iti._init();
            input.setAttribute("data-intl-tel-input-id", iti.id);
            window.intlTelInputGlobals.instances[iti.id] = iti;
            return iti;
        };
    }();
});;
var commonValidation = commonValidation || (function (window, document, undefined) {

    var errorMessages = new Array();
    $.fn.doesExist = function () { return jQuery(this).length > 0; };
    jQuery.fn.exists = function () { return this.length > 0; };

    function scrollToTop() {
        $("html, body").animate({ scrollTop: 0 }, "slow");
    }

    function scrollToErrorPanel() {
        $("html, body").animate({ scrollTop: $(".panel_error").offset().top }, "slow");
    }

    var clearErrorPanel = function () {
        clearOldMessages();
    };

    var show = function () {
        var selector = ".panel_error";
        if ($(selector).exists()) {
            $(selector).show();
        }

        commonModule.scrollToMessage(selector);
    };
    
    function clearOldMessages() {
        $(".input-validation-error").removeClass("input-validation-error");
        $(".validation-summary-errors").removeClass("validation-summary-errors")
                                       .addClass("validation-summary-valid").find("ul").children().remove();
        
        if ($(".panel_error").exists()) { $(".panel_error").filter(":not(.persistent_message)").hide(); }
        if ($(".panel_success").exists()) { $(".panel_success").filter(":not(.persistent_message)").hide(); }
        if ($(".panel_info").exists()) { $(".panel_info").filter(":not(.persistent_message)").hide(); }

        errorMessages = new Array();
    }

    function appendValidationSummaryErrors(input, errorMessage, showInBold) {
        var validationSummary = $(".validation-summary-errors");
        if (validationSummary == undefined || validationSummary.length === 0) {
            validationSummary = $(".validation-summary-valid");
            validationSummary.addClass("validation-summary-errors");
            validationSummary.removeClass("validation-summary-valid");
        }
        $(input).addClass("input-validation-error");
        
        // http://stackoverflow.com/a/1473742/564957
        // has value already been displayed
        if (errorMessage != null && $.inArray(errorMessage, errorMessages) == -1) {
            var formattedErrorMessage = errorMessage;
            if (showInBold) {
                formattedErrorMessage = "<b>" + errorMessage + "</b>";
            }
            validationSummary.find("ul").append($("<li>").append(formattedErrorMessage));
            errorMessages.push(errorMessage);
        }

        validationSummary.find("ul").show();

        $(".panel_error").show();
    }
    
    //Use other panel
    function showFailureMessage(data, options, errorThrown) {
        var message = "Ummmm... This is awkward - an error has occured: ";

        if (options != null) {
            if (options.message != null) {
                message = options.message;
            }
        }        

        if (errorThrown != null) {
            message = errorThrown;
        } else {
            var errorMessage = commonModule.parseServerSideException(data).message;
            message += errorMessage == "" ? "" : " " + errorMessage;
        }

        appendValidationSummaryErrors(null, message, true);
    }

    function validateEmail(email) {
        // Regex is taken from https://emailregex.com/ - javascript section
        var filter = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
        return filter.test(email);
    }
    
    function handleUnhandledErrors(onHandleComplete) {
        $.ajaxSetup({
            error: function (jqXHR, textStatus, errorThrown) {
                clearOldMessages();
                if (jqXHR.status == 401) {
                    appendValidationSummaryErrors(null, "Event organiser does not have permission to run the report against the selected events");
                } else {
                    if (jqXHR.status === 0 && jqXHR.statusText === "abort") {
                        // do nothing, this is the autcomplete canceling subsquent ajax requests
                    } else {
                        appendValidationSummaryErrors(null, "Unhandled error: " + textStatus + ": " + errorThrown);
                    }
                    onHandleComplete();
                }
            }
        });
    }

    return {
        scrollToTop: function() {
            scrollToTop();
        },
        scrollToErrorPanel: function () {
            scrollToErrorPanel();
        },
        clearErrorPanel: function () {
            clearErrorPanel();
        },
        clearOldMessages: function () {
            clearOldMessages();
        },
        showErrorMessage: function (errorMessage) {
            commonModule.showErrorMessage("#messagePanel", errorMessage);
        },
        showSuccessMessage: function (errorMessage) {
            commonModule.showSuccessMessage("#messagePanel", errorMessage);
        },
        appendValidationSummaryErrors: function (input, errorMessage, showInBold) {
            appendValidationSummaryErrors(input, errorMessage, showInBold);
        },
        show: function () {
            show();
        },
        showFailureMessage: function (data, options, errorThrown) {
            showFailureMessage(data, options, errorThrown);
        },
        validateEmail: function(email) {
            return validateEmail(email);
        },
        handleUnhandledErrors : handleUnhandledErrors
    };

})(this, this.document);
;
