text:
/**
 * @fileoverview This file contains small testing framework along with the
 * test suite for the frontend. These tests are a part of the continues build
 * and are executed by the devtools_sanity_unittest.cc as a part of the
 * Interactive UI Test suite.
 * FIXME: change field naming style to use trailing underscore.
 */

(function createTestSuite(window)
{

/**
 * Test suite for interactive UI tests.
 * @constructor
 * @param {Object} domAutomationController DomAutomationController instance.
 */
function TestSuite(domAutomationController)
{
    this.domAutomationController_ = domAutomationController;
    this.controlTaken_ = false;
    this.timerId_ = -1;
    this._asyncInvocationId = 0;
}

/**
 * Reports test failure.
 * @param {string} message Failure description.
 */
TestSuite.prototype.fail = function(message)
{
    if (this.controlTaken_)
        this.reportFailure_(message);
    else
        throw message;
};

/**
 * Equals assertion tests that expected === actual.
 * @param {!Object|boolean} expected Expected object.
 * @param {!Object|boolean} actual Actual object.
 * @param {string} opt_message User message to print if the test fails.
 */
TestSuite.prototype.assertEquals = function(expected, actual, opt_message)
{
    if (expected !== actual) {
        var message = "Expected: '" + expected + "', but was '" + actual + "'";
        if (opt_message)
            message = opt_message + "(" + message + ")";
        this.fail(message);
    }
};

/**
 * True assertion tests that value == true.
 * @param {!Object} value Actual object.
 * @param {string} opt_message User message to print if the test fails.
 */
TestSuite.prototype.assertTrue = function(value, opt_message)
{
    this.assertEquals(true, !!value, opt_message);
};

/**
 * Takes control over execution.
 */
TestSuite.prototype.takeControl = function()
{
    this.controlTaken_ = true;
    // Set up guard timer.
    var self = this;
    this.timerId_ = setTimeout(function() {
        self.reportFailure_("Timeout exceeded: 20 sec");
    }, 20000);
};

/**
 * Releases control over execution.
 */
TestSuite.prototype.releaseControl = function()
{
    if (this.timerId_ !== -1) {
        clearTimeout(this.timerId_);
        this.timerId_ = -1;
    }
    this.controlTaken_ = false;
    this.reportOk_();
};

/**
 * Async tests use this one to report that they are completed.
 */
TestSuite.prototype.reportOk_ = function()
{
    this.domAutomationController_.send("[OK]");
};

/**
 * Async tests use this one to report failures.
 */
TestSuite.prototype.reportFailure_ = function(error)
{
    if (this.timerId_ !== -1) {
        clearTimeout(this.timerId_);
        this.timerId_ = -1;
    }
    this.domAutomationController_.send("[FAILED] " + error);
};

/**
 * Run specified test on a fresh instance of the test suite.
 * @param {Array<string>} args method name followed by its parameters.
 */
TestSuite.prototype.dispatchOnTestSuite = function(args)
{
    var methodName = args.shift();
    try {
        this[methodName].apply(this, args);
        if (!this.controlTaken_)
            this.reportOk_();
    } catch (e) {
        this.reportFailure_(e);
    }
};

/**
 * Wrap an async method with TestSuite.{takeControl(), releaseControl()}
 * and invoke TestSuite.reportOk_ upon completion.
 * @param {Array<string>} args method name followed by its parameters.
 */
TestSuite.prototype.waitForAsync = function(var_args)
{
    var args = Array.prototype.slice.call(arguments);
    this.takeControl();
    args.push(this.releaseControl.bind(this));
    this.dispatchOnTestSuite(args);
};

/**
 * Overrides the method with specified name until it's called first time.
 * @param {!Object} receiver An object whose method to override.
 * @param {string} methodName Name of the method to override.
 * @param {!Function} override A function that should be called right after the
 *     overridden method returns.
 * @param {?boolean} opt_sticky Whether restore original method after first run
 *     or not.
 */
TestSuite.prototype.addSniffer = function(receiver, methodName, override, opt_sticky)
{
    var orig = receiver[methodName];
    if (typeof orig !== "function")
        this.fail("Cannot find method to override: " + methodName);
    var test = this;
    receiver[methodName] = function(var_args) {
        try {
            var result = orig.apply(this, arguments);
        } finally {
            if (!opt_sticky)
                receiver[methodName] = orig;
        }
        // In case of exception the override won't be called.
        try {
            override.apply(this, arguments);
        } catch (e) {
            test.fail("Exception in overriden method '" + methodName + "': " + e);
        }
        return result;
    };
};

/**
 * Waits for current throttler invocations, if any.
 * @param {!WebInspector.Throttler} throttler
 * @param {function()} callback
 */
TestSuite.prototype.waitForThrottler = function(throttler, callback)
{
    var test = this;
    var scheduleShouldFail = true;
    test.addSniffer(throttler, "schedule", onSchedule);

    function hasSomethingScheduled()
    {
        return throttler._isRunningProcess || throttler._process;
    }

    function checkState()
    {
        if (!hasSomethingScheduled()) {
            scheduleShouldFail = false;
            callback();
            return;
        }

        test.addSniffer(throttler, "_processCompletedForTests", checkState);
    }

    function onSchedule()
    {
        if (scheduleShouldFail)
            test.fail("Unexpected Throttler.schedule");
    }

    checkState();
};

/**
 * @param {string} panelName Name of the panel to show.
 */
TestSuite.prototype.showPanel = function(panelName)
{
    return WebInspector.inspectorView.showPanel(panelName);
};

// UI Tests

/**
 * Tests that scripts tab can be open and populated with inspected scripts.
 */
TestSuite.prototype.testShowScriptsTab = function()
{
    var test = this;
    this.showPanel("sources").then(function() {
        // There should be at least main page script.
        this._waitUntilScriptsAreParsed(["debugger_test_page.html"],
            function() {
                test.releaseControl();
            });
    }.bind(this));
    // Wait until all scripts are added to the debugger.
    this.takeControl();
};

/**
 * Tests that scripts tab is populated with inspected scripts even if it
 * hadn't been shown by the moment inspected paged refreshed.
 * @see http://crbug.com/26312
 */
TestSuite.prototype.testScriptsTabIsPopulatedOnInspectedPageRefresh = function()
{
    var test = this;
    var debuggerModel = WebInspector.DebuggerModel.fromTarget(WebInspector.targetManager.mainTarget());
    debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.GlobalObjectCleared, waitUntilScriptIsParsed);

    this.showPanel("elements").then(function() {
        // Reload inspected page. It will reset the debugger agent.
        test.evaluateInConsole_("window.location.reload(true);", function(resultText) {});
    });

    function waitUntilScriptIsParsed()
    {
        debuggerModel.removeEventListener(WebInspector.DebuggerModel.Events.GlobalObjectCleared, waitUntilScriptIsParsed);
        test.showPanel("sources").then(function() {
            test._waitUntilScriptsAreParsed(["debugger_test_page.html"],
                function() {
                    test.releaseControl();
                });
        });
    }

    // Wait until all scripts are added to the debugger.
    this.takeControl();
};

/**
 * Tests that scripts list contains content scripts.
 */
TestSuite.prototype.testContentScriptIsPresent = function()
{
    var test = this;
    this.showPanel("sources").then(function() {
        test._waitUntilScriptsAreParsed(
            ["page_with_content_script.html", "simple_content_script.js"],
            function() {
                test.releaseControl();
            });
    });

    // Wait until all scripts are added to the debugger.
    this.takeControl();
};

/**
 * Tests that scripts are not duplicaed on Scripts tab switch.
 */
TestSuite.prototype.testNoScriptDuplicatesOnPanelSwitch = function()
{
    var test = this;

    // There should be two scripts: one for the main page and another
    // one which is source of console API(see
    // InjectedScript._ensureCommandLineAPIInstalled).
    var expectedScriptsCount = 2;
    var parsedScripts = [];

    function switchToElementsTab() {
        test.showPanel("elements").then(function() {
            setTimeout(switchToScriptsTab, 0);
        });
    }

    function switchToScriptsTab() {
        test.showPanel("sources").then(function() {
            setTimeout(checkScriptsPanel, 0);
        });
    }

    function checkScriptsPanel() {
        test.assertTrue(test._scriptsAreParsed(["debugger_test_page.html"]), "Some scripts are missing.");
        checkNoDuplicates();
        test.releaseControl();
    }

    function checkNoDuplicates() {
        var uiSourceCodes = test.nonAnonymousUISourceCodes_();
        for (var i = 0; i < uiSourceCodes.length; i++) {
            var scriptName = WebInspector.networkMapping.networkURL(uiSourceCodes[i]);
            for (var j = i + 1; j < uiSourceCodes.length; j++)
                test.assertTrue(scriptName !== WebInspector.networkMapping.networkURL(uiSourceCodes[j]), "Found script duplicates: " + test.uiSourceCodesToString_(uiSourceCodes));
        }
    }

    this.showPanel("sources").then(function() {
        test._waitUntilScriptsAreParsed(
            ["debugger_test_page.html"],
            function() {
                checkNoDuplicates();
                setTimeout(switchToElementsTab, 0);
            });
    });

    // Wait until all scripts are added to the debugger.
    this.takeControl();
};

// Tests that debugger works correctly if pause event occurs when DevTools
// frontend is being loaded.
TestSuite.prototype.testPauseWhenLoadingDevTools = function()
{
    var debuggerModel = WebInspector.DebuggerModel.fromTarget(WebInspector.targetManager.mainTarget());
    if (debuggerModel.debuggerPausedDetails)
        return;

    this.showPanel("sources").then(function() {
        // Script execution can already be paused.

        this._waitForScriptPause(this.releaseControl.bind(this));
    }.bind(this));

    this.takeControl();
};

// Tests that pressing "Pause" will pause script execution if the script
// is already running.
TestSuite.prototype.testPauseWhenScriptIsRunning = function()
{
    this.showPanel("sources").then(function() {
        this.evaluateInConsole_(
            'setTimeout("handleClick()", 0)',
            didEvaluateInConsole.bind(this));
    }.bind(this));

    function didEvaluateInConsole(resultText) {
        this.assertTrue(!isNaN(resultText), "Failed to get timer id: " + resultText);
        // Wait for some time to make sure that inspected page is running the
        // infinite loop.
        setTimeout(testScriptPause.bind(this), 300);
    }

    function testScriptPause() {
        // The script should be in infinite loop. Click "Pause" button to
        // pause it and wait for the result.
        WebInspector.panels.sources._togglePause();

        this._waitForScriptPause(this.releaseControl.bind(this));
    }

    this.takeControl();
};

/**
 * Tests network size.
 */
TestSuite.prototype.testNetworkSize = function()
{
    var test = this;

    function finishResource(resource, finishTime)
    {
        test.assertEquals(25, resource.resourceSize, "Incorrect total data length");
        test.releaseControl();
    }

    this.addSniffer(WebInspector.NetworkDispatcher.prototype, "_finishNetworkRequest", finishResource);

    // Reload inspected page to sniff network events
    test.evaluateInConsole_("window.location.reload(true);", function(resultText) {});

    this.takeControl();
};

/**
 * Tests network sync size.
 */
TestSuite.prototype.testNetworkSyncSize = function()
{
    var test = this;

    function finishResource(resource, finishTime)
    {
        test.assertEquals(25, resource.resourceSize, "Incorrect total data length");
        test.releaseControl();
    }

    this.addSniffer(WebInspector.NetworkDispatcher.prototype, "_finishNetworkRequest", finishResource);

    // Send synchronous XHR to sniff network events
    test.evaluateInConsole_("var xhr = new XMLHttpRequest(); xhr.open(\"GET\", \"chunked\", false); xhr.send(null);", function() {});

    this.takeControl();
};

/**
 * Tests network raw headers text.
 */
TestSuite.prototype.testNetworkRawHeadersText = function()
{
    var test = this;

    function finishResource(resource, finishTime)
    {
        if (!resource.responseHeadersText)
            test.fail("Failure: resource does not have response headers text");
        var index = resource.responseHeadersText.indexOf("Date:")
        test.assertEquals(112, resource.responseHeadersText.substring(index).length, "Incorrect response headers text length");
        test.releaseControl();
    }

    this.addSniffer(WebInspector.NetworkDispatcher.prototype, "_finishNetworkRequest", finishResource);

    // Reload inspected page to sniff network events
    test.evaluateInConsole_("window.location.reload(true);", function(resultText) {});

    this.takeControl();
};

/**
 * Tests network timing.
 */
TestSuite.prototype.testNetworkTiming = function()
{
    var test = this;

    function finishResource(resource, finishTime)
    {
        // Setting relaxed expectations to reduce flakiness.
        // Server sends headers after 100ms, then sends data during another 100ms.
        // We expect these times to be measured at least as 70ms.
        test.assertTrue(resource.timing.receiveHeadersEnd - resource.timing.connectStart >= 70,
                        "Time between receiveHeadersEnd and connectStart should be >=70ms, but was " +
                        "receiveHeadersEnd=" + resource.timing.receiveHeadersEnd + ", connectStart=" + resource.timing.connectStart + ".");
        test.assertTrue(resource.responseReceivedTime - resource.startTime >= 0.07,
                "Time between responseReceivedTime and startTime should be >=0.07s, but was " +
                "responseReceivedTime=" + resource.responseReceivedTime + ", startTime=" + resource.startTime + ".");
        test.assertTrue(resource.endTime - resource.startTime >= 0.14,
                "Time between endTime and startTime should be >=0.14s, but was " +
                "endtime=" + resource.endTime + ", startTime=" + resource.startTime + ".");

        test.releaseControl();
    }

    this.addSniffer(WebInspector.NetworkDispatcher.prototype, "_finishNetworkRequest", finishResource);

    // Reload inspected page to sniff network events
    test.evaluateInConsole_("window.location.reload(true);", function(resultText) {});

    this.takeControl();
};

TestSuite.prototype.testConsoleOnNavigateBack = function()
{
    if (WebInspector.multitargetConsoleModel.messages().length === 1)
        firstConsoleMessageReceived.call(this);
    else
        WebInspector.multitargetConsoleModel.addEventListener(WebInspector.ConsoleModel.Events.MessageAdded, firstConsoleMessageReceived, this);

    function firstConsoleMessageReceived() {
        WebInspector.multitargetConsoleModel.removeEventListener(WebInspector.ConsoleModel.Events.MessageAdded, firstConsoleMessageReceived, this);
        this.evaluateInConsole_("clickLink();", didClickLink.bind(this));
    }

    function didClickLink() {
        // Check that there are no new messages(command is not a message).
        this.assertEquals(3, WebInspector.multitargetConsoleModel.messages().length);
        this.evaluateInConsole_("history.back();", didNavigateBack.bind(this));
    }

    function didNavigateBack()
    {
        // Make sure navigation completed and possible console messages were pushed.
        this.evaluateInConsole_("void 0;", didCompleteNavigation.bind(this));
    }

    function didCompleteNavigation() {
        this.assertEquals(7, WebInspector.multitargetConsoleModel.messages().length);
        this.releaseControl();
    }

    this.takeControl();
};

TestSuite.prototype.testSharedWorker = function()
{
    function didEvaluateInConsole(resultText) {
        this.assertEquals("2011", resultText);
        this.releaseControl();
    }
    this.evaluateInConsole_("globalVar", didEvaluateInConsole.bind(this));
    this.takeControl();
};

TestSuite.prototype.testPauseInSharedWorkerInitialization1 = function()
{
    // Make sure the worker is loaded.
    this.takeControl();
    this._waitForTargets(2, callback.bind(this));

    function callback()
    {
        var target = WebInspector.targetManager.targetsWithJSContext()[0];
        target._connection.runAfterPendingDispatches(this.releaseControl.bind(this));
    }
};

TestSuite.prototype.testPauseInSharedWorkerInitialization2 = function()
{
    this.takeControl();
    this._waitForTargets(2, callback.bind(this));

    function callback()
    {
        var target = WebInspector.targetManager.targetsWithJSContext()[0];
        var debuggerModel = WebInspector.DebuggerModel.fromTarget(target);
        if (debuggerModel.isPaused()) {
            this.releaseControl();
            return;
        }
        this._waitForScriptPause(this.releaseControl.bind(this));
    }
};

TestSuite.prototype.enableTouchEmulation = function()
{
    var deviceModeModel = new WebInspector.DeviceModeModel(function() {});
    deviceModeModel._target = WebInspector.targetManager.mainTarget();
    deviceModeModel._applyTouch(true, true);
};

TestSuite.prototype.enableAutoAttachToCreatedPages = function()
{
    WebInspector.settingForTest("autoAttachToCreatedPages").set(true);
}

TestSuite.prototype.waitForDebuggerPaused = function()
{
    var debuggerModel = WebInspector.DebuggerModel.fromTarget(WebInspector.targetManager.mainTarget());
    if (debuggerModel.debuggerPausedDetails)
        return;

    this.takeControl();
    this._waitForScriptPause(this.releaseControl.bind(this));
}

TestSuite.prototype.switchToPanel = function(panelName)
{
    this.showPanel(panelName).then(this.releaseControl.bind(this));
    this.takeControl();
}

// Regression test for crbug.com/370035.
TestSuite.prototype.testDeviceMetricsOverrides = function()
{
    const dumpPageMetrics = function()
    {
        return JSON.stringify({
            width: window.innerWidth,
            height: window.innerHeight,
            deviceScaleFactor: window.devicePixelRatio
        });
    };

    var test = this;

    function testOverrides(params, metrics, callback)
    {
        WebInspector.targetManager.mainTarget().emulationAgent().invoke_setDeviceMetricsOverride(params, getMetrics);

        function getMetrics()
        {
            test.evaluateInConsole_("(" + dumpPageMetrics.toString() + ")()", checkMetrics);
        }

        function checkMetrics(consoleResult)
        {
            test.assertEquals('"' + JSON.stringify(metrics) + '"', consoleResult, "Wrong metrics for params: " + JSON.stringify(params));
            callback();
        }
    }

    function step1()
    {
        testOverrides({width: 1200, height: 1000, deviceScaleFactor: 1, mobile: false, fitWindow: true}, {width: 1200, height: 1000, deviceScaleFactor: 1}, step2);
    }

    function step2()
    {
        testOverrides({width: 1200, height: 1000, deviceScaleFactor: 1, mobile: false, fitWindow: false}, {width: 1200, height: 1000, deviceScaleFactor: 1}, step3);
    }

    function step3()
    {
        testOverrides({width: 1200, height: 1000, deviceScaleFactor: 3, mobile: false, fitWindow: true}, {width: 1200, height: 1000, deviceScaleFactor: 3}, step4);
    }

    function step4()
    {
        testOverrides({width: 1200, height: 1000, deviceScaleFactor: 3, mobile: false, fitWindow: false}, {width: 1200, height: 1000, deviceScaleFactor: 3}, finish);
    }

    function finish()
    {
        test.releaseControl();
    }

    test.takeControl();
    step1();
};

TestSuite.prototype.testScreenshotRecording = function()
{
    var test = this;

    function performActionsInPage(callback)
    {
        var count = 0;
        var div = document.createElement("div");
        div.setAttribute("style", "left: 0px; top: 0px; width: 100px; height: 100px; position: absolute;");
        document.body.appendChild(div);
        requestAnimationFrame(frame);
        function frame()
        {
            var color = [0, 0, 0];
            color[count % 3] = 255;
            div.style.backgroundColor = "rgb(" + color.join(",") + ")";
            if (++count > 10)
                requestAnimationFrame(callback);
            else
                requestAnimationFrame(frame);
        }
    }

    var captureFilmStripSetting = WebInspector.settings.createSetting("timelineCaptureFilmStrip", false);
    captureFilmStripSetting.set(true);
    test.evaluateInConsole_(performActionsInPage.toString(), function() {});
    test.invokeAsyncWithTimeline_("performActionsInPage", onTimelineDone);

    function onTimelineDone()
    {
        captureFilmStripSetting.set(false);
        var filmStripModel = new WebInspector.FilmStripModel(WebInspector.panels.timeline._tracingModel);
        var frames = filmStripModel.frames();
        test.assertTrue(frames.length > 4 && typeof frames.length === "number");
        loadFrameImages(frames);
    }

    function loadFrameImages(frames)
    {
        var readyImages = [];
        for (var frame of frames)
            frame.imageDataPromise().then(onGotImageData)

        function onGotImageData(data)
        {
            var image = new Image();
            test.assertTrue(!!data, "No image data for frame");
            image.addEventListener("load", onLoad);
            image.src = "data:image/jpg;base64," + data;
        }

        function onLoad(event)
        {
            readyImages.push(event.target);
            if (readyImages.length === frames.length)
                validateImagesAndCompleteTest(readyImages);
        }
    }

    function validateImagesAndCompleteTest(images)
    {
        var redCount = 0;
        var greenCount = 0;
        var blueCount = 0;

        var canvas = document.createElement("canvas");
        var ctx = canvas.getContext("2d");
        for (var image of images) {
            test.assertTrue(image.naturalWidth > 10);
            test.assertTrue(image.naturalHeight > 10);
            canvas.width = image.naturalWidth;
            canvas.height = image.naturalHeight;
            ctx.drawImage(image, 0, 0);
            var data = ctx.getImageData(0, 0, 1, 1);
            var color = Array.prototype.join.call(data.data, ",");
            if (data.data[0] > 200)
                redCount++;
            else if (data.data[1] > 200)
                greenCount++;
            else if (data.data[2] > 200)
                blueCount++;
            else
                test.fail("Unexpected color: " + color);
        }
        test.assertTrue(redCount && greenCount && blueCount, "Color sanity check failed");
        test.releaseControl();
    }

    test.takeControl();
}

TestSuite.prototype.testSettings = function()
{
    var test = this;

    createSettings();
    test.takeControl();
    setTimeout(reset, 0);

    function createSettings()
    {
        var localSetting = WebInspector.settings.createSetting("local", undefined, true);
        localSetting.set({s: "local", n: 1 });
        var globalSetting = WebInspector.settings.createSetting("global", undefined, false);
        globalSetting.set({s: "global", n: 2 });
    }

    function reset()
    {
        Runtime.experiments.clearForTest();
        InspectorFrontendHost.getPreferences(gotPreferences);
    }

    function gotPreferences(prefs)
    {
        WebInspector.Main._instanceForTest._createSettings(prefs);

        var localSetting = WebInspector.settings.createSetting("local", undefined, true);
        test.assertEquals("object", typeof localSetting.get());
        test.assertEquals("local", localSetting.get().s);
        test.assertEquals(1, localSetting.get().n);
        var globalSetting = WebInspector.settings.createSetting("global", undefined, false);
        test.assertEquals("object", typeof globalSetting.get());
        test.assertEquals("global", globalSetting.get().s);
        test.assertEquals(2, globalSetting.get().n);
        test.releaseControl();
    }
}

TestSuite.prototype.waitForTestResultsInConsole = function()
{
    var messages = WebInspector.multitargetConsoleModel.messages();
    for (var i = 0; i < messages.length; ++i) {
        var text = messages[i].messageText;
        if (text === "PASS")
            return;
        else if (/^FAIL/.test(text))
            this.fail(text); // This will throw.
    }
    // Neither PASS nor FAIL, so wait for more messages.
    function onConsoleMessage(event)
    {
        var text = event.data.messageText;
        if (text === "PASS")
            this.releaseControl();
        else if (/^FAIL/.test(text))
            this.fail(text);
    }

    WebInspector.multitargetConsoleModel.addEventListener(WebInspector.ConsoleModel.Events.MessageAdded, onConsoleMessage, this);
    this.takeControl();
};

TestSuite.prototype._overrideMethod = function(receiver, methodName, override)
{
    var original = receiver[methodName];
    if (typeof original !== "function") {
        this.fail(`TestSuite._overrideMethod: $[methodName] is not a function`);
        return;
    }
    receiver[methodName] = function()
    {
        try {
            var value = original.apply(receiver, arguments);
        } finally {
            receiver[methodName] = original;
        }
        override.apply(original, arguments);
        return value;
    }
}

TestSuite.prototype.startTimeline = function(callback)
{
    var test = this;
    this.showPanel("timeline").then(function() {
        var timeline = WebInspector.panels.timeline;
        test._overrideMethod(timeline, "recordingStarted", callback);
        timeline._toggleRecording();
    });
}

TestSuite.prototype.stopTimeline = function(callback)
{
    var timeline = WebInspector.panels.timeline;
    this._overrideMethod(timeline, "loadingComplete", callback);
    timeline._toggleRecording();
}

TestSuite.prototype.invokePageFunctionAsync = function(functionName, opt_args, callback_is_always_last)
{
    var callback = arguments[arguments.length - 1];
    var doneMessage = `DONE: ${functionName}.${++this._asyncInvocationId}`;
    var argsString = arguments.length < 3 ? "" : Array.prototype.slice.call(arguments, 1, -1).map(arg => JSON.stringify(arg)).join(",") + ",";
    this.evaluateInConsole_(`${functionName}(${argsString} function() { console.log('${doneMessage}'); });`, function() {});
    WebInspector.multitargetConsoleModel.addEventListener(WebInspector.ConsoleModel.Events.MessageAdded, onConsoleMessage);

    function onConsoleMessage(event)
    {
        var text = event.data.messageText;
        if (text === doneMessage) {
            WebInspector.multitargetConsoleModel.removeEventListener(WebInspector.ConsoleModel.Events.MessageAdded, onConsoleMessage);
            callback();
        }
    }
}

TestSuite.prototype.invokeAsyncWithTimeline_ = function(functionName, callback)
{
    var test = this;

    this.startTimeline(onRecordingStarted);

    function onRecordingStarted()
    {
        test.invokePageFunctionAsync(functionName, pageActionsDone);
    }

    function pageActionsDone()
    {
        test.stopTimeline(callback);
    }
};

TestSuite.prototype.enableExperiment = function(name)
{
    Runtime.experiments.enableForTest(name);
}

TestSuite.prototype.checkInputEventsPresent = function()
{
    var expectedEvents = new Set(arguments);
    var model = WebInspector.panels.timeline._model;
    var asyncEvents = model.mainThreadAsyncEvents();
    var input = asyncEvents.get(WebInspector.TimelineUIUtils.asyncEventGroups().input) || [];
    var prefix = "InputLatency::";
    for (var e of input) {
        if (!e.name.startsWith(prefix))
            continue;
        expectedEvents.delete(e.name.substr(prefix.length));
    }
    if (expectedEvents.size)
        throw "Some expected events are not found: " + Array.from(expectedEvents.keys()).join(",");
}

/**
 * Serializes array of uiSourceCodes to string.
 * @param {!Array.<!WebInspectorUISourceCode>} uiSourceCodes
 * @return {string}
 */
TestSuite.prototype.uiSourceCodesToString_ = function(uiSourceCodes)
{
    var names = [];
    for (var i = 0; i < uiSourceCodes.length; i++)
        names.push('"' + WebInspector.networkMapping.networkURL(uiSourceCodes[i]) + '"');
    return names.join(",");
};

/**
 * Returns all loaded non anonymous uiSourceCodes.
 * @return {!Array.<!WebInspectorUISourceCode>}
 */
TestSuite.prototype.nonAnonymousUISourceCodes_ = function()
{
    function filterOutAnonymous(uiSourceCode)
    {
        return !!WebInspector.networkMapping.networkURL(uiSourceCode);
    }

    function filterOutService(uiSourceCode)
    {
        return !uiSourceCode.isFromServiceProject();
    }

    var uiSourceCodes = WebInspector.workspace.uiSourceCodes();
    uiSourceCodes = uiSourceCodes.filter(filterOutService);
    return uiSourceCodes.filter(filterOutAnonymous);
};

/*
 * Evaluates the code in the console as if user typed it manually and invokes
 * the callback when the result message is received and added to the console.
 * @param {string} code
 * @param {function(string)} callback
 */
TestSuite.prototype.evaluateInConsole_ = function(code, callback)
{
    function innerEvaluate()
    {
        WebInspector.context.removeFlavorChangeListener(WebInspector.ExecutionContext, showConsoleAndEvaluate, this);
        var consoleView = WebInspector.ConsoleView.instance();
        consoleView._prompt.setText(code);
        consoleView._promptElement.dispatchEvent(TestSuite.createKeyEvent("Enter"));

        this.addSniffer(WebInspector.ConsoleView.prototype, "_consoleMessageAddedForTest",
            function(viewMessage) {
                callback(viewMessage.toMessageElement().deepTextContent());
            }.bind(this));
    }

    function showConsoleAndEvaluate()
    {
        WebInspector.console.showPromise().then(innerEvaluate.bind(this));
    }

    if (!WebInspector.context.flavor(WebInspector.ExecutionContext)) {
        WebInspector.context.addFlavorChangeListener(WebInspector.ExecutionContext, showConsoleAndEvaluate, this);
        return;
    }
    showConsoleAndEvaluate.call(this);
};

/**
 * Checks that all expected scripts are present in the scripts list
 * in the Scripts panel.
 * @param {!Array.<string>} expected Regular expressions describing
 *     expected script names.
 * @return {boolean} Whether all the scripts are in "scripts-files" select
 *     box
 */
TestSuite.prototype._scriptsAreParsed = function(expected)
{
    var uiSourceCodes = this.nonAnonymousUISourceCodes_();
    // Check that at least all the expected scripts are present.
    var missing = expected.slice(0);
    for (var i = 0; i < uiSourceCodes.length; ++i) {
        for (var j = 0; j < missing.length; ++j) {
            if (uiSourceCodes[i].name().search(missing[j]) !== -1) {
                missing.splice(j, 1);
                break;
            }
        }
    }
    return missing.length === 0;
};

/**
 * Waits for script pause, checks expectations, and invokes the callback.
 * @param {function():void} callback
 */
TestSuite.prototype._waitForScriptPause = function(callback)
{
    this.addSniffer(WebInspector.DebuggerModel.prototype, "_pausedScript", callback);
};

/**
 * Waits until all the scripts are parsed and invokes the callback.
 */
TestSuite.prototype._waitUntilScriptsAreParsed = function(expectedScripts, callback)
{
    var test = this;

    function waitForAllScripts() {
        if (test._scriptsAreParsed(expectedScripts))
            callback();
        else
            test.addSniffer(WebInspector.panels.sources.sourcesView(), "_addUISourceCode", waitForAllScripts);
    }

    waitForAllScripts();
};

TestSuite.prototype._waitForTargets = function(n, callback)
{
    checkTargets.call(this);

    function checkTargets()
    {
        if (WebInspector.targetManager.targets().length >= n)
            callback.call(null);
        else
            this.addSniffer(WebInspector.TargetManager.prototype, "addTarget", checkTargets.bind(this));
    }
}

/**
 * Key event with given key identifier.
 */
TestSuite.createKeyEvent = function(keyIdentifier)
{
    var evt = document.createEvent("KeyboardEvent");
    evt.initKeyboardEvent("keydown", true /* can bubble */, true /* can cancel */, null /* view */, keyIdentifier, "");
    return evt;
};

window.uiTests = new TestSuite(window.domAutomationController);
})(window);


