Uname: Linux webm005.cluster107.gra.hosting.ovh.net 5.15.167-ovh-vps-grsec-zfs-classid #1 SMP Tue Sep 17 08:14:20 UTC 2024 x86_64
User: 6036 (villadal)
Group: 100 (users)
Disabled functions: NONE
Safe mode: On[ PHPinfo ]
//home/villadal/www/wp-content/plugins///wordfence/////js      ( Reset | Go to )
File Name: admin.1756145765.js
Edit
(function($) {
    var sprintf,
        __;

    if (!window['wordfenceAdmin']) { //To compile for checking: java -jar /usr/local/bin/closure.jar --js=admin.js --js_output_file=test.js
        window['wordfenceAdmin'] = {
            isSmallScreen: false,
            loading16: '<div class="wfLoading16"></div>',
            loadingCount: 0,
            dbCheckTables: [],
            dbCheckCount_ok: 0,
            dbCheckCount_skipped: 0,
            dbCheckCount_errors: 0,
            issues: [],
            ignoreData: false,
            iconErrorMsgs: [],
            scanIDLoaded: 0,
            colorboxQueue: [],
            mode: '',
            visibleIssuesPanel: 'new',
            preFirstScanMsgsLoaded: false,
            newestActivityTime: 0, //must be 0 to force loading of all initially
            elementGeneratorIter: 1,
            reloadConfigPage: false,
            nonce: false,
            liveTrafficUpdatePending: false,
            activityLogUpdatePending: false,
            lastALogCtime: 0,
            lastIssueUpdateTime: 0,
            activityQueue: [],
            totalActAdded: 0,
            maxActivityLogItems: 1000,
            scanReqAnimation: false,
            debugOn: false,
            blockedCountriesPending: [],
            ownCountry: "",
            schedStartHour: false,
            currentPointer: false,
            countryMap: false,
            countryCodesToSave: "",
            performanceScale: 3,
            performanceMinWidth: 20,
            _windowHasFocus: true,
            serverTimestampOffset: 0,
            serverMicrotime: 0,
            wfLiveTraffic: null,
            loadingBlockedIPs: false,
            scanRunning: false,
            basePageName: '',
            pendingChanges: {},
            scanStalled: false,
            siteCleaningIssueTypes: ['file', 'checkGSB', 'checkSpamIP', 'commentBadURL', 'knownfile', 'optionBadURL', 'postBadTitle', 'postBadURL', 'spamvertizeCheck', 'suspiciousAdminUsers'],

            //Screen sizes
            SCREEN_XS: 'xs',
            SCREEN_SM: 'sm',
            SCREEN_MD: 'md',
            SCREEN_LG: 'lg',

            init: function() {
                this.isSmallScreen = window.matchMedia("only screen and (max-width: 500px)").matches;
                
                this.nonce = WordfenceAdminVars.firstNonce;
                this.debugOn = WordfenceAdminVars.debugOn == '1' ? true : false;
                this.scanRunning = WordfenceAdminVars.scanRunning == '1' ? true : false;
                this.basePageName = document.title;
                var startTicker = false;
                var self = this;

                $(window).on('blur', function() {
                    self._windowHasFocus = false;
                }).on('focus', function() {
                    self._windowHasFocus = true;
                }).focus();

                $('.do-show').click(function() {
                    var $this = $(this);
                    $this.hide();
                    $($this.data('selector')).show();
                    return false;
                });
                
                $('.downloadLogFile').each(function() {
                    $(this).attr('href', WordfenceAdminVars.ajaxURL + '?action=wordfence_downloadLogFile&nonce=' + WFAD.nonce + '&logfile=' + encodeURIComponent($(this).data('logfile')));
                });

                $('#doSendEmail').click(function() {
                    var ticket = $('#_ticketnumber').val();
                    if (ticket === null || typeof ticket === "undefined" || ticket.length == 0) {
                        self.colorboxModal((self.isSmallScreen ? '300px' : '400px'), __("Error"), __("Please include your support ticket number or forum username."));
                        return;
                    }
                    WFAD.ajax('wordfence_sendDiagnostic', {email: $('#_email').val(), ticket: ticket}, function(res) {
                        if (res.result) {
                            self.colorboxModal((self.isSmallScreen ? '300px' : '400px'), __("Email Diagnostic Report"), __("Diagnostic report has been sent successfully."));
                        } else {
                            self.colorboxModal((self.isSmallScreen ? '300px' : '400px'), __("Error"), __("There was an error while sending the email."));
                        }
                    });
                });

                $('#exportDiagnostics').click(function() {
                    self.showLoading();

                    var diagnosticsExportWindow = window.open(WordfenceAdminVars.ajaxURL + '?action=wordfence_exportDiagnostics&nonce=' + WFAD.nonce);
                    diagnosticsExportWindow.onbeforeunload = function() {
                        self.removeLoading();
                    };
                    return false;
                });

                $('#sendByEmail').click(function() {
                    $('#sendByEmailForm').removeClass('hidden');
                    $(this).hide();
                });

                $('#expandAllDiagnostics').click(function() {
                    $('#wf-diagnostics').find('.wf-block').each(function() {
                        var el = $(this);
                        if (!el.hasClass('wf-active')) {
                            el.find('.wf-block-header').trigger('click');
                        }
                    })
                });

                $(window).bind("scroll", function() {
                    $(this).scrollTop() > 200 ? $(".wf-scrollTop").fadeIn() : $(".wf-scrollTop").fadeOut()
                });
                $(".wf-scrollTop").click(function(e) {
                    return e.stopPropagation(), $("body,html").animate({
                        scrollTop: 0
                    }, 800), !1;
                });

                var tabs = jQuery('.wf-page-tabs').find('.wf-tab a');
                if (tabs.length > 0) {
                    tabs.click(function() {
                        jQuery('.wf-page-tabs').find('.wf-tab').removeClass('wf-active').find('a').attr('aria-selected', 'false');
                        jQuery('.wf-tab-content').removeClass('wf-active');
                        
                        var tab = jQuery(this).closest('.wf-tab');
                        tab.addClass('wf-active');
                        tab.find('a').attr('aria-selected', 'true');
                        var content = jQuery('#' + tab.data('target'));
                        content.addClass('wf-active');
                        document.title = tab.data('pageTitle') + " \u2039 " + self.basePageName;
                        self.sectionInit();
                        $(window).trigger('wfTabChange', [tab.data('target')]);
                    });
                    if (window.location.hash) {
                        var hashes = WFAD.parseHashes();
                        var hash = hashes[hashes.length - 1];
                        for (var i = 0; i < tabs.length; i++) {
                            if (hash == jQuery(tabs[i]).closest('.wf-tab').data('target')) {
                                jQuery(tabs[i]).trigger('click');
                            }
                        }
                    }
                    else {
                        jQuery(tabs[0]).trigger('click');
                    }
                    jQuery(window).on('hashchange', function () {
                        var hashes = WFAD.parseHashes();
                        var hash = hashes[hashes.length - 1];
                        for (var i = 0; i < tabs.length; i++) {
                            if (hash == jQuery(tabs[i]).closest('.wf-tab').data('target')) {
                                jQuery(tabs[i]).trigger('click');
                            }
                        }
                    });
                }
                else {
                    this.sectionInit();
                }
                
                if (this.mode) {
                    jQuery(document).bind('cbox_closed', function() {
                        self.colorboxIsOpen = false;
                        self.colorboxServiceQueue();
                    });
                }
                
                if ($('.wf-options-controls-spacer').length) { //The WP code doesn't move update nags and we need to
                    $('.update-nag, #update-nag').insertAfter($('.wf-options-controls-spacer'));
                }
                
                $('.wf-block-header-action-disclosure').each(function() {
                    $(this).on('keydown', function(e) {
                        if (e.keyCode == 32) {
                            e.preventDefault();
                            e.stopPropagation();

                            $(this).closest('.wf-block-header').trigger('click');
                        }
                    });
                    
                    $(this).closest('.wf-block-header').css('cursor', 'pointer');
                    $(this).closest('.wf-block-header').on('click', function(e) {
                        // Let links in the header work.
                        if (e.target && e.target.nodeName === 'A' && e.target.href) {
                            return;
                        }
                        e.preventDefault();
                        e.stopPropagation();
                        
                        if ($(this).closest('.wf-block').hasClass('wf-disabled')) {
                            return;
                        }
                        
                        var isActive = $(this).closest('.wf-block').hasClass('wf-active');
                        if (isActive) {
                            //$(this).closest('.wf-block').removeClass('wf-active');
                            $(this).closest('.wf-block').find('.wf-block-content').slideUp({
                                always: function() {
                                    $(this).closest('.wf-block').removeClass('wf-active');
                                    $(this).attr('aria-checked', 'false');
                                }
                            });
                        }
                        else {
                            //$(this).closest('.wf-block').addClass('wf-active');
                            $(this).closest('.wf-block').find('.wf-block-content').slideDown({
                                always: function() {
                                    $(this).closest('.wf-block').addClass('wf-active');
                                    $(this).attr('aria-checked', 'true');
                                }
                            });
                        }
                        
                        WFAD.ajax('wordfence_saveDisclosureState', {name: $(this).closest('.wf-block').data('persistenceKey'), state: !isActive}, function() {}, function() {}, true);
                    });
                });
                
                //On/Off Option
                $('.wf-option.wf-option-toggled .wf-option-checkbox').each(function() {
                    $(this).on('keydown', function(e) {
                        if (e.keyCode == 32) {
                            e.preventDefault();
                            e.stopPropagation();
                            
                            $(this).trigger('click');
                        }
                    });
                    
                    $(this).on('click', function(e) {
                        e.preventDefault();
                        e.stopPropagation();
                        
                        var optionElement = $(this).closest('.wf-option');
                        if (optionElement.hasClass('wf-option-premium') || optionElement.hasClass('wf-disabled')) {
                            return;
                        }
                        
                        var option = optionElement.data('option');
                        var value = false;
                        var isActive = $(this).hasClass('wf-checked');
                        if (isActive) {
                            $(this).removeClass('wf-checked').attr('aria-checked', 'false');
                            value = optionElement.data('disabledValue');
                        }
                        else {
                            $(this).addClass('wf-checked').attr('aria-checked', 'true');
                            value = optionElement.data('enabledValue');
                        }
                        
                        var originalValue = optionElement.data('originalValue');
                        if (originalValue == value) {
                            delete WFAD.pendingChanges[option];
                        }
                        else {
                            WFAD.pendingChanges[option] = value;
                        }

                        $(optionElement).trigger('change', [false]);
                        WFAD.updatePendingChanges();
                    });
                    
                    $(this).parent().find('.wf-option-title').on('click', function(e) {
                        var links = $(this).find('a');
                        var buffer = 10;
                        for (var i = 0; i < links.length; i++) {
                            var t = $(links[i]).offset().top;
                            var l = $(links[i]).offset().left;
                            var b = t + $(links[i]).height();
                            var r = l + $(links[i]).width();
                            
                            if (e.pageX > l - buffer && e.pageX < r + buffer && e.pageY > t - buffer && e.pageY < b + buffer) {
                                return; 
                            }
                        }
                        $(this).parent().find('.wf-option-checkbox').trigger('click');
                    }).css('cursor', 'pointer');
                });

                //On/Off Boolean Switch Option
                $('.wf-option.wf-option-toggled-boolean-switch .wf-boolean-switch').each(function() {
                    $(this).on('keydown', function(e) {
                        if (e.keyCode == 32) {
                            e.preventDefault();
                            e.stopPropagation();

                            $(this).trigger('click');
                        }
                    });
                    
                    $(this).on('click', function(e) {
                        e.preventDefault();
                        e.stopPropagation();
                        
                        $(this).find('.wf-boolean-switch-handle').trigger('click');
                    });

                    $(this).find('.wf-boolean-switch-handle').on('click', function(e) {
                        e.preventDefault();
                        e.stopPropagation();

                        var optionElement = $(this).closest('.wf-option');
                        if (optionElement.hasClass('wf-option-premium') || optionElement.hasClass('wf-disabled')) {
                            return;
                        }

                        var switchElement = $(this).closest('.wf-boolean-switch');
                        var option = optionElement.data('option');
                        var value = false;
                        var isActive = switchElement.hasClass('wf-active');
                        if (isActive) {
                            switchElement.removeClass('wf-active').attr('aria-checked', 'false');
                            value = optionElement.data('disabledValue');
                        }
                        else {
                            switchElement.addClass('wf-active').attr('aria-checked', 'true');
                            value = optionElement.data('enabledValue');
                        }

                        var originalValue = optionElement.data('originalValue');
                        if (originalValue == value) {
                            delete WFAD.pendingChanges[option];
                        }
                        else {
                            WFAD.pendingChanges[option] = value;
                        }

                        $(optionElement).trigger('change', [false]);
                        WFAD.updatePendingChanges();
                    });

                    $(this).parent().find('.wf-option-title').on('click', function(e) {
                        var links = $(this).find('a');
                        var buffer = 10;
                        for (var i = 0; i < links.length; i++) {
                            var t = $(links[i]).offset().top;
                            var l = $(links[i]).offset().left;
                            var b = t + $(links[i]).height();
                            var r = l + $(links[i]).width();

                            if (e.pageX > l - buffer && e.pageX < r + buffer && e.pageY > t - buffer && e.pageY < b + buffer) {
                                return;
                            }
                        }
                        $(this).parent().find('.wf-boolean-switch-handle').trigger('click');
                    }).css('cursor', 'pointer');
                });

                //On/Off Segmented Option
                $('.wf-option.wf-option-toggled-segmented [type=radio]').each(function() {
                    $(this).on('click', function(e) {
                        var optionElement = $(this).closest('.wf-option');
                        if (optionElement.hasClass('wf-option-premium') || optionElement.hasClass('wf-disabled')) {
                            return;
                        }

                        var option = optionElement.data('option');
                        var value = this.value;

                        var originalValue = optionElement.data('originalValue');
                        if (originalValue == value) {
                            delete WFAD.pendingChanges[option];
                        }
                        else {
                            WFAD.pendingChanges[option] = value;
                        }

                        $(optionElement).trigger('change', [false]);
                        WFAD.updatePendingChanges();
                    });
                });

                //On/Off Multiple Option
                $('.wf-option.wf-option-toggled-multiple .wf-option-checkbox').each(function() {
                    $(this).on('keydown', function(e) {
                        if (e.keyCode == 32) {
                            e.preventDefault();
                            e.stopPropagation();

                            $(this).trigger('click');
                        }
                    });
                    
                    $(this).on('click', function(e) {
                        e.preventDefault();
                        e.stopPropagation();

                        var optionElement = $(this).closest('.wf-option');
                        if (optionElement.hasClass('wf-option-premium') || optionElement.hasClass('wf-disabled')) {
                            return;
                        }

                        var checkboxElement = $(this).closest('ul');
                        var option = checkboxElement.data('option');
                        var value = false;
                        var isActive = $(this).hasClass('wf-checked');
                        if (isActive) {
                            $(this).removeClass('wf-checked').attr('aria-checked', 'false');
                            value = checkboxElement.data('disabledValue');
                        }
                        else {
                            $(this).addClass('wf-checked').attr('aria-checked', 'true');
                            value = checkboxElement.data('enabledValue');
                        }

                        var originalValue = checkboxElement.data('originalValue');
                        if (originalValue == value) {
                            delete WFAD.pendingChanges[option];
                        }
                        else {
                            WFAD.pendingChanges[option] = value;
                        }

                        $(optionElement).trigger('change', [false]);
                        WFAD.updatePendingChanges();
                    });
                });

                //On/Off Option with menu and Option with menu
                $('.wf-option.wf-option-toggled-select .wf-option-checkbox').each(function() {
                    $(this).on('keydown', function(e) {
                        if (e.keyCode == 32) {
                            e.preventDefault();
                            e.stopPropagation();

                            $(this).trigger('click');
                        }
                    });
                    
                    $(this).on('click', function(e) {
                        e.preventDefault();
                        e.stopPropagation();

                        var optionElement = $(this).closest('.wf-option');
                        if (optionElement.hasClass('wf-option-premium') || optionElement.hasClass('wf-disabled')) {
                            return;
                        }
                        
                        var selectElement = optionElement.find('.wf-option-select select');
                        var option = optionElement.data('toggleOption');
                        var value = false;
                        var isActive = $(this).hasClass('wf-checked');
                        if (isActive) {
                            $(this).removeClass('wf-checked').attr('aria-checked', 'false');
                            selectElement.attr('disabled', true);
                            value = optionElement.data('disabledToggleValue');
                        }
                        else {
                            $(this).addClass('wf-checked').attr('aria-checked', 'true');
                            selectElement.attr('disabled', false);
                            value = optionElement.data('enabledToggleValue');
                        }

                        if (option === undefined) {
                            return;
                        }

                        var originalValue = optionElement.data('originalToggleValue');
                        if (originalValue == value) {
                            delete WFAD.pendingChanges[option];
                        }
                        else {
                            WFAD.pendingChanges[option] = value;
                        }

                        $(optionElement).trigger('change', [false]);
                        WFAD.updatePendingChanges();
                    });
                    
                    $(this).parent().find('.wf-option-title').on('click', function(e) {
                        var links = $(this).find('a');
                        var buffer = 10;
                        for (var i = 0; i < links.length; i++) {
                            var t = $(links[i]).offset().top;
                            var l = $(links[i]).offset().left;
                            var b = t + $(links[i]).height();
                            var r = l + $(links[i]).width();

                            if (e.pageX > l - buffer && e.pageX < r + buffer && e.pageY > t - buffer && e.pageY < b + buffer) {
                                return;
                            }
                        }
                        $(this).closest('.wf-option').find('.wf-option-checkbox').trigger('click');
                    }).css('cursor', 'pointer');
                });

                $('.wf-option.wf-option-toggled-select > .wf-option-content > ul > li.wf-option-select select, .wf-option.wf-option-select > .wf-option-content > ul > li.wf-option-select select, .wf-option.wf-option-select > li.wf-option-select select').each(function() {
                    if (!$.fn.wfselect2) { return; }
                    
                    var width = WFAD.isSmallScreen ? '200px' : 'resolve';
                    if ($(this).data('preferredWidth')) {
                        width = $(this).data('preferredWidth');
                    }
                    
                    $(this).wfselect2({
                        minimumResultsForSearch: -1,
                        width: width
                    }).on('change', function () {
                        var optionElement = $(this).closest('.wf-option');
                        var option = optionElement.data('selectOption');
                        var value = $(this).val();
                        
                        if (option === undefined) {
                            return;
                        }

                        var originalValue = optionElement.data('originalSelectValue');
                        if (originalValue == value) {
                            delete WFAD.pendingChanges[option];
                        }
                        else {
                            WFAD.pendingChanges[option] = value;
                        }

                        $(optionElement).trigger('change', [false]);
                        WFAD.updatePendingChanges();
                    });
                }).triggerHandler('change');
                
                //Text field option
                $('.wf-option.wf-option-text > .wf-option-content > ul > li.wf-option-text input').on('change paste keyup', function() {
                    var e = this;
                    
                    setTimeout(function() {
                        var optionElement = $(e).closest('.wf-option');
                        var option = optionElement.data('textOption');
                        
                        if (typeof option !== 'undefined') {
                            var value = $(e).val();
    
                            var originalValue = optionElement.data('originalTextValue');
                            if (originalValue == value) {
                                delete WFAD.pendingChanges[option];
                            }
                            else {
                                WFAD.pendingChanges[option] = value;
                            }
    
                            $(optionElement).trigger('change', [false]);
                            WFAD.updatePendingChanges();
                        }
                    }, 4);
                });

                //Text area option
                $('.wf-option.wf-option-textarea > .wf-option-content > ul > li.wf-option-textarea textarea').on('change paste keyup', function() {
                    var e = this;
                    
                    setTimeout(function() {
                        var optionElement = $(e).closest('.wf-option');
                        var option = optionElement.data('textOption');
                        var value = $(e).val();
    
                        var originalValue = optionElement.data('originalTextValue');
                        if (originalValue == value) {
                            delete WFAD.pendingChanges[option];
                        }
                        else {
                            WFAD.pendingChanges[option] = value;
                        }
    
                        $(optionElement).trigger('change', [false]);
                        WFAD.updatePendingChanges();
                    }, 4);
                });

                //Value entry token option
                if ($.fn.wfselect2) {
                    $('.wf-option.wf-option-token select').wfselect2({
                        tags: true,
                        tokenSeparators: [','],
                        width: 'element',
                        minimumResultsForSearch: -1,
                        selectOnClose: true,
                        matcher: function(params, data) {
                            return null;
                        }
                    }).on('wfselect2:unselect', function(e){
                        jQuery(e.params.data.element).remove();
                    }).on('wfselect2:opening wfselect2:close', function(e){
                        $('body').toggleClass('wf-select2-suppress-dropdown', e.type == 'wfselect2:opening');
                    }).on('change', function () {
                        var optionElement = $(this).closest('.wf-option');
                        var option = optionElement.data('tokenOption');
                        var value = $(this).val();
                        if (!(value instanceof Array)) {
                            value = [];
                        }
    
                        var selected = $(this).find('option:selected');
                        var tagsElement = optionElement.find('.wf-option-token-tags');
                        var list = $('<ul>');
                        selected.each(function(index, option) {
                            option = $(option);
                            var value = option.val();
                            var destroyButton = $('<a>').addClass('wf-destroy-tag-selected')
                                .text('x')
                                .off('click.wfselect2-copy')
                                .on('click.wfselect2-copy', function(e) {
                                    option.prop('selected', false);
                                    option.parents('select').trigger('change');
                                    option.remove();
                                });
                            var li = $('<li>').addClass('wf-tag-selected')
                                .text(value)
                                .prepend(destroyButton);
                            list.append(li);
                        });
                        tagsElement.html('').append(list);
    
                        var originalValue = optionElement.data('originalTokenValue');
                        var match = true;
                        if (value.length != originalValue.length) {
                            match = false;
                        }
                        else {
                            value = value.sort();
                            originalValue = originalValue.sort();
                            for (var i = 0; i < value.length; i++) {
                                if (value[i] !== originalValue[i]) {
                                    match = false;
                                }
                            }
                        }
                        if (match) {
                            delete WFAD.pendingChanges[option];
                        }
                        else {
                            WFAD.pendingChanges[option] = value;
                        }
    
                        $(optionElement).trigger('change', [false]);
                        WFAD.updatePendingChanges();
                    }).triggerHandler('change');
    
                    $('.wf-option.wf-option-token select').each(function() { 
                        $(this).data('wfselect2').$container.addClass('wf-select2-placeholder-fix wf-select2-hide-tags');
                    });
                }
                
                //Switch Option
                $('.wf-option.wf-option-switch .wf-switch > li').each(function(index, element) {
                    $(this).on('keydown', function(e) {
                        if (e.keyCode == 32) {
                            e.preventDefault();
                            e.stopPropagation();

                            $(this).trigger('click');
                        }
                    });
                    
                    $(element).on('click', function(e) {
                        e.preventDefault();
                        e.stopPropagation();

                        var optionElement = $(this).closest('ul.wf-option-switch, div.wf-option-switch');
                        var optionName = optionElement.data('optionName');
                        var originalValue = optionElement.data('originalValue');
                        var value = $(this).data('optionValue');

                        var control = $(this).closest('.wf-switch');
                        control.find('li').each(function() {
                            $(this).toggleClass('wf-active', value == $(this).data('optionValue')).attr('aria-checked', value == $(this).data('optionValue') ? 'true' : 'false');
                        });

                        if (originalValue == value) {
                            delete WFAD.pendingChanges[optionName];
                        }
                        else {
                            WFAD.pendingChanges[optionName] = value;
                        }

                        $(optionElement).trigger('change', [false]);
                        WFAD.updatePendingChanges();
                    });
                });

                $(document).focus();

                // (docs|support).wordfence.com GA links
                $(document).on('click', 'a', function() {
                    if (this.href && this.href.indexOf('utm_source') > -1) {
                        return;
                    }
                    var utm = '';
                    if ((this.host == 'www.wordfence.com' || this.host == 'wordfence.com') && /^\/help(?:$|\/)/.test(this.pathname)) {
                        utm = 'utm_source=plugin&utm_medium=pluginUI&utm_campaign=docsIcon';
                    }
                    if (utm) {
                        utm = (this.search ? '&' : '?') + utm;
                        this.href = this.protocol + '//' + this.host + this.pathname + this.search + utm + this.hash;
                    }

                    if (this.href == 'http://support.wordfence.com/') {
                        this.href = 'https://support.wordfence.com/support/home?utm_source=plugin&utm_medium=pluginUI&utm_campaign=supportLink';
                    }
                });
            },
            sectionInit: function() {
                var self = this;
                this.mode = false;
                if (jQuery('#wordfenceMode_dashboard:visible').length > 0) {
                    this.mode = 'dashboard';
                } else if (jQuery('#wordfenceMode_scan:visible').length > 0) {
                    this.mode = 'scan';
                } else if (jQuery('#wordfenceMode_waf:visible').length > 0) {
                    this.mode = 'waf';
                } else if (jQuery('#wordfenceMode_liveTraffic:visible').length > 0) {
                    this.mode = 'liveTraffic';
                    this.setupSwitches('wfLiveTrafficOnOff', 'liveTrafficEnabled', function() {
                    });
                    jQuery('#wfLiveTrafficOnOff').change(function() {
                        self.updateSwitch('wfLiveTrafficOnOff', 'liveTrafficEnabled', function() {
                            window.location.reload(true);
                        });
                    });

                    this.updateLiveTraffic();
                    if (this.liveInt > 0) {
                        clearInterval(this.liveInt);
                        this.liveInt = 0;
                    }
                    this.liveInt = setInterval(function() {
                        self.updateLiveTraffic();
                    }, WordfenceAdminVars.actUpdateInterval);
                } else if (jQuery('#wordfenceMode_twoFactor:visible').length > 0) {
                    this.mode = 'twoFactor';
                    this.loadTwoFactor();
                } else if (jQuery('#wordfenceMode_whois:visible').length > 0) {
                    this.mode = 'whois';
                    this.calcRangeTotal();
                } else if (jQuery('#wordfenceMode_scanScheduling:visible').length > 0) {
                    this.mode = 'scanScheduling';
                    this.sched_modeChange();
                }
            },
            /**
             * Returns whether or not the screen size is within the size given. This may be a numerical value
             * or one of the WFAD_SCREEN_ constants.
             *
             * @param size
             * @returns {boolean}
             */
            screenSize: function(size) {
                switch (size) {
                    case WFAD.SCREEN_XS:
                        return window.matchMedia("only screen and (max-width: 767px)").matches;
                    case WFAD.SCREEN_SM:
                        return window.matchMedia("only screen and (max-width: 991px)").matches;
                    case WFAD.SCREEN_MD:
                        return window.matchMedia("only screen and (max-width: 1199px)").matches;
                    case WFAD.SCREEN_LG:
                        return window.matchMedia("only screen and (max-width: 32767px)").matches;
                }

                var parsed = parseInt(size);
                if (isNaN(parsed)) {
                    return false;
                }
                return window.matchMedia("only screen and (max-width: " + parsed + "px)").matches;
            },
            sendTestEmail: function(email) {
                var self = this;
                this.ajax('wordfence_sendTestEmail', {email: email}, function(res) {
                    if (res.result) {
                        self.colorboxModalHTML((self.isSmallScreen ? '300px' : '400px'), __("Test Email Sent"), sprintf(__("Your test email was sent to the requested email address. The result we received from the WordPress wp_mail() function was: %s<br /><br />A 'True' result means WordPress thinks the mail was sent without errors. A 'False' result means that WordPress encountered an error sending your mail. Note that it's possible to get a 'True' response with an error elsewhere in your mail system that may cause emails to not be delivered."), res.result));
                    }
                });
            },
            sendTestActivityReport: function(email) {
                var self = this;
                this.ajax(
                    'wordfence_email_summary_email_address_debug',
                    {email: email},
                    function(res) {
                        if (res.result) {
                            self.colorboxModalHTML((self.isSmallScreen ? '300px' : '400px'), ("Test Activity Report"), res.result);
                        }
                    }
                );
            },
            updateSwitch: function(elemID, configItem, cb) {
                var setting = jQuery('#' + elemID).is(':checked');
                this.updateConfig(configItem, jQuery('#' + elemID).is(':checked') ? 1 : 0, cb);
            },
            setupSwitches: function(elemID, configItem, cb) {
                jQuery('.wfOnOffSwitch-checkbox').change(function() {
                    jQuery.data(this, 'lastSwitchChange', (new Date()).getTime());
                });
                var self = this;
                jQuery('div.wfOnOffSwitch').mouseup(function() {
                    var elem = jQuery(this);
                    setTimeout(function() {
                        var checkedElem = elem.find('.wfOnOffSwitch-checkbox');
                        if ((new Date()).getTime() - jQuery.data(checkedElem[0], 'lastSwitchChange') > 300) {
                            checkedElem.prop('checked', !checkedElem.is(':checked'));
                            self.updateSwitch(elemID, configItem, cb);
                        }
                    }, 50);
                });
            },
            updateConfig: function(key, val, cb) {
                this.ajax('wordfence_updateConfig', {key: key, val: val}, function(ret) {
                    if (cb) {
                        cb(ret);
                    }
                });
            },
            updateIPPreview: function(val, cb) {
                this.ajax('wordfence_updateIPPreview', val, function(ret) {
                    if (cb) {
                        cb(ret);
                    }
                });
            },
            wordfenceSatisfactionChoice: function(choice) {
                if (choice == 'yes') {
                    $('#wordfenceSatisfactionPrompt-yes').slideDown(400, function() {
                        $('#wordfenceSatisfactionPrompt-initial .wf-btn').addClass('wf-disabled').css('opacity', 0.3);
                        $('#wordfenceSatisfactionPrompt-initial .wf-btn:first-of-type').css('opacity', 0.8);
                    });
                    WFAD.ajax('wordfence_wordfenceSatisfactionChoice', {choice: choice});
                }
                else if (choice == 'no') {
                    $('#wordfenceSatisfactionPrompt-no').slideDown(400, function() {
                        $('#wordfenceSatisfactionPrompt-initial .wf-btn').addClass('wf-disabled').css('opacity', 0.3);
                        $('#wordfenceSatisfactionPrompt-initial .wf-btn:last-of-type').css('opacity', 0.8);
                    });
                    WFAD.ajax('wordfence_wordfenceSatisfactionChoice', {choice: choice});
                }
                else if (choice == 'feedback') {
                    WFAD.ajax('wordfence_wordfenceSatisfactionChoice', {
                            choice: choice,
                            feedback: $('#wordfenceSatisfactionPrompt-feedback').val(),
                        },
                        function(res) { $('#wordfenceSatisfactionPrompt-no').fadeOut(); $('#wordfenceSatisfactionPrompt-complete').fadeIn(); },
                        function() { $('#wordfenceSatisfactionPrompt-no').fadeOut(); $('#wordfenceSatisfactionPrompt-complete').fadeIn(); }
                    );
                }
                else if (choice == 'dismiss') {
                    $('#wordfenceSatisfactionPrompt').fadeOut();
                    WFAD.ajax('wordfence_wordfenceSatisfactionChoice', {choice: choice});
                }
            },
            tourFinish: function(page) {
                if (WFAD.currentPointer) {
                    WFAD.currentPointer.pointer('destroy');
                    WFAD.currentPointer = false;
                }
                
                $('#wf-onboarding-tour-overlay').fadeOut();
                WFAD.ajax('wordfence_tourClosed', {page: page}, function(res) {});
            },
            tour: function(contentID, elemID, edge, align, previousCallback, nextCallback) {
                if (WFAD.currentPointer) {
                    WFAD.currentPointer.pointer('destroy');
                    WFAD.currentPointer = false;
                }
                
                var options = {
                    pointerClass: 'wf-tour-pointer',
                    buttons: function(event, t) {
                        return null;
                    },
                    close: function() {
                    },
                    content: $('#' + contentID).tmpl().html(),
                    pointerWidth: 700, 
                    position: {
                        edge: edge,
                        align: align
                    }
                };
                var element = $('#' + elemID);
                $('#wf-onboarding-tour-overlay').fadeIn();
                WFAD.currentPointer = element.pointer(options).pointer('open');
                
                if (previousCallback) {
                    $('#wf-tour-previous a').on('click', function(e) {
                        e.preventDefault();
                        e.stopPropagation();

                        previousCallback();
                    });
                }
                
                if (nextCallback) {
                    $('#wf-tour-continue a').on('click', function(e) {
                        e.preventDefault();
                        e.stopPropagation();

                        nextCallback();
                    });
                }
                
                $('#wf-tour-close').on('click', function(e) {
                    e.preventDefault();
                    e.stopPropagation();

                    WFAD.tourComplete();
                });

                var wpPointer = $('.wf-tour-pointer');
                if (wpPointer.length > 0) {
                    $('html, body').animate({
                        scrollTop: wpPointer.offset().top - 100
                    }, 1000);
                }
            },
            showLoading: function() {
                this.loadingCount++;
                if (this.loadingCount == 1) {
                    $('<div id="wordfenceWorking">' + __('Wordfence is working...') + '</div>').appendTo('body');
                }
            },
            removeLoading: function() {
                this.loadingCount--;
                if (this.loadingCount == 0) {
                    jQuery('#wordfenceWorking').remove();
                }
            },
            switch2FAToNew: function() {
                
            },
            switch2FAToOld: function() {
                window.location.reload(true);
            },
            startActivityLogUpdates: function() {
                var self = this;
                setInterval(function() {
                    self.updateActivityLog();
                }, parseInt(WordfenceAdminVars.actUpdateInterval));
            },
            updateActivityLog: function() {
                if (this.activityLogUpdatePending || (!this.windowHasFocus() && WordfenceAdminVars.allowsPausing == '1')) {
                    if (!jQuery('body').hasClass('wordfenceLiveActivityPaused') && !this.activityLogUpdatePending) {
                        jQuery('body').addClass('wordfenceLiveActivityPaused');
                    }
                    return;
                }
                if (jQuery('body').hasClass('wordfenceLiveActivityPaused')) {
                    jQuery('body').removeClass('wordfenceLiveActivityPaused');
                }
                WFAD.loadingIssues = true;
                this.activityLogUpdatePending = true;
                var self = this;
                this.ajax('wordfence_activityLogUpdate', {
                    lastctime: this.lastALogCtime,
                    lastissuetime: this.lastIssueUpdateTime,
                }, function(res) {
                    self.doneUpdateActivityLog(res);
                }, function() {
                    self.activityLogUpdatePending = false;
                }, true);

            },
            doneUpdateActivityLog: function(res) {
                this.actNextUpdateAt = (new Date()).getTime() + parseInt(WordfenceAdminVars.actUpdateInterval);
                if (res.ok) {
                    if (res.items.length > 0) {
                        this.activityQueue.push.apply(this.activityQueue, res.items);
                        this.lastALogCtime = res.items[res.items.length - 1].ctime;
                        this.processActQueue(res.currentScanID);
                    }
                    if (res.signatureUpdateTime) {
                        this.updateSignaturesTimestamp(res.signatureUpdateTime);
                    }

                    var oldScanStalled = WFAD.scanStalled;
                    WFAD.scanStalled = (res.scanStalled == '1' ? true : false);
                    var oldScanRunning = WFAD.scanRunning;
                    WFAD.scanRunning = (res.scanRunning == '1' && !WFAD.scanStalled) ? true : false;
                    
                    if (res.scanFailedHTML && !WFAD.scanRunning) {
                        jQuery('#wf-scan-failed').html(res.scanFailedHTML);
                        jQuery('#wf-scan-failed').show();
                        $(window).trigger('wfScanUpdateButtons');
                    }
                    else {
                        jQuery('#wf-scan-failed').hide();
                    }
                    
                    if (res.lastMessage) {
                        $('#wf-scan-last-status').html(res.lastMessage);
                    }
                    
                    if (res.issues) {
                        this.lastIssueUpdateTime = res.issueUpdateTimestamp;
                        this.displayIssues(res);
                    }
                    
                    if (res.issueCounts) {
                        WFAD.updateIssueCounts(res.issueCounts);
                    }
                    
                    WFAD.loadingIssues = false;

                    if (res.scanStats) {
                        var keys = Object.keys(res.scanStats);
                        for (var i = 0; i < keys.length; i++) {
                            $('.' + keys[i]).text(res.scanStats[keys[i]]); 
                        }
                    }

                    if (res.scanStages) {
                        var keys = Object.keys(res.scanStages);
                        for (var i = 0; i < keys.length; i++) { 
                            var element = $('#wf-scan-' + keys[i]);
                            if (element) {
                                var existingClasses = element.attr('class');
                                if (existingClasses.match(/ /)) {
                                    existingClasses = existingClasses.split(' ');
                                }
                                else {
                                    existingClasses = [existingClasses];
                                }
                                
                                var newClasses = res.scanStages[keys[i]];
                                if (newClasses.match(/ /)) {
                                    newClasses = newClasses.split(' ');
                                }
                                else {
                                    newClasses = [newClasses];
                                }
                                
                                var mismatch = false;
                                if (existingClasses.length != newClasses.length) {
                                    mismatch = true;
                                }
                                else {
                                    var intersection = existingClasses.filter(function(value) {
                                        for (var n = 0; n < newClasses.length; n++) {
                                            if (newClasses[n] == value) {
                                                return true;
                                            }
                                        }
                                        return false;
                                    });
                                    mismatch = (intersection.length != newClasses.length);
                                }
                                
                                if (mismatch) {
                                    element.removeClass();
                                    element.addClass(newClasses.join(' '));
                                }
                                
                                if (oldScanRunning != WFAD.scanRunning) {
                                    if (WFAD.scanRunning) {
                                        $('#wf-scan-running-bar').show();
                                    }
                                    else {
                                        $('#wf-scan-running-bar').hide();
                                    }
                                    $(window).trigger('wfScanUpdateButtons');
                                }
                                else if (oldScanStalled != WFAD.scanStalled) {
                                    $(window).trigger('wfScanUpdateButtons');
                                }
                            }
                        }
                    }
                }
                this.activityLogUpdatePending = false;
            },

            updateSignaturesTimestamp: function(signatureUpdateTime) {
                var date = new Date(signatureUpdateTime * 1000);

                var dateString = date.toString();
                if (date.toLocaleString) {
                    dateString = date.toLocaleString();
                }

                var sigTimestampEl = $('#wf-scan-sigs-last-update');
                var newText = sprintf(__('Last Updated: %s'), dateString);
                if (sigTimestampEl.text() !== newText) {
                    sigTimestampEl.text(newText)
                        .css({
                            'opacity': 0
                        })
                        .animate({
                            'opacity': 1
                        }, 500);
                }
            },

            processActQueue: function(currentScanID) {
                if (this.activityQueue.length > 0) {
                    this.addActItem(this.activityQueue.shift());
                    this.totalActAdded++;
                    if (this.totalActAdded > this.maxActivityLogItems) {
                        jQuery('#wf-scan-activity-log > li:first').remove();
                        this.totalActAdded--;
                    }
                    var timeTillNextUpdate = this.actNextUpdateAt - (new Date()).getTime();
                    var maxRate = 50 / 1000; //Rate per millisecond
                    var bulkTotal = 0;
                    while (this.activityQueue.length > 0 && this.activityQueue.length / timeTillNextUpdate > maxRate) {
                        var item = this.activityQueue.shift();
                        if (item) {
                            bulkTotal++;
                            this.addActItem(item);
                        }
                    }
                    this.totalActAdded += bulkTotal;
                    if (this.totalActAdded > this.maxActivityLogItems) {
                        jQuery('#wf-scan-activity-log > li:lt(' + bulkTotal + ')').remove();
                        this.totalActAdded -= bulkTotal;
                    }
                    var minDelay = 100;
                    var delay = minDelay;
                    if (timeTillNextUpdate < 1) {
                        delay = minDelay;
                    } else {
                        delay = Math.round(timeTillNextUpdate / this.activityQueue.length);
                        if (delay < minDelay) {
                            delay = minDelay;
                        }
                    }
                    var self = this;
                    setTimeout(function() {
                        self.processActQueue();
                    }, delay);
                }
                jQuery('#wf-scan-activity-log').scrollTop(jQuery('#wf-scan-activity-log').prop('scrollHeight'));
            },
            processActArray: function(arr) {
                for (var i = 0; i < arr.length; i++) {
                    this.addActItem(arr[i]);
                }
            },
            addActItem: function(item) {
                if (!item) {
                    return;
                }
                if (!item.msg) {
                    return;
                }
                if (item.msg.indexOf('SUM_') == 0) {
                    this.processSummaryLine(item);
                }
                else if (this.debugOn || item.level < 4) {

                    var html = '<li class="wfActivityLine';
                    if (this.debugOn) {
                        html += ' wf' + item.type;
                    }
                    html += '">[' + item.date + ']&nbsp;' + item.msg + '</div>';
                    jQuery('#wf-scan-activity-log').append(html);
                    if (/Scan complete\./i.test(item.msg) || /Scan interrupted\./i.test(item.msg)) {
                        this.loadIssues();
                    }
                }
            },
            processSummaryLine: function(item) {
                var msg, summaryUpdated;
                if (item.msg.indexOf('SUM_START:') != -1) {
                    msg = item.msg.replace('SUM_START:', '');
                    jQuery('#consoleSummary').append('<div class="wfSummaryLine"><div class="wfSummaryDate">[' + item.date + ']</div><div class="wfSummaryMsg">' + msg + '</div><div class="wfSummaryResult"><div class="wfSummaryLoading"></div></div><div class="wfClear"></div>');
                    summaryUpdated = true;
                } else if (item.msg.indexOf('SUM_ENDBAD') != -1) {
                    msg = item.msg.replace('SUM_ENDBAD:', '');
                    jQuery('div.wfSummaryMsg:contains("' + msg + '")').next().addClass('wfSummaryBad').html('Problems found.');
                    summaryUpdated = true;
                } else if (item.msg.indexOf('SUM_ENDFAILED') != -1) {
                    msg = item.msg.replace('SUM_ENDFAILED:', '');
                    jQuery('div.wfSummaryMsg:contains("' + msg + '")').next().addClass('wfSummaryBad').html('Failed.');
                    summaryUpdated = true;
                } else if (item.msg.indexOf('SUM_ENDOK') != -1) {
                    msg = item.msg.replace('SUM_ENDOK:', '');
                    jQuery('div.wfSummaryMsg:contains("' + msg + '")').next().addClass('wfSummaryOK').html('Secure.');
                    summaryUpdated = true;
                } else if (item.msg.indexOf('SUM_ENDSUCCESS') != -1) {
                    msg = item.msg.replace('SUM_ENDSUCCESS:', '');
                    jQuery('div.wfSummaryMsg:contains("' + msg + '")').next().addClass('wfSummaryOK').html('Success.');
                    summaryUpdated = true;
                } else if (item.msg.indexOf('SUM_ENDERR') != -1) {
                    msg = item.msg.replace('SUM_ENDERR:', '');
                    jQuery('div.wfSummaryMsg:contains("' + msg + '")').next().addClass('wfSummaryErr').html('An error occurred.');
                    summaryUpdated = true;
                } else if (item.msg.indexOf('SUM_ENDSKIPPED') != -1) {
                    msg = item.msg.replace('SUM_ENDSKIPPED:', '');
                    jQuery('div.wfSummaryMsg:contains("' + msg + '")').next().addClass('wfSummaryResult').html('Skipped.');
                    summaryUpdated = true;
                } else if (item.msg.indexOf('SUM_ENDIGNORED') != -1) {
                    msg = item.msg.replace('SUM_ENDIGNORED:', '');
                    jQuery('div.wfSummaryMsg:contains("' + msg + '")').next().addClass('wfSummaryIgnored').html('Ignored.');
                    summaryUpdated = true;
                } else if (item.msg.indexOf('SUM_DISABLED:') != -1) {
                    msg = item.msg.replace('SUM_DISABLED:', '');
                    jQuery('#consoleSummary').append('<div class="wfSummaryLine"><div class="wfSummaryDate">[' + item.date + ']</div><div class="wfSummaryMsg">' + msg + '</div><div class="wfSummaryResult">' + __('Disabled') + '</div><div class="wfClear"></div>');
                    summaryUpdated = true;
                } else if (item.msg.indexOf('SUM_PAIDONLY:') != -1) {
                    msg = item.msg.replace('SUM_PAIDONLY:', '');
                    jQuery('#consoleSummary').append('<div class="wfSummaryLine"><div class="wfSummaryDate">[' + item.date + ']</div><div class="wfSummaryMsg">' + msg + '</div><div class="wfSummaryResult"><a href="https://www.wordfence.com/wordfence-signup/" target="_blank"  rel="noopener noreferrer">' + __('Paid Members Only') + ' (' + __('opens in new tab') + ')</a></div><div class="wfClear"></div>');
                    summaryUpdated = true;
                } else if (item.msg.indexOf('SUM_FINAL:') != -1) {
                    msg = item.msg.replace('SUM_FINAL:', '');
                    jQuery('#consoleSummary').append('<div class="wfSummaryLine"><div class="wfSummaryDate">[' + item.date + ']</div><div class="wfSummaryMsg wfSummaryFinal">' + msg + '</div><div class="wfSummaryResult wfSummaryOK">' + __('Scan Complete.') + '</div><div class="wfClear"></div>');
                } else if (item.msg.indexOf('SUM_PREP:') != -1) {
                    msg = item.msg.replace('SUM_PREP:', '');
                    jQuery('#consoleSummary').empty().html('<div class="wfSummaryLine"><div class="wfSummaryDate">[' + item.date + ']</div><div class="wfSummaryMsg">' + msg + '</div><div class="wfSummaryResult" id="wfStartingScan"><div class="wfSummaryLoading"></div></div><div class="wfClear"></div>');
                } else if (item.msg.indexOf('SUM_KILLED:') != -1) {
                    msg = item.msg.replace('SUM_KILLED:', '');
                    jQuery('#consoleSummary').empty().html('<div class="wfSummaryLine"><div class="wfSummaryDate">[' + item.date + ']</div><div class="wfSummaryMsg">' + msg + '</div><div class="wfSummaryResult wfSummaryOK">' + __('Scan Complete.') + '</div><div class="wfClear"></div>');
                }
            },
            processActQueueItem: function() {
                var item = this.activityQueue.shift();
                if (item) {
                    jQuery('#consoleActivity').append('<div class="wfActivityLine wf' + item.type + '">[' + item.date + ']&nbsp;' + item.msg + '</div>');
                    this.totalActAdded++;
                    if (this.totalActAdded > this.maxActivityLogItems) {
                        jQuery('#consoleActivity div:first').remove();
                        this.totalActAdded--;
                    }
                    if (item.msg == 'Scan complete.') {
                        this.loadIssues();
                    }
                }
            },
            updateLiveTraffic: function(forceUpdate) {
                if ((!forceUpdate) && (this.liveTrafficUpdatePending || (!this.windowHasFocus() && WordfenceAdminVars.allowsPausing == '1'))) {
                    if (!jQuery('body').hasClass('wordfenceLiveActivityPaused') && !this.liveTrafficUpdatePending) {
                        jQuery('body').addClass('wordfenceLiveActivityPaused');
                    }
                    return;
                }
                if (jQuery('body').hasClass('wordfenceLiveActivityPaused')) {
                    jQuery('body').removeClass('wordfenceLiveActivityPaused');
                }
                
                if (this.mode == 'liveTraffic') {
                    this.liveTrafficUpdatePending = true;
                    var self = this;
                    var otherParams = this.newestActivityTime;
                    var data = '';
                    
                    if (this.wfLiveTraffic) {
                        data += this.wfLiveTraffic.getCurrentQueryString({
                            since: this.newestActivityTime
                        });
                    }

                    data += '&otherParams=' + encodeURIComponent(otherParams);
                    this.ajax('wordfence_ticker', data, function(res) {
                        self.handleLiveTrafficReturn(res);
                    }, function() {
                        self.liveTrafficUpdatePending = false;
                    }, true);
                }
            },
            handleLiveTrafficReturn: function(res) {
                this.liveTrafficUpdatePending = false;
                this.serverTimestampOffset = (new Date().getTime() / 1000) - res.serverTime;
                this.serverMicrotime = res.serverMicrotime;
                
                var newMsg = "Idle";
                var oldMsg = jQuery('.wf-live-activity-message').text();
                if (res.msg) { newMsg = res.msg; }
                if (newMsg && newMsg != oldMsg) {
                    jQuery('.wf-live-activity-message').hide().html(newMsg).fadeIn(200);
                }

                if (this.mode == 'liveTraffic') {
                    if (res.events.length > 0) {
                        this.newestActivityTime = res.events[0]['ctime'];
                    }
                    
                    if (typeof WFAD.wfLiveTraffic !== undefined) {
                        WFAD.wfLiveTraffic.prependListings(res.events, res);
                        this.reverseLookupIPs();
                        this.avatarLookup();
                        this.updateTimeAgo();
                    }
                }
            },
            avatarLookup: function() {
                var ids = [];
                $('.wfAvatar').each(function(idx, elem) {
                    var userID = Number.parseInt($(elem).data('userid'));
                    if (!Number.isNaN(userID) && !$(elem).data('wfAvatarDone')) {
                        $(elem).data('wfAvatarDone', true);
                        ids.push(userID);
                    }
                });
                
                if (ids.length < 1) { return; }
                
                var uni = {};
                var uniqueIDs = [];
                for (var i = 0; i < ids.length; i++) {
                    if (!uni[ids[i]]) {
                        uni[ids[i]] = true;
                        uniqueIDs.push(ids[i]);
                    }
                }
                this.ajax('wordfence_avatarLookup', {
                        ids: uniqueIDs.join(',')
                    },
                    function(res) {
                        if (res.ok) {
                            $('.wfAvatar').each(function(idx, elem) {
                                var userID = Number.parseInt($(elem).data('userid'));
                                if (!Number.isNaN(userID)) {
                                    if (res.avatars[userID]) {
                                        $(elem).html(res.avatars[userID]);
                                    }
                                }
                            });
                        }
                    }, false, false);
            },
            reverseLookupIPs: function() {
                var self = this;
                var ips = [];
                jQuery('.wfReverseLookup').each(function(idx, elem) {
                    var txt = jQuery(elem).text().trim();
                    if (/^\d+\.\d+\.\d+\.\d+$/.test(txt) && (!jQuery(elem).data('wfReverseDone'))) {
                        jQuery(elem).data('wfReverseDone', true);
                        ips.push(txt);
                    }
                });
                if (ips.length < 1) {
                    return;
                }
                var uni = {};
                var uniqueIPs = [];
                for (var i = 0; i < ips.length; i++) {
                    if (!uni[ips[i]]) {
                        uni[ips[i]] = true;
                        uniqueIPs.push(ips[i]);
                    }
                }
                this.ajax('wordfence_reverseLookup', {
                        ips: uniqueIPs.join(',')
                    },
                    function(res) {
                        if (res.ok) {
                            jQuery('.wfReverseLookup').each(function(idx, elem) {
                                var el = jQuery(elem);
                                var txt = el.text().trim();
                                for (var ip in res.ips) {
                                    if (txt == ip) {
                                        if (res.ips[ip]) {
                                            var hostnameTemplate = el.attr('data-reverse-lookup-template');
                                            if (hostnameTemplate) {
                                                jQuery(elem).html(jQuery.tmpl($('#' + hostnameTemplate), {
                                                    ip: res.ips[ip]
                                                }));
                                            } else if (el.hasClass('wf-hostname-only')) {
                                                jQuery(elem).text(res.ips[ip]);
                                            } else {
                                                jQuery(elem).html('<strong>Hostname:</strong>&nbsp;' + self.htmlEscape(res.ips[ip]));
                                            }
                                        } else {
                                            jQuery(elem).html('');
                                        }
                                    }
                                }
                            });
                        }
                    }, false, false);
            },
            killScan: function(callback) {
                this.ajax('wordfence_killScan', {}, function(res) {
                    if (res.ok) {
                        typeof callback === 'function' && callback(true);
                        WFAD.scanRunning = false;
                        WFAD.scanFailed = false;
                        $(window).trigger('wfScanUpdateButtons');
                    } else {
                        typeof callback === 'function' && callback(false);
                    }
                });
            },
            startScan: function() {
                this.ajax('wordfence_scan', {}, function(res) {
                    if (res.ok) {
                        WFAD.scanRunning = true;
                        $('#wf-scan-results-new').empty();
                        $('#wf-scan-bulk-buttons-delete, #wf-scan-bulk-buttons-repair').addClass('wf-disabled');
                        WFAD.updateIssueCounts(res.issueCounts);
                        $(window).trigger('wfScanUpdateButtons');
                    }
                });
            },
            loadIssues: function(callback, offset, limit) {
                if (this.mode != 'scan') {
                    return;
                }
                offset = offset || 0;
                limit = limit || WordfenceAdminVars.scanIssuesPerPage;
                var self = this;
                this.ajax('wordfence_loadIssues', {offset: offset, limit: limit}, function(res) {
                    var newCount = parseInt(res.issueCounts.new) || 0;
                    var ignoredCount = (parseInt(res.issueCounts.ignoreP) || 0) + (parseInt(res.issueCounts.ignoreC) || 0);
                    jQuery('#wfNewIssuesTab .wfIssuesCount').text(' (' + newCount + ')');
                    jQuery('#wfIgnoredIssuesTab .wfIssuesCount').text(' (' + ignoredCount + ')'); 
                    self.displayIssues(res, callback);
                });
            },
            loadMoreIssues: function(callback, offset, limit, ignoredOffset, ignoredLimit) {
                offset = offset || 0;
                limit = limit || WordfenceAdminVars.scanIssuesPerPage;
                ignoredOffset = ignoredOffset || 0;
                ignoredLimit = ignoredLimit || WordfenceAdminVars.scanIssuesPerPage;
                
                if (offset >= WFAD.scanIssuesNewCount && ignoredOffset >= WFAD.scanIssuesIgnoredCount) {
                    return;
                }
                
                WFAD.ajax('wordfence_loadIssues', {offset: offset, limit: limit, ignoredOffset: ignoredOffset, ignoredLimit: ignoredLimit}, function(res) {
                    WFAD.updateIssueCounts(res.issueCounts);
                    WFAD.appendIssues(res.issues, callback);
                });
            },
            sev2num: function(str) {
                if (/wfProbSev1/.test(str)) {
                    return 1;
                } else if (/wfProbSev2/.test(str)) {
                    return 2;
                } else {
                    return 0;
                }
            },
            isIssueExpanded: function(issueID) {
                var key = 'wf-scan-issue-expanded-' + issueID;
                if (window.localStorage) {
                    return !!parseInt(window.localStorage.getItem(key));
                }
                return false;
            },
            expandIssue: function(issueID, makeVisible) {
                var key = 'wf-scan-issue-expanded-' + issueID;
                if (window.localStorage) {
                    window.localStorage.setItem(key, makeVisible ? 1 : 0);
                }
            },
            displayIssues: function(res, callback) {
                for (var issueStatus in res.issues) {
                    var containerID = 'wf-scan-results-' + issueStatus;
                    if ($('#' + containerID).length < 1) {
                        continue;
                    }
                    
                    if (res.issues[issueStatus].length < 1) {
                        continue;
                    }
                    
                    $('#' + containerID).empty();
                }
                
                WFAD.appendIssues(res.issues, callback);
                
                return true;
            },
            appendIssues: function(issues, callback) {
                for (var issueStatus in issues) {
                    var containerID = 'wf-scan-results-' + issueStatus;
                    if ($('#' + containerID).length < 1) {
                        continue;
                    }
                    
                    var container = $('#' + containerID);
                    for (var i = 0; i < issues[issueStatus].length; i++) {
                        var issueObject = issues[issueStatus][i];
                        WFAD.appendIssue(issueObject, container);
                    }
                }
                
                WFAD.sortIssues();
                WFAD.updateBulkButtons();
                if (typeof callback === 'function') {
                    callback();
                }
            },
            appendIssue: function(issueObject, container) {
                var issueType = issueObject.type;
                var tmplName = 'issueTmpl_' + issueType;
                var template = $('#' + tmplName);
                if (template.length) {
                    var issue = template.tmpl(issueObject);
                    issue.data('sourceData', issueObject);
                    issue.data('templateName', tmplName);
                    if (this.isIssueExpanded(issueObject.id)) {
                        issue.addClass('wf-active');
                    }

                    //Hook up Details button
                    issue.find('.wf-issue-control-show-details').on('click', function(e) {
                        e.preventDefault();
                        e.stopPropagation();

                        var isActive = $(this).closest('.wf-issue').hasClass('wf-active');
                        var issueID = $(this).closest('.wf-issue').data('issueId'); 
                        WFAD.expandIssue(issueID, !isActive);
                        $(this).closest('.wf-issue').toggleClass('wf-active', !isActive);
                    });

                    //Hook up Ignore button
                    issue.find('.wf-issue-control-ignore').each(function() {
                        var issueID = $(this).closest('.wf-issue').data('issueId');
                        var menu = $(this).parent().find('.wf-issue-control-ignore-menu').menu().hide();

                        $(this).on('click', function(e) {
                            e.preventDefault();
                            e.stopPropagation();

                            var ignoreAction = $(this).data('ignoreAction');
                            if (ignoreAction == 'choice') {
                                menu.show().position({
                                    my: "left top",
                                    at: "left bottom",
                                    of: this
                                });

                                $(document).on('click', function() {
                                    menu.hide();
                                });
                            }
                            else {
                                var self = this;
                                WFAD.updateIssueStatus(issueID, ignoreAction, function(res) {
                                    if (res.ok) {
                                        var issueContainer = $(self).closest('.wf-scan-results-issues');
                                        var issueElement = $(self).closest('.wf-issue');
                                        var sourceData = issueElement.data('sourceData');
                                        sourceData['status'] = ignoreAction;

                                        var targetContainerID = 'wf-scan-results-' + (issueContainer.attr('id') == 'wf-scan-results-new' ? 'ignored' : 'new');
                                        var targetContainer = $('#' + targetContainerID);
                                        issueElement.remove();
                                        WFAD.appendIssue(sourceData, targetContainer);
                                        WFAD.sortIssues();
                                        WFAD.updateIssueCounts(res.issueCounts);
                                        WFAD.repositionSiteCleaningCallout();
                                        WFAD.updateBulkButtons();
                                    }
                                });
                            }
                        });

                        menu.find('.wf-issue-control-ignore-menu-ignorec').on('click', function(e) {
                            e.preventDefault();
                            e.stopPropagation();

                            var self = this;
                            WFAD.updateIssueStatus(issueID, 'ignoreC', function(res) {
                                if (res.ok) {
                                    var issueContainer = $(self).closest('.wf-scan-results-issues');
                                    var issueElement = $(self).closest('.wf-issue');
                                    var sourceData = issueElement.data('sourceData');
                                    sourceData['status'] = 'ignoreC';

                                    var targetContainerID = 'wf-scan-results-' + (issueContainer.attr('id') == 'wf-scan-results-new' ? 'ignored' : 'new');
                                    var targetContainer = $('#' + targetContainerID);
                                    issueElement.remove();
                                    WFAD.appendIssue(sourceData, targetContainer);
                                    WFAD.sortIssues();
                                    WFAD.updateIssueCounts(res.issueCounts);
                                    WFAD.repositionSiteCleaningCallout();
                                    WFAD.updateBulkButtons();
                                }
                            });
                        });

                        menu.find('.wf-issue-control-ignore-menu-ignorep').on('click', function(e) {
                            e.preventDefault();
                            e.stopPropagation();

                            var self = this;
                            WFAD.updateIssueStatus(issueID, 'ignoreP', function(res) {
                                if (res.ok) {
                                    var issueContainer = $(self).closest('.wf-scan-results-issues');
                                    var issueElement = $(self).closest('.wf-issue');
                                    var sourceData = issueElement.data('sourceData');
                                    sourceData['status'] = 'ignoreP';

                                    var targetContainerID = 'wf-scan-results-' + (issueContainer.attr('id') == 'wf-scan-results-new' ? 'ignored' : 'new');
                                    var targetContainer = $('#' + targetContainerID);
                                    issueElement.remove();
                                    WFAD.appendIssue(sourceData, targetContainer);
                                    WFAD.sortIssues();
                                    WFAD.updateIssueCounts(res.issueCounts);
                                    WFAD.repositionSiteCleaningCallout();
                                    WFAD.updateBulkButtons();
                                }
                            });
                        });
                    });
                    
                    //Hook up Mark as Fixed button
                    issue.find('.wf-issue-control-mark-fixed').each(function() {
                        var issueID = $(this).closest('.wf-issue').data('issueId');

                        $(this).on('click', function(e) {
                            e.preventDefault();
                            e.stopPropagation();

                            var self = this;
                            WFAD.updateIssueStatus(issueID, 'delete', function(res) {
                                if (res.ok) {
                                    var issueElement = $(self).closest('.wf-issue');
                                    issueElement.remove();
                                    WFAD.updateIssueCounts(res.issueCounts);
                                    WFAD.repositionSiteCleaningCallout();
                                    WFAD.updateBulkButtons();
                                }
                            });
                        });
                    });
                    
                    //Hook up Delete File button
                    issue.find('.wf-issue-control-delete-file').each(function() {
                        var issueID = $(this).closest('.wf-issue').data('issueId');

                        $(this).on('click', function(e) {
                            e.preventDefault();
                            e.stopPropagation();

                            var self = this;
                            WFAD.deleteFile(issueID, false, function(res) {
                                if (res.ok) {
                                    var issueElement = $(self).closest('.wf-issue');
                                    issueElement.remove();
                                    WFAD.updateIssueCounts(res.issueCounts);
                                    WFAD.repositionSiteCleaningCallout();
                                    WFAD.updateBulkButtons();
                                    WFAD.colorboxModal((WFAD.isSmallScreen ? '300px' : '400px'), __("Success deleting file"), sprintf(__("The file %s was successfully deleted."), res.file));
                                }
                                else if (res.errorMsg) {
                                    WFAD.colorboxError(res.errorMsg, res.tokenInvalid);
                                }
                            });
                        });
                    });

                    //Hook up Repair button
                    issue.find('.wf-issue-control-repair').each(function() {
                        // Show prompt to download repair file

                        var issueID = $(this).closest('.wf-issue').data('issueId');

                        $(this).on('click', function(e) {
                            e.preventDefault();
                            e.stopPropagation();

                            WFAD.promptToRepairFile(issueID, issueObject.data);
                        });
                    });
                    
                    //Hook up Hide File button
                    issue.find('.wf-issue-control-hide-file').each(function() {
                        var issueID = $(this).closest('.wf-issue').data('issueId');

                        $(this).on('click', function(e) {
                            e.preventDefault();
                            e.stopPropagation();

                            var self = this;
                            WFAD.hideFile(issueID, function(res) {
                                if (res.ok) {
                                    var issueElement = $(self).closest('.wf-issue');
                                    issueElement.remove();
                                    WFAD.updateIssueCounts(res.issueCounts);
                                    WFAD.repositionSiteCleaningCallout();
                                    WFAD.updateBulkButtons();
                                    WFAD.colorboxModal((WFAD.isSmallScreen ? '300px' : '400px'), __("File hidden successfully"), sprintf(__("The file %s was successfully hidden from public view."), res.file));
                                }
                                else if (res.errorMsg) {
                                    WFAD.colorboxError(res.errorMsg, res.tokenInvalid);
                                }
                            });
                        });
                    });

                    //Hook up Tooltips
                    issue.find('[data-tooltip]').each(function() {
                        $(this).tooltip({
                            tooltipClass: "wf-tooltip",
                        });
                    });

                    //Swap out if the row already exists
                    var existing = $('.wf-issue[data-issue-id="' + issueObject.id + '"]');
                    if (existing.length) {
                        existing.replaceWith(issue);
                    }
                    else {
                        container.append(issue);
                    }

                    //Make row tappable
                    issue.find('.wf-issue-summary').on('mousedown', function(e) {
                        $(this).data('clickTapX', e.pageX).data('clickTapY', e.pageY);
                    }).on('click', function(e) {
                        var buffer = 10;
                        var clickTapX = $(this).data('clickTapX');
                        var clickTapY = $(this).data('clickTapY');
                        if (clickTapX > e.pageX - buffer && clickTapX < e.pageX + buffer && clickTapY > e.pageY - buffer && clickTapY < e.pageY + buffer) {
                            var links = $(this).find('a');
                            for (var i = 0; i < links.length; i++) {
                                var t = $(links[i]).offset().top;
                                var l = $(links[i]).offset().left;
                                var b = t + $(links[i]).height();
                                var r = l + $(links[i]).width();

                                if (e.pageX > l - buffer && e.pageX < r + buffer && e.pageY > t - buffer && e.pageY < b + buffer) {
                                    return;
                                }
                            }
                            
                            $(this).closest('.wf-issue').find('li.wf-issue-controls .wf-issue-control-show-details').trigger('click');
                        }
                    }).css('cursor', 'pointer');
                }
            },
            sortIssues: function() {
                var issueTypes = ['new', 'ignored'];
                for (var i = 0; i < issueTypes.length; i++) {
                    var containerID = 'wf-scan-results-' + issueTypes[i];
                    if ($('#' + containerID).length < 1) {
                        continue;
                    }

                    var container = $('#' + containerID);
                    var issuesDOM = container.find('.wf-issue');
                    issuesDOM.detach();
                    issuesDOM.sort(function(a, b) {
                        var severityA = $(a).data('issueSeverity');
                        var severityB = $(b).data('issueSeverity');
                        if (severityA > severityB) { return -1; }
                        else if (severityA < severityB) { return 1; }

                        var typeA = $(a).data('issueType');
                        var typeB = $(b).data('issueType');
                        
                        var typeAIndex = WFAD.siteCleaningIssueTypes.indexOf(typeA);
                        var typeBIndex = WFAD.siteCleaningIssueTypes.indexOf(typeB);
                        if (typeAIndex > -1 && typeBIndex > -1) {
                            if (typeAIndex < typeBIndex) { return -1; }
                            else if (typeAIndex > typeBIndex) { return 1; }
                            return 0;
                        }
                        else if (typeAIndex > -1) {
                            return -1;
                        }
                        else if (typeBIndex > -1) {
                            return 1;
                        }
                        
                        if (typeA < typeB) { return -1; }
                        else if (typeA > typeB) { return 1; }

                        return 0;
                    });
                    container.append(issuesDOM);
                }

                WFAD.repositionSiteCleaningCallout();
                WFAD.scanIssuesOffset = $('#wf-scan-results-new .wf-issue').length;
                WFAD.scanIssuesIgnoredOffset = $('#wf-scan-results-ignored .wf-issue').length;
            },
            updateBulkButtons: function() {
                var containerID = 'wf-scan-results-new';
                if ($('#' + containerID).length < 1) {
                    return;
                }

                var hasDeleteable = false;
                var hasRepairable = false;
                
                var container = $('#' + containerID);
                var issuesDOM = container.find('.wf-issue');
                for (var i = 0; i < issuesDOM.length; i++) {
                    var sourceData = $(issuesDOM[i]).data('sourceData');
                    if (sourceData) {
                        if (sourceData.data.canDelete) {
                            hasDeleteable = true;
                        }

                        if (sourceData.data.canFix) {
                            hasRepairable = true;
                        }

                        if (hasDeleteable && hasRepairable) {
                            break;
                        }
                    }
                }

                $('#wf-scan-bulk-buttons-delete').toggleClass('wf-disabled', !hasDeleteable);
                $('#wf-scan-bulk-buttons-repair').toggleClass('wf-disabled', !hasRepairable);
            },
            updateIssueCounts: function(issueCounts) {
                var newCount = (typeof issueCounts['new'] === 'undefined' ? 0 : parseInt(issueCounts['new']));
                var ignoredCount = (typeof issueCounts['ignoreC'] === 'undefined' ? 0 : parseInt(issueCounts['ignoreC'])) + (typeof issueCounts['ignoreP'] === 'undefined' ? 0 : parseInt(issueCounts['ignoreP']));
                WFAD.scanIssuesNewCount = newCount;
                WFAD.scanIssuesIgnoredCount = ignoredCount;
                WFAD.scanIssuesTotalCount = newCount + ignoredCount;
                
                $('#wf-scan-tab-new a').html($('#wf-scan-tab-new').data('tabTitle') + ' (' + newCount + ')');
                $('#wf-scan-tab-ignored a').html($('#wf-scan-tab-ignored').data('tabTitle') + ' (' + ignoredCount + ')'); 

                if (newCount == 0) {
                    var existing = $('.wf-issue[data-issue-id="no-issues-new"]');
                    if (existing.length == 0) {
                        var issue = $('#issueTmpl_noneFound').tmpl({shortMsg: __('No new issues have been found.'), id: 'no-issues-new'});
                        $('#wf-scan-results-new').append(issue);
                    }
                }
                else {
                    $('.wf-issue[data-issue-id="no-issues-new"]').remove();
                }
                
                if (ignoredCount == 0) {
                    var existing = $('.wf-issue[data-issue-id="no-issues-ignored"]');
                    if (existing.length == 0) {
                        var issue = $('#issueTmpl_noneFound').tmpl({shortMsg: __('No issues have been ignored.'), id: 'no-issues-ignored'});
                        $('#wf-scan-results-ignored').append(issue);
                    }
                }
                else {
                    $('.wf-issue[data-issue-id="no-issues-ignored"]').remove();
                }
            },
            repositionSiteCleaningCallout: function() {
                $('.wf-issue-site-cleaning').remove();
                
                var issueTypes = WFAD.siteCleaningIssueTypes;
                for (var i = 0; i < issueTypes.length; i++) {
                    if ($('#wf-scan-results-new .wf-issue-' + issueTypes[i]).length) {
                        if (!!$('#wf-scan-results-new .wf-issue-' + issueTypes[i]).data('betaSignatures')) {
                            $('#wf-scan-results-new .wf-issue').first().after($('#siteCleaningBetaSigsTmpl').tmpl());
                        }
                        else if (!!$('#wf-scan-results-new .wf-issue-' + issueTypes[i]).data('highSensitivity')) {
                            $('#wf-scan-results-new .wf-issue').first().after($('#siteCleaningHighSenseTmpl').tmpl());
                        }
                        else {
                            $('#wf-scan-results-new .wf-issue').first().after($('#siteCleaningTmpl').tmpl());
                        }
                        return;
                    }
                }
            },
            ajax: function(action, data, cb, cbErr, noLoading) {
                if (typeof(data) == 'string') {
                    if (data.length > 0) {
                        data += '&';
                    }
                    data += 'action=' + action + '&nonce=' + this.nonce;
                } else if (typeof(data) == 'object' && data instanceof Array) {
                    // jQuery serialized form data
                    data.push({
                        name: 'action',
                        value: action
                    });
                    data.push({
                        name: 'nonce',
                        value: this.nonce
                    });
                } else if (typeof(data) == 'object') {
                    data['action'] = action;
                    data['nonce'] = this.nonce;
                }
                if (!cb) {
                    cb = function() {
                    };
                }
                if (!cbErr) {
                    cbErr = function() {
                    };
                }
                var self = this;
                if (!noLoading) {
                    this.showLoading();
                }
                jQuery.ajax({
                    type: 'POST',
                    url: WordfenceAdminVars.ajaxURL,
                    dataType: "json",
                    data: data,
                    success: function(json) {
                        if (!noLoading) {
                            self.removeLoading();
                        }
                        if (json && json.nonce) {
                            self.nonce = json.nonce;
                        }
                        if (json && json.errorMsg) {
                            WFAD.colorboxError(json.errorMsg, json.tokenInvalid);
                        }
                        cb(json);
                    },
                    error: function() {
                        if (!noLoading) {
                            self.removeLoading();
                        }
                        cbErr();
                    }
                });
            },
            colorbox: function(width, heading, body, settings) {
                if (typeof settings === 'undefined') {
                    settings = {};
                }
                this.colorboxQueue.push([width, "<h3>" + heading + "</h3><p>" + body + "</p>", settings]);
                this.colorboxServiceQueue();
            },
            colorboxModalHTML: function(width, heading, body, settings) {
                if (typeof settings === 'undefined') {
                    settings = {};
                }
                
                var prompt = $.tmpl(WordfenceAdminVars.modalHTMLTemplate, {title: heading, message: body});
                var promptHTML = $("<div />").append(prompt).html();
                var callback = settings.onComplete;
                settings.overlayClose = false;
                settings.closeButton = false;
                settings.className = 'wf-modal';
                settings.onComplete = function() {
                    $('#wf-generic-modal-close').on('click', function(e) {
                        e.preventDefault();
                        e.stopPropagation();

                        WFAD.colorboxClose();
                    });

                    typeof callback === 'function' && callback();
                };
                this.colorboxHTML(width, promptHTML, settings)
            },
            colorboxModal: function(width, heading, body, settings) {
                if (typeof settings === 'undefined') {
                    settings = {};
                }

                var prompt = $.tmpl(WordfenceAdminVars.modalTemplate, {title: heading, message: body});
                var promptHTML = $("<div />").append(prompt).html();
                var callback = settings.onComplete;
                settings.overlayClose = false;
                settings.closeButton = false;
                settings.className = 'wf-modal';
                settings.onComplete = function() {
                    $('#wf-generic-modal-close').on('click', function(e) {
                        e.preventDefault();
                        e.stopPropagation();

                        WFAD.colorboxClose();
                    });

                    typeof callback === 'function' && callback();
                };
                this.colorboxHTML(width, promptHTML, settings)
            },
            colorboxError: function(errorMsg, isTokenError) {
                var callback = false;
                if (isTokenError) {
                    if (WFAD.tokenErrorShowing) {
                        return;
                    }
                    
                    callback = function() {
                        setTimeout(function() {
                            WFAD.tokenErrorShowing = false;
                        }, 30000);
                    };
                    
                    WFAD.tokenErrorShowing = true;
                }

                var prompt = $.tmpl(WordfenceAdminVars.tokenInvalidTemplate, {title: __('An error occurred'), message: errorMsg});
                var promptHTML = $("<div />").append(prompt).html();
                var settings = {};
                settings.overlayClose = false;
                settings.closeButton = false;
                settings.className = 'wf-modal';
                settings.onComplete = function() {
                    $('#wf-token-invalid-modal-reload').on('click', function(e) {
                        e.preventDefault();
                        e.stopPropagation();

                        window.location.reload(true);
                    });

                    typeof callback === 'function' && callback();
                };
                WFAD.colorboxHTML((WFAD.isSmallScreen ? '300px' : '400px'), promptHTML, settings);
            },
            colorboxHTML: function(width, html, settings) {
                if (typeof settings === 'undefined') {
                    settings = {};
                }
                this.colorboxQueue.push([width, html, settings]);
                this.colorboxServiceQueue();
            },
            colorboxServiceQueue: function() {
                if (this.colorboxIsOpen) {
                    return;
                }
                if (this.colorboxQueue.length < 1) {
                    return;
                }
                var elem = this.colorboxQueue.shift();
                this.colorboxOpen(elem[0], elem[1], elem[2]);
            },
            colorboxOpen: function(width, html, settings) {
                var self = this;
                this.colorboxIsOpen = true;
                var onClosed = settings.onClosed || null;
                jQuery.extend(settings, {
                    width: width,
                    html: html,
                    onClosed: function() {
                        self.colorboxClose();
                        if (onClosed)
                            onClosed();
                    }
                });
                jQuery.wfcolorbox(settings);
            },
            colorboxClose: function() {
                this.colorboxIsOpen = false;
                jQuery.wfcolorbox.close();
            },
            bulkOperationConfirmed: function(op) {
                WFAD.colorboxClose();
                this.ajax('wordfence_bulkOperation', {
                    op: op
                }, function(res) {
                    if (res.ok) {
                        for (var i = 0; i < res.idsRemoved.length; i++) {
                            $('.wf-issue[data-issue-id="' + res.idsRemoved[i] + '"]').remove();
                        }

                        WFAD.updateIssueCounts(res.issueCounts);
                        WFAD.repositionSiteCleaningCallout();
                        WFAD.updateBulkButtons();
                        setTimeout(function() {
                            WFAD.colorboxModalHTML((WFAD.isSmallScreen ? '300px' : '400px'), res.bulkHeading, res.bulkBody);
                        }, 500);
                    }
                });
            },
            deleteFile: function(issueID, force, callback) {
                this.ajax('wordfence_deleteFile', {
                    issueID: issueID,
                    forceDelete: force
                }, function(res) {
                    if (res.needsCredentials) {
                        document.location.href = res.redirect;
                    } else {
                        typeof callback === 'function' && callback(res);
                    }
                });
            },
            promptToRepairFile: function(issueID, data) {
                if (window.localStorage) {
                    var sudoExpiration = window.localStorage.getItem('wf-repair-file-sudo');
                    if (sudoExpiration && parseInt(sudoExpiration, 10) > new Date().getTime()) {
                        this.repairFile(issueID);
                        return;
                    }
                }
                WFAD.colorboxModalHTML((WFAD.isSmallScreen ? '300px' : '400px'), __("Download Backup File"), __('Please make a backup of this file before proceeding. If you need to restore this backup file, you can copy it to the following path from your site\'s root:') + '<p class="wf-padding-add-top-medium"><code>' + data.file + '</code></p>'
                    + '<a href="' + WFAD.makeDownloadFileLink(data) + '" onclick="jQuery(\'#wfRepairFileNextBtn\').prop(\'disabled\', false); return true;">' + __('Click here to download a backup copy of this file now') + '</a><p class="wf-flex-horizontal">' +
                    '<input type="button" class="wf-btn wf-btn-primary" name="but1" id="wfRepairFileNextBtn" value="Repair File" disabled="disabled" onclick="WFAD.promptToRepairFileDone(' + parseInt(issueID, 10) + ', jQuery(\'#forceRepairFileCheckbox\').prop(\'checked\'));this.disabled=true;" />' +
                    '<label class="wf-padding-add-left"><input type="checkbox" id="forceRepairFileCheckbox" onclick="jQuery(\'#wfRepairFileNextBtn\').prop(\'disabled\', !this.checked); return true;"> ' + __('Don\'t ask again') + '</label>' +
                    '</p>' +
                    '<div class="wordfenceHelpLink"><a href="' + WordfenceAdminVars.supportURLs['scan-result-repair-modified-files'] + '" target="_blank" rel="noopener noreferrer" class="wfhelp"></a><a href="' + WordfenceAdminVars.supportURLs['scan-result-repair-modified-files'] + '" target="_blank" rel="noopener noreferrer">' + __('Learn more about repairing modified files.') + ' (' + __('opens in new tab') + ')</a></div>'
                );
            },
            promptToRepairFileDone: function(issueID, dontPromptAgain) {
                if (dontPromptAgain) {
                    if (window.localStorage) {
                        window.localStorage.setItem('wf-repair-file-sudo', (new Date().getTime() + 86400000));
                    }
                }
                this.repairFile(issueID);
            },
            repairFile: function(issueID) {
                var self = this;
                self.colorboxClose();
                this.restoreFile(issueID, function(res) {
                    if (res.ok) {
                        var issueElement = $('.wf-issue[data-issue-id=' + parseInt(issueID, 10) + ']');
                        issueElement.remove();
                        self.updateIssueCounts(res.issueCounts);
                        self.repositionSiteCleaningCallout();
                        self.updateBulkButtons();
                        self.colorboxModal((self.isSmallScreen ? '300px' : '400px'), __("Success restoring file"), sprintf(__("The file %s was successfully restored."), res.file));
                    }
                    else if (res.errorMsg) {
                        self.colorboxError(res.errorMsg, res.tokenInvalid);
                    }
                });
            },
            deleteDatabaseOption: function(issueID) {
                var self = this;
                this.ajax('wordfence_deleteDatabaseOption', {
                    issueID: issueID
                }, function(res) {
                    self.doneDeleteDatabaseOption(res);
                });
            },
            doneDeleteDatabaseOption: function(res) {
                var cb = false;
                var self = this;
                if (res.ok) {
                    this.loadIssues(function() {
                        self.colorboxModal((self.isSmallScreen ? '300px' : '400px'), __("Success removing option"), sprintf(__("The option %s was successfully removed."), res.option_name));
                    });
                } else if (res.cerrorMsg) {
                    this.loadIssues(function() {
                        WFAD.colorboxError(res.cerrorMsg, res.tokenInvalid);
                    });
                }
            },
            useRecommendedHowGetIPs: function(issueID) {
                var self = this;
                this.ajax('wordfence_misconfiguredHowGetIPsChoice', {
                    issueID: issueID,
                    choice: 'yes'
                }, function(res) {
                    if (res.ok) {
                        jQuery('#wordfenceMisconfiguredHowGetIPsNotice').fadeOut();
                        
                        self.loadIssues(function() {
                            self.colorboxModal((self.isSmallScreen ? '300px' : '400px'), __("Success updating option"), __("The 'How does Wordfence get IPs' option was successfully updated to the recommended value."));
                        });
                    } else if (res.cerrorMsg) {
                        self.loadIssues(function() {
                            WFAD.colorboxError(res.cerrorMsg, res.tokenInvalid);
                        }); 
                    }
                });    
            },
            fixFPD: function(issueID) {
                var self = this;
                var title = __("Full Path Disclosure");
                issueID = parseInt(issueID);

                this.ajax('wordfence_checkHtaccess', {}, function(res) {
                    if (res.ok) {
                        self.colorboxModalHTML((self.isSmallScreen ? '300px' : '400px'), title, __('We are about to change your <em>.htaccess</em> file. Please make a backup of this file before proceeding.')
                            + '<br/>'
                            + '<a href="' + WordfenceAdminVars.ajaxURL + '?action=wordfence_downloadHtaccess&nonce=' + self.nonce + '" onclick="jQuery(\'#wfFPDNextBut\').prop(\'disabled\', false); return true;">' + __('Click here to download a backup copy of your .htaccess file now') + '</a><br /><br /><input type="button" class="wf-btn wf-btn-default" name="but1" id="wfFPDNextBut" value="Click to fix .htaccess" disabled="disabled" onclick="WFAD.fixFPD_WriteHtAccess(' + issueID + ');" />');
                    } else if (res.nginx) {
                        self.colorboxModalHTML((self.isSmallScreen ? '300px' : '400px'), title, __('You are using an Nginx web server and using a FastCGI processor like PHP5-FPM. You will need to manually modify your php.ini to disable <em>display_error</em>'));
                    } else if (res.err) {
                        self.colorboxModal((self.isSmallScreen ? '300px' : '400px'), __("We encountered a problem"), sprintf(__("We can't modify your .htaccess file for you because: %s"), res.err));
                    }
                });
            },
            fixFPD_WriteHtAccess: function(issueID) {
                var self = this;
                self.colorboxClose();
                this.ajax('wordfence_fixFPD', {
                    issueID: issueID
                }, function(res) {
                    if (res.ok) {
                        self.loadIssues(function() {
                            self.colorboxModal((self.isSmallScreen ? '300px' : '400px'), __("File restored OK"), __("The Full Path disclosure issue has been fixed"));
                        });
                    } else {
                        self.loadIssues(function() {
                            WFAD.colorboxError(res.cerrorMsg, res.tokenInvalid);
                        });
                    }
                });
            },
            
            hideFile: function(issueID, callback) {
                WFAD.ajax('wordfence_checkHtaccess', {}, function(checkRes) {
                    if (checkRes.ok) {
                        WFAD.colorboxModalHTML((WFAD.isSmallScreen ? '300px' : '400px'), __('.htaccess change'), __('We are about to change your <em>.htaccess</em> file. Please make a backup of this file before proceeding.')
                            + '<br/>'
                            + '<a id="dlButton" href="' + WordfenceAdminVars.ajaxURL + '?action=wordfence_downloadHtaccess&nonce=' + WFAD.nonce + '">' + __('Click here to download a backup copy of your .htaccess file now') + '</a>'
                            + '<br /><br /><input type="button" class="wf-btn wf-btn-default" name="but1" id="wfFPDNextBut" value="' + __('Click to fix .htaccess') + '" disabled="disabled" />'
                        );
                        $('#dlButton').on('click', function(e) {
                            $('#wfFPDNextBut').prop('disabled', false);
                        });
                        $('#wfFPDNextBut').on('click', function(e) {
                            e.preventDefault();
                            e.stopPropagation();

                            WFAD.ajax('wordfence_hideFileHtaccess', {
                                issueID: issueID
                            }, function(res) {
                                WFAD.colorboxClose();
                                typeof callback === 'function' && callback(res);
                            });
                        });
                    }
                    else if (checkRes.nginx) {
                        WFAD.colorboxModal((WFAD.isSmallScreen ? '300px' : '400px'), __('Unable to automatically hide file'), __('You are using an Nginx web server and using a FastCGI processor like PHP5-FPM. You will need to manually delete or hide those files.'));
                    }
                    else if (checkRes.err) {
                        WFAD.colorboxModal((WFAD.isSmallScreen ? '300px' : '400px'), __("We encountered a problem"), sprintf(__("We can't modify your .htaccess file for you because: %s"), res.err));
                    }
                });
            },

            restoreFile: function(issueID, callback) {
                this.ajax('wordfence_restoreFile', {
                    issueID: issueID
                }, function(res) {
                    if (res.needsCredentials) {
                        document.location.href = res.redirect;
                    }
                    else {
                        typeof callback === 'function' && callback(res);
                    }
                });
            },

            disableDirectoryListing: function(issueID) {
                var self = this;
                var title = "Disable Directory Listing";
                issueID = parseInt(issueID);

                this.ajax('wordfence_checkHtaccess', {}, function(res) {
                    if (res.ok) {
                        self.colorboxModalHTML((self.isSmallScreen ? '300px' : '400px'), title, __('We are about to change your <em>.htaccess</em> file. Please make a backup of this file before proceeding.')
                            + '<br/>'
                            + '<a href="' + WordfenceAdminVars.ajaxURL + '?action=wordfence_downloadHtaccess&nonce=' + self.nonce + '" onclick="jQuery(\'#wf-htaccess-confirm\').prop(\'disabled\', false); return true;">' + __('Click here to download a backup copy of your .htaccess file now') + '</a>' +
                            '<br /><br />' +
                            '<button class="wf-btn wf-btn-default" type="button" id="wf-htaccess-confirm" disabled="disabled" onclick="WFAD.confirmDisableDirectoryListing(' + issueID + ');">' + __('Add code to .htaccess') + '</button>');
                    } else if (res.nginx) {
                        self.colorboxModalHTML((self.isSmallScreen ? '300px' : '400px'), __("You are using Nginx as your web server. You'll need to disable autoindexing in your nginx.conf. See the <a target='_blank'  rel='noopener noreferrer' href='https://nginx.org/en/docs/http/ngx_http_autoindex_module.html'>Nginx docs for more info</a> on how to do this."));
                    } else if (res.err) {
                        self.colorboxModal((self.isSmallScreen ? '300px' : '400px'), __("We encountered a problem"), sprintf(__("We can't modify your .htaccess file for you because: %s"), res.err));
                    }
                });
            },
            confirmDisableDirectoryListing: function(issueID) {
                var self = this;
                this.colorboxClose();
                this.ajax('wordfence_disableDirectoryListing', {
                    issueID: issueID
                }, function(res) {
                    if (res.ok) {
                        self.loadIssues(function() {
                            self.colorboxModal((self.isSmallScreen ? '300px' : '400px'), __("Directory Listing Disabled"), __("Directory listing has been disabled on your server."));
                        });
                    } else {
                        //self.loadIssues(function() {
                        //    self.colorbox('400px', 'An error occurred', res.errorMsg);
                        //});
                    }
                });
            },

            deleteIssue: function(id) {
                var self = this;
                this.ajax('wordfence_deleteIssue', {id: id}, function(res) {
                    self.loadIssues();
                });
            },
            updateIssueStatus: function(id, st, callback) {
                this.ajax('wordfence_updateIssueStatus', {id: id, 'status': st}, function(res) {
                    typeof callback === 'function' && callback(res);
                });
            },
            es: function(val) {
                if (val) {
                    return val;
                } else {
                    return "";
                }
            },
            noQuotes: function(str) {
                return str.replace(/"/g, '&#34;').replace(/\'/g, '&#145;');
            },
            commify: function(num) {
                return ("" + num).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,");
            },
            switchToLiveTab: function(elem) {
                jQuery('.wfTab1').removeClass('selected');
                jQuery(elem).addClass('selected');
                jQuery('.wfDataPanel').hide();
                var self = this;
                jQuery('#wfActivity').fadeIn(function() {
                    self.completeLiveTabSwitch();
                });
            },
            completeLiveTabSwitch: function() {
                this.ajax('wordfence_loadActivityLog', {}, function(res) {
                    var html = '<a href="#" class="wfALogMailLink" onclick="WFAD.emailActivityLog(); return false;" role="button"></a><a href="#" class="wfALogReloadLink" onclick="WFAD.reloadActivityData(); return false;" role="button"></a>';
                    if (res.events && res.events.length > 0) {
                        jQuery('#wfActivity').empty();
                        for (var i = 0; i < res.events.length; i++) {
                            var timeTaken = '0.0000';
                            if (res.events[i + 1]) {
                                timeTaken = (res.events[i].ctime - res.events[i + 1].ctime).toFixed(4);
                            }
                            var red = "";
                            if (res.events[i].type == 'error') {
                                red = ' class="wfWarn" ';
                            }
                            html += '<div ' + red + 'class="wfALogEntry"><span ' + red + 'class="wfALogTime">[' + res.events[i].type + '&nbsp;:&nbsp;' + timeTaken + '&nbsp;:&nbsp;' + res.events[i].timeAgo + ' ago]</span>&nbsp;' + res.events[i].msg + "</div>";
                        }
                        jQuery('#wfActivity').html(html);
                    } else {
                        jQuery('#wfActivity').html("<p>&nbsp;&nbsp;" + __('No activity to report yet. Please complete your first scan.') + "</p>");
                    }
                });
            },
            emailActivityLog: function() {
                this.colorboxModalHTML((this.isSmallScreen ? '300px' : '400px'), __('Email Wordfence Activity Log'), __("Enter the email address you would like to send the Wordfence activity log to. Note that the activity log may contain thousands of lines of data. This log is usually only sent to a member of the Wordfence support team. It also contains your PHP configuration from the phpinfo() function for diagnostic data.") + "<br /><br /><input type='text' value='wftest@wordfence.com' size='20' id='wfALogRecip' /><input class='wf-btn wf-btn-default' type='button' value='" + __('Send') + "' onclick=\"WFAD.completeEmailActivityLog();\" />");
            },
            completeEmailActivityLog: function() {
                WFAD.colorboxClose();
                var email = jQuery('#wfALogRecip').val();
                if (!/^[^@]+@[^@]+$/.test(email)) {
                    alert(__("Please enter a valid email address."));
                    return;
                }
                var self = this;
                this.ajax('wordfence_sendActivityLog', {email: jQuery('#wfALogRecip').val()}, function(res) {
                    if (res.ok) {
                        self.colorboxModal((self.isSmallScreen ? '300px' : '400px'), __('Activity Log Sent'), sprintf(__("Your Wordfence activity log was sent to %s"), email));
                    }
                });
            },
            reloadActivityData: function() {
                jQuery('#wfActivity').html('<div class="wfLoadingWhite32"></div>'); //&nbsp;<br />&nbsp;<br />&nbsp;<br />&nbsp;<br />&nbsp;<br />&nbsp;<br />&nbsp;<br />&nbsp;<br />&nbsp;<br />&nbsp;<br />
                this.completeLiveTabSwitch();
            },
            switchToSummaryTab: function(elem) {
                jQuery('.wfTab1').removeClass('selected');
                jQuery(elem).addClass('selected');
                jQuery('.wfDataPanel').hide();
                jQuery('#wfSummaryTables').fadeIn();
            },
            switchIssuesTab: function(elem, type) {
                jQuery('.wfTab2').removeClass('selected');
                jQuery('.wfIssuesContainer').hide();
                jQuery(elem).addClass('selected');
                this.visibleIssuesPanel = type;
                jQuery('#wfIssues_' + type).fadeIn();
            },
            switchTab: function(tabElement, tabClass, contentClass, selectedContentID, callback) {
                jQuery('.' + tabClass).removeClass('selected');
                jQuery(tabElement).addClass('selected');
                jQuery('.' + contentClass).hide().html('<div class="wfLoadingWhite32"></div>');
                var func = function() {
                };
                if (callback) {
                    func = function() {
                        callback();
                    };
                }
                jQuery('#' + selectedContentID).fadeIn(func);
            },
            reloadLiveTraffic: function() {
                this.newestActivityTime = 0;
                this.updateLiveTraffic(true);
            },
            ucfirst: function(str) {
                str = "" + str;
                return str.charAt(0).toUpperCase() + str.slice(1);
            },
            makeIPTrafLink: function(IP) {
                return WordfenceAdminVars.siteBaseURL + '?_wfsf=IPTraf&nonce=' + this.nonce + '&IP=' + encodeURIComponent(IP);
            },
            getRealFileParameters: function(data) {
                if ('realFile' in data) {
                    return '&realFile=' + encodeURIComponent(this.es(data['realFile'])) + '&realFileToken=' + encodeURIComponent(this.es(data['realFileToken']));
                }
                else {
                    return '';
                }
            },
            makeDiffLink: function(dat) {
                return WordfenceAdminVars.siteBaseURL + '?_wfsf=diff&nonce=' + this.nonce +
                    '&file=' + encodeURIComponent(this.es(dat['file'])) +
                    this.getRealFileParameters(dat) +
                    '&cType=' + encodeURIComponent(this.es(dat['cType'])) +
                    '&cKey=' + encodeURIComponent(this.es(dat['cKey'])) +
                    '&cName=' + encodeURIComponent(this.es(dat['cName'])) +
                    '&cVersion=' + encodeURIComponent(this.es(dat['cVersion']));
            },
            makeViewFileLink: function(data) {
                return WordfenceAdminVars.siteBaseURL + '?_wfsf=view&nonce=' + this.nonce + '&file=' + encodeURIComponent(data.file) + this.getRealFileParameters(data);
            },
            makeDownloadFileLink: function(data) {
                return WordfenceAdminVars.siteBaseURL + '?_wfsf=download&nonce=' + this.nonce + '&file=' + encodeURIComponent(data.file) + this.getRealFileParameters(data);
            },
            makeViewOptionLink: function(option, siteID) {
                return WordfenceAdminVars.siteBaseURL + '?_wfsf=viewOption&nonce=' + this.nonce + '&option=' + encodeURIComponent(option) + '&site_id=' + encodeURIComponent(siteID);
            },
            parseHashes: function() {
                var hashes = window.location.hash.replace('%23', '#');
                var splitHashes = hashes.split('#');
                var result = [];
                for (var i = 0; i < splitHashes.length; i++) {
                    if (splitHashes[i].length > 0) {
                        result.push(splitHashes[i]);
                    }
                }
                return result;
            },
            makeTimeAgo: function(t) {
                var months = Math.floor(t / (86400 * 30));
                var days = Math.floor(t / 86400);
                var hours = Math.floor(t / 3600);
                var minutes = Math.floor(t / 60);
                if (months > 0) {
                    days -= months * 30;
                    return this.pluralize(months, 'month', days, 'day');
                } else if (days > 0) {
                    hours -= days * 24;
                    return this.pluralize(days, 'day', hours, 'hour');
                } else if (hours > 0) {
                    minutes -= hours * 60;
                    return this.pluralize(hours, 'hour', minutes, 'min');
                } else if (minutes > 0) {
                    //t -= minutes * 60;
                    return this.pluralize(minutes, 'minute');
                } else {
                    return Math.round(t) + " seconds";
                }
            },
            pluralize: function(m1, t1, m2, t2) {
                if (m1 != 1) {
                    t1 = t1 + 's';
                }
                if (m2 != 1) {
                    t2 = t2 + 's';
                }
                if (m1 && m2) {
                    return m1 + ' ' + t1 + ' ' + m2 + ' ' + t2;
                } else {
                    return m1 + ' ' + t1;
                }
            },
            isValidIP: function(ip) {
                if (!ip) {
                    return false;
                }
                ip = ip.replace(/ /g, '');
                if (ip.match(/^(?:\d{1,3}(?:\.|$)){4}/)) { //IPv4
                    var octets = ip.split('.');
                    if (octets.length != 4) {
                        return false;
                    }
                    
                    for (var i = 0; i < octets.length; i++) {
                        if (parseInt(octets[i]) > 255) {
                            return false;
                        }
                    }

                    return !!this.inet_pton(ip);
                }
                else if (ip.match(/^((?:[\da-f]{1,4}(?::|)){0,8})(::)?((?:[\da-f]{1,4}(?::|)){0,8})$/i)) { //IPv6
                    if (ip == '::') {
                        return true;
                    }

                    var colonCount = ip.split(':').length - 1;
                    var doubleColonPos = ip.indexOf('::');
                    if (doubleColonPos > -1) {
                        var expansionLength = ((doubleColonPos == 0 || doubleColonPos == ip.length - 2) ? 9 : 8) - colonCount;
                        if (expansionLength == 0) { //Double-colon in a full IPv6 address
                            return false;
                        }
                        
                        var expansion = '';
                        for (i = 0; i < expansionLength; i++) {
                            expansion += ':0000';
                        }
                        ip = ip.replace('::', expansion + ':');
                        ip = ip.replace(/(?:^\:|\:$)/, '', ip);
                    }

                    var ipGroups = ip.split(':');
                    var ipBin = '';
                    for (i = 0; i < ipGroups.length; i++) {
                        var group = ipGroups[i];
                        if (group.length > 4 || group.length == 0) {
                            return false;
                        }
                        group = ("0000" + group).slice(-4);
                        var b1 = parseInt(group.slice(0, 2), 16);
                        var b2 = parseInt(group.slice(-2), 16);
                        if (isNaN(b1) || isNaN(b2)) {
                            return false;
                        }
                        ipBin += String.fromCharCode(b1) + String.fromCharCode(b2);
                    }

                    return ipBin.length == 16 ? true : false;
                }
                
                return false;
            },
            parseIPRange: function(range) {
                if (!range) {
                    return false;
                }
                range = range.replace(/ /g, '');
                range = range.replace(/[\u2013-\u2015]/g, '-'); //Non-hyphen dashes to hyphen
                if (range && /^[^\-]+\-[^\-]+$/.test(range)) {
                    var count = 1;
                    var countOverflow = false;

                    var ips = range.split('-');
                    var ip1 = this.inet_pton(ips[0]);
                    var ip2 = this.inet_pton(ips[1]);

                    if (ip1 === false || !this.isValidIP(ips[0]) || ip2 === false || !this.isValidIP(ips[1])) {
                        return false;
                    }
                    
                    //Both to 16-byte binary strings
                    var binStart = ("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff" + ip1).slice(-16);
                    var binEnd = ("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff" + ip2).slice(-16);

                    for (var i = 0; i < binStart.length; i++) {
                        var n0 = binStart.charCodeAt(i);
                        var n1 = binEnd.charCodeAt(i);

                        if (i < 11 && n1 - n0 > 0) { //Based on Number.MAX_SAFE_INTEGER, which equals 2 ^ 53 - 1. Any of the first 9 bytes and part of the 10th that add to the range will put us over that
                            countOverflow = true;
                            break;
                        }
                        else if (i < 11 && n1 - n0 < 0) {
                            return false;
                        }

                        count += (n1 - n0) << (8 * (15 - i));
                        if (count < 1) {
                            return false;
                        }
                    }
                    
                    return {start: ip1, end: ip2, count: count, countOverflow: countOverflow};
                }
                else if (range && /^[^\/]+\/\d+$/.test(range)) {
                    var count = 1;
                    var countOverflow = false;

                    var components = range.split('/');
                    var ip = this.inet_pton(components[0]);
                    var bits = parseInt(components[1]);
                    
                    if (ip === false || !this.isValidIP(components[0])) {
                        return false;
                    }
                    
                    var binIP = ("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff" + ip).slice(-16);
                    if (binIP.slice(12) === "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff") {
                        if (bits < 1 || bits > 32) {
                            return false;
                        }
                    }
                    else {
                        if (bits < 1 || bits > 128) {
                            return false;
                        }
                    }
                    
                    if (bits >= 53) {
                        countOverflow = true;
                        count = Math.pow(2, 53) - 1; /* Number.MAX_SAFE_INTEGER is unavailable in IE */
                    }
                    else {
                        count = Math.pow(2, bits);
                    }

                    return {ip: ip, bits: bits, count: count, countOverflow: countOverflow};
                }
                
                return false;
            },
            calcRangeTotal: function() {
                var range = jQuery('#ipRange').val();
                if (!range) {
                    return;
                }
                range = range.replace(/ /g, '');
                range = range.replace(/[\u2013-\u2015]/g, '-'); //Non-hyphen dashes to hyphen
                if (range && /^[^\-]+\-[^\-]+$/.test(range)) {
                    var count = 1;
                    var countOverflow = false;
                    var badRange = false;
                    var badIP = false;
                    
                    var ips = range.split('-');
                    var ip1 = this.inet_pton(ips[0]);
                    var ip2 = this.inet_pton(ips[1]);
                    
                    if (ip1 === false || ip2 === false) {
                        badIP = true;
                    }
                    else {
                        //Both to 16-byte binary strings
                        var binStart = ("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff" + ip1).slice(-16);
                        var binEnd = ("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff" + ip2).slice(-16);
                        
                        for (var i = 0; i < binStart.length; i++) {
                            var n0 = binStart.charCodeAt(i);
                            var n1 = binEnd.charCodeAt(i);
                            
                            if (i < 11 && n1 - n0 > 0) { //Based on Number.MAX_SAFE_INTEGER, which equals 2 ^ 53 - 1. Any of the first 9 bytes and part of the 10th that add to the range will put us over that
                                countOverflow = true;
                                break;
                            }
                            else if (i < 11 && n1 - n0 < 0) {
                                badRange = true;
                                break;
                            }
                            
                            count += (n1 - n0) << (8 * (15 - i));
                            if (count < 1) {
                                badRange = true;
                                break;
                            }
                        }
                    }
                    
                    if (badIP) {
                        jQuery('#wfShowRangeTotal').html("<span style=\"color: #F00;\">Invalid IP entered.</span>"); 
                        return;
                    }
                    else if (badRange) {
                        jQuery('#wfShowRangeTotal').html("<span style=\"color: #F00;\">Invalid. Starting IP is greater than ending IP.</span>");
                        return;
                    }
                    else if (countOverflow) {
                        jQuery('#wfShowRangeTotal').html("<span style=\"color: #0A0;\">Valid: &gt;281474976710656 addresses in range.</span>");
                        return;
                    }

                    jQuery('#wfShowRangeTotal').html("<span style=\"color: #0A0;\">Valid: " + count + " addresses in range.</span>"); 
                }
                else {
                    jQuery('#wfShowRangeTotal').empty();
                }
            },
            completeWhois: function(res, ret) {
                ret = ret === undefined ? false : !!ret;
                var self = this;
                var rawhtml = "";
                var ipRangeTmpl = jQuery("<div><div class='wf-flex-row'>" +
                    "<a class=\"wf-btn wf-btn-default wf-flex-row-0\" href=\"${adminUrl}\">" + __('Block This Network') + "</a>" +
                    "<span class='wf-flex-row-1 wf-padding-add-left'>{{html totalStr}}{{if totalStr.indexOf(ipRange) == -1}} (${ipRange}){{/if}}" +
                    '{{if (totalIPs)}}<br>[' + __('${totalIPs} addresses in this network') + ']{{/if}}' +
                    "</span></div></div>");
                if (res.ok && res.result && res.result.rawdata && res.result.rawdata.length > 0) {
                    for (var i = 0; i < res.result.rawdata.length; i++) {
                        res.result.rawdata[i] = jQuery('<div />').text(res.result.rawdata[i]).html();
                        res.result.rawdata[i] = res.result.rawdata[i].replace(/([a-zA-Z0-9\-._+]+@[a-zA-Z0-9\-._]+)/, "<a href=\"mailto:$1\">$1<\/a>");
                        res.result.rawdata[i] = res.result.rawdata[i].replace(/(https?:\/\/[a-zA-Z0-9\-._+\/?&=#%:@;]+)/, "<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"$1\">$1<\/a>");

                        function wfm21(str, startStr, ipRange, offset, totalStr) {
                            var ips = ipRange.split(/\s*\-\s*/);
                            var totalIPs = NaN;
                            if (ips[0].indexOf(':') < 0) {
                                var ip1num = self.inet_aton(ips[0]);
                                var ip2num = self.inet_aton(ips[1]);
                                totalIPs = ip2num - ip1num + 1;
                            }
                            var adminUrl = "admin.php?page=WordfenceWAF&wfBlockRange=" + encodeURIComponent(ipRange) + "#top#blocking";
                            return jQuery(ipRangeTmpl).tmpl({
                                adminUrl: adminUrl,
                                totalStr: totalStr,
                                ipRange: ipRange,
                                totalIPs: totalIPs
                            }).wrapAll('<div>').parent().html();
                        }

                        function buildRangeLink2(str, startStr, octet1, octet2, octet3, octet4, cidrRange, offset, totalStr) {

                            octet3 = octet3.length > 0 ? octet3 : '0';
                            octet4 = octet4.length > 0 ? octet4 : '0';

                            var rangeStart = [octet1, octet2, octet3, octet4].join('.');
                            var rangeStartNum = self.inet_aton(rangeStart);
                            cidrRange = parseInt(cidrRange, 10);
                            if (!isNaN(rangeStartNum) && cidrRange > 0 && cidrRange < 32) {
                                var rangeEndNum = rangeStartNum;
                                for (var i = 32, j = 1; i >= cidrRange; i--, j *= 2) {
                                    rangeEndNum |= j;
                                }
                                rangeEndNum = rangeEndNum >>> 0;
                                var ipRange = self.inet_ntoa(rangeStartNum) + ' - ' + self.inet_ntoa(rangeEndNum);
                                var totalIPs = rangeEndNum - rangeStartNum + 1;
                                var adminUrl = "admin.php?page=WordfenceWAF&wfBlockRange=" + encodeURIComponent(ipRange) + "#top#blocking";
                                return jQuery(ipRangeTmpl).tmpl({
                                    adminUrl: adminUrl,
                                    totalStr: totalStr,
                                    ipRange: ipRange,
                                    totalIPs: totalIPs
                                }).wrapAll('<div>').parent().html();

                            }
                            return str;
                        }

                        var rangeRegex = /(.*?)(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3} - \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|[a-f0-9:.]{3,} - [a-f0-9:.]{3,}).*$/i;
                        var cidrRegex = /(.*?)(\d{1,3})\.(\d{1,3})\.?(\d{0,3})\.?(\d{0,3})\/(\d{1,3}).*$/i;
                        if (rangeRegex.test(res.result.rawdata[i])) {
                            res.result.rawdata[i] = res.result.rawdata[i].replace(rangeRegex, wfm21);
                            rawhtml += res.result.rawdata[i];
                        } else if (cidrRegex.test(res.result.rawdata[i])) {
                            res.result.rawdata[i] = res.result.rawdata[i].replace(cidrRegex, buildRangeLink2);
                            rawhtml += res.result.rawdata[i];
                        } else {
                            rawhtml += res.result.rawdata[i] + "<br />";
                        }
                    }
                    rawhtml = rawhtml.replace(/<\/div><br \/>/g, '</div>');
                } else {
                    var message = __('Sorry, but no data for that IP or domain was found.');
                    var content = jQuery('<span style="color: #F00;">');
                    content.text(message);
                    rawhtml = content.get(0).outerHTML;
                }
                if (ret) {
                    return rawhtml;
                }
                jQuery('#wfrawhtml').html(rawhtml);
            },
            blockIPUARange: function(ipRange, hostname, uaRange, referer, reason) {
                if (!/\w+/.test(reason)) {
                    this.colorboxModal('300px', __("Please specify a reason"), __("You forgot to include a reason you're blocking this IP range. We ask you to include this for your own record keeping."));
                    return;
                }
                ipRange = ipRange.replace(/ /g, '').toLowerCase();
                ipRange = ipRange.replace(/[\u2013-\u2015]/g, '-'); //Non-hyphen dashes to hyphen
                if (ipRange) {
                    var range = ipRange.split('-'),
                        validRange;
                    if (range.length !== 2) {
                        validRange = false;
                    } else if (range[0].match(':')) {
                        validRange = this.inet_pton(range[0]) !== false && this.inet_pton(range[1]) !== false;
                    } else if (range[0].match('.')) {
                        validRange = this.inet_aton(range[0]) !== false && this.inet_aton(range[1]) !== false;
                    }
                    if (!validRange) {
                        this.colorboxModal('300px', __('Specify a valid IP range'), __("Please specify a valid IP address range in the form of \"1.2.3.4 - 1.2.3.5\" without quotes. Make sure the dash between the IP addresses in a normal dash (a minus sign on your keyboard) and not another character that looks like a dash."));
                        return;
                    }
                }
                if (hostname && !/^[a-z0-9\.\*\-]+$/i.test(hostname)) {
                    this.colorboxModalHTML('300px', __('Specify a valid hostname'), sprintf(__('%s is not valid hostname'), '<i>' + this.htmlEscape(hostname) + '</i>'));
                    return;
                }
                if (!(/\w+/.test(ipRange) || /\w+/.test(uaRange) || /\w+/.test(referer) || /\w+/.test(hostname))) {
                    this.colorboxModal('300px', __('Specify an IP range, Hostname or Browser pattern'), __("Please specify either an IP address range, Hostname or a web browser pattern to match."));
                    return;
                }
                var self = this;
                this.ajax('wordfence_blockIPUARange', {
                    ipRange: ipRange,
                    hostname: hostname,
                    uaRange: uaRange,
                    referer: referer,
                    reason: reason
                }, function(res) {
                    if (res.ok) {
                        self.loadBlockRanges();
                        return;
                    }
                });
            },
            blockIP: function(IP, reason, callback) {
                var self = this;
                this.ajax('wordfence_blockIP', {
                    IP: IP,
                    reason: reason
                }, function(res) {
                    if (res.errorMsg) {
                        return;
                    } else {
                        self.reloadLiveTraffic();
                        typeof callback === 'function' && callback();
                    }
                });
            },
            unlockOutIP: function(IP) {
                var self = this;
                this.ajax('wordfence_unlockOutIP', {
                    IP: IP
                }, function(res) {
                    self.staticTabChanged();
                });
            },
            unblockIP: function(IP, callback) {
                var self = this;
                this.ajax('wordfence_unblockIP', {
                    IP: IP
                }, function(res) {
                    self.reloadLiveTraffic();
                    typeof callback === 'function' && callback();
                });
            },
            unblockNetwork: function(id) {
                var self = this;
                this.ajax('wordfence_unblockRange', {
                    id: id
                }, function(res) {
                    self.reloadLiveTraffic();
                });
            },
            unblockIPTwo: function(IP) {
                var self = this;
                this.ajax('wordfence_unblockIP', {
                    IP: IP
                }, function(res) {
                    self.staticTabChanged();
                });
            },
            permBlockIP: function(IP) {
                var self = this;
                this.ajax('wordfence_permBlockIP', {
                    IP: IP
                }, function(res) {
                    self.staticTabChanged();
                });
            },
            makeElemID: function() {
                return 'wfElemGen' + this.elementGeneratorIter++;
            },
            pulse: function(sel) {
                jQuery(sel).fadeIn(function() {
                    setTimeout(function() {
                        jQuery(sel).fadeOut();
                    }, 2000);
                });
            },
            twoFacStatus: function(msg) {
                this.colorboxModal('300px', __('Two Factor Status'), msg);
            },
            addTwoFactor: function(username, phone, mode) {
                var self = this;
                this.ajax('wordfence_addTwoFactor', {
                    username: username,
                    phone: phone,
                    mode: mode
                }, function(res) {
                    if (res.ok) {
                        if (mode == 'authenticator') {
                            var totpURL = "otpauth://totp/" + encodeURI(res.homeurl) + encodeURI(" (" + res.username + ")") + "?" + res.uriQueryString + "&issuer=Wordfence";                             
                            var message = __('Scan the code below with your authenticator app to add this account. Some authenticator apps also allow you to type in the text version instead.') + "<br><div id=\"wfTwoFactorQRCodeTable\"></div><br><strong>" + __('Key:') + "</strong> <input type=\"text\"" + (self.isSmallScreen ? "" : " size=\"45\"") + " value=\"" + res.base32Secret + "\" onclick=\"this.select();\" readonly>";
                            if (res.recoveryCodes.length > 0) {
                                message = message + "<br><br><strong>" + __('Recovery Codes') + "</strong><br><p>" + sprintf(__("Use one of these %s codes to log in if you lose access to your authenticator device. Codes are 16 characters long, plus optional spaces. Each one may be used only once."), res.recoveryCodes.length) + "</p><ul id=\"wfTwoFactorRecoveryCodes\">";

                                var recoveryCodeFileContents = __('Cellphone Sign-In Recovery Codes') + " - " + res.homeurl + " (" + res.username + ")\r\n";
                                recoveryCodeFileContents = recoveryCodeFileContents + "\r\n" + __("Each line of 16 letters and numbers is a single recovery code, with optional spaces for readability. When typing your password, enter \"wf\" followed by the entire code like \"mypassword wf1234 5678 90AB CDEF\". If your site shows a separate prompt for entering a code after entering only your username and password, enter only the code like \"1234 5678 90AB CDEF\". Your recovery codes are:") + "\r\n\r\n";
                                var splitter = /.{4}/g;
                                for (var i = 0; i < res.recoveryCodes.length; i++) { 
                                    var code = res.recoveryCodes[i];
                                    var chunks = code.match(splitter);
                                    message = message + "<li>" + chunks[0] + " " + chunks[1] + " " + chunks[2] + " " + chunks[3] + "</li>";
                                    recoveryCodeFileContents = recoveryCodeFileContents + chunks[0] + " " + chunks[1] + " " + chunks[2] + " " + chunks[3] + "\r\n"; 
                                }
                                
                                message = message + "</ul>";
                                
                                message = message + "<p class=\"wf-center\"><a href=\"#\" class=\"wf-btn wf-btn-default\" id=\"wfTwoFactorDownload\" target=\"_blank\" rel=\"noopener noreferrer\"><i class=\"dashicons dashicons-download\"></i> " + __('Download') + "</a></p>";
                            }

                            message = message + "<p><em>" + __("This will be shown only once. Keep these codes somewhere safe.") + "</em></p>";
                            
                            self.colorboxModalHTML((self.isSmallScreen ? '300px' : '440px'), __("Authentication Code"), message, {onComplete: function() {
                                jQuery('#wfTwoFactorQRCodeTable').qrcode({text: totpURL, width: (self.isSmallScreen ? 175 : 256), height: (self.isSmallScreen ? 175 : 256)});
                                jQuery('#wfTwoFactorDownload').on('click', function(e) {
                                    e.preventDefault();
                                    e.stopPropagation();
                                    saveAs(new Blob([recoveryCodeFileContents], {type: "text/plain;charset=" + document.characterSet}), self.htmlEscape(res.homeurl) + "_" + self.htmlEscape(res.username) + "_recoverycodes.txt");
                                });
                            }});
                        }
                        else {
                            if (res.recoveryCodes.length > 0) {
                                var message = "<p>" + sprintf(__("Use one of these %s codes to log in if you are unable to access your phone. Codes are 16 characters long, plus optional spaces. Each one may be used only once."), res.recoveryCodes.length) + "</p><ul id=\"wfTwoFactorRecoveryCodes\">";

                                var recoveryCodeFileContents = __('Cellphone Sign-In Recovery Codes') + " - " + res.homeurl + " (" + res.username + ")\r\n";
                                recoveryCodeFileContents = recoveryCodeFileContents + "\r\n" + __("Each line of 16 letters and numbers is a single recovery code, with optional spaces for readability. When typing your password, enter \"wf\" followed by the entire code like \"mypassword wf1234 5678 90AB CDEF\". If your site shows a separate prompt for entering a code after entering only your username and password, enter only the code like \"1234 5678 90AB CDEF\". Your recovery codes are:") + "\r\n\r\n";
                                var splitter = /.{4}/g;
                                for (var i = 0; i < res.recoveryCodes.length; i++) {
                                    var code = res.recoveryCodes[i];
                                    var chunks = code.match(splitter);
                                    message = message + "<li>" + chunks[0] + " " + chunks[1] + " " + chunks[2] + " " + chunks[3] + "</li>";
                                    recoveryCodeFileContents = recoveryCodeFileContents + chunks[0] + " " + chunks[1] + " " + chunks[2] + " " + chunks[3] + "\r\n";
                                }

                                message = message + "<p class=\"wf-center\"><a href=\"#\" class=\"wf-btn wf-btn-default\" id=\"wfTwoFactorDownload\" target=\"_blank\" rel=\"noopener noreferrer\"><i class=\"dashicons dashicons-download\"></i> " + __('Download') + "</a></p>";

                                message = message + "</ul><p><em>" + __("This will be shown only once. Keep these codes somewhere safe.") + "</em></p>";

                                self.colorboxModalHTML((self.isSmallScreen ? '300px' : '400px'), __("Recovery Codes"), message, {onComplete: function() {
                                    jQuery('#wfTwoFactorDownload').on('click', function(e) {
                                        e.preventDefault();
                                        e.stopPropagation();
                                        saveAs(new Blob([recoveryCodeFileContents], {type: "text/plain;charset=" + document.characterSet}), self.htmlEscape(res.homeurl) + "_" + self.htmlEscape(res.username) + "_recoverycodes.txt");
                                    });
                                }});
                            }
                        }
                        
                        var updatedTwoFac = jQuery('#wfTwoFacUserTmpl').tmpl({users: [res]});
                        jQuery('#twoFactorUser-none').remove();
                        jQuery('#wfTwoFacUsers > table > tbody:last-child').append(updatedTwoFac.find('tbody > tr'));
                    }
                });
            },
            twoFacActivate: function(userID, code) {
                var self = this;
                this.ajax('wordfence_twoFacActivate', {
                    userID: userID,
                    code: code
                }, function(res) {
                    if (res.ok) {
                        var updatedTwoFac = jQuery('#wfTwoFacUserTmpl').tmpl({users: [res]});
                        updatedTwoFac.find('tbody > tr').each(function(index, element) {
                            jQuery('#' + jQuery(element).attr('id')).replaceWith(element);
                        });
                        self.twoFacStatus(__('Cellphone Sign-in activated for user.'));
                    }
                });
            },
            delTwoFac: function(userID) {
                this.ajax('wordfence_twoFacDel', {
                    userID: userID
                }, function(res) {
                    if (res.ok) {
                        jQuery('#twoFactorUser-' + res.userID).fadeOut(function() {
                            jQuery(this).remove();
                            
                            if (jQuery('#wfTwoFacUsers > table > tbody:last-child').children().length == 0) {
                                jQuery('#wfTwoFacUsers').html(jQuery('#wfTwoFacUserTmpl').tmpl({users: []}));
                            }
                        });
                    }
                });
            },
            loadTwoFactor: function() {
                this.ajax('wordfence_loadTwoFactor', {}, function(res) {
                    jQuery('#wfTwoFacUsers').html(jQuery('#wfTwoFacUserTmpl').tmpl(res));
                });
            },
            getQueryParam: function(name) {
                name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
                var regexS = "[\\?&]" + name + "=([^&#]*)";
                var regex = new RegExp(regexS);
                var results = regex.exec(window.location.search);
                if (results == null) {
                    return "";
                } else {
                    return decodeURIComponent(results[1].replace(/\+/g, " "));
                }
            },
            inet_aton: function(dot) {
                var d = dot.split('.');
                return ((((((+d[0]) * 256) + (+d[1])) * 256) + (+d[2])) * 256) + (+d[3]);
            },
            inet_ntoa: function(num) {
                var d = num % 256;
                for (var i = 3; i > 0; i--) {
                    num = Math.floor(num / 256);
                    d = num % 256 + '.' + d;
                }
                return d;
            },

            inet_pton: function(a) {
                //  discuss at: http://phpjs.org/functions/inet_pton/
                // original by: Theriault
                //   example 1: inet_pton('::');
                //   returns 1: '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0'
                //   example 2: inet_pton('127.0.0.1');
                //   returns 2: '\x7F\x00\x00\x01'

                var r, m, x, i, j, f = String.fromCharCode;
                m = a.match(/^(?:\d{1,3}(?:\.|$)){4}/); // IPv4
                if (m) {
                    m = m[0].split('.');
                    m = f(m[0]) + f(m[1]) + f(m[2]) + f(m[3]);
                    // Return if 4 bytes, otherwise false.
                    return m.length === 4 ? m : false;
                }
                r = /^((?:[\da-f]{1,4}(?::|)){0,8})(::)?((?:[\da-f]{1,4}(?::|)){0,8})$/i;
                m = a.match(r); // IPv6
                if (m) {
                    if (a == '::') {
                        return "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
                    }

                    var colonCount = a.split(':').length - 1;
                    var doubleColonPos = a.indexOf('::');
                    if (doubleColonPos > -1) {
                        var expansionLength = ((doubleColonPos == 0 || doubleColonPos == a.length - 2) ? 9 : 8) - colonCount;
                        var expansion = '';
                        for (i = 0; i < expansionLength; i++) {
                            expansion += ':0000';
                        }
                        a = a.replace('::', expansion + ':');
                        a = a.replace(/(?:^\:|\:$)/, '', a);
                    }
                    
                    var ipGroups = a.split(':');
                    var ipBin = '';
                    for (i = 0; i < ipGroups.length; i++) {
                        var group = ipGroups[i];
                        if (group.length > 4) {
                            return false;
                        }
                        group = ("0000" + group).slice(-4);
                        var b1 = parseInt(group.slice(0, 2), 16);
                        var b2 = parseInt(group.slice(-2), 16);
                        if (isNaN(b1) || isNaN(b2)) {
                            return false;
                        }
                        ipBin += f(b1) + f(b2);
                    }
                    
                    return ipBin.length == 16 ? ipBin : false;
                }
                return false; // Invalid IP.
            },
            inet_ntop: function(a) {
                //  discuss at: http://phpjs.org/functions/inet_ntop/
                // original by: Theriault
                //   example 1: inet_ntop('\x7F\x00\x00\x01');
                //   returns 1: '127.0.0.1'
                //   example 2: inet_ntop('\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1');
                //   returns 2: '::1'

                var i = 0,
                    m = '',
                    c = [];
                a += '';
                if (a.length === 4) { // IPv4
                    return [
                        a.charCodeAt(0), a.charCodeAt(1), a.charCodeAt(2), a.charCodeAt(3)].join('.');
                } else if (a.length === 16) { // IPv6
                    for (i = 0; i < 16; i++) {
                        c.push(((a.charCodeAt(i++) << 8) + a.charCodeAt(i))
                            .toString(16));
                    }
                    return c.join(':')
                        .replace(/((^|:)0(?=:|$))+:?/g, function(t) {
                            m = (t.length > m.length) ? t : m;
                            return t;
                        })
                        .replace(m || ' ', '::');
                } else { // Invalid length
                    return false;
                }
            },

            deleteAdminUser: function(issueID) {
                var self = this;
                this.ajax('wordfence_deleteAdminUser', {
                    issueID: issueID
                }, function(res) {
                    if (res.ok) {
                        self.loadIssues(function() {
                            self.colorboxModal((self.isSmallScreen ? '300px' : '400px'), __("Successfully deleted admin"), sprintf(__("The admin user %s was successfully deleted."), res.user_login));
                        });
                    } else if (res.errorMsg) {
                        self.loadIssues(function() {
                            WFAD.colorboxError(res.errorMsg, res.tokenInvalid);
                        });
                    }
                });
            },

            revokeAdminUser: function(issueID) {
                var self = this;
                this.ajax('wordfence_revokeAdminUser', {
                    issueID: issueID
                }, function(res) {
                    if (res.ok) {
                        self.loadIssues(function() {
                            self.colorboxModal((self.isSmallScreen ? '300px' : '400px'), __("Successfully revoked admin"), sprintf(__("All capabilties of admin user %s were successfully revoked."), res.user_login));
                        });
                    } else if (res.errorMsg) {
                        self.loadIssues(function() {
                            WFAD.colorboxError(res.errorMsg, res.tokenInvalid);
                        });
                    }
                });
            },
            
            acknowledgeAdminUser: function (issueID) {
                var self = this;
                this.ajax('wordfence_acknowledgeAdminUser', {
                    issueID: issueID
                }, function(res) {
                    if (res.ok) {
                        self.loadIssues(function() {
                            self.colorboxModal((self.isSmallScreen ? '300px' : '400px'), __("Successfully acknowledged admin"), sprintf(__("The admin user %s will no longer show up in future scans."), res.user_login));
                        });
                    } else if (res.errorMsg) {
                        self.loadIssues(function() {
                            WFAD.colorboxError(res.errorMsg, res.tokenInvalid);
                        });
                    }
                });
            },

            windowHasFocus: function() {
                if (typeof document.hasFocus === 'function') {
                    return document.hasFocus();
                }
                // Older versions of Opera
                return this._windowHasFocus;
            },

            htmlEscape: function(html) {
                return String(html)
                    .replace(/&/g, '&amp;')
                    .replace(/"/g, '&quot;')
                    .replace(/'/g, '&#39;')
                    .replace(/</g, '&lt;')
                    .replace(/>/g, '&gt;');
            },

            permanentlyBlockAllIPs: function(type) {
                var self = this;
                this.ajax('wordfence_permanentlyBlockAllIPs', {
                    type: type
                }, function(res) {
                    $('#wfTabs').find('.wfTab1').eq(0).trigger('click');
                });
            },

            showTimestamp: function(timestamp, serverTime, format) {
                serverTime = serverTime === undefined ? new Date().getTime() / 1000 : serverTime;
                format = format === undefined ? '${dateTime} (${timeAgo} ago)' : format;
                var date = new Date(timestamp * 1000);

                return jQuery.tmpl(format, {
                    dateTime: date.toLocaleDateString() + ' ' + date.toLocaleTimeString(),
                    timeAgo: this.makeTimeAgo(serverTime - timestamp)
                });
            },

            updateTimeAgo: function() {
                var self = this;
                jQuery('.wfTimeAgo-timestamp').each(function(idx, elem) {
                    var el = jQuery(elem);
                    var testEl = el;
                    if (typeof jQuery === "function" && testEl instanceof jQuery) {
                        testEl = testEl[0];
                    }

                    var rect = testEl.getBoundingClientRect();
                    if (!(rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth))) {
                        return;
                    }
                    
                    var timestamp = el.data('wfctime');
                    if (!timestamp) {
                        timestamp = el.attr('data-timestamp');
                    }
                    var serverTime = self.serverMicrotime;
                    var format = el.data('wfformat');
                    if (!format) {
                        format = el.attr('data-format');
                    }
                    el.html(self.showTimestamp(timestamp, serverTime, format));
                });
            },

            wafData: {
                whitelistedURLParams: []
            },
            restoreWAFData: {
                whitelistedURLParams: []
            },
            
            wafWhitelistedBulkChangeEnabled: function(enabled) {
                $('.wf-whitelist-table-bulk-checkbox.wf-option-checkbox.wf-checked').each(function() {
                    $(this).closest('tr').find('.wf-whitelist-item-enabled.wf-option-checkbox').each(function() {
                        if (($(this).hasClass('wf-checked') && !enabled) || (!$(this).hasClass('wf-checked') && enabled)) {
                            var tr = $(this).closest('tr');
                            if (tr.is(':visible')) {
                                WFAD.wafWhitelistedChangeEnabled(tr.data('key'), enabled);
                            }
                        }
                    });
                })
            },
            
            wafWhitelistedChangeEnabled: function(key, enabled) {
                $('#waf-whitelisted-urls-wrapper .whitelist-table > tbody > tr[data-key="' + key + '"]').each(function() {
                    var adding = !!$(this).data('adding');
                    if (adding) {
                        WFAD.pendingChanges['whitelistedURLParams']['add'][key]['data']['disabled'] = !enabled ? 1 : 0;
                    }
                    else {
                        if (!(WFAD.pendingChanges['whitelistedURLParams'] instanceof Object)) {
                            WFAD.pendingChanges['whitelistedURLParams'] = {};
                        }

                        if (!(WFAD.pendingChanges['whitelistedURLParams']['enabled'] instanceof Object)) {
                            WFAD.pendingChanges['whitelistedURLParams']['enabled'] = {};
                        }

                        WFAD.pendingChanges['whitelistedURLParams']['enabled'][key] = !!enabled ? 1 : 0;
                    }
                    $(this).find('.wf-whitelist-item-enabled.wf-option-checkbox').toggleClass('wf-checked', !!enabled);
                });
            },

            wafWhitelistedBulkDelete: function() {
                $('.wf-whitelist-table-bulk-checkbox.wf-option-checkbox.wf-checked').each(function() {
                    $(this).closest('tr').find('.wf-whitelist-item-enabled.wf-option-checkbox').each(function() {
                        var tr = $(this).closest('tr');
                        if (tr.is(':visible')) {
                            WFAD.wafWhitelistedDelete(tr.data('key'));
                        }
                    });
                });
            },

            wafWhitelistedDelete: function(key) {
                $('#waf-whitelisted-urls-wrapper .whitelist-table > tbody > tr[data-key="' + key + '"]').each(function() {
                    var adding = !!$(this).data('adding');
                    if (adding) {
                        delete WFAD.pendingChanges['whitelistedURLParams']['add'][key];
                    }
                    else {
                        if (!(WFAD.pendingChanges['whitelistedURLParams'] instanceof Object)) {
                            WFAD.pendingChanges['whitelistedURLParams'] = {};
                        }

                        if (!(WFAD.pendingChanges['whitelistedURLParams']['delete'] instanceof Object)) {
                            WFAD.pendingChanges['whitelistedURLParams']['delete'] = {};
                        }

                        WFAD.pendingChanges['whitelistedURLParams']['delete'][key] = 1;
                    }

                    for (var i = 0; i < WFAD.wafData.whitelistedURLParams.length; i++) {
                        var testKey = WFAD.wafData.whitelistedURLParams[i].path + '|' + WFAD.wafData.whitelistedURLParams[i].paramKey;
                        if (testKey == key) {
                            WFAD.wafData.whitelistedURLParams.splice(i, 1);
                            break;
                        }
                    }
                });
            },

            wafConfigPageRender: function() {
                WFAD.wafData.ruleCount = 0;
                if (WFAD.wafData.rules) {
                    WFAD.wafData.ruleCount = Object.keys(WFAD.wafData.rules).length;
                }
                
                var whitelistedIPsEl = $('#waf-whitelisted-urls-tmpl').tmpl(WFAD.wafData);
                $('#waf-whitelisted-urls-wrapper').html(whitelistedIPsEl);

                var rulesEl = $('#waf-rules-tmpl').tmpl(WFAD.wafData);
                $('#waf-rules-wrapper').html(rulesEl);
                
                $('#waf-show-all-rules-button').on('click', function(e) {
                    e.preventDefault();
                    e.stopPropagation();
                    
                    $('#waf-rules-wrapper').addClass('wf-show-all');
                });

                if (WFAD.wafData['rulesLastUpdated']) {
                    var date = new Date(WFAD.wafData['rulesLastUpdated'] * 1000);
                    WFAD.renderWAFRulesLastUpdated(date);
                }
                $(window).trigger('wordfenceWAFConfigPageRender');
            },

            renderWAFRulesLastUpdated: function(date) {
                var dateString = date.toString();
                if (date.toLocaleString) {
                    dateString = date.toLocaleString();
                }
                $('#waf-rules-last-updated').text(sprintf(__('Last Updated: %s'), dateString))
                    .css({
                        'opacity': 0
                    })
                    .animate({
                        'opacity': 1
                    }, 500);
            },

            renderWAFRulesNextUpdate: function(date) {
                var dateString = date.toString();
                if (date.toLocaleString) {
                    dateString = date.toLocaleString();
                }
                $('#waf-rules-next-update').text(sprintf(__('Next Update Check: %s'), dateString))
                    .css({
                        'opacity': 0
                    })
                    .animate({
                        'opacity': 1
                    }, 500);
            },

            wafUpdateRules: function(onSuccess) {
                var self = this;
                this.ajax('wordfence_updateWAFRules', {}, function(res) {
                    self.wafData = res;
                    self.restoreWAFData.rules = res.rules;
                    self.restoreWAFData.rulesLastUpdated = res.rulesLastUpdated;
                    self.wafConfigPageRender();
                    if (self.wafData['updated']) {
                        if (!self.wafData['isPaid']) {
                            self.colorboxModalHTML((self.isSmallScreen ? '300px' : '400px'), __('Rules Updated'), __('Your rules have been updated successfully. You are currently using the free version of Wordfence. Upgrade to Wordfence premium to have your rules updated automatically as new threats emerge. <a href="https://www.wordfence.com/wafUpdateRules1/wordfence-signup/">Click here to purchase a premium license</a>. <em>Note: Your rules will still update every 30 days as a free user.</em>'));
                        } else {
                            self.colorboxModal((self.isSmallScreen ? '300px' : '400px'), __('Rules Updated'), __('Your rules have been updated successfully.'));
                        }
                    }
                    else {
                        if (self.wafData['failure'] == 'ratelimit') {
                            self.colorboxModal((self.isSmallScreen ? '300px' : '400px'), __('Rule Update Failed'), __('No rules were updated. Your website has reached the maximum number of rule update requests. Please try again later.'));
                        }
                        else if (self.wafData['failure'] == 'unreachable') {
                            self.colorboxModal((self.isSmallScreen ? '300px' : '400px'), __('Rule Update Failed'), __('No rules were updated. Please verify your website can reach the Wordfence servers.'));
                        }
                        else {
                            self.colorboxModal((self.isSmallScreen ? '300px' : '400px'), __('Rule Update Failed'), __('No rules were updated. Please verify you have permissions to write to the /wp-content/wflogs directory.'));
                        }
                    }
                    if (typeof onSuccess === 'function') {
                        return onSuccess.apply(this, arguments);
                    }
                });
            },

            dateFormat: function(date) {
                if (date instanceof Date) {
                    if (date.toLocaleString) {
                        return date.toLocaleString();
                    }
                    return date.toString();
                }
                return date;
            },

            confirmWAFConfigureAutoPrepend: function() {
                var self = this;
                this.ajax('wordfence_wafConfigureAutoPrepend', {}, function(res) {
                    self.colorboxModal((self.isSmallScreen ? '300px' : '400px'), __('.htaccess Updated'), __("Your .htaccess has been updated successfully. Please verify your site is functioning normally."));
                });
            },
            
            updatePendingChanges: function() {
                $(window).off('beforeunload', WFAD._unsavedOptionsHandler);
                if (Object.keys(WFAD.pendingChanges).length) {
                    $('#wf-cancel-changes').removeClass('wf-disabled');
                    $('#wf-save-changes').removeClass('wf-disabled');
                    $(window).on('beforeunload', WFAD._unsavedOptionsHandler);
                }
                else {
                    $('#wf-cancel-changes').addClass('wf-disabled');
                    $('#wf-save-changes').addClass('wf-disabled');
                }
            },
            
            _unsavedOptionsHandler: function(e) {
                var message = __("You have unsaved changes to your options. If you leave this page, those changes will be lost."); //Only shows on older browsers, newer browsers don't allow message customization
                e = e || window.event;
                if (e) {
                    e.returnValue = message; //IE and Firefox
                }
                return message; //Others
            },
            
            setOption: function(key, value, successCallback, failureCallback, failureAfterModal) {
                var changes = {};
                changes[key] = value;
                this.ajax('wordfence_saveOptions', {changes: JSON.stringify(changes), page: WFAD.getParameterByName('page')}, function(res) {
                    if (res.success) {
                        typeof successCallback == 'function' && successCallback(res);
                    }
                    else {
                        failureAfterModal = typeof failureAfterModal !== 'undefined' && failureAfterModal;
                        var modalSettings = {};
                        if (failureAfterModal)
                            modalSettings.onClosed = failureCallback;
                        WFAD.colorboxModal((self.isSmallScreen ? '300px' : '400px'), __('Error Saving Option'), res.error, modalSettings);
                        if (!failureAfterModal)
                            typeof failureCallback == 'function' && failureCallback(res);
                    } 
                });
            },

            saveOptions: function(successCallback, failureCallback) {
                if (!Object.keys(WFAD.pendingChanges).length) {
                    return;
                }
                var self = this;

                this.ajax('wordfence_saveOptions', {changes: JSON.stringify(WFAD.pendingChanges), page: WFAD.getParameterByName('page')}, function(res) {
                    if (res.success) {
                        typeof successCallback == 'function' && successCallback(res); 
                    }
                    else {
                        WFAD.colorboxModal((self.isSmallScreen ? '300px' : '400px'), __('Error Saving Options'), res.error);
                        typeof failureCallback == 'function' && failureCallback
                    }
                });
            },
            
            enableAllOptionsPage: function() {
                this.ajax('wordfence_enableAllOptionsPage', {}, function(res) {
                    if (res.redirect) {
                        window.location.href = res.redirect;
                    }
                    else {
                        WFAD.colorboxModal((self.isSmallScreen ? '300px' : '400px'), __('Error Enabling All Options Page'), res.error);
                    }
                });
            },

            getParameterByName: function(name, url) {
                if (!url) url = window.location.href;
                name = name.replace(/[\[\]]/g, "\\$&");
                var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
                    results = regex.exec(url);
                if (!results) return null;
                if (!results[2]) return '';
                return decodeURIComponent(results[2].replace(/\+/g, " "));
            },

            base64_decode: function(s) {
                var e = {}, i, b = 0, c, x, l = 0, a, r = '', w = String.fromCharCode, L = s.length;
                var A = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
                for (i = 0; i < 64; i++) {
                    e[A.charAt(i)] = i;
                }
                for (x = 0; x < L; x++) {
                    c = e[s.charAt(x)];
                    b = (b << 6) + c;
                    l += 6;
                    while (l >= 8) {
                        ((a = (b >>> (l -= 8)) & 0xff) || (x < (L - 2))) && (r += w(a));
                    }
                }
                return r;
            },
            
            base64_encode: function (input) {
                var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
                var output = "";
                var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
                var i = 0;

                while (i < input.length) {
                    chr1 = input.charCodeAt(i++);
                    chr2 = input.charCodeAt(i++);
                    chr3 = input.charCodeAt(i++);

                    enc1 = chr1 >> 2;
                    enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
                    enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
                    enc4 = chr3 & 63;

                    if (isNaN(chr2)) {
                        enc3 = enc4 = 64;
                    }
                    else if (isNaN(chr3)) {
                        enc4 = 64;
                    }

                    output = output + chars.charAt(enc1) + chars.charAt(enc2) + chars.charAt(enc3) + chars.charAt(enc4);
                }

                return output;
            }
        };

        window['WFAD'] = window['wordfenceAdmin'];
        setInterval(function() {
            WFAD.updateTimeAgo();
        }, 1000);
    }

    __ = window.wfi18n.__;
    sprintf = window.wfi18n.sprintf;

    jQuery(function() {
        wordfenceAdmin.init();
        jQuery(window).on('focus', function() {
            if (jQuery('body').hasClass('wordfenceLiveActivityPaused')) {
                jQuery('body').removeClass('wordfenceLiveActivityPaused');
            }
        });
    });

    $(function() {
        $('#wf-mobile-controls').on('click', function(e) {
            e.preventDefault();
            e.stopPropagation();

            $.wfMobileMenu({
                menuItems: [
                    {title: __('Save Changes'), primary: true, disabled: $('#wf-save-changes').hasClass('wf-disabled'), action: function() { $('#wf-save-changes').trigger('click'); }},
                    {title: __('Cancel Changes'), primary: false, disabled: $('#wf-cancel-changes').hasClass('wf-disabled'), action: function() { $('#wf-cancel-changes').trigger('click'); }},
                    {title: __('Restore Defaults'), primary: false, disabled: $('#wf-restore-defaults').hasClass('wf-disabled'), action: function() { $('#wf-restore-defaults').trigger('click'); }}
                ]
            });
        });
        
        $('#wf-restore-defaults').on('click', function(e) {
            e.preventDefault();
            e.stopPropagation();

            var restoreDefaultsSection = $(this).data('restoreDefaultsSection');
            var prompt = $('#wfTmpl_restoreDefaultsPrompt').tmpl();
            var promptHTML = $("<div />").append(prompt).html();
            WFAD.colorboxHTML((WFAD.isSmallScreen ? '300px' : '400px'), promptHTML, {overlayClose: false, closeButton: false, className: 'wf-modal', onComplete: function() {
                $('#wf-restore-defaults-prompt-cancel').on('click', function(e) {
                    e.preventDefault();
                    e.stopPropagation();

                    WFAD.colorboxClose();
                });

                $('#wf-restore-defaults-prompt-confirm').on('click', function(e) {
                    e.preventDefault();
                    e.stopPropagation();

                    WFAD.ajax('wordfence_restoreDefaults', {section: restoreDefaultsSection}, function(res) {
                        if (res.success) {
                            window.location.reload(true);
                        }
                        else {
                            WFAD.colorboxClose();
                            WFAD.colorboxModal((WFAD.isSmallScreen ? '300px' : '400px'), __('Error Restoring Defaults'), res.error);
                        }
                    });
                });
            }});
        });
        
        $('#wf-save-changes').on('click', function(e) {
            e.preventDefault();
            e.stopPropagation();

            WFAD.saveOptions(function(res) {
                WFAD.pendingChanges = {}; 
                WFAD.updatePendingChanges();

                if (res.redirect) {
                    window.location.href = res.redirect;
                }
                else {
                    window.location.reload(true);
                }
            });
        });

        $('#wf-cancel-changes').on('click', function(e) {
            e.preventDefault();
            e.stopPropagation();

            WFAD.pendingChanges = {};

            WFAD.updatePendingChanges();

            //On/Off options
            $('.wf-option.wf-option-toggled').each(function() {
                var enabledValue = $(this).data('enabledValue');
                var disabledValue = $(this).data('disabledValue');
                var originalValue = $(this).data('originalValue');
                if (enabledValue == originalValue) {
                    $(this).find('.wf-option-checkbox').addClass('wf-checked').attr('aria-checked', 'true');
                }
                else {
                    $(this).find('.wf-option-checkbox').removeClass('wf-checked').attr('aria-checked', 'false');
                }
                $(this).trigger('change', [true]);
            });
            
            $('.wf-option-toggled-boolean-switch').each(function() {
                var enabledValue = $(this).data('enabledValue');
                var disabledValue = $(this).data('disabledValue');
                var originalValue = $(this).data('originalValue');
                if (enabledValue == originalValue) {
                    $(this).find('.wf-boolean-switch').addClass('wf-active').attr('aria-checked', 'true');
                }
                else {
                    $(this).find('.wf-boolean-switch').removeClass('wf-active').attr('aria-checked', 'false');
                }
                $(this).trigger('change', [true]);
            });

            $('.wf-option.wf-option-toggled-segmented').each(function() {
                var originalValue = $(this).data('originalValue');
                $(this).find('[type=radio]').each(function() {
                    if (this.value == originalValue) {
                        this.checked = true;
                        return false;
                    }
                });
                $(this).trigger('change', [true]);
            });

            //On/Off multiple options
            $('.wf-option.wf-option-toggled-multiple').each(function() {
                $(this).find('.wf-option-checkboxes > ul').each(function() {
                    var enabledValue = $(this).data('enabledValue');
                    var disabledValue = $(this).data('disabledValue');
                    var originalValue = $(this).data('originalValue');
                    if (enabledValue == originalValue) {
                        $(this).find('.wf-option-checkbox').addClass('wf-checked').attr('aria-checked', 'true');
                    }
                    else {
                        $(this).find('.wf-option-checkbox').removeClass('wf-checked').attr('aria-checked', 'false');
                    }
                });
                $(this).trigger('change', [true]);
            });

            //On/Off options with menu
            $('.wf-option.wf-option-toggled-select').each(function() {
                var selectElement = $(this).find('.wf-option-select select');
                var enabledToggleValue = $(this).data('enabledToggleValue');
                var disabledToggleValue = $(this).data('disabledToggleValue');
                var originalToggleValue = $(this).data('originalToggleValue');
                if (enabledToggleValue == originalToggleValue) {
                    $(this).find('.wf-option-checkbox').addClass('wf-checked').attr('aria-checked', 'true');
                    selectElement.attr('disabled', false);
                }
                else {
                    $(this).find('.wf-option-checkbox').removeClass('wf-checked').attr('aria-checked', 'false');
                    selectElement.attr('disabled', true);
                }

                var originalSelectValue = $(this).data('originalSelectValue');
                $(this).find('.wf-option-select select').val(originalSelectValue).trigger('change');
                $(this).trigger('change', [true]);
            });

            //Menu options
            $('.wf-option.wf-option-select').each(function() {
                var originalSelectValue = $(this).data('originalSelectValue');
                $(this).find('.wf-option-select select').val(originalSelectValue).trigger('change');
                $(this).trigger('change', [true]);
            });

            //Text options
            $('.wf-option.wf-option-text').each(function() {
                var originalTextValue = $(this).data('originalTextValue');
                if (typeof originalTextValue !== 'undefined') {
                    $(this).find('.wf-option-text input').val(originalTextValue);
                }
                $(this).trigger('change', [true]);
            });

            //Text area options
            $('.wf-option.wf-option-textarea').each(function() {
                var originalTextValue = $(this).data('originalTextValue');
                $(this).find('.wf-option-textarea textarea').val(originalTextValue);
                $(this).trigger('change', [true]);
            });

            //Token options
            $('.wf-option.wf-option-token').each(function() {
                var originalTokenValue = $(this).data('originalTokenValue');
                $(this).find('select').val(originalTokenValue).trigger('change');
                $(this).trigger('change', [true]);
            });
            
            //Switch options
            $('.wf-option.wf-option-switch').each(function() {
                var originalValue = $(this).data('originalValue');
                $(this).find('.wf-switch > li').each(function() {
                    $(this).toggleClass('wf-active', originalValue == $(this).data('optionValue')).attr('aria-checked', originalValue == $(this).data('optionValue') ? 'true' : 'false');
                });
                $(this).trigger('change', [true]);
            });

            //Other options
            $(window).trigger('wfOptionsReset');
        });

        var select2s = $('.wf-select2');
        if (select2s.length && $.fn.wfselect2) {
            select2s.wfselect2({
                minimumResultsForSearch: 5
            });
        }


        if ($.fn.tooltip) {
            $('.wf-status-circular').each(function() {
                var circle = $(this);
                var tmplID = 'tooltip-' + this.id + '-tmpl';
                var circleTmpl = $('#' + tmplID);
                if (circleTmpl.length) {
                    circle.tooltip({
                        tooltipClass: "wf-circle-tooltip",
                        position: {
                            my: "left-40 bottom",
                            at: "center top",
                            using: function(obj, info) {
                                var el = $(this);
                                el.removeClass('wf-tooltip-vertical-top wf-tooltip-vertical-bottom ' +
                                    'wf-tooltip-horizontal-left wf-tooltip-horizontal-right')
                                .addClass('wf-tooltip-vertical-' + info.vertical)
                                .addClass('wf-tooltip-horizontal-' + info.horizontal);

                                $(this).css({
                                    left: obj.left + 'px',
                                    top: obj.top + 'px'
                                });
                            }
                        },
                        items: this,
                        close: function (event, ui) {
                            ui.tooltip.hover(
                                function () {
                                    $(this).stop(true).fadeTo(400, 1);
                                },
                                function () {
                                    $(this).fadeOut("400", function () {
                                        $(this).remove();
                                    })
                                });
                        },
                        content: function() {
                            var circleClone = $(this).clone();
                            circleClone.find('svg, .wf-status-circular-text').css('opacity', 1.0);
                            var circleHTML = $(circleClone).html();
                            return circleTmpl.tmpl({
                                statusCircle: circleHTML
                            });
                        }
                    })
                    // .tooltip('open');
                }
            });
        }
    });
})(jQuery);

//wfCircularProgress
jQuery.fn.wfCircularProgress = function(options) {
    var __ = window.wfi18n.__;
    var sprintf = window.wfi18n.sprintf;

    jQuery(this).each(function() {
        var creationOptions;
        try {
            creationOptions = JSON.parse(jQuery(this).data('wfCircularProgressOptions'));
        }
        catch (e) { /* Ignore */ }
        if (typeof creationOptions !== 'object') {
            creationOptions = {};
        }
        var opts = jQuery.extend({}, jQuery.fn.wfCircularProgress.defaults, creationOptions, options);

        var center = Math.floor(opts.diameter / 2);
        var insetRadius = center - opts.strokeWidth * 2;

        var circumference = 2 * insetRadius * Math.PI;
        var finalOffset = -(circumference * (1 - opts.endPercent));
        var initialOffset = -(circumference);

        var terminatorRadius = Math.floor(opts.strokeWidth * 1.5);
        var terminatorDiameter = 2 * terminatorRadius;
        var finalTerminatorX = center - insetRadius * Math.cos(Math.PI * 2 * (opts.endPercent - 0.25));
        var finalTerminatorY = center + insetRadius * Math.sin(Math.PI * 2 * (opts.endPercent - 0.25));
        var initialTerminatorX = center - insetRadius * Math.cos(Math.PI * 2 * (opts.startPercent - 0.25));
        var initialTerminatorY = center + insetRadius * Math.sin(Math.PI * 2 * (opts.startPercent - 0.25));

        var terminatorSVG = "m 0,-" + terminatorRadius + " a " + terminatorRadius + "," + terminatorRadius + " 0 1 1 0," + terminatorDiameter + " a " + terminatorRadius + "," + terminatorRadius + " 0 1 1 0,-" + terminatorDiameter;
        
        jQuery(this).data('wfCircularProgressOptions', JSON.stringify(opts));
        
        jQuery(this).css('width', opts.diameter + 'px');
        jQuery(this).css('height', opts.diameter + 'px');

        var svg = jQuery(this).find('svg');
        if (svg.length == 0) { svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); jQuery(this).append(svg); }
        var inactivePath = jQuery(this).find('.wf-status-circular-inactive-path');
        if (inactivePath.length == 0) { inactivePath = document.createElementNS("http://www.w3.org/2000/svg", "path"); jQuery(inactivePath).addClass('wf-status-circular-inactive-path'); jQuery(svg).append(inactivePath); }
        var activePath = jQuery(this).find('.wf-status-circular-active-path');
        if (activePath.length == 0) { activePath = document.createElementNS("http://www.w3.org/2000/svg", "path"); jQuery(activePath).addClass('wf-status-circular-active-path'); jQuery(svg).append(activePath); }
        var terminator = jQuery(this).find('.wf-status-circular-terminator');
        if (terminator.length == 0) { terminator = document.createElementNS("http://www.w3.org/2000/svg", "path"); jQuery(terminator).addClass('wf-status-circular-terminator'); jQuery(svg).append(terminator); }
        var text = jQuery(this).find('.wf-status-circular-text');
        if (text.length == 0) { text = jQuery('<div class="wf-status-circular-text"></div>'); jQuery(this).append(text); }
        var pendingOverlay = jQuery(this).find('.wf-status-overlay-text');
        if (pendingOverlay.length == 0) { pendingOverlay = jQuery('<div class="wf-status-overlay-text"></div>'); jQuery(this).append(pendingOverlay); }

        jQuery(svg).attr('viewBox', '0 0 ' + opts.diameter + ' ' + opts.diameter);
        jQuery(svg).css('display', 'block');
        jQuery(svg).css('width', opts.diameter + 'px');
        jQuery(svg).css('height', opts.diameter + 'px');
        jQuery(inactivePath).attr('d', 'M ' + center + ',' + center + ' m 0,-' + insetRadius + ' a ' + insetRadius + ',' +insetRadius + ' 0 1 1 0,' + (2 * insetRadius) + ' a ' + insetRadius + ',' + insetRadius + ' 0 1 1 0,-' + (2 * insetRadius));
        jQuery(inactivePath).attr('stroke', opts.inactiveColor);
        jQuery(inactivePath).attr('stroke-width', opts.strokeWidth);
        jQuery(inactivePath).attr('fill-opacity', 0);
        jQuery(activePath).attr('d', 'M ' + center + ',' + center + ' m 0,-' + insetRadius + ' a ' + insetRadius + ',' + insetRadius + ' 0 1 1 0,' + (2 * insetRadius) + ' a ' + insetRadius + ',' + insetRadius + ' 0 1 1 0,-' + (2 * insetRadius));
        jQuery(activePath).attr('stroke', opts.color);
        jQuery(activePath).attr('stroke-width', opts.strokeWidth);
        jQuery(activePath).attr('stroke-dasharray', circumference + ',' + circumference);
        jQuery(activePath).attr('stroke-dashoffset', initialOffset);
        jQuery(activePath).attr('fill-opacity', 0);
        jQuery(terminator).attr('d', 'M ' + initialTerminatorX + ',' + initialTerminatorY + ' ' + terminatorSVG);
        jQuery(terminator).attr('stroke', opts.color);
        jQuery(terminator).attr('stroke-width', opts.strokeWidth);
        jQuery(terminator).attr('fill', '#ffffff');
        jQuery(pendingOverlay).html(opts.pendingMessage);

        jQuery(pendingOverlay).animate({
            opacity: opts.pendingOverlay ? 1.0 : 0.0,
        }, {
            duration: 500,
            step: function(value) {
                var opacity = 1.0 - (value * 0.8);
                jQuery(svg).css('opacity', opacity);
                jQuery(text).css('opacity', opacity);
            },
            complete: function() {
                jQuery(svg).css('opacity', opts.pendingOverlay ? 0.2 : 1.0);
                jQuery(text).css('opacity', opts.pendingOverlay ? 0.2 : 1.0);
            }
        });
        
        jQuery(activePath).animate({
            "stroke-dashoffset": finalOffset + 'px'
        }, {
            duration: 500,
            step: function(value) {
                var percentage = 1 + value / circumference;
                var x = center - insetRadius * Math.cos(Math.PI * 2 * (percentage - 0.25));
                var y = center + insetRadius * Math.sin(Math.PI * 2 * (percentage - 0.25));
                jQuery(terminator).attr('d', 'M ' + x + ',' + y + ' ' + terminatorSVG);
                text.html(Math.round(percentage * 100) + '%');
            },
            complete: function() {
                text.html(Math.round(opts.endPercent * 100) + '%');
            }
        });
    });
};

(function() {
    var __ = window.wfi18n.__;
    var sprintf = window.wfi18n.sprintf;

    jQuery.fn.wfCircularProgress.defaults = {
        startPercent: 0,
        endPercent: 1,
        color: '#16bc9b',
        inactiveColor: '#ececec',
        strokeWidth: 3,
        diameter: 100,
        pendingOverlay: false,
        pendingMessage: __('Note: Status will update when changes are saved'),
    };
})();

//wfDrawer
(function ($, document, window) {
    var __ = window.wfi18n.__;
    var sprintf = window.wfi18n.sprintf;

    var defaults = {
        width: '600px',
        clickOverlayDismiss: false,
        content: false,
        onComplete: false,
    };
    
    var publicMethod = $.fn['wfDrawer'] = $['wfDrawer'] = function (options) {
        var opts = $.extend({}, defaults, options);

        var overlay = $('<div class="wf-drawer-overlay"></div>').css('opacity', 0);
        if (opts.clickOverlayDismiss) {
            overlay.on('click', function(e) {
                e.preventDefault();
                e.stopPropagation();

                $.wfDrawer.close();
            });
        }
        $('body').append(overlay);

        var drawer = $('<div class="wf-drawer"></div>').css('width', opts.width).css('right', '-' + opts.width);
        if (opts.content) {
            drawer.append(opts.content);
        }
        $('body').append(drawer);

        overlay.animate({
            "opacity": 1
        });
        drawer.animate({
                "right": '0px'
            },
            {
                complete: function() {
                    typeof opts.onComplete === 'function' && opts.onComplete();
                }
            });
    };

    publicMethod.close = function() {
        var overlay = $('.wf-drawer-overlay');
        overlay.animate({
                "opacity": 0
            },
            {
                complete: function() {
                    overlay.remove();
                }
            });
        
        var drawer = $('.wf-drawer');
        drawer.animate({
                "right": '-' + drawer.css('width')
            },
            {
                complete: function() {
                    drawer.remove();
                }
            });
    };
}(jQuery, document, window));

//wfMobileMenu
(function ($, document, window) {
    var __ = window.wfi18n.__;
    var sprintf = window.wfi18n.sprintf;

    var defaults = {
        width: '280px',
        clickOverlayDismiss: true,
        menuItems: [],
        onDismiss: false,
    };

    var publicMethod = $.fn['wfMobileMenu'] = $['wfMobileMenu'] = function (options) {
        var opts = $.extend({}, defaults, options);

        var overlay = $('<div class="wf-mobile-menu-overlay"></div>').css('opacity', 0);
        if (opts.clickOverlayDismiss) {
            overlay.on('click', function(e) {
                e.preventDefault();
                e.stopPropagation();

                typeof opts.onDismiss === 'function' && opts.onDismiss(false);
                $.wfMobileMenu.close();
            });
        }
        $('body').append(overlay);

        var menu = $('<div class="wf-mobile-menu"><ul class="wf-mobile-menu-items"></ul></div>').css('width', opts.width).css('bottom', '-9999px');
        var itemsWrapper = menu.find('.wf-mobile-menu-items');
        for (var i = 0; i < opts.menuItems.length; i++) {
            var button = $('<li><a href="#" class="wf-btn wf-btn-callout-subtle" role="button"></a></li>');
            button.find('a').text(opts.menuItems[i].title).css('width', opts.width).on('click', null, {action: opts.menuItems[i].action}, function(e) {
                e.preventDefault();
                e.stopPropagation();
                
                typeof opts.onDismiss === 'function' && opts.onDismiss(true);
                $.wfMobileMenu.close();
                e.data.action();
            });
            
            if (opts.menuItems[i].primary) {
                button.find('a').addClass('wf-btn-primary');
            }
            else {
                button.find('a').addClass('wf-btn-default');
            }
            
            if (opts.menuItems[i].disabled) {
                button.find('a').addClass('wf-disabled');
            }
            
            itemsWrapper.append(button);
        }

        var button = $('<li class="wf-padding-add-top-small"><a href="#" class="wf-btn wf-btn-callout-subtle wf-btn-default" role="button">' + __('Close') + '</a></li>');
        button.find('a').css('width', opts.width).on('click', function(e) {
            e.preventDefault();
            e.stopPropagation();

            typeof opts.onDismiss === 'function' && opts.onDismiss(false);
            $.wfMobileMenu.close();
        });
        itemsWrapper.append(button);
        
        $('body').append(menu);
        menu.css('bottom', '-' + menu.height() + 'px');

        overlay.animate({
            "opacity": 1
        });
        menu.animate({
                bottom: '0px'
            },
            {
                complete: function() {
                    typeof opts.onComplete === 'function' && opts.onComplete();
                }
            });
    };

    publicMethod.close = function() {
        var overlay = $('.wf-mobile-menu-overlay');
        overlay.animate({
                "opacity": 0
            },
            {
                complete: function() {
                    overlay.remove();
                }
            });

        var menu = $('.wf-mobile-menu');
        menu.animate({
            bottom: '-' + menu.height() + 'px'
            },
            {
                complete: function() {
                    menu.remove();
                }
            });
    };
}(jQuery, document, window));

/*! @source https://github.com/eligrey/FileSaver.js/blob/master/dist/FileSaver.min.js */

(function(a,b){if("function"==typeof define&&define.amd)define([],b);else if("undefined"!=typeof exports)b();else{b(),a.FileSaver={exports:{}}.exports}})(this,function(){"use strict";function b(a,b){return"undefined"==typeof b?b={autoBom:!1}:"object"!=typeof b&&(console.warn("Deprecated: Expected third argument to be a object"),b={autoBom:!b}),b.autoBom&&/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(a.type)?new Blob(["\uFEFF",a],{type:a.type}):a}function c(a,b,c){var d=new XMLHttpRequest;d.open("GET",a),d.responseType="blob",d.onload=function(){g(d.response,b,c)},d.onerror=function(){console.error("could not download file")},d.send()}function d(a){var b=new XMLHttpRequest;b.open("HEAD",a,!1);try{b.send()}catch(a){}return 200<=b.status&&299>=b.status}function e(a){try{a.dispatchEvent(new MouseEvent("click"))}catch(c){var b=document.createEvent("MouseEvents");b.initMouseEvent("click",!0,!0,window,0,0,0,80,20,!1,!1,!1,!1,0,null),a.dispatchEvent(b)}}var f="object"==typeof window&&window.window===window?window:"object"==typeof self&&self.self===self?self:"object"==typeof global&&global.global===global?global:void 0,a=/Macintosh/.test(navigator.userAgent)&&/AppleWebKit/.test(navigator.userAgent)&&!/Safari/.test(navigator.userAgent),g=f.saveAs||("object"!=typeof window||window!==f?function(){}:"download"in HTMLAnchorElement.prototype&&!a?function(b,g,h){var i=f.URL||f.webkitURL,j=document.createElement("a");g=g||b.name||"download",j.download=g,j.rel="noopener","string"==typeof b?(j.href=b,j.origin===location.origin?e(j):d(j.href)?c(b,g,h):e(j,j.target="_blank")):(j.href=i.createObjectURL(b),setTimeout(function(){i.revokeObjectURL(j.href)},4E4),setTimeout(function(){e(j)},0))}:"msSaveOrOpenBlob"in navigator?function(f,g,h){if(g=g||f.name||"download","string"!=typeof f)navigator.msSaveOrOpenBlob(b(f,h),g);else if(d(f))c(f,g,h);else{var i=document.createElement("a");i.href=f,i.target="_blank",setTimeout(function(){e(i)})}}:function(b,d,e,g){if(g=g||open("","_blank"),g&&(g.document.title=g.document.body.innerText="downloading..."),"string"==typeof b)return c(b,d,e);var h="application/octet-stream"===b.type,i=/constructor/i.test(f.HTMLElement)||f.safari,j=/CriOS\/[\d]+/.test(navigator.userAgent);if((j||h&&i||a)&&"undefined"!=typeof FileReader){var k=new FileReader;k.onloadend=function(){var a=k.result;a=j?a:a.replace(/^data:[^;]*;/,"data:attachment/file;"),g?g.location.href=a:location=a,g=null},k.readAsDataURL(b)}else{var l=f.URL||f.webkitURL,m=l.createObjectURL(b);g?g.location=m:location.href=m,g=null,setTimeout(function(){l.revokeObjectURL(m)},4E4)}});f.saveAs=g.saveAs=g,"undefined"!=typeof module&&(module.exports=g)});

All system for education purposes only. For more tools: Telegram @jackleet

Mr.X Private Shell

Logo
-
New File | New Folder
Command
SQL