testcafe
Version:
Automated browser testing for the modern web development stack.
215 lines (210 loc) • 38 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const commander_1 = require("commander");
const dedent_1 = __importDefault(require("dedent"));
const read_file_relative_1 = require("read-file-relative");
const runtime_1 = require("../errors/runtime");
const types_1 = require("../errors/types");
const type_assertions_1 = require("../errors/runtime/type-assertions");
const get_viewport_width_1 = __importDefault(require("../utils/get-viewport-width"));
const string_1 = require("../utils/string");
const get_options_1 = require("../utils/get-options");
const get_filter_fn_1 = __importDefault(require("../utils/get-filter-fn"));
const REMOTE_ALIAS_RE = /^remote(?::(\d*))?$/;
const DESCRIPTION = dedent_1.default(`
In the browser list, you can use browser names (e.g. "ie", "chrome", etc.) as well as paths to executables.
To run tests against all installed browsers, use the "all" alias.
To use a remote browser connection (e.g., to connect a mobile device), specify "remote" as the browser alias.
If you need to connect multiple devices, add a colon and the number of browsers you want to connect (e.g., "remote:3").
To run tests in a browser accessed through a browser provider plugin, specify a browser alias that consists of two parts - the browser provider name prefix and the name of the browser itself; for example, "saucelabs:chrome@51".
You can use one or more file paths or glob patterns to specify which tests to run.
More info: https://devexpress.github.io/testcafe/documentation
`);
class CLIArgumentParser {
constructor(cwd) {
this.program = new commander_1.Command('testcafe');
this.cwd = cwd || process.cwd();
this.src = null;
this.browsers = null;
this.filter = null;
this.remoteCount = 0;
this.opts = null;
this._describeProgram();
}
static _parsePortNumber(value) {
type_assertions_1.assertType(type_assertions_1.is.nonNegativeNumberString, null, 'Port number', value);
return parseInt(value, 10);
}
static _getDescription() {
// NOTE: add empty line to workaround commander-forced indentation on the first line.
return '\n' + string_1.wordWrap(DESCRIPTION, 2, get_viewport_width_1.default(process.stdout));
}
_describeProgram() {
const version = JSON.parse(read_file_relative_1.readSync('../../package.json')).version;
this.program
.version(version, '-v, --version')
.usage('[options] <comma-separated-browser-list> <file-or-glob ...>')
.description(CLIArgumentParser._getDescription())
.option('-b, --list-browsers [provider]', 'output the aliases for local browsers or browsers available through the specified browser provider')
.option('-r, --reporter <name[:outputFile][,...]>', 'specify the reporters and optionally files where reports are saved')
.option('-s, --screenshots <path>', 'enable screenshot capturing and specify the path to save the screenshots to')
.option('-S, --screenshots-on-fails', 'take a screenshot whenever a test fails')
.option('-p, --screenshot-path-pattern <pattern>', 'use patterns to compose screenshot file names and paths: ${BROWSER}, ${BROWSER_VERSION}, ${OS}, etc.')
.option('-q, --quarantine-mode', 'enable the quarantine mode')
.option('-d, --debug-mode', 'execute test steps one by one pausing the test after each step')
.option('-e, --skip-js-errors', 'make tests not fail when a JS error happens on a page')
.option('-u, --skip-uncaught-errors', 'ignore uncaught errors and unhandled promise rejections, which occur during test execution')
.option('-t, --test <name>', 'run only tests with the specified name')
.option('-T, --test-grep <pattern>', 'run only tests matching the specified pattern')
.option('-f, --fixture <name>', 'run only fixtures with the specified name')
.option('-F, --fixture-grep <pattern>', 'run only fixtures matching the specified pattern')
.option('-a, --app <command>', 'launch the tested app using the specified command before running tests')
.option('-c, --concurrency <number>', 'run tests concurrently')
.option('-L, --live', 'enable live mode. In this mode, TestCafe watches for changes you make in the test files. These changes immediately restart the tests so that you can see the effect.')
.option('--test-meta <key=value[,key2=value2,...]>', 'run only tests with matching metadata')
.option('--fixture-meta <key=value[,key2=value2,...]>', 'run only fixtures with matching metadata')
.option('--debug-on-fail', 'pause the test if it fails')
.option('--app-init-delay <ms>', 'specify how much time it takes for the tested app to initialize')
.option('--selector-timeout <ms>', 'set the amount of time within which selectors make attempts to obtain a node to be returned')
.option('--assertion-timeout <ms>', 'set the amount of time within which assertion should pass')
.option('--page-load-timeout <ms>', 'set the amount of time within which TestCafe waits for the `window.load` event to fire on page load before proceeding to the next test action')
.option('--speed <factor>', 'set the speed of test execution (0.01 ... 1)')
.option('--ports <port1,port2>', 'specify custom port numbers')
.option('--hostname <name>', 'specify the hostname')
.option('--proxy <host>', 'specify the host of the proxy server')
.option('--proxy-bypass <rules>', 'specify a comma-separated list of rules that define URLs accessed bypassing the proxy server')
.option('--ssl <options>', 'specify SSL options to run TestCafe proxy server over the HTTPS protocol')
.option('--video <path>', ' record videos of test runs')
.option('--video-options <option=value[,...]>', 'specify video recording options')
.option('--video-encoding-options <option=value[,...]>', 'specify encoding options')
.option('--disable-page-reloads', 'disable page reloads between tests')
.option('--dev', 'enables mechanisms to log and diagnose errors')
.option('--qr-code', 'outputs QR-code that repeats URLs used to connect the remote browsers')
.option('--sf, --stop-on-first-fail', 'stop an entire test run if any test fails')
// NOTE: these options will be handled by chalk internally
.option('--color', 'force colors in command line')
.option('--no-color', 'disable colors in command line');
}
_filterAndCountRemotes(browser) {
const remoteMatch = browser.match(REMOTE_ALIAS_RE);
if (remoteMatch) {
this.remoteCount += parseInt(remoteMatch[1], 10) || 1;
return false;
}
return true;
}
async _parseFilteringOptions() {
if (this.opts.testGrep)
this.opts.testGrep = get_options_1.getGrepOptions('--test-grep', this.opts.testGrep);
if (this.opts.fixtureGrep)
this.opts.fixtureGrep = get_options_1.getGrepOptions('--fixture-grep', this.opts.fixtureGrep);
if (this.opts.testMeta)
this.opts.testMeta = await get_options_1.getMetaOptions('--test-meta', this.opts.testMeta);
if (this.opts.fixtureMeta)
this.opts.fixtureMeta = await get_options_1.getMetaOptions('--fixture-meta', this.opts.fixtureMeta);
this.filter = get_filter_fn_1.default(this.opts);
}
_parseAppInitDelay() {
if (this.opts.appInitDelay) {
type_assertions_1.assertType(type_assertions_1.is.nonNegativeNumberString, null, 'Tested app initialization delay', this.opts.appInitDelay);
this.opts.appInitDelay = parseInt(this.opts.appInitDelay, 10);
}
}
_parseSelectorTimeout() {
if (this.opts.selectorTimeout) {
type_assertions_1.assertType(type_assertions_1.is.nonNegativeNumberString, null, 'Selector timeout', this.opts.selectorTimeout);
this.opts.selectorTimeout = parseInt(this.opts.selectorTimeout, 10);
}
}
_parseAssertionTimeout() {
if (this.opts.assertionTimeout) {
type_assertions_1.assertType(type_assertions_1.is.nonNegativeNumberString, null, 'Assertion timeout', this.opts.assertionTimeout);
this.opts.assertionTimeout = parseInt(this.opts.assertionTimeout, 10);
}
}
_parsePageLoadTimeout() {
if (this.opts.pageLoadTimeout) {
type_assertions_1.assertType(type_assertions_1.is.nonNegativeNumberString, null, 'Page load timeout', this.opts.pageLoadTimeout);
this.opts.pageLoadTimeout = parseInt(this.opts.pageLoadTimeout, 10);
}
}
_parseSpeed() {
if (this.opts.speed)
this.opts.speed = parseFloat(this.opts.speed);
}
_parseConcurrency() {
if (this.opts.concurrency)
this.opts.concurrency = parseInt(this.opts.concurrency, 10);
}
_parsePorts() {
if (this.opts.ports) {
this.opts.ports = this.opts.ports
.split(',')
.map(CLIArgumentParser._parsePortNumber);
if (this.opts.ports.length < 2)
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.portsOptionRequiresTwoNumbers);
}
}
_parseBrowserList() {
const browsersArg = this.program.args[0] || '';
this.browsers = string_1.splitQuotedText(browsersArg, ',')
.filter(browser => browser && this._filterAndCountRemotes(browser));
}
async _parseSslOptions() {
if (this.opts.ssl)
this.opts.ssl = await get_options_1.getSSLOptions(this.opts.ssl);
}
async _parseReporters() {
const reporters = this.opts.reporter ? this.opts.reporter.split(',') : [];
this.opts.reporter = reporters.map(reporter => {
const separatorIndex = reporter.indexOf(':');
if (separatorIndex < 0)
return { name: reporter };
const name = reporter.substring(0, separatorIndex);
const output = reporter.substring(separatorIndex + 1);
return { name, output };
});
}
_parseFileList() {
this.src = this.program.args.slice(1);
}
async _parseVideoOptions() {
if (this.opts.videoOptions)
this.opts.videoOptions = await get_options_1.getVideoOptions(this.opts.videoOptions);
if (this.opts.videoEncodingOptions)
this.opts.videoEncodingOptions = await get_options_1.getVideoOptions(this.opts.videoEncodingOptions);
}
_getProviderName() {
this.opts.providerName = this.opts.listBrowsers === true ? void 0 : this.opts.listBrowsers;
}
async parse(argv) {
this.program.parse(argv);
this.args = this.program.args;
this.opts = this.program.opts();
// NOTE: the '-list-browsers' option only lists browsers and immediately exits the app.
// Therefore, we don't need to process other arguments.
if (this.opts.listBrowsers) {
this._getProviderName();
return;
}
this._parseSelectorTimeout();
this._parseAssertionTimeout();
this._parsePageLoadTimeout();
this._parseAppInitDelay();
this._parseSpeed();
this._parsePorts();
this._parseBrowserList();
this._parseConcurrency();
this._parseFileList();
await this._parseFilteringOptions();
await this._parseVideoOptions();
await this._parseSslOptions();
await this._parseReporters();
}
}
exports.default = CLIArgumentParser;
module.exports = exports.default;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXJndW1lbnQtcGFyc2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NsaS9hcmd1bWVudC1wYXJzZXIuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSx5Q0FBb0M7QUFDcEMsb0RBQTRCO0FBQzVCLDJEQUFzRDtBQUN0RCwrQ0FBaUQ7QUFDakQsMkNBQWlEO0FBQ2pELHVFQUFtRTtBQUNuRSxxRkFBMkQ7QUFDM0QsNENBQTREO0FBQzVELHNEQUFzRztBQUN0RywyRUFBaUQ7QUFFakQsTUFBTSxlQUFlLEdBQUcscUJBQXFCLENBQUM7QUFFOUMsTUFBTSxXQUFXLEdBQUcsZ0JBQU0sQ0FBQzs7Ozs7Ozs7Ozs7OztDQWExQixDQUFDLENBQUM7QUFFSCxNQUFxQixpQkFBaUI7SUFDbEMsWUFBYSxHQUFHO1FBQ1osSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJLG1CQUFPLENBQUMsVUFBVSxDQUFDLENBQUM7UUFFdkMsSUFBSSxDQUFDLEdBQUcsR0FBRyxHQUFHLElBQUksT0FBTyxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBRWhDLElBQUksQ0FBQyxHQUFHLEdBQVcsSUFBSSxDQUFDO1FBQ3hCLElBQUksQ0FBQyxRQUFRLEdBQU0sSUFBSSxDQUFDO1FBQ3hCLElBQUksQ0FBQyxNQUFNLEdBQVEsSUFBSSxDQUFDO1FBQ3hCLElBQUksQ0FBQyxXQUFXLEdBQUcsQ0FBQyxDQUFDO1FBQ3JCLElBQUksQ0FBQyxJQUFJLEdBQVUsSUFBSSxDQUFDO1FBRXhCLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO0lBQzVCLENBQUM7SUFFRCxNQUFNLENBQUMsZ0JBQWdCLENBQUUsS0FBSztRQUMxQiw0QkFBVSxDQUFDLG9CQUFFLENBQUMsdUJBQXVCLEVBQUUsSUFBSSxFQUFFLGFBQWEsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUVuRSxPQUFPLFFBQVEsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDL0IsQ0FBQztJQUVELE1BQU0sQ0FBQyxlQUFlO1FBQ2xCLHFGQUFxRjtRQUNyRixPQUFPLElBQUksR0FBRyxpQkFBUSxDQUFDLFdBQVcsRUFBRSxDQUFDLEVBQUUsNEJBQWdCLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFDN0UsQ0FBQztJQUVELGdCQUFnQjtRQUNaLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsNkJBQUksQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDO1FBRS9ELElBQUksQ0FBQyxPQUFPO2FBQ1AsT0FBTyxDQUFDLE9BQU8sRUFBRSxlQUFlLENBQUM7YUFDakMsS0FBSyxDQUFDLDZEQUE2RCxDQUFDO2FBQ3BFLFdBQVcsQ0FBQyxpQkFBaUIsQ0FBQyxlQUFlLEVBQUUsQ0FBQzthQUVoRCxNQUFNLENBQUMsZ0NBQWdDLEVBQUUsb0dBQW9HLENBQUM7YUFDOUksTUFBTSxDQUFDLDBDQUEwQyxFQUFFLG9FQUFvRSxDQUFDO2FBQ3hILE1BQU0sQ0FBQywwQkFBMEIsRUFBRSw2RUFBNkUsQ0FBQzthQUNqSCxNQUFNLENBQUMsNEJBQTRCLEVBQUUseUNBQXlDLENBQUM7YUFDL0UsTUFBTSxDQUFDLHlDQUF5QyxFQUFFLHNHQUFzRyxDQUFDO2FBQ3pKLE1BQU0sQ0FBQyx1QkFBdUIsRUFBRSw0QkFBNEIsQ0FBQzthQUM3RCxNQUFNLENBQUMsa0JBQWtCLEVBQUUsZ0VBQWdFLENBQUM7YUFDNUYsTUFBTSxDQUFDLHNCQUFzQixFQUFFLHVEQUF1RCxDQUFDO2FBQ3ZGLE1BQU0sQ0FBQyw0QkFBNEIsRUFBRSw0RkFBNEYsQ0FBQzthQUNsSSxNQUFNLENBQUMsbUJBQW1CLEVBQUUsd0NBQXdDLENBQUM7YUFDckUsTUFBTSxDQUFDLDJCQUEyQixFQUFFLCtDQUErQyxDQUFDO2FBQ3BGLE1BQU0sQ0FBQyxzQkFBc0IsRUFBRSwyQ0FBMkMsQ0FBQzthQUMzRSxNQUFNLENBQUMsOEJBQThCLEVBQUUsa0RBQWtELENBQUM7YUFDMUYsTUFBTSxDQUFDLHFCQUFxQixFQUFFLHdFQUF3RSxDQUFDO2FBQ3ZHLE1BQU0sQ0FBQyw0QkFBNEIsRUFBRSx3QkFBd0IsQ0FBQzthQUM5RCxNQUFNLENBQUMsWUFBWSxFQUFFLHNLQUFzSyxDQUFDO2FBQzVMLE1BQU0sQ0FBQywyQ0FBMkMsRUFBRSx1Q0FBdUMsQ0FBQzthQUM1RixNQUFNLENBQUMsOENBQThDLEVBQUUsMENBQTBDLENBQUM7YUFDbEcsTUFBTSxDQUFDLGlCQUFpQixFQUFFLDRCQUE0QixDQUFDO2FBQ3ZELE1BQU0sQ0FBQyx1QkFBdUIsRUFBRSxpRUFBaUUsQ0FBQzthQUNsRyxNQUFNLENBQUMseUJBQXlCLEVBQUUsNkZBQTZGLENBQUM7YUFDaEksTUFBTSxDQUFDLDBCQUEwQixFQUFFLDJEQUEyRCxDQUFDO2FBQy9GLE1BQU0sQ0FBQywwQkFBMEIsRUFBRSwrSUFBK0ksQ0FBQzthQUNuTCxNQUFNLENBQUMsa0JBQWtCLEVBQUUsOENBQThDLENBQUM7YUFDMUUsTUFBTSxDQUFDLHVCQUF1QixFQUFFLDZCQUE2QixDQUFDO2FBQzlELE1BQU0sQ0FBQyxtQkFBbUIsRUFBRSxzQkFBc0IsQ0FBQzthQUNuRCxNQUFNLENBQUMsZ0JBQWdCLEVBQUUsc0NBQXNDLENBQUM7YUFDaEUsTUFBTSxDQUFDLHdCQUF3QixFQUFFLDhGQUE4RixDQUFDO2FBQ2hJLE1BQU0sQ0FBQyxpQkFBaUIsRUFBRSwwRUFBMEUsQ0FBQzthQUNyRyxNQUFNLENBQUMsZ0JBQWdCLEVBQUUsNkJBQTZCLENBQUM7YUFDdkQsTUFBTSxDQUFDLHNDQUFzQyxFQUFFLGlDQUFpQyxDQUFDO2FBQ2pGLE1BQU0sQ0FBQywrQ0FBK0MsRUFBRSwwQkFBMEIsQ0FBQzthQUNuRixNQUFNLENBQUMsd0JBQXdCLEVBQUUsb0NBQW9DLENBQUM7YUFDdEUsTUFBTSxDQUFDLE9BQU8sRUFBRSwrQ0FBK0MsQ0FBQzthQUNoRSxNQUFNLENBQUMsV0FBVyxFQUFFLHVFQUF1RSxDQUFDO2FBQzVGLE1BQU0sQ0FBQyw0QkFBNEIsRUFBRSwyQ0FBMkMsQ0FBQztZQUVsRiwwREFBMEQ7YUFDekQsTUFBTSxDQUFDLFNBQVMsRUFBRSw4QkFBOEIsQ0FBQzthQUNqRCxNQUFNLENBQUMsWUFBWSxFQUFFLGdDQUFnQyxDQUFDLENBQUM7SUFDaEUsQ0FBQztJQUVELHNCQUFzQixDQUFFLE9BQU87UUFDM0IsTUFBTSxXQUFXLEdBQUcsT0FBTyxDQUFDLEtBQUssQ0FBQyxlQUFlLENBQUMsQ0FBQztRQUVuRCxJQUFJLFdBQVcsRUFBRTtZQUNiLElBQUksQ0FBQyxXQUFXLElBQUksUUFBUSxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDdEQsT0FBTyxLQUFLLENBQUM7U0FDaEI7UUFFRCxPQUFPLElBQUksQ0FBQztJQUNoQixDQUFDO0lBRUQsS0FBSyxDQUFDLHNCQUFzQjtRQUN4QixJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUTtZQUNsQixJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsR0FBRyw0QkFBYyxDQUFDLGFBQWEsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBRTNFLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXO1lBQ3JCLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxHQUFHLDRCQUFjLENBQUMsZ0JBQWdCLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUVwRixJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUTtZQUNsQixJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsR0FBRyxNQUFNLDRCQUFjLENBQUMsYUFBYSxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7UUFFakYsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVc7WUFDckIsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLEdBQUcsTUFBTSw0QkFBYyxDQUFDLGdCQUFnQixFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUM7UUFFMUYsSUFBSSxDQUFDLE1BQU0sR0FBRyx1QkFBVyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUN6QyxDQUFDO0lBRUQsa0JBQWtCO1FBQ2QsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRTtZQUN4Qiw0QkFBVSxDQUFDLG9CQUFFLENBQUMsdUJBQXVCLEVBQUUsSUFBSSxFQUFFLGlDQUFpQyxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUM7WUFFeEcsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsWUFBWSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1NBQ2pFO0lBQ0wsQ0FBQztJQUVELHFCQUFxQjtRQUNqQixJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsZUFBZSxFQUFFO1lBQzNCLDRCQUFVLENBQUMsb0JBQUUsQ0FBQyx1QkFBdUIsRUFBRSxJQUFJLEVBQUUsa0JBQWtCLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQztZQUU1RixJQUFJLENBQUMsSUFBSSxDQUFDLGVBQWUsR0FBRyxRQUFRLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxlQUFlLEVBQUUsRUFBRSxDQUFDLENBQUM7U0FDdkU7SUFDTCxDQUFDO0lBRUQsc0JBQXNCO1FBQ2xCLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsRUFBRTtZQUM1Qiw0QkFBVSxDQUFDLG9CQUFFLENBQUMsdUJBQXVCLEVBQUUsSUFBSSxFQUFFLG1CQUFtQixFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztZQUU5RixJQUFJLENBQUMsSUFBSSxDQUFDLGdCQUFnQixHQUFHLFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLGdCQUFnQixFQUFFLEVBQUUsQ0FBQyxDQUFDO1NBQ3pFO0lBQ0wsQ0FBQztJQUVELHFCQUFxQjtRQUNqQixJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsZUFBZSxFQUFFO1lBQzNCLDRCQUFVLENBQUMsb0JBQUUsQ0FBQyx1QkFBdUIsRUFBRSxJQUFJLEVBQUUsbUJBQW1CLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQztZQUU3RixJQUFJLENBQUMsSUFBSSxDQUFDLGVBQWUsR0FBRyxRQUFRLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxlQUFlLEVBQUUsRUFBRSxDQUFDLENBQUM7U0FDdkU7SUFDTCxDQUFDO0lBRUQsV0FBVztRQUNQLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLO1lBQ2YsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLEdBQUcsVUFBVSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDdEQsQ0FBQztJQUVELGlCQUFpQjtRQUNiLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXO1lBQ3JCLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxHQUFHLFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUMsQ0FBQztJQUNwRSxDQUFDO0lBRUQsV0FBVztRQUNQLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUU7WUFDakIsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLO2lCQUM1QixLQUFLLENBQUMsR0FBRyxDQUFDO2lCQUNWLEdBQUcsQ0FBQyxpQkFBaUIsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO1lBRTdDLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxHQUFHLENBQUM7Z0JBQzFCLE1BQU0sSUFBSSxzQkFBWSxDQUFDLHNCQUFjLENBQUMsNkJBQTZCLENBQUMsQ0FBQztTQUM1RTtJQUNMLENBQUM7SUFFRCxpQkFBaUI7UUFDYixNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUM7UUFFL0MsSUFBSSxDQUFDLFFBQVEsR0FBRyx3QkFBZSxDQUFDLFdBQVcsRUFBRSxHQUFHLENBQUM7YUFDNUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsT0FBTyxJQUFJLElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO0lBQzVFLENBQUM7SUFFRCxLQUFLLENBQUMsZ0JBQWdCO1FBQ2xCLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHO1lBQ2IsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLEdBQUcsTUFBTSwyQkFBYSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDM0QsQ0FBQztJQUVELEtBQUssQ0FBQyxlQUFlO1FBQ2pCLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUUxRSxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsR0FBRyxTQUFTLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxFQUFFO1lBQzFDLE1BQU0sY0FBYyxHQUFHLFFBQVEsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUM7WUFFN0MsSUFBSSxjQUFjLEdBQUcsQ0FBQztnQkFDbEIsT0FBTyxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsQ0FBQztZQUU5QixNQUFNLElBQUksR0FBSyxRQUFRLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxjQUFjLENBQUMsQ0FBQztZQUNyRCxNQUFNLE1BQU0sR0FBRyxRQUFRLENBQUMsU0FBUyxDQUFDLGNBQWMsR0FBRyxDQUFDLENBQUMsQ0FBQztZQUV0RCxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxDQUFDO1FBQzVCLENBQUMsQ0FBQyxDQUFDO0lBQ1AsQ0FBQztJQUVELGNBQWM7UUFDVixJQUFJLENBQUMsR0FBRyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMxQyxDQUFDO0lBRUQsS0FBSyxDQUFDLGtCQUFrQjtRQUNwQixJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsWUFBWTtZQUN0QixJQUFJLENBQUMsSUFBSSxDQUFDLFlBQVksR0FBRyxNQUFNLDZCQUFlLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUUzRSxJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsb0JBQW9CO1lBQzlCLElBQUksQ0FBQyxJQUFJLENBQUMsb0JBQW9CLEdBQUcsTUFBTSw2QkFBZSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsb0JBQW9CLENBQUMsQ0FBQztJQUMvRixDQUFDO0lBRUQsZ0JBQWdCO1FBQ1osSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLEtBQUssSUFBSSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUM7SUFDL0YsQ0FBQztJQUVELEtBQUssQ0FBQyxLQUFLLENBQUUsSUFBSTtRQUNiLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBRXpCLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUM7UUFFOUIsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDO1FBRWhDLHVGQUF1RjtRQUN2Rix1REFBdUQ7UUFDdkQsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRTtZQUN4QixJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztZQUN4QixPQUFPO1NBQ1Y7UUFFRCxJQUFJLENBQUMscUJBQXFCLEVBQUUsQ0FBQztRQUM3QixJQUFJLENBQUMsc0JBQXNCLEVBQUUsQ0FBQztRQUM5QixJQUFJLENBQUMscUJBQXFCLEVBQUUsQ0FBQztRQUM3QixJQUFJLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztRQUMxQixJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7UUFDbkIsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBQ25CLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1FBQ3pCLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1FBQ3pCLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztRQUV0QixNQUFNLElBQUksQ0FBQyxzQkFBc0IsRUFBRSxDQUFDO1FBQ3BDLE1BQU0sSUFBSSxDQUFDLGtCQUFrQixFQUFFLENBQUM7UUFDaEMsTUFBTSxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztRQUM5QixNQUFNLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztJQUNqQyxDQUFDO0NBQ0o7QUFyT0Qsb0NBcU9DIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tbWFuZCB9IGZyb20gJ2NvbW1hbmRlcic7XG5pbXBvcnQgZGVkZW50IGZyb20gJ2RlZGVudCc7XG5pbXBvcnQgeyByZWFkU3luYyBhcyByZWFkIH0gZnJvbSAncmVhZC1maWxlLXJlbGF0aXZlJztcbmltcG9ydCB7IEdlbmVyYWxFcnJvciB9IGZyb20gJy4uL2Vycm9ycy9ydW50aW1lJztcbmltcG9ydCB7IFJVTlRJTUVfRVJST1JTIH0gZnJvbSAnLi4vZXJyb3JzL3R5cGVzJztcbmltcG9ydCB7IGFzc2VydFR5cGUsIGlzIH0gZnJvbSAnLi4vZXJyb3JzL3J1bnRpbWUvdHlwZS1hc3NlcnRpb25zJztcbmltcG9ydCBnZXRWaWV3UG9ydFdpZHRoIGZyb20gJy4uL3V0aWxzL2dldC12aWV3cG9ydC13aWR0aCc7XG5pbXBvcnQgeyB3b3JkV3JhcCwgc3BsaXRRdW90ZWRUZXh0IH0gZnJvbSAnLi4vdXRpbHMvc3RyaW5nJztcbmltcG9ydCB7IGdldFNTTE9wdGlvbnMsIGdldFZpZGVvT3B0aW9ucywgZ2V0TWV0YU9wdGlvbnMsIGdldEdyZXBPcHRpb25zIH0gZnJvbSAnLi4vdXRpbHMvZ2V0LW9wdGlvbnMnO1xuaW1wb3J0IGdldEZpbHRlckZuIGZyb20gJy4uL3V0aWxzL2dldC1maWx0ZXItZm4nO1xuXG5jb25zdCBSRU1PVEVfQUxJQVNfUkUgPSAvXnJlbW90ZSg/OjooXFxkKikpPyQvO1xuXG5jb25zdCBERVNDUklQVElPTiA9IGRlZGVudChgXG4gICAgSW4gdGhlIGJyb3dzZXIgbGlzdCwgeW91IGNhbiB1c2UgYnJvd3NlciBuYW1lcyAoZS5nLiBcImllXCIsIFwiY2hyb21lXCIsIGV0Yy4pIGFzIHdlbGwgYXMgcGF0aHMgdG8gZXhlY3V0YWJsZXMuXG5cbiAgICBUbyBydW4gdGVzdHMgYWdhaW5zdCBhbGwgaW5zdGFsbGVkIGJyb3dzZXJzLCB1c2UgdGhlIFwiYWxsXCIgYWxpYXMuXG5cbiAgICBUbyB1c2UgYSByZW1vdGUgYnJvd3NlciBjb25uZWN0aW9uIChlLmcuLCB0byBjb25uZWN0IGEgbW9iaWxlIGRldmljZSksIHNwZWNpZnkgXCJyZW1vdGVcIiBhcyB0aGUgYnJvd3NlciBhbGlhcy5cbiAgICBJZiB5b3UgbmVlZCB0byBjb25uZWN0IG11bHRpcGxlIGRldmljZXMsIGFkZCBhIGNvbG9uIGFuZCB0aGUgbnVtYmVyIG9mIGJyb3dzZXJzIHlvdSB3YW50IHRvIGNvbm5lY3QgKGUuZy4sIFwicmVtb3RlOjNcIikuXG5cbiAgICBUbyBydW4gdGVzdHMgaW4gYSBicm93c2VyIGFjY2Vzc2VkIHRocm91Z2ggYSBicm93c2VyIHByb3ZpZGVyIHBsdWdpbiwgc3BlY2lmeSBhIGJyb3dzZXIgYWxpYXMgdGhhdCBjb25zaXN0cyBvZiB0d28gcGFydHMgLSB0aGUgYnJvd3NlciBwcm92aWRlciBuYW1lIHByZWZpeCBhbmQgdGhlIG5hbWUgb2YgdGhlIGJyb3dzZXIgaXRzZWxmOyBmb3IgZXhhbXBsZSwgXCJzYXVjZWxhYnM6Y2hyb21lQDUxXCIuXG5cbiAgICBZb3UgY2FuIHVzZSBvbmUgb3IgbW9yZSBmaWxlIHBhdGhzIG9yIGdsb2IgcGF0dGVybnMgdG8gc3BlY2lmeSB3aGljaCB0ZXN0cyB0byBydW4uXG5cbiAgICBNb3JlIGluZm86IGh0dHBzOi8vZGV2ZXhwcmVzcy5naXRodWIuaW8vdGVzdGNhZmUvZG9jdW1lbnRhdGlvblxuYCk7XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIENMSUFyZ3VtZW50UGFyc2VyIHtcbiAgICBjb25zdHJ1Y3RvciAoY3dkKSB7XG4gICAgICAgIHRoaXMucHJvZ3JhbSA9IG5ldyBDb21tYW5kKCd0ZXN0Y2FmZScpO1xuXG4gICAgICAgIHRoaXMuY3dkID0gY3dkIHx8IHByb2Nlc3MuY3dkKCk7XG5cbiAgICAgICAgdGhpcy5zcmMgICAgICAgICA9IG51bGw7XG4gICAgICAgIHRoaXMuYnJvd3NlcnMgICAgPSBudWxsO1xuICAgICAgICB0aGlzLmZpbHRlciAgICAgID0gbnVsbDtcbiAgICAgICAgdGhpcy5yZW1vdGVDb3VudCA9IDA7XG4gICAgICAgIHRoaXMub3B0cyAgICAgICAgPSBudWxsO1xuXG4gICAgICAgIHRoaXMuX2Rlc2NyaWJlUHJvZ3JhbSgpO1xuICAgIH1cblxuICAgIHN0YXRpYyBfcGFyc2VQb3J0TnVtYmVyICh2YWx1ZSkge1xuICAgICAgICBhc3NlcnRUeXBlKGlzLm5vbk5lZ2F0aXZlTnVtYmVyU3RyaW5nLCBudWxsLCAnUG9ydCBudW1iZXInLCB2YWx1ZSk7XG5cbiAgICAgICAgcmV0dXJuIHBhcnNlSW50KHZhbHVlLCAxMCk7XG4gICAgfVxuXG4gICAgc3RhdGljIF9nZXREZXNjcmlwdGlvbiAoKSB7XG4gICAgICAgIC8vIE5PVEU6IGFkZCBlbXB0eSBsaW5lIHRvIHdvcmthcm91bmQgY29tbWFuZGVyLWZvcmNlZCBpbmRlbnRhdGlvbiBvbiB0aGUgZmlyc3QgbGluZS5cbiAgICAgICAgcmV0dXJuICdcXG4nICsgd29yZFdyYXAoREVTQ1JJUFRJT04sIDIsIGdldFZpZXdQb3J0V2lkdGgocHJvY2Vzcy5zdGRvdXQpKTtcbiAgICB9XG5cbiAgICBfZGVzY3JpYmVQcm9ncmFtICgpIHtcbiAgICAgICAgY29uc3QgdmVyc2lvbiA9IEpTT04ucGFyc2UocmVhZCgnLi4vLi4vcGFja2FnZS5qc29uJykpLnZlcnNpb247XG5cbiAgICAgICAgdGhpcy5wcm9ncmFtXG4gICAgICAgICAgICAudmVyc2lvbih2ZXJzaW9uLCAnLXYsIC0tdmVyc2lvbicpXG4gICAgICAgICAgICAudXNhZ2UoJ1tvcHRpb25zXSA8Y29tbWEtc2VwYXJhdGVkLWJyb3dzZXItbGlzdD4gPGZpbGUtb3ItZ2xvYiAuLi4+JylcbiAgICAgICAgICAgIC5kZXNjcmlwdGlvbihDTElBcmd1bWVudFBhcnNlci5fZ2V0RGVzY3JpcHRpb24oKSlcblxuICAgICAgICAgICAgLm9wdGlvbignLWIsIC0tbGlzdC1icm93c2VycyBbcHJvdmlkZXJdJywgJ291dHB1dCB0aGUgYWxpYXNlcyBmb3IgbG9jYWwgYnJvd3NlcnMgb3IgYnJvd3NlcnMgYXZhaWxhYmxlIHRocm91Z2ggdGhlIHNwZWNpZmllZCBicm93c2VyIHByb3ZpZGVyJylcbiAgICAgICAgICAgIC5vcHRpb24oJy1yLCAtLXJlcG9ydGVyIDxuYW1lWzpvdXRwdXRGaWxlXVssLi4uXT4nLCAnc3BlY2lmeSB0aGUgcmVwb3J0ZXJzIGFuZCBvcHRpb25hbGx5IGZpbGVzIHdoZXJlIHJlcG9ydHMgYXJlIHNhdmVkJylcbiAgICAgICAgICAgIC5vcHRpb24oJy1zLCAtLXNjcmVlbnNob3RzIDxwYXRoPicsICdlbmFibGUgc2NyZWVuc2hvdCBjYXB0dXJpbmcgYW5kIHNwZWNpZnkgdGhlIHBhdGggdG8gc2F2ZSB0aGUgc2NyZWVuc2hvdHMgdG8nKVxuICAgICAgICAgICAgLm9wdGlvbignLVMsIC0tc2NyZWVuc2hvdHMtb24tZmFpbHMnLCAndGFrZSBhIHNjcmVlbnNob3Qgd2hlbmV2ZXIgYSB0ZXN0IGZhaWxzJylcbiAgICAgICAgICAgIC5vcHRpb24oJy1wLCAtLXNjcmVlbnNob3QtcGF0aC1wYXR0ZXJuIDxwYXR0ZXJuPicsICd1c2UgcGF0dGVybnMgdG8gY29tcG9zZSBzY3JlZW5zaG90IGZpbGUgbmFtZXMgYW5kIHBhdGhzOiAke0JST1dTRVJ9LCAke0JST1dTRVJfVkVSU0lPTn0sICR7T1N9LCBldGMuJylcbiAgICAgICAgICAgIC5vcHRpb24oJy1xLCAtLXF1YXJhbnRpbmUtbW9kZScsICdlbmFibGUgdGhlIHF1YXJhbnRpbmUgbW9kZScpXG4gICAgICAgICAgICAub3B0aW9uKCctZCwgLS1kZWJ1Zy1tb2RlJywgJ2V4ZWN1dGUgdGVzdCBzdGVwcyBvbmUgYnkgb25lIHBhdXNpbmcgdGhlIHRlc3QgYWZ0ZXIgZWFjaCBzdGVwJylcbiAgICAgICAgICAgIC5vcHRpb24oJy1lLCAtLXNraXAtanMtZXJyb3JzJywgJ21ha2UgdGVzdHMgbm90IGZhaWwgd2hlbiBhIEpTIGVycm9yIGhhcHBlbnMgb24gYSBwYWdlJylcbiAgICAgICAgICAgIC5vcHRpb24oJy11LCAtLXNraXAtdW5jYXVnaHQtZXJyb3JzJywgJ2lnbm9yZSB1bmNhdWdodCBlcnJvcnMgYW5kIHVuaGFuZGxlZCBwcm9taXNlIHJlamVjdGlvbnMsIHdoaWNoIG9jY3VyIGR1cmluZyB0ZXN0IGV4ZWN1dGlvbicpXG4gICAgICAgICAgICAub3B0aW9uKCctdCwgLS10ZXN0IDxuYW1lPicsICdydW4gb25seSB0ZXN0cyB3aXRoIHRoZSBzcGVjaWZpZWQgbmFtZScpXG4gICAgICAgICAgICAub3B0aW9uKCctVCwgLS10ZXN0LWdyZXAgPHBhdHRlcm4+JywgJ3J1biBvbmx5IHRlc3RzIG1hdGNoaW5nIHRoZSBzcGVjaWZpZWQgcGF0dGVybicpXG4gICAgICAgICAgICAub3B0aW9uKCctZiwgLS1maXh0dXJlIDxuYW1lPicsICdydW4gb25seSBmaXh0dXJlcyB3aXRoIHRoZSBzcGVjaWZpZWQgbmFtZScpXG4gICAgICAgICAgICAub3B0aW9uKCctRiwgLS1maXh0dXJlLWdyZXAgPHBhdHRlcm4+JywgJ3J1biBvbmx5IGZpeHR1cmVzIG1hdGNoaW5nIHRoZSBzcGVjaWZpZWQgcGF0dGVybicpXG4gICAgICAgICAgICAub3B0aW9uKCctYSwgLS1hcHAgPGNvbW1hbmQ+JywgJ2xhdW5jaCB0aGUgdGVzdGVkIGFwcCB1c2luZyB0aGUgc3BlY2lmaWVkIGNvbW1hbmQgYmVmb3JlIHJ1bm5pbmcgdGVzdHMnKVxuICAgICAgICAgICAgLm9wdGlvbignLWMsIC0tY29uY3VycmVuY3kgPG51bWJlcj4nLCAncnVuIHRlc3RzIGNvbmN1cnJlbnRseScpXG4gICAgICAgICAgICAub3B0aW9uKCctTCwgLS1saXZlJywgJ2VuYWJsZSBsaXZlIG1vZGUuIEluIHRoaXMgbW9kZSwgVGVzdENhZmUgd2F0Y2hlcyBmb3IgY2hhbmdlcyB5b3UgbWFrZSBpbiB0aGUgdGVzdCBmaWxlcy4gVGhlc2UgY2hhbmdlcyBpbW1lZGlhdGVseSByZXN0YXJ0IHRoZSB0ZXN0cyBzbyB0aGF0IHlvdSBjYW4gc2VlIHRoZSBlZmZlY3QuJylcbiAgICAgICAgICAgIC5vcHRpb24oJy0tdGVzdC1tZXRhIDxrZXk9dmFsdWVbLGtleTI9dmFsdWUyLC4uLl0+JywgJ3J1biBvbmx5IHRlc3RzIHdpdGggbWF0Y2hpbmcgbWV0YWRhdGEnKVxuICAgICAgICAgICAgLm9wdGlvbignLS1maXh0dXJlLW1ldGEgPGtleT12YWx1ZVssa2V5Mj12YWx1ZTIsLi4uXT4nLCAncnVuIG9ubHkgZml4dHVyZXMgd2l0aCBtYXRjaGluZyBtZXRhZGF0YScpXG4gICAgICAgICAgICAub3B0aW9uKCctLWRlYnVnLW9uLWZhaWwnLCAncGF1c2UgdGhlIHRlc3QgaWYgaXQgZmFpbHMnKVxuICAgICAgICAgICAgLm9wdGlvbignLS1hcHAtaW5pdC1kZWxheSA8bXM+JywgJ3NwZWNpZnkgaG93IG11Y2ggdGltZSBpdCB0YWtlcyBmb3IgdGhlIHRlc3RlZCBhcHAgdG8gaW5pdGlhbGl6ZScpXG4gICAgICAgICAgICAub3B0aW9uKCctLXNlbGVjdG9yLXRpbWVvdXQgPG1zPicsICdzZXQgdGhlIGFtb3VudCBvZiB0aW1lIHdpdGhpbiB3aGljaCBzZWxlY3RvcnMgbWFrZSBhdHRlbXB0cyB0byBvYnRhaW4gYSBub2RlIHRvIGJlIHJldHVybmVkJylcbiAgICAgICAgICAgIC5vcHRpb24oJy0tYXNzZXJ0aW9uLXRpbWVvdXQgPG1zPicsICdzZXQgdGhlIGFtb3VudCBvZiB0aW1lIHdpdGhpbiB3aGljaCBhc3NlcnRpb24gc2hvdWxkIHBhc3MnKVxuICAgICAgICAgICAgLm9wdGlvbignLS1wYWdlLWxvYWQtdGltZW91dCA8bXM+JywgJ3NldCB0aGUgYW1vdW50IG9mIHRpbWUgd2l0aGluIHdoaWNoIFRlc3RDYWZlIHdhaXRzIGZvciB0aGUgYHdpbmRvdy5sb2FkYCBldmVudCB0byBmaXJlIG9uIHBhZ2UgbG9hZCBiZWZvcmUgcHJvY2VlZGluZyB0byB0aGUgbmV4dCB0ZXN0IGFjdGlvbicpXG4gICAgICAgICAgICAub3B0aW9uKCctLXNwZWVkIDxmYWN0b3I+JywgJ3NldCB0aGUgc3BlZWQgb2YgdGVzdCBleGVjdXRpb24gKDAuMDEgLi4uIDEpJylcbiAgICAgICAgICAgIC5vcHRpb24oJy0tcG9ydHMgPHBvcnQxLHBvcnQyPicsICdzcGVjaWZ5IGN1c3RvbSBwb3J0IG51bWJlcnMnKVxuICAgICAgICAgICAgLm9wdGlvbignLS1ob3N0bmFtZSA8bmFtZT4nLCAnc3BlY2lmeSB0aGUgaG9zdG5hbWUnKVxuICAgICAgICAgICAgLm9wdGlvbignLS1wcm94eSA8aG9zdD4nLCAnc3BlY2lmeSB0aGUgaG9zdCBvZiB0aGUgcHJveHkgc2VydmVyJylcbiAgICAgICAgICAgIC5vcHRpb24oJy0tcHJveHktYnlwYXNzIDxydWxlcz4nLCAnc3BlY2lmeSBhIGNvbW1hLXNlcGFyYXRlZCBsaXN0IG9mIHJ1bGVzIHRoYXQgZGVmaW5lIFVSTHMgYWNjZXNzZWQgYnlwYXNzaW5nIHRoZSBwcm94eSBzZXJ2ZXInKVxuICAgICAgICAgICAgLm9wdGlvbignLS1zc2wgPG9wdGlvbnM+JywgJ3NwZWNpZnkgU1NMIG9wdGlvbnMgdG8gcnVuIFRlc3RDYWZlIHByb3h5IHNlcnZlciBvdmVyIHRoZSBIVFRQUyBwcm90b2NvbCcpXG4gICAgICAgICAgICAub3B0aW9uKCctLXZpZGVvIDxwYXRoPicsICcgcmVjb3JkIHZpZGVvcyBvZiB0ZXN0IHJ1bnMnKVxuICAgICAgICAgICAgLm9wdGlvbignLS12aWRlby1vcHRpb25zIDxvcHRpb249dmFsdWVbLC4uLl0+JywgJ3NwZWNpZnkgdmlkZW8gcmVjb3JkaW5nIG9wdGlvbnMnKVxuICAgICAgICAgICAgLm9wdGlvbignLS12aWRlby1lbmNvZGluZy1vcHRpb25zIDxvcHRpb249dmFsdWVbLC4uLl0+JywgJ3NwZWNpZnkgZW5jb2Rpbmcgb3B0aW9ucycpXG4gICAgICAgICAgICAub3B0aW9uKCctLWRpc2FibGUtcGFnZS1yZWxvYWRzJywgJ2Rpc2FibGUgcGFnZSByZWxvYWRzIGJldHdlZW4gdGVzdHMnKVxuICAgICAgICAgICAgLm9wdGlvbignLS1kZXYnLCAnZW5hYmxlcyBtZWNoYW5pc21zIHRvIGxvZyBhbmQgZGlhZ25vc2UgZXJyb3JzJylcbiAgICAgICAgICAgIC5vcHRpb24oJy0tcXItY29kZScsICdvdXRwdXRzIFFSLWNvZGUgdGhhdCByZXBlYXRzIFVSTHMgdXNlZCB0byBjb25uZWN0IHRoZSByZW1vdGUgYnJvd3NlcnMnKVxuICAgICAgICAgICAgLm9wdGlvbignLS1zZiwgLS1zdG9wLW9uLWZpcnN0LWZhaWwnLCAnc3RvcCBhbiBlbnRpcmUgdGVzdCBydW4gaWYgYW55IHRlc3QgZmFpbHMnKVxuXG4gICAgICAgICAgICAvLyBOT1RFOiB0aGVzZSBvcHRpb25zIHdpbGwgYmUgaGFuZGxlZCBieSBjaGFsayBpbnRlcm5hbGx5XG4gICAgICAgICAgICAub3B0aW9uKCctLWNvbG9yJywgJ2ZvcmNlIGNvbG9ycyBpbiBjb21tYW5kIGxpbmUnKVxuICAgICAgICAgICAgLm9wdGlvbignLS1uby1jb2xvcicsICdkaXNhYmxlIGNvbG9ycyBpbiBjb21tYW5kIGxpbmUnKTtcbiAgICB9XG5cbiAgICBfZmlsdGVyQW5kQ291bnRSZW1vdGVzIChicm93c2VyKSB7XG4gICAgICAgIGNvbnN0IHJlbW90ZU1hdGNoID0gYnJvd3Nlci5tYXRjaChSRU1PVEVfQUxJQVNfUkUpO1xuXG4gICAgICAgIGlmIChyZW1vdGVNYXRjaCkge1xuICAgICAgICAgICAgdGhpcy5yZW1vdGVDb3VudCArPSBwYXJzZUludChyZW1vdGVNYXRjaFsxXSwgMTApIHx8IDE7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICBhc3luYyBfcGFyc2VGaWx0ZXJpbmdPcHRpb25zICgpIHtcbiAgICAgICAgaWYgKHRoaXMub3B0cy50ZXN0R3JlcClcbiAgICAgICAgICAgIHRoaXMub3B0cy50ZXN0R3JlcCA9IGdldEdyZXBPcHRpb25zKCctLXRlc3QtZ3JlcCcsIHRoaXMub3B0cy50ZXN0R3JlcCk7XG5cbiAgICAgICAgaWYgKHRoaXMub3B0cy5maXh0dXJlR3JlcClcbiAgICAgICAgICAgIHRoaXMub3B0cy5maXh0dXJlR3JlcCA9IGdldEdyZXBPcHRpb25zKCctLWZpeHR1cmUtZ3JlcCcsIHRoaXMub3B0cy5maXh0dXJlR3JlcCk7XG5cbiAgICAgICAgaWYgKHRoaXMub3B0cy50ZXN0TWV0YSlcbiAgICAgICAgICAgIHRoaXMub3B0cy50ZXN0TWV0YSA9IGF3YWl0IGdldE1ldGFPcHRpb25zKCctLXRlc3QtbWV0YScsIHRoaXMub3B0cy50ZXN0TWV0YSk7XG5cbiAgICAgICAgaWYgKHRoaXMub3B0cy5maXh0dXJlTWV0YSlcbiAgICAgICAgICAgIHRoaXMub3B0cy5maXh0dXJlTWV0YSA9IGF3YWl0IGdldE1ldGFPcHRpb25zKCctLWZpeHR1cmUtbWV0YScsIHRoaXMub3B0cy5maXh0dXJlTWV0YSk7XG5cbiAgICAgICAgdGhpcy5maWx0ZXIgPSBnZXRGaWx0ZXJGbih0aGlzLm9wdHMpO1xuICAgIH1cblxuICAgIF9wYXJzZUFwcEluaXREZWxheSAoKSB7XG4gICAgICAgIGlmICh0aGlzLm9wdHMuYXBwSW5pdERlbGF5KSB7XG4gICAgICAgICAgICBhc3NlcnRUeXBlKGlzLm5vbk5lZ2F0aXZlTnVtYmVyU3RyaW5nLCBudWxsLCAnVGVzdGVkIGFwcCBpbml0aWFsaXphdGlvbiBkZWxheScsIHRoaXMub3B0cy5hcHBJbml0RGVsYXkpO1xuXG4gICAgICAgICAgICB0aGlzLm9wdHMuYXBwSW5pdERlbGF5ID0gcGFyc2VJbnQodGhpcy5vcHRzLmFwcEluaXREZWxheSwgMTApO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgX3BhcnNlU2VsZWN0b3JUaW1lb3V0ICgpIHtcbiAgICAgICAgaWYgKHRoaXMub3B0cy5zZWxlY3RvclRpbWVvdXQpIHtcbiAgICAgICAgICAgIGFzc2VydFR5cGUoaXMubm9uTmVnYXRpdmVOdW1iZXJTdHJpbmcsIG51bGwsICdTZWxlY3RvciB0aW1lb3V0JywgdGhpcy5vcHRzLnNlbGVjdG9yVGltZW91dCk7XG5cbiAgICAgICAgICAgIHRoaXMub3B0cy5zZWxlY3RvclRpbWVvdXQgPSBwYXJzZUludCh0aGlzLm9wdHMuc2VsZWN0b3JUaW1lb3V0LCAxMCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBfcGFyc2VBc3NlcnRpb25UaW1lb3V0ICgpIHtcbiAgICAgICAgaWYgKHRoaXMub3B0cy5hc3NlcnRpb25UaW1lb3V0KSB7XG4gICAgICAgICAgICBhc3NlcnRUeXBlKGlzLm5vbk5lZ2F0aXZlTnVtYmVyU3RyaW5nLCBudWxsLCAnQXNzZXJ0aW9uIHRpbWVvdXQnLCB0aGlzLm9wdHMuYXNzZXJ0aW9uVGltZW91dCk7XG5cbiAgICAgICAgICAgIHRoaXMub3B0cy5hc3NlcnRpb25UaW1lb3V0ID0gcGFyc2VJbnQodGhpcy5vcHRzLmFzc2VydGlvblRpbWVvdXQsIDEwKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIF9wYXJzZVBhZ2VMb2FkVGltZW91dCAoKSB7XG4gICAgICAgIGlmICh0aGlzLm9wdHMucGFnZUxvYWRUaW1lb3V0KSB7XG4gICAgICAgICAgICBhc3NlcnRUeXBlKGlzLm5vbk5lZ2F0aXZlTnVtYmVyU3RyaW5nLCBudWxsLCAnUGFnZSBsb2FkIHRpbWVvdXQnLCB0aGlzLm9wdHMucGFnZUxvYWRUaW1lb3V0KTtcblxuICAgICAgICAgICAgdGhpcy5vcHRzLnBhZ2VMb2FkVGltZW91dCA9IHBhcnNlSW50KHRoaXMub3B0cy5wYWdlTG9hZFRpbWVvdXQsIDEwKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIF9wYXJzZVNwZWVkICgpIHtcbiAgICAgICAgaWYgKHRoaXMub3B0cy5zcGVlZClcbiAgICAgICAgICAgIHRoaXMub3B0cy5zcGVlZCA9IHBhcnNlRmxvYXQodGhpcy5vcHRzLnNwZWVkKTtcbiAgICB9XG5cbiAgICBfcGFyc2VDb25jdXJyZW5jeSAoKSB7XG4gICAgICAgIGlmICh0aGlzLm9wdHMuY29uY3VycmVuY3kpXG4gICAgICAgICAgICB0aGlzLm9wdHMuY29uY3VycmVuY3kgPSBwYXJzZUludCh0aGlzLm9wdHMuY29uY3VycmVuY3ksIDEwKTtcbiAgICB9XG5cbiAgICBfcGFyc2VQb3J0cyAoKSB7XG4gICAgICAgIGlmICh0aGlzLm9wdHMucG9ydHMpIHtcbiAgICAgICAgICAgIHRoaXMub3B0cy5wb3J0cyA9IHRoaXMub3B0cy5wb3J0c1xuICAgICAgICAgICAgICAgIC5zcGxpdCgnLCcpXG4gICAgICAgICAgICAgICAgLm1hcChDTElBcmd1bWVudFBhcnNlci5fcGFyc2VQb3J0TnVtYmVyKTtcblxuICAgICAgICAgICAgaWYgKHRoaXMub3B0cy5wb3J0cy5sZW5ndGggPCAyKVxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBHZW5lcmFsRXJyb3IoUlVOVElNRV9FUlJPUlMucG9ydHNPcHRpb25SZXF1aXJlc1R3b051bWJlcnMpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgX3BhcnNlQnJvd3Nlckxpc3QgKCkge1xuICAgICAgICBjb25zdCBicm93c2Vyc0FyZyA9IHRoaXMucHJvZ3JhbS5hcmdzWzBdIHx8ICcnO1xuXG4gICAgICAgIHRoaXMuYnJvd3NlcnMgPSBzcGxpdFF1b3RlZFRleHQoYnJvd3NlcnNBcmcsICcsJylcbiAgICAgICAgICAgIC5maWx0ZXIoYnJvd3NlciA9PiBicm93c2VyICYmIHRoaXMuX2ZpbHRlckFuZENvdW50UmVtb3Rlcyhicm93c2VyKSk7XG4gICAgfVxuXG4gICAgYXN5bmMgX3BhcnNlU3NsT3B0aW9ucyAoKSB7XG4gICAgICAgIGlmICh0aGlzLm9wdHMuc3NsKVxuICAgICAgICAgICAgdGhpcy5vcHRzLnNzbCA9IGF3YWl0IGdldFNTTE9wdGlvbnModGhpcy5vcHRzLnNzbCk7XG4gICAgfVxuXG4gICAgYXN5bmMgX3BhcnNlUmVwb3J0ZXJzICgpIHtcbiAgICAgICAgY29uc3QgcmVwb3J0ZXJzID0gdGhpcy5vcHRzLnJlcG9ydGVyID8gdGhpcy5vcHRzLnJlcG9ydGVyLnNwbGl0KCcsJykgOiBbXTtcblxuICAgICAgICB0aGlzLm9wdHMucmVwb3J0ZXIgPSByZXBvcnRlcnMubWFwKHJlcG9ydGVyID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHNlcGFyYXRvckluZGV4ID0gcmVwb3J0ZXIuaW5kZXhPZignOicpO1xuXG4gICAgICAgICAgICBpZiAoc2VwYXJhdG9ySW5kZXggPCAwKVxuICAgICAgICAgICAgICAgIHJldHVybiB7IG5hbWU6IHJlcG9ydGVyIH07XG5cbiAgICAgICAgICAgIGNvbnN0IG5hbWUgICA9IHJlcG9ydGVyLnN1YnN0cmluZygwLCBzZXBhcmF0b3JJbmRleCk7XG4gICAgICAgICAgICBjb25zdCBvdXRwdXQgPSByZXBvcnRlci5zdWJzdHJpbmcoc2VwYXJhdG9ySW5kZXggKyAxKTtcblxuICAgICAgICAgICAgcmV0dXJuIHsgbmFtZSwgb3V0cHV0IH07XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIF9wYXJzZUZpbGVMaXN0ICgpIHtcbiAgICAgICAgdGhpcy5zcmMgPSB0aGlzLnByb2dyYW0uYXJncy5zbGljZSgxKTtcbiAgICB9XG5cbiAgICBhc3luYyBfcGFyc2VWaWRlb09wdGlvbnMgKCkge1xuICAgICAgICBpZiAodGhpcy5vcHRzLnZpZGVvT3B0aW9ucylcbiAgICAgICAgICAgIHRoaXMub3B0cy52aWRlb09wdGlvbnMgPSBhd2FpdCBnZXRWaWRlb09wdGlvbnModGhpcy5vcHRzLnZpZGVvT3B0aW9ucyk7XG5cbiAgICAgICAgaWYgKHRoaXMub3B0cy52aWRlb0VuY29kaW5nT3B0aW9ucylcbiAgICAgICAgICAgIHRoaXMub3B0cy52aWRlb0VuY29kaW5nT3B0aW9ucyA9IGF3YWl0IGdldFZpZGVvT3B0aW9ucyh0aGlzLm9wdHMudmlkZW9FbmNvZGluZ09wdGlvbnMpO1xuICAgIH1cblxuICAgIF9nZXRQcm92aWRlck5hbWUgKCkge1xuICAgICAgICB0aGlzLm9wdHMucHJvdmlkZXJOYW1lID0gdGhpcy5vcHRzLmxpc3RCcm93c2VycyA9PT0gdHJ1ZSA/IHZvaWQgMCA6IHRoaXMub3B0cy5saXN0QnJvd3NlcnM7XG4gICAgfVxuXG4gICAgYXN5bmMgcGFyc2UgKGFyZ3YpIHtcbiAgICAgICAgdGhpcy5wcm9ncmFtLnBhcnNlKGFyZ3YpO1xuXG4gICAgICAgIHRoaXMuYXJncyA9IHRoaXMucHJvZ3JhbS5hcmdzO1xuXG4gICAgICAgIHRoaXMub3B0cyA9IHRoaXMucHJvZ3JhbS5vcHRzKCk7XG5cbiAgICAgICAgLy8gTk9URTogdGhlICctbGlzdC1icm93c2Vycycgb3B0aW9uIG9ubHkgbGlzdHMgYnJvd3NlcnMgYW5kIGltbWVkaWF0ZWx5IGV4aXRzIHRoZSBhcHAuXG4gICAgICAgIC8vIFRoZXJlZm9yZSwgd2UgZG9uJ3QgbmVlZCB0byBwcm9jZXNzIG90aGVyIGFyZ3VtZW50cy5cbiAgICAgICAgaWYgKHRoaXMub3B0cy5saXN0QnJvd3NlcnMpIHtcbiAgICAgICAgICAgIHRoaXMuX2dldFByb3ZpZGVyTmFtZSgpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5fcGFyc2VTZWxlY3RvclRpbWVvdXQoKTtcbiAgICAgICAgdGhpcy5fcGFyc2VBc3NlcnRpb25UaW1lb3V0KCk7XG4gICAgICAgIHRoaXMuX3BhcnNlUGFnZUxvYWRUaW1lb3V0KCk7XG4gICAgICAgIHRoaXMuX3BhcnNlQXBwSW5pdERlbGF5KCk7XG4gICAgICAgIHRoaXMuX3BhcnNlU3BlZWQoKTtcbiAgICAgICAgdGhpcy5fcGFyc2VQb3J0cygpO1xuICAgICAgICB0aGlzLl9wYXJzZUJyb3dzZXJMaXN0KCk7XG4gICAgICAgIHRoaXMuX3BhcnNlQ29uY3VycmVuY3koKTtcbiAgICAgICAgdGhpcy5fcGFyc2VGaWxlTGlzdCgpO1xuXG4gICAgICAgIGF3YWl0IHRoaXMuX3BhcnNlRmlsdGVyaW5nT3B0aW9ucygpO1xuICAgICAgICBhd2FpdCB0aGlzLl9wYXJzZVZpZGVvT3B0aW9ucygpO1xuICAgICAgICBhd2FpdCB0aGlzLl9wYXJzZVNzbE9wdGlvbnMoKTtcbiAgICAgICAgYXdhaXQgdGhpcy5fcGFyc2VSZXBvcnRlcnMoKTtcbiAgICB9XG59XG4iXX0=