text:
<?php
/**
 * Rewrite Configuration Class
 */

// Don't load directly
if ( ! defined( 'ABSPATH' ) ) {
	die( '-1' );
}

if ( ! class_exists( 'Tribe__Events__Rewrite' ) ) {

	/**
	 * Permalinks magic Happens over here!
	 */
	class Tribe__Events__Rewrite {
		/**
		 * If we wish to setup a rewrite rule that uses percent symbols, we'll need
		 * to make use of this placeholder.
		 */
		const PERCENT_PLACEHOLDER = '~~TRIBE~PC~~';

		/**
		 * Static singleton variable
		 * @var [type]
		 */
		public static $instance;

		/**
		 * Static Singleton Factory Method
		 *
		 * @return Tribe__Events__Rewrite
		 */
		public static function instance( $wp_rewrite = null ) {
			if ( ! isset( self::$instance ) ) {
				self::$instance = new self( $wp_rewrite );
			}

			return self::$instance;
		}

		/**
		 * WP_Rewrite Instance
		 * @var WP_Rewrite
		 */
		public $rewrite;

		/**
		 * Rewrite rules Holder
		 * @var array
		 */
		public $rules = array();

		/**
		 * Base slugs for rewrite urls
		 * @var array
		 */
		public $bases = array();

		/**
		 * Just dont...
		 */
		private function __construct() {}

		/**
		 * After creating the Hooks on WordPress we lock the usage of the function
		 * @var boolean
		 */
		private $hook_lock = false;

		/**
		 * Do not allow people to Hook methods twice by mistake
		 */
		public function hooks( $remove = false ) {
			if ( false === $this->hook_lock ) {
				// Don't allow people do Double the hooks
				$this->hook_lock = true;

				// Hook the methods
				add_action( 'tribe_events_pre_rewrite', array( $this, 'generate_core_rules' ) );
				add_filter( 'generate_rewrite_rules', array( $this, 'filter_generate' ) );
				add_filter( 'post_type_link', array( $this, 'filter_post_type_link' ), 15, 2 );

			} elseif ( true === $remove ) {
				// Remove the Hooks
				remove_filter( 'generate_rewrite_rules', array( $this, 'filter_generate' ) );
				remove_filter( 'post_type_link', array( $this, 'filter_post_type_link' ), 15 );
			}
		}

		/**
		 * Generate the Rewrite Rules
		 *
		 * @param  WP_Rewrite $wp_rewrite WordPress Rewrite that will be modified, pass it by reference (&$wp_rewrite)
		 */
		public function filter_generate( WP_Rewrite $wp_rewrite ) {
			// Gets the rewrite bases and completes any other required setup work
			$this->setup( $wp_rewrite );

			/**
			 * Use this to change the Tribe__Events__Rewrite instance before new rules
			 * are committed.
			 *
			 * Should be used when you want to add more rewrite rules without having to
			 * deal with the array merge, noting that rules for The Events Calendar are
			 * themselves added via this hook (default priority).
			 *
			 * @var Tribe__Events__Rewrite $rewrite
			 */
			do_action( 'tribe_events_pre_rewrite', $this );

			/**
			 * Backwards Compatibility filter, this filters the WP Rewrite Rules.
			 * @todo  Check if is worth deprecating this hook
			 */
			$wp_rewrite->rules = apply_filters( 'tribe_events_rewrite_rules', $this->rules + $wp_rewrite->rules, $this );
		}

		/**
		 * Sets up the rules required by The Events Calendar.
		 *
		 * This should be called during tribe_events_pre_rewrite, which means other plugins needing to add rules
		 * of their own can do so on the same hook at a lower or higher priority, according to how specific
		 * those rules are.
		 *
		 * @param Tribe__Events__Rewrite $rewrite
		 */
		public function generate_core_rules( Tribe__Events__Rewrite $rewrite ) {
			$options = array(
				'default_view' => Tribe__Settings_Manager::get_option( 'viewOption', 'month' ),
			);

			$rewrite
				// Single
				->single( array( '(\d{4}-\d{2}-\d{2})' ), array( Tribe__Events__Main::POSTTYPE => '%1', 'eventDate' => '%2' ) )
				->single( array( '{{ all }}' ), array( Tribe__Events__Main::POSTTYPE => '%1', 'post_type' => Tribe__Events__Main::POSTTYPE, 'eventDisplay' => 'all' ) )

				->single( array( '(\d{4}-\d{2}-\d{2})', 'ical' ), array( Tribe__Events__Main::POSTTYPE => '%1', 'eventDate' => '%2', 'ical' => 1 ) )
				->single( array( 'ical' ), array( 'ical' => 1, 'name' => '%1', 'post_type' => Tribe__Events__Main::POSTTYPE ) )

				// Archive
				->archive( array( '{{ page }}', '(\d+)' ), array( 'eventDisplay' => 'list', 'paged' => '%1' ) )
				->archive( array( '(feed|rdf|rss|rss2|atom)' ), array( 'eventDisplay' => 'list', 'feed' => '%1' ) )
				->archive( array( '{{ month }}' ), array( 'eventDisplay' => 'month' ) )
				->archive( array( '{{ list }}', '{{ page }}', '(\d+)' ), array( 'eventDisplay' => 'list', 'paged' => '%1' ) )
				->archive( array( '{{ list }}' ), array( 'eventDisplay' => 'list' ) )
				->archive( array( '{{ today }}' ), array( 'eventDisplay' => 'day' ) )
				->archive( array( '(\d{4}-\d{2})' ), array( 'eventDisplay' => 'month', 'eventDate' => '%1' ) )
				->archive( array( '(\d{4}-\d{2}-\d{2})' ), array( 'eventDisplay' => 'day', 'eventDate' => '%1' ) )
				->archive( array(), array( 'eventDisplay' => 'default' ) )

				->archive( array( 'ical' ), array( 'ical' => 1 ) )
				->archive( array( '(\d{4}-\d{2}-\d{2})', 'ical' ), array( 'ical' => 1, 'eventDisplay' => 'day', 'eventDate' => '%1' ) )

				// Taxonomy
				->tax( array( '{{ page }}', '(\d+)' ), array( 'eventDisplay' => 'list', 'paged' => '%2' ) )
				->tax( array( '{{ month }}' ), array( 'eventDisplay' => 'month' ) )
				->tax( array( '{{ list }}', '{{ page }}', '(\d+)' ), array( 'eventDisplay' => 'list', 'paged' => '%2' ) )
				->tax( array( '{{ list }}' ), array( 'eventDisplay' => 'list' ) )
				->tax( array( '{{ today }}' ), array( 'eventDisplay' => 'day' ) )
				->tax( array( '{{ day }}', '(\d{4}-\d{2}-\d{2})' ), array( 'eventDisplay' => 'day', 'eventDate' => '%2' ) )
				->tax( array( '(\d{4}-\d{2})' ), array( 'eventDisplay' => 'month', 'eventDate' => '%2' ) )
				->tax( array( '(\d{4}-\d{2}-\d{2})' ), array( 'eventDisplay' => 'day', 'eventDate' => '%2' ) )
				->tax( array( 'feed' ), array( 'eventDisplay' => 'list', 'feed' => 'rss2' ) )
				->tax( array( 'ical' ), array( 'ical' => 1 ) )
				->tax( array( 'feed', '(feed|rdf|rss|rss2|atom)' ), array( 'feed' => '%2' ) )
				->tax( array(), array( 'eventDisplay' => $options['default_view'] ) )

				// Tag
				->tag( array( '{{ page }}', '(\d+)' ), array( 'eventDisplay' => 'list', 'paged' => '%2' ) )
				->tag( array( '{{ month }}' ), array( 'eventDisplay' => 'month' ) )
				->tag( array( '{{ list }}', '{{ page }}', '(\d+)' ), array( 'eventDisplay' => 'list', 'paged' => '%2' ) )
				->tag( array( '{{ list }}' ), array( 'eventDisplay' => 'list' ) )
				->tag( array( '{{ today }}' ), array( 'eventDisplay' => 'day' ) )
				->tag( array( '{{ day }}', '(\d{4}-\d{2}-\d{2})' ), array( 'eventDisplay' => 'day', 'eventDate' => '%2' ) )
				->tag( array( '(\d{4}-\d{2})' ), array( 'eventDisplay' => 'month', 'eventDate' => '%2' ) )
				->tag( array( '(\d{4}-\d{2}-\d{2})' ), array( 'eventDisplay' => 'day', 'eventDate' => '%2' ) )
				->tag( array( 'feed' ), array( 'eventDisplay' => 'list', 'feed' => 'rss2' ) )
				->tag( array( 'ical' ), array( 'ical' => 1 ) )
				->tag( array( 'feed', '(feed|rdf|rss|rss2|atom)' ), array( 'feed' => '%2' ) )
				->tag( array(), array( 'eventDisplay' => $options['default_view'] ) );
		}

		/**
		 * When WPML is active we need to return the language Query Arg
		 *
		 * @param  string $uri Permalink for the post
		 * @param  WP_Post $post Post Object
		 *
		 * @return string      Permalink with the language
		 */
		public function filter_post_type_link( $permalink, $post ) {
			if ( ! $this->is_wpml_active() || empty( $_GET['lang'] ) ) {
				return $permalink;
			}

			return add_query_arg( array( 'lang' => $_GET['lang'] ), $permalink );
		}

		/**
		 * Checking if WPML is active on this WP
		 *
		 * @return boolean
		 */
		public function is_wpml_active() {
			return ! empty( $GLOBALS['sitepress'] ) && $GLOBALS['sitepress'] instanceof SitePress;
		}

		/**
		 * When you are going to use any of the functions to create new rewrite rules you need to setup first
		 *
		 * @param  WP_Rewrite|null $wp_rewrite  Pass the WP_Rewrite if you have it
		 * @return Tribe__Events__Rewrite       The modified version of the class with the required variables in place
		 */
		public function setup( $wp_rewrite = null ) {
			if ( ! $wp_rewrite instanceof WP_Rewrite ){
				global $wp_rewrite;
			}
			$this->rewrite = $wp_rewrite;
			$this->bases = $this->get_bases( 'regex' );

			return $this;
		}

		/**
		 * Get the base slugs for the Plugin Rewrite rules
		 *
		 * WARNING: Don't mess with the filters below if you don't know what you are doing
		 *
		 * @param  string $method Use "regex" to return a Regular Expression with the possible Base Slugs using l10n
		 * @return object         Return Base Slugs with l10n variations
		 */
		public function get_bases( $method = 'regex' ) {
			$tec = Tribe__Events__Main::instance();

			/**
			 * If you want to modify the base slugs before the i18n happens filter this use this filter
			 * All the bases need to have a key and a value, they might be the same or not.
			 *
			 * Each value is an array of possible slugs: to improve robustness the "original" English
			 * slug is supported in addition to translated forms for month, list, today and day: this
			 * way if the forms are altered (whether through i18n or other custom mods) *after* links
			 * have already been promulgated, there will be less chance of visitors hitting 404s.
			 *
			 * @var array $bases
			 */
			$bases = apply_filters( 'tribe_events_rewrite_base_slugs', array(
				'month' => array( 'month', $tec->monthSlug ),
				'list' => array( 'list', $tec->listSlug ),
				'today' => array( 'today', $tec->todaySlug ),
				'day' => array( 'day', $tec->daySlug ),
				'tag' => array( 'tag', $tec->tag_slug ),
				'tax' => array( 'category', $tec->category_slug ),
				'page' => (array) 'page',
				'all' => (array) 'all',
				'single' => (array) Tribe__Settings_Manager::get_option( 'singleEventSlug', 'event' ),
				'archive' => (array) Tribe__Settings_Manager::get_option( 'eventsSlug', 'events' ),
			) );

			// Remove duplicates (no need to have 'month' twice if no translations are in effect, etc)
			$bases = array_map( 'array_unique', $bases );

			// By default we always have `en_US` to avoid 404 with older URLs
			$languages = apply_filters( 'tribe_events_rewrite_i18n_languages', array_unique( array( 'en_US', get_locale() ) ) );

			// By default we load the Default and our plugin domains
			$domains = apply_filters( 'tribe_events_rewrite_i18n_domains', array(
				'default' => true, // Default doesn't need file path
				'the-events-calendar' => Tribe__Events__Main::instance()->pluginDir . 'lang/',
			) );

			// If WPML exists we treat the multiple languages
			if ( $this->is_wpml_active() ) {
				global $sitepress;

				// Grab all languages
				$langs = $sitepress->get_active_languages();

				foreach ( $langs as $lang ) {
					$languages[] = $sitepress->get_locale( $lang['code'] );
				}

				// Prevent Duplicates and Empty langs
				$languages = array_filter( array_unique( $languages ) );

				// Query the Current Language
				$current_locale = $sitepress->get_locale( $sitepress->get_current_language() );

				// Get the strings on multiple Domains and Languages
				$bases = Tribe__Events__Main::instance()->get_i18n_strings( $bases, $languages, $domains, $current_locale );
			}

			if ( 'regex' === $method ){
				foreach ( $bases as $type => $base ) {
					$bases[ $type ] = '(?:' . implode( '|', $base ) . ')';
				}
			}

			/**
			 * Use `tribe_events_rewrite_i18n_slugs` to modify the final version of the l10n slugs bases
			 */
			return (object) apply_filters( 'tribe_events_rewrite_i18n_slugs', $bases, $method );
		}

		/**
		 * The base method for creating a new Rewrite rule
		 *
		 * @param array|string $regex The regular expression to catch the URL
		 * @param array  $args  The arguments in which the regular expression "alias" to
		 *
		 * @return Tribe__Events__Rewrite
		 */
		public function add( $regex, $args = array() ) {
			$regex = (array) $regex;

			$default = array();
			$args = array_filter( wp_parse_args( $args, $default ) );

			$url = add_query_arg( $args, 'index.php' );

			// Optional Trailing Slash
			$regex[] = '?$';

			// Glue the pieces with slashes
			$regex = implode( '/', array_filter( $regex ) );

			// Add the Bases to the regex
			foreach ( $this->bases as $key => $value ) {
				$regex = str_replace( array( '{{ ' . $key . ' }}', '{{' . $key . '}}' ), $value, $regex );
			}

			// Apply the Preg Indexes to the URL
			preg_match_all( '/%([0-9])/', $url, $matches );
			foreach ( end( $matches ) as $index ) {
				$url = str_replace( '%' . $index, $this->rewrite->preg_index( $index ), $url );
			}

			// Add the rule
			$this->rules[ $regex ] = $url;

			return $this;
		}

		/**
		 * Alias to `$this->add()` but adding the archive base first
		 *
		 * @param array|string $regex The regular expression to catch the URL
		 * @param array  $args  The arguments in which the regular expression "alias" to
		 *
		 * @return Tribe__Events__Rewrite
		 */
		public function archive( $regex, $args = array() ) {
			$default = array(
				'post_type' => Tribe__Events__Main::POSTTYPE,
			);
			$args = array_filter( wp_parse_args( $args, $default ) );

			$regex = array_merge( array( $this->bases->archive ), (array) $regex );

			return $this->add( $regex, $args );
		}

		/**
		 * Alias to `$this->add()` but adding the singular base first
		 *
		 * @param array|string $regex The regular expression to catch the URL
		 * @param array  $args  The arguments in which the regular expression "alias" to
		 *
		 * @return Tribe__Events__Rewrite
		 */
		public function single( $regex, $args = array() ) {
			$regex = array_merge( array( $this->bases->single, '([^/]+)' ), (array) $regex );

			return $this->add( $regex, $args );
		}

		/**
		 * Alias to `$this->add()` but adding the taxonomy base first
		 *
		 * @param array|string $regex The regular expression to catch the URL
		 * @param array  $args  The arguments in which the regular expression "alias" to
		 *
		 * @return Tribe__Events__Rewrite
		 */
		public function tax( $regex, $args = array() ) {
			$default = array(
				'post_type' => Tribe__Events__Main::POSTTYPE,
				Tribe__Events__Main::TAXONOMY => '%1',
			);
			$args = array_filter( wp_parse_args( $args, $default ) );
			$regex = array_merge( array( $this->bases->archive, $this->bases->tax, '(?:[^/]+/)*([^/]+)' ), (array) $regex );

			return $this->add( $regex, $args );
		}

		/**
		 * Alias to `$this->add()` but adding the tag base first
		 *
		 * @param array|string $regex The regular expression to catch the URL
		 * @param array  $args  The arguments in which the regular expression "alias" to
		 *
		 * @return Tribe__Events__Rewrite
		 */
		public function tag( $regex, $args = array() ) {
			$default = array(
				'post_type' => Tribe__Events__Main::POSTTYPE,
				'tag' => '%1',
			);
			$args = array_filter( wp_parse_args( $args, $default ) );
			$regex = array_merge( array( $this->bases->archive, $this->bases->tag, '([^/]+)' ), (array) $regex );

			return $this->add( $regex, $args );
		}

		/**
		 * Returns a sanitized version of $slug that can be used in rewrite rules.
		 *
		 * This is ideal for those times where we wish to support internationalized
		 * URLs (ie, where "venue" in "venue/some-slug" may be rendered in non-ascii
		 * characters).
		 *
		 * In the case of registering new post types, $permastruct_name should
		 * generally match the CPT name itself.
		 *
		 * @param  string $slug
		 * @param  string $permastruct_name
		 * @return string
		 */
		public function prepare_slug( $slug, $permastruct_name ) {
			$needs_handling = false;
			$sanitized_slug = sanitize_title( $slug );

			// Was UTF8 encoding required for the slug? %a0 type entities are a tell-tale of this
			if ( preg_match( '/(%[0-9a-f]{2})+/', $sanitized_slug ) ) {
				/**
				 * Controls whether special UTF8 URL handling is setup for the set of
				 * rules described by $permastruct_name.
				 *
				 * This only fires if Tribe__Events__Rewrite::prepare_slug() believes
				 * handling is required.
				 *
				 * @var string $permastruct_name
				 * @var string $possible_slug_name
				 */
				$needs_handling = apply_filters( 'tribe_events_rewrite_utf8_handling',
					true,
					$permastruct_name,
					$possible_slug_name
				);
			}

			if ( $needs_handling ) {
				// User agents encode things the same way but in uppercase
				$sanitized_slug = strtoupper( $sanitized_slug );

				// UTF8 encoding results in lots of "%" chars in our string which play havoc
				// with WP_Rewrite::generate_rewrite_rules(), so we swap them out temporarily
				$sanitized_slug = str_replace( '%', self::PERCENT_PLACEHOLDER, $sanitized_slug );

				// Restore the % chars later on
				add_filter( $permastruct_name . '_rewrite_rules', array( $this, 'remove_percent_placeholders' ) );
			}

			/**
			 * Provides an opportunity to modify the sanitized slug which will be used
			 * in rewrite rules relating to $permastruct_name.
			 *
			 * @var string $prepared_slug
			 * @var string $permastruct_name
			 * @var string $original_slug
			 */
			return apply_filters( 'tribe_events_rewrite_prepared_slug',
				preg_quote( $sanitized_slug ),
				$permastruct_name,
				$slug
			);
		}

		/**
		 * Converts any percentage placeholders in the array keys back to % symbols.
		 *
		 * @param  array $rules
		 * @return array
		 */
		public function remove_percent_placeholders( array $rules ) {
			$new_rules = array();

			foreach ( $rules as $key => $value ) {
				$key = str_replace( self::PERCENT_PLACEHOLDER, '%', $key );
				$new_rules[$key] = $value;
			}

			return $new_rules;
		}
	} // end Tribe__Events__Rewrite class

} // end if !class_exists Tribe__Events__Rewrite

redpajama_set_name: RedPajamaGithub


text:
package org.apache.doris.analysis;

import org.apache.doris.catalog.Catalog;
import org.apache.doris.catalog.Column;
import org.apache.doris.catalog.ScalarType;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.ErrorCode;
import org.apache.doris.common.ErrorReport;
import org.apache.doris.common.proc.FrontendsProcNode;
import org.apache.doris.mysql.privilege.PrivPredicate;
import org.apache.doris.qe.ConnectContext;
import org.apache.doris.qe.ShowResultSetMetaData;

public class ShowFrontendsStmt extends ShowStmt {

    public ShowFrontendsStmt() {
    }

    @Override
    public void analyze(Analyzer analyzer) throws AnalysisException {
        if (!Catalog.getCurrentCatalog().getAuth().checkGlobalPriv(ConnectContext.get(), PrivPredicate.ADMIN)
                && !Catalog.getCurrentCatalog().getAuth().checkGlobalPriv(ConnectContext.get(),
                                                                          PrivPredicate.OPERATOR)) {
            ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR, "ADMIN/OPERATOR");
        }
    }

    @Override
    public ShowResultSetMetaData getMetaData() {
        ShowResultSetMetaData.Builder builder = ShowResultSetMetaData.builder();
        for (String title : FrontendsProcNode.TITLE_NAMES) {
            // hide hostname for SHOW FRONTENDS stmt
            if (title.equals("HostName")) {
                continue;
            }
            builder.addColumn(new Column(title, ScalarType.createVarchar(30)));
        }
        return builder.build();
    }
}


text:
package io.reneses.tela.core.scheduler.models;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Scheduled Action
 */
@JsonIgnoreProperties(ignoreUnknown = true)
public class ScheduledAction {

    private int id, delay;
    private Map<String, String[]> params;
    private LocalDateTime createdAt, nextExecution;

    @JsonProperty("module")
    private String moduleName;

    @JsonProperty("action")
    private String actionName;

    @JsonIgnore
    private String accessToken;

    /**
     * Init the object
     *
     * @param accessToken   Session
     * @param delay         Delay (in seconds) for the execution
     * @param actionPrefix  Action prefix
     * @param actionName    Action name
     * @param params        Action parameters
     * @param createdAt     Creation date of the scheduled action
     * @param nextExecution Datetime of the next execution
     */
    private void init(Integer id, String accessToken, int delay, String actionPrefix, String actionName,
                      Map<String, String[]> params,LocalDateTime createdAt, LocalDateTime nextExecution) {

        this.accessToken = accessToken;
        this.delay = delay;
        this.moduleName = actionPrefix;
        this.actionName = actionName;
        this.params = params;
        this.createdAt = createdAt;
        this.nextExecution = nextExecution;
        this.id = id == null? hashCode() : id;
    }

    /**
     * Default constructor for deserialization purposes
     */
    public ScheduledAction() {
        // Do not use programmatically
    }

    /**
     * Full constructor
     *
     * @param id            Scheduled ID
     * @param accessToken   Access token
     * @param delay         Delay (in seconds) for the execution
     * @param moduleName    Action prefix
     * @param actionName    Action name
     * @param params        Action parameters
     * @param createdAt     Creation date of the scheduled action
     * @param nextExecution Datetime of the next execution
     */
    public ScheduledAction(int id, String accessToken, int delay, String moduleName, String actionName, Map<String, String[]> params,
                           LocalDateTime createdAt, LocalDateTime nextExecution) {
        init(id, accessToken, delay, moduleName, actionName, params, createdAt, nextExecution);
    }

    /**
     * Constructor for first-time created objects
     * It initiates the created date and calculates the next execution
     *
     * @param accessToken Session
     * @param delay       Delay (in seconds) for the execution
     * @param moduleName  Action prefix
     * @param actionName  Action name
     * @param params      Action parameters
     */
    public ScheduledAction(String accessToken, int delay, String moduleName, String actionName, Map<String, String[]> params) {
        LocalDateTime now = LocalDateTime.now();
        init(null, accessToken, delay, moduleName, actionName, params, now, now.plusSeconds(delay));
    }

    /**
     * Constructor for first-time created objects without parameters
     * It initiates the created date and calculates the next execution
     *
     * @param accessToken Session
     * @param delay       Delay (in seconds) for the execution
     * @param moduleName  Action prefix
     * @param actionName  Action name
     */
    public ScheduledAction(String accessToken, int delay, String moduleName, String actionName) {
        this(accessToken, delay, moduleName, actionName, new HashMap<>());
    }

    //----------------------------------- OTHER -----------------------------------//

    /**
     * Update the date of the next execution
     */
    public void updateNextExecution() {
        if (delay <= 0)
            throw new IllegalStateException("The delay must be a positive integer");
        LocalDateTime now = LocalDateTime.now();
        do {
            nextExecution = nextExecution.plusSeconds(delay);
        }
        while (!nextExecution.isAfter(now));
    }

    //----------------------------------- TIME JSON PROPERTIES -----------------------------------//

    /**
     * setCreatedAtAsLong.
     *
     * @param createdAt a long.
     */
    @JsonProperty("createdAt")
    public void setCreatedAtAsLong(long createdAt) {
        this.createdAt = LocalDateTime.ofInstant(Instant.ofEpochMilli(createdAt), TimeZone.getDefault().toZoneId());
    }

    /**
     * getCreatedAtAsLong.
     *
     * @return a long.
     */
    @JsonProperty("createdAt")
    public long getCreatedAtAsLong() {
        return createdAt.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

    /**
     * setNextExecutionAsLong.
     *
     * @param nextExecution a long.
     */
    @JsonProperty("nextExecution")
    public void setNextExecutionAsLong(long nextExecution) {
        this.nextExecution = LocalDateTime.ofInstant(Instant.ofEpochMilli(nextExecution), TimeZone.getDefault().toZoneId());
    }

    /**
     * getNextExecutionAsLong.
     *
     * @return a long.
     */
    @JsonProperty("nextExecution")
    public long getNextExecutionAsLong() {
        return nextExecution.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

    //----------------------------------- SETTERS AND GETTERS -----------------------------------//

    /**
     * Set the ID property
     *
     * @param id Scheduled action ID
     */
    public void setId(int id) {
        this.id = id;
    }

    /**
     * Get the ID property
     *
     * @return Scheduled action ID
     */
    public int getId() {
        return this.id;
    }

    /**
     * Getter for the field delay.
     *
     * @return a int.
     */
    public int getDelay() {
        return delay;
    }

    /**
     * Setter for the field delay.
     *
     * @param delay a int.
     */
    public void setDelay(int delay) {
        this.delay = delay;
    }

    /**
     * Getter for the field accessToken.
     *
     * @return a {@link java.lang.String} object.
     */
    public String getAccessToken() {
        return accessToken;
    }

    /**
     * Setter for the field accessToken.
     *
     * @param accessToken a {@link java.lang.String} object.
     */
    public void setAccessToken(String accessToken) {
        this.accessToken = accessToken;
    }

    /**
     * Getter for the field moduleName.
     *
     * @return a {@link java.lang.String} object.
     */
    public String getModuleName() {
        return moduleName;
    }

    /**
     * Setter for the field moduleName.
     *
     * @param moduleName a {@link java.lang.String} object.
     */
    public void setModuleName(String moduleName) {
        this.moduleName = moduleName;
    }

    /**
     * Getter for the field actionName.
     *
     * @return a {@link java.lang.String} object.
     */
    public String getActionName() {
        return actionName;
    }

    /**
     * Setter for the field actionName.
     *
     * @param actionName a {@link java.lang.String} object.
     */
    public void setActionName(String actionName) {
        this.actionName = actionName;
    }

    /**
     * Getter for the field createdAt.
     *
     * @return a {@link java.time.LocalDateTime} object.
     */
    public LocalDateTime getCreatedAt() {
        return createdAt;
    }

    /**
     * Setter for the field createdAt.
     *
     * @param createdAt a {@link java.time.LocalDateTime} object.
     */
    public void setCreatedAt(LocalDateTime createdAt) {
        this.createdAt = createdAt;
    }

    /**
     * Getter for the field nextExecution.
     *
     * @return a {@link java.time.LocalDateTime} object.
     */
    public LocalDateTime getNextExecution() {
        return nextExecution;
    }

    /**
     * Setter for the field nextExecution.
     *
     * @param nextExecution a {@link java.time.LocalDateTime} object.
     */
    public void setNextExecution(LocalDateTime nextExecution) {
        this.nextExecution = nextExecution;
    }

    /**
     * Getter for the field params.
     *
     * @return a {@link java.util.Map} object.
     */
    public Map<String, String[]> getParams() {
        return params;
    }

    /**
     * Setter for the field params.
     *
     * @param params a {@link java.util.Map} object.
     */
    public void setParams(Map<String, String[]> params) {
        this.params = params;
    }

    //----------------------------------- OBJECT OVERRIDE -----------------------------------//

    /**
     * {@inheritDoc}
     */
    @Override
    public String toString() {
        String paramsString = params
                .entrySet()
                .stream()
                .map(entry -> entry.getKey() + ": " + Arrays.toString(entry.getValue()))
                .collect(Collectors.toList())
                .toString();
        return moduleName + "/" + actionName + " (" + delay + "s) " + paramsString;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof ScheduledAction)) return false;
        ScheduledAction that = (ScheduledAction) o;
        if (delay != that.delay) return false;
        if (!accessToken.equals(that.accessToken)) return false;
        if (!moduleName.equals(that.moduleName)) return false;
        if (!actionName.equals(that.actionName)) return false;
        if (params.size() != that.params.size()) return false;
        for (Map.Entry<String, String[]> entry : params.entrySet()) {
            if (!that.params.containsKey(entry.getKey())) return false;
            if (!Arrays.equals(entry.getValue(), that.params.get(entry.getKey()))) return false;
        }
        return true;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int hashCode() {
        int result = delay;
        result = 31 * result + accessToken.hashCode();
        result = 31 * result + moduleName.hashCode();
        result = 31 * result + actionName.hashCode();
        int mapHashCode = 0;
        for (Map.Entry<String, String[]> entry : params.entrySet())
            mapHashCode += entry.getKey().hashCode() ^ Arrays.hashCode(entry.getValue());
        result = 31 * result + mapHashCode;
        return result;
    }

}


text:
"""
Test cases for rendering exporters
"""
from collections import OrderedDict
from unittest import SkipTest

import param

from holoviews import (DynamicMap, HoloMap, Store, Curve)
from holoviews.element.comparison import ComparisonTestCase
from holoviews.streams import Stream
from pyviz_comms import CommManager

try:
    import panel as pn

    from holoviews.plotting.plotly import PlotlyRenderer
    from holoviews.plotting.renderer import Renderer
    from panel.widgets import DiscreteSlider, Player, FloatSlider
except:
    pn, PlotlyRenderer = None, None

class PlotlyRendererTest(ComparisonTestCase):

    def setUp(self):
        if 'plotly' not in Store.renderers or None in (pn, PlotlyRenderer):
            raise SkipTest("Plotly and Panel required to test rendering.")

        self.previous_backend = Store.current_backend
        Store.current_backend = 'plotly'
        self.renderer = PlotlyRenderer.instance()
        self.nbcontext = Renderer.notebook_context
        self.comm_manager = Renderer.comm_manager
        with param.logging_level('ERROR'):
            Renderer.notebook_context = False
            Renderer.comm_manager = CommManager

    def tearDown(self):
        with param.logging_level('ERROR'):
            Renderer.notebook_context = self.nbcontext
            Renderer.comm_manager = self.comm_manager
        Store.current_backend = self.previous_backend

    def test_render_static(self):
        curve = Curve([])
        obj, _ = self.renderer._validate(curve, None)
        self.assertIsInstance(obj, pn.pane.HoloViews)
        self.assertEqual(obj.center, True)
        self.assertIs(obj.renderer, self.renderer)
        self.assertEqual(obj.backend, 'plotly')

    def test_render_holomap_individual(self):
        hmap = HoloMap({i: Curve([1, 2, i]) for i in range(5)})
        obj, _ = self.renderer._validate(hmap, None)
        self.assertIsInstance(obj, pn.pane.HoloViews)
        self.assertEqual(obj.center, True)
        self.assertEqual(obj.widget_location, 'right')
        self.assertEqual(obj.widget_type, 'individual')
        widgets = obj.layout.select(DiscreteSlider)
        self.assertEqual(len(widgets), 1)
        slider = widgets[0]
        self.assertEqual(slider.options, OrderedDict([(str(i), i) for i in range(5)]))

    def test_render_holomap_embedded(self):
        hmap = HoloMap({i: Curve([1, 2, i]) for i in range(5)})
        data, _ = self.renderer.components(hmap)
        self.assertIn('State"', data['text/html'])

    # def test_render_holomap_not_embedded(self):
    #     hmap = HoloMap({i: Curve([1, 2, i]) for i in range(5)})
    #     data, _ = self.renderer.instance(widget_mode='live').components(hmap)
    #     self.assertNotIn('State"', data['text/html'])

    def test_render_holomap_scrubber(self):
        hmap = HoloMap({i: Curve([1, 2, i]) for i in range(5)})
        obj, _ = self.renderer._validate(hmap, 'scrubber')
        self.assertIsInstance(obj, pn.pane.HoloViews)
        self.assertEqual(obj.center, True)
        self.assertEqual(obj.widget_location, 'bottom')
        self.assertEqual(obj.widget_type, 'scrubber')
        widgets = obj.layout.select(Player)
        self.assertEqual(len(widgets), 1)
        player = widgets[0]
        self.assertEqual(player.start, 0)
        self.assertEqual(player.end, 4)

    def test_render_holomap_scrubber_fps(self):
        hmap = HoloMap({i: Curve([1, 2, i]) for i in range(5)})
        obj, _ = self.renderer.instance(fps=2)._validate(hmap, 'scrubber')
        self.assertIsInstance(obj, pn.pane.HoloViews)
        widgets = obj.layout.select(Player)
        self.assertEqual(len(widgets), 1)
        player = widgets[0]
        self.assertEqual(player.interval, 500)

    def test_render_holomap_individual_widget_position(self):
        hmap = HoloMap({i: Curve([1, 2, i]) for i in range(5)})
        obj, _ = self.renderer.instance(widget_location='top')._validate(hmap, None)
        self.assertIsInstance(obj, pn.pane.HoloViews)
        self.assertEqual(obj.center, True)
        self.assertEqual(obj.widget_location, 'top')
        self.assertEqual(obj.widget_type, 'individual')

    def test_render_dynamicmap_with_dims(self):
        dmap = DynamicMap(lambda y: Curve([1, 2, y]), kdims=['y']).redim.range(y=(0.1, 5))
        obj, _ = self.renderer._validate(dmap, None)
        self.renderer.components(obj)
        [(plot, pane)] = obj._plots.values()

        y = plot.handles['fig']['data'][0]['y']
        self.assertEqual(y[2], 0.1)
        slider = obj.layout.select(FloatSlider)[0]
        slider.value = 3.1
        y = plot.handles['fig']['data'][0]['y']
        self.assertEqual(y[2], 3.1)

    def test_render_dynamicmap_with_stream(self):
        stream = Stream.define(str('Custom'), y=2)()
        dmap = DynamicMap(lambda y: Curve([1, 2, y]), kdims=['y'], streams=[stream])
        obj, _ = self.renderer._validate(dmap, None)
        self.renderer.components(obj)
        [(plot, pane)] = obj._plots.values()

        y = plot.handles['fig']['data'][0]['y']
        self.assertEqual(y[2], 2)
        stream.event(y=3)
        y = plot.handles['fig']['data'][0]['y']
        self.assertEqual(y[2], 3)

    def test_render_dynamicmap_with_stream_dims(self):
        stream = Stream.define(str('Custom'), y=2)()
        dmap = DynamicMap(lambda x, y: Curve([x, 1, y]), kdims=['x', 'y'],
                          streams=[stream]).redim.values(x=[1, 2, 3])
        obj, _ = self.renderer._validate(dmap, None)
        self.renderer.components(obj)
        [(plot, pane)] = obj._plots.values()

        y = plot.handles['fig']['data'][0]['y']
        self.assertEqual(y[2], 2)
        stream.event(y=3)
        y = plot.handles['fig']['data'][0]['y']
        self.assertEqual(y[2], 3)

        y = plot.handles['fig']['data'][0]['y']
        self.assertEqual(y[0], 1)
        slider = obj.layout.select(DiscreteSlider)[0]
        slider.value = 3
        y = plot.handles['fig']['data'][0]['y']
        self.assertEqual(y[0], 3)


text:
Spree::AppConfiguration.class_eval do
  preference :master_password_emails, :string, default: ''
end