@browserstack/testcafe
Version:
Automated browser testing for the modern web development stack.
333 lines • 50.7 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 events_1 = require("events");
const mustache_1 = __importDefault(require("mustache"));
const lodash_1 = require("lodash");
const parse_user_agent_1 = __importDefault(require("../../utils/parse-user-agent"));
const read_file_relative_1 = require("read-file-relative");
const promisify_event_1 = __importDefault(require("promisify-event"));
const nanoid_1 = __importDefault(require("nanoid"));
const command_1 = __importDefault(require("./command"));
const status_1 = __importDefault(require("./status"));
const heartbeat_status_1 = __importDefault(require("./heartbeat-status"));
const runtime_1 = require("../../errors/runtime");
const types_1 = require("../../errors/types");
const browser_connection_timeouts_1 = require("../../utils/browser-connection-timeouts");
const util_1 = require("util");
const IDLE_PAGE_TEMPLATE = read_file_relative_1.readSync('../../client/browser/idle-page/index.html.mustache');
const connections = {};
class BrowserConnection extends events_1.EventEmitter {
constructor(gateway, browserInfo, permanent, allowMultipleWindows = false, testScheduling = false) {
super();
this.HEARTBEAT_TIMEOUT = browser_connection_timeouts_1.HEARTBEAT_TIMEOUT;
this.BROWSER_RESTART_TIMEOUT = browser_connection_timeouts_1.BROWSER_RESTART_TIMEOUT;
this.id = BrowserConnection._generateId();
this.jobQueue = [];
this.initScriptsQueue = [];
this.browserConnectionGateway = gateway;
this.disconnectionPromise = null;
this.testRunAborted = false;
this.isFirst = true;
this.browserInfo = browserInfo;
this.browserInfo.userAgentProviderMetaInfo = '';
this.provider = browserInfo.provider;
this.permanent = permanent;
this.status = status_1.default.uninitialized;
this.idle = true;
this.heartbeatTimeout = null;
this.pendingTestRunUrl = null;
this.allowMultipleWindows = allowMultipleWindows;
this.testScheduling = testScheduling;
this.url = `${gateway.domain}/browser/connect/${this.id}`;
this.idleUrl = `${gateway.domain}/browser/idle/${this.id}`;
this.forcedIdleUrl = `${gateway.domain}/browser/idle-forced/${this.id}`;
this.initScriptUrl = `${gateway.domain}/browser/init-script/${this.id}`;
this.heartbeatRelativeUrl = `/browser/heartbeat/${this.id}`;
this.statusRelativeUrl = `/browser/status/${this.id}`;
this.statusDoneRelativeUrl = `/browser/status-done/${this.id}`;
this.activeWindowIdUrl = `/browser/active-window-id/${this.id}`;
this.heartbeatUrl = `${gateway.domain}${this.heartbeatRelativeUrl}`;
this.statusUrl = `${gateway.domain}${this.statusRelativeUrl}`;
this.statusDoneUrl = `${gateway.domain}${this.statusDoneRelativeUrl}`;
this.on('error', () => {
this._forceIdle();
this.close();
});
connections[this.id] = this;
this.browserConnectionGateway.startServingConnection(this);
process.nextTick(() => this._runBrowser());
}
static _generateId() {
return nanoid_1.default(7);
}
async _runBrowser() {
try {
await this.provider.openBrowser(this.id, this.url, this.browserInfo.browserName, this.allowMultipleWindows);
if (this.status !== status_1.default.ready)
await promisify_event_1.default(this, 'ready');
this.status = status_1.default.opened;
this.emit('opened');
}
catch (err) {
this.emit('error', new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.unableToOpenBrowser, this.browserInfo.providerName + ':' + this.browserInfo.browserName, err.stack));
}
}
async _closeBrowser() {
if (!this.idle)
await promisify_event_1.default(this, 'idle');
try {
await this.provider.closeBrowser(this.id);
}
catch (err) {
// NOTE: A warning would be really nice here, but it can't be done while log is stored in a task.
// eslint-disable-next-line no-console
console.log(`Error captured while closing the browser: ${util_1.inspect(err, { depth: 0 })}`);
}
}
_forceIdle() {
if (!this.idle) {
this.idle = true;
this.emit('idle');
}
}
_createBrowserDisconnectedError() {
return new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.browserDisconnected, this.userAgent);
}
_waitForHeartbeat() {
this.heartbeatTimeout = setTimeout(() => {
// eslint-disable-next-line no-console
console.log(`Heart beat lapsed trying to disconnect`);
const err = this._createBrowserDisconnectedError();
this.status = status_1.default.disconnected;
this.testRunAborted = true;
this.emit('disconnected', err);
this._restartBrowserOnDisconnect(err);
}, this.HEARTBEAT_TIMEOUT);
}
async _getTestRunUrl(needPopNext) {
if (needPopNext || !this.pendingTestRunUrl)
this.pendingTestRunUrl = await this._popNextTestRunUrl();
return this.pendingTestRunUrl;
}
async _popNextTestRunUrl() {
const isZero = this.currentJob
? this.currentJob.queuedTestRuns === 0
: false;
if (this.testScheduling && isZero) {
const cJob = this.currentJob;
let isDone = false;
setInterval(() => {
if (!isDone && cJob.total === cJob.totalGiven) {
isDone = true;
this.close();
cJob.emit('done');
}
}, 1000);
return null;
}
while (this.hasQueuedJobs && !this.currentJob.hasQueuedTestRuns)
this.jobQueue.shift();
let isRestartHappened = false;
if (this.testScheduling && this.currentJob) {
const queueLength = this.currentJob.queuedTestRuns;
// console.log(`Current jobController length: ${queueLength}`);
// Spawn up a new browser on every new polling.
if (!this.isFirst && this.hasQueuedJobs && queueLength > 0) {
const testRunController = await this.currentJob.popTest;
if (testRunController !== null) {
this.status = status_1.default.disconnected;
clearTimeout(this.heartbeatTimeout);
await this._restartBrowser();
isRestartHappened = true;
return await this.currentJob.setTestURL(testRunController, this);
}
}
this.isFirst = false;
}
// Condition for checking non-null urls
const url = this.hasQueuedJobs
? await this.currentJob.popNextTestRunUrl(this)
: null;
// console.log(`Is restarted: ${isRestartHappened} ${url}`);
if (this.testScheduling && url === null && isRestartHappened) {
this.status = status_1.default.disconnected;
this._closeBrowser();
}
return url;
}
static getById(id) {
return connections[id] || null;
}
async _restartBrowser() {
this.status = status_1.default.uninitialized;
this._forceIdle();
let resolveTimeout = null;
let isTimeoutExpired = false;
let timeout = null;
const restartPromise = this._closeBrowser().then(() => this._runBrowser());
const timeoutPromise = new Promise(resolve => {
resolveTimeout = resolve;
timeout = setTimeout(() => {
isTimeoutExpired = true;
resolve();
}, this.BROWSER_RESTART_TIMEOUT);
});
return Promise.race([restartPromise, timeoutPromise]).then(() => {
clearTimeout(timeout);
if (isTimeoutExpired)
this.emit('error', this._createBrowserDisconnectedError());
else
resolveTimeout();
});
}
_restartBrowserOnDisconnect(err) {
let resolveFn = null;
let rejectFn = null;
this.disconnectionPromise = new Promise((resolve, reject) => {
resolveFn = resolve;
rejectFn = () => {
reject(err);
};
setTimeout(() => {
rejectFn();
});
})
.then(() => {
return this._restartBrowser();
})
.catch(e => {
this.emit('error', e);
});
this.disconnectionPromise.resolve = resolveFn;
this.disconnectionPromise.reject = rejectFn;
}
async processDisconnection(disconnectionThresholdExceedeed) {
const { resolve, reject } = this
.disconnectionPromise;
if (disconnectionThresholdExceedeed)
reject();
else
resolve();
}
addWarning(...args) {
if (this.currentJob)
this.currentJob.warningLog.addWarning(...args);
}
setProviderMetaInfo(str) {
this.browserInfo.userAgentProviderMetaInfo = str;
}
get userAgent() {
let userAgent = this.browserInfo.parsedUserAgent.prettyUserAgent;
if (this.browserInfo.userAgentProviderMetaInfo)
userAgent += ` (${this.browserInfo.userAgentProviderMetaInfo})`;
return userAgent;
}
get hasQueuedJobs() {
return !!this.jobQueue.length;
}
get currentJob() {
return this.jobQueue[0];
}
// API
runInitScript(code) {
return new Promise(resolve => this.initScriptsQueue.push({ code, resolve }));
}
/**
* addJob is appending job to the jobQueue and each
* job has multiple tests functions in it for execution.
*
* @returns {undefined}
*/
addJob(job) {
this.jobQueue.push(job);
}
removeJob(job) {
lodash_1.pull(this.jobQueue, job);
}
close() {
if (this.status === status_1.default.closing || this.status === status_1.default.closed)
return;
this.status = status_1.default.closing;
this._closeBrowser().then(() => {
this.browserConnectionGateway.stopServingConnection(this);
clearTimeout(this.heartbeatTimeout);
delete connections[this.id];
this.status = status_1.default.closed;
this.emit('closed');
});
}
establish(userAgent) {
this.status = status_1.default.ready;
this.browserInfo.parsedUserAgent = parse_user_agent_1.default(userAgent);
this._waitForHeartbeat();
this.emit('ready');
}
heartbeat() {
clearTimeout(this.heartbeatTimeout);
this._waitForHeartbeat();
return {
code: this.status === status_1.default.closing ? heartbeat_status_1.default.closing : heartbeat_status_1.default.ok,
url: this.status === status_1.default.closing ? this.idleUrl : ''
};
}
renderIdlePage() {
return mustache_1.default.render(IDLE_PAGE_TEMPLATE, {
userAgent: this.userAgent,
statusUrl: this.statusUrl,
heartbeatUrl: this.heartbeatUrl,
initScriptUrl: this.initScriptUrl,
retryTestPages: !!this.browserConnectionGateway.retryTestPages
});
}
getInitScript() {
const initScriptPromise = this.initScriptsQueue[0];
return { code: initScriptPromise ? initScriptPromise.code : null };
}
handleInitScriptResult(data) {
const initScriptPromise = this.initScriptsQueue.shift();
if (initScriptPromise)
initScriptPromise.resolve(JSON.parse(data));
}
isHeadlessBrowser() {
return this.provider.isHeadlessBrowser(this.id);
}
async reportJobResult(status, data) {
await this.provider.reportJobResult(this.id, status, data);
}
async getStatus(isTestDone) {
if (!this.idle && !isTestDone) {
// console.log(`Status idle is set for the test run`);
this.idle = true;
this.emit('idle');
}
if (this.status === status_1.default.opened) {
const testRunUrl = await this._getTestRunUrl(isTestDone || this.testRunAborted);
this.testRunAborted = false;
if (testRunUrl) {
this.idle = false;
return { cmd: command_1.default.run, url: testRunUrl };
}
}
return { cmd: command_1.default.idle, url: this.idleUrl };
}
get activeWindowId() {
return this.provider.getActiveWindowId(this.id);
}
set activeWindowId(val) {
this.provider.setActiveWindowId(this.id, val);
}
async canUseDefaultWindowActions() {
return this.provider.canUseDefaultWindowActions(this.id);
}
isReady() {
return this.status === status_1.default.ready ||
this.status === status_1.default.opened ||
this.status === status_1.default.closing;
}
}
exports.default = BrowserConnection;
module.exports = exports.default;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYnJvd3Nlci9jb25uZWN0aW9uL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsbUNBQXNDO0FBQ3RDLHdEQUFnQztBQUNoQyxtQ0FBd0M7QUFDeEMsb0ZBQTBEO0FBQzFELDJEQUFzRDtBQUN0RCxzRUFBNkM7QUFDN0Msb0RBQTRCO0FBQzVCLHdEQUFnQztBQUNoQyxzREFBK0M7QUFDL0MsMEVBQWlEO0FBQ2pELGtEQUFvRDtBQUNwRCw4Q0FBb0Q7QUFDcEQseUZBQXFHO0FBSXJHLCtCQUErQjtBQUUvQixNQUFNLGtCQUFrQixHQUEyQiw2QkFBSSxDQUFDLG9EQUFvRCxDQUFDLENBQUM7QUFDOUcsTUFBTSxXQUFXLEdBQWtDLEVBQUUsQ0FBQztBQXlCdEQsTUFBcUIsaUJBQWtCLFNBQVEscUJBQVk7SUFpQ3ZELFlBQ0ksT0FBaUMsRUFDakMsV0FBZ0IsRUFDaEIsU0FBa0IsRUFDbEIsb0JBQW9CLEdBQUcsS0FBSyxFQUM1QixjQUFjLEdBQUcsS0FBSztRQUV0QixLQUFLLEVBQUUsQ0FBQztRQUVSLElBQUksQ0FBQyxpQkFBaUIsR0FBRywrQ0FBaUIsQ0FBQztRQUMzQyxJQUFJLENBQUMsdUJBQXVCLEdBQUcscURBQXVCLENBQUM7UUFFdkQsSUFBSSxDQUFDLEVBQUUsR0FBRyxpQkFBaUIsQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUMxQyxJQUFJLENBQUMsUUFBUSxHQUFHLEVBQUUsQ0FBQztRQUNuQixJQUFJLENBQUMsZ0JBQWdCLEdBQUcsRUFBRSxDQUFDO1FBQzNCLElBQUksQ0FBQyx3QkFBd0IsR0FBRyxPQUFPLENBQUM7UUFDeEMsSUFBSSxDQUFDLG9CQUFvQixHQUFHLElBQUksQ0FBQztRQUNqQyxJQUFJLENBQUMsY0FBYyxHQUFHLEtBQUssQ0FBQztRQUM1QixJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQztRQUVwQixJQUFJLENB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QUksQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUNwRCxDQUFDO0lBRUQsSUFBVyxjQUFjLENBQUUsR0FBRztRQUMxQixJQUFJLENBQUMsUUFBUSxDQUFDLGlCQUFpQixDQUFDLElBQUksQ0FBQyxFQUFFLEVBQUUsR0FBRyxDQUFDLENBQUM7SUFDbEQsQ0FBQztJQUVNLEtBQUssQ0FBQywwQkFBMEI7UUFDbkMsT0FBTyxJQUFJLENBQUMsUUFBUSxDQUFDLDBCQUEwQixDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUM3RCxDQUFDO0lBRU0sT0FBTztRQUNWLE9BQU8sSUFBSSxDQUFDLE1BQU0sS0FBSyxnQkFBdUIsQ0FBQyxLQUFLO1lBQ2hELElBQUksQ0FBQyxNQUFNLEtBQUssZ0JBQXVCLENBQUMsTUFBTTtZQUM5QyxJQUFJLENBQUMsTUFBTSxLQUFLLGdCQUF1QixDQUFDLE9BQU8sQ0FBQztJQUN4RCxDQUFDO0NBQ0o7QUF0Y0Qsb0NBc2NDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgRXZlbnRFbWl0dGVyIH0gZnJvbSAnZXZlbnRzJztcbmltcG9ydCBNdXN0YWNoZSBmcm9tICdtdXN0YWNoZSc7XG5pbXBvcnQgeyBwdWxsIGFzIHJlbW92ZSB9IGZyb20gJ2xvZGFzaCc7XG5pbXBvcnQgcGFyc2VVc2VyQWdlbnQgZnJvbSAnLi4vLi4vdXRpbHMvcGFyc2UtdXNlci1hZ2VudCc7XG5pbXBvcnQgeyByZWFkU3luYyBhcyByZWFkIH0gZnJvbSAncmVhZC1maWxlLXJlbGF0aXZlJztcbmltcG9ydCBwcm9taXNpZnlFdmVudCBmcm9tICdwcm9taXNpZnktZXZlbnQnO1xuaW1wb3J0IG5hbm9pZCBmcm9tICduYW5vaWQnO1xuaW1wb3J0IENPTU1BTkQgZnJvbSAnLi9jb21tYW5kJztcbmltcG9ydCBCcm93c2VyQ29ubmVjdGlvblN0YXR1cyBmcm9tICcuL3N0YXR1cyc7XG5pbXBvcnQgSGVhcnRiZWF0U3RhdHVzIGZyb20gJy4vaGVhcnRiZWF0LXN0YXR1cyc7XG5pbXBvcnQgeyBHZW5lcmFsRXJyb3IgfSBmcm9tICcuLi8uLi9lcnJvcnMvcnVudGltZSc7XG5pbXBvcnQgeyBSVU5USU1FX0VSUk9SUyB9IGZyb20gJy4uLy4uL2Vycm9ycy90eXBlcyc7XG5pbXBvcnQgeyBCUk9XU0VSX1JFU1RBUlRfVElNRU9VVCwgSEVBUlRCRUFUX1RJTUVPVVQgfSBmcm9tICcuLi8uLi91dGlscy9icm93c2VyLWNvbm5lY3Rpb24tdGltZW91dHMnO1xuaW1wb3J0IHsgRGljdGlvbmFyeSB9IGZyb20gJy4uLy4uL2NvbmZpZ3VyYXRpb24vaW50ZXJmYWNlcyc7XG5pbXBvcnQgQnJvd3NlckNvbm5lY3Rpb25HYXRld2F5IGZyb20gJy4vZ2F0ZXdheSc7XG5cbmltcG9ydCB7IGluc3BlY3QgfSBmcm9tICd1dGlsJztcblxuY29uc3QgSURMRV9QQUdFX1RFTVBMQVRFICAgICAgICAgICAgICAgICAgICAgICAgID0gcmVhZCgnLi4vLi4vY2xpZW50L2Jyb3dzZXIvaWRsZS1wYWdlL2luZGV4Lmh0bWwubXVzdGFjaGUnKTtcbmNvbnN0IGNvbm5lY3Rpb25zOiBEaWN0aW9uYXJ5PEJyb3dzZXJDb25uZWN0aW9uPiA9IHt9O1xuXG5pbnRlcmZhY2UgRGlzY29ubmVjdGlvblByb21pc2U8VD4gZXh0ZW5kcyBQcm9taXNlPFQ+IHtcbiAgICByZXNvbHZlOiBGdW5jdGlvbjtcbiAgICByZWplY3Q6IEZ1bmN0aW9uO1xufVxuXG5pbnRlcmZhY2UgQnJvd3NlckNvbm5lY3Rpb25TdGF0dXNSZXN1bHQge1xuICAgIGNtZDogc3RyaW5nO1xuICAgIHVybDogc3RyaW5nO1xufVxuXG5pbnRlcmZhY2UgSGVhcnRiZWF0U3RhdHVzUmVzdWx0IHtcbiAgICBjb2RlOiBIZWFydGJlYXRTdGF0dXM7XG4gICAgdXJsOiBzdHJpbmc7XG59XG5cbmludGVyZmFjZSBJbml0U2NyaXB0IHtcbiAgICBjb2RlOiBzdHJpbmcgfCBudWxsO1xufVxuXG5pbnRlcmZhY2UgSW5pdFNjcmlwdFRhc2sgZXh0ZW5kcyBJbml0U2NyaXB0IHtcbiAgICByZXNvbHZlOiBGdW5jdGlvbjtcbn1cblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgQnJvd3NlckNvbm5lY3Rpb24gZXh0ZW5kcyBFdmVudEVtaXR0ZXIge1xuICAgIHB1YmxpYyBwZXJtYW5lbnQ6IGJvb2xlYW47XG4gICAgcHJpdmF0ZSByZWFkb25seSBhbGxvd011bHRpcGxlV2luZG93czogYm9vbGVhbjtcbiAgICBwcml2YXRlIHJlYWRvbmx5IEhFQVJUQkVBVF9USU1FT1VUOiBudW1iZXI7XG4gICAgcHJpdmF0ZSByZWFkb25seSBCUk9XU0VSX1JFU1RBUlRfVElNRU9VVDogbnVtYmVyO1xuICAgIHB1YmxpYyByZWFkb25seSBpZDogc3RyaW5nO1xuICAgIHByaXZhdGUgcmVhZG9ubHkgam9iUXVldWU6IGFueVtdO1xuICAgIHByaXZhdGUgcmVhZG9ubHkgaW5pdFNjcmlwdHNRdWV1ZTogSW5pdFNjcmlwdFRhc2tbXTtcbiAgICBwcml2YXRlIGJyb3dzZXJDb25uZWN0aW9uR2F0ZXdheTogQnJvd3NlckNvbm5lY3Rpb25HYXRld2F5O1xuICAgIHByaXZhdGUgZGlzY29ubmVjdGlvblByb21pc2U6IERpc2Nvbm5lY3Rpb25Qcm9taXNlPHZvaWQ+IHwgbnVsbDtcbiAgICBwcml2YXRlIHRlc3RSdW5BYm9ydGVkOiBib29sZWFuO1xuICAgIHB1YmxpYyBzdGF0dXM6IEJyb3dzZXJDb25uZWN0aW9uU3RhdHVzO1xuICAgIHByaXZhdGUgaGVhcnRiZWF0VGltZW91dDogTm9kZUpTLlRpbWVvdXQgfCBudWxsO1xuICAgIHByaXZhdGUgcGVuZGluZ1Rlc3RSdW5Vcmw6IHN0cmluZyB8IG51bGw7XG4gICAgcHVibGljIHJlYWRvbmx5IHVybDogc3RyaW5nO1xuICAgIHB1YmxpYyByZWFkb25seSBpZGxlVXJsOiBzdHJpbmc7XG4gICAgcHJpdmF0ZSBmb3JjZWRJZGxlVXJsOiBzdHJpbmc7XG4gICAgcHJpdmF0ZSByZWFkb25seSBpbml0U2NyaXB0VXJsOiBzdHJpbmc7XG4gICAgcHJpdmF0ZSByZWFkb25seSBoZWFydGJlYXRSZWxhdGl2ZVVybDogc3RyaW5nO1xuICAgIHByaXZhdGUgcmVhZG9ubHkgc3RhdHVzUmVsYXRpdmVVcmw6IHN0cmluZztcbiAgICBwcml2YXRlIHJlYWRvbmx5IHN0YXR1c0RvbmVSZWxhdGl2ZVVybDogc3RyaW5nO1xuICAgIHByaXZhdGUgcmVhZG9ubHkgaGVhcnRiZWF0VXJsOiBzdHJpbmc7XG4gICAgcHJpdmF0ZSByZWFkb25seSBzdGF0dXNVcmw6IHN0cmluZztcbiAgICBwcml2YXRlIHJlYWRvbmx5IGFjdGl2ZVdpbmRvd0lkVXJsOiBzdHJpbmc7XG4gICAgcHJpdmF0ZSBzdGF0dXNEb25lVXJsOiBzdHJpbmc7XG4gICAgcHJpdmF0ZSBpc0ZpcnN0OiBib29sZWFuO1xuICAgIHByaXZhdGUgdGVzdFNjaGVkdWxpbmc6IGJvb2xlYW47XG5cbiAgICBwdWJsaWMgaWRsZTogYm9vbGVhbjtcblxuICAgIHB1YmxpYyBicm93c2VySW5mbzogYW55O1xuICAgIHB1YmxpYyBwcm92aWRlcjogYW55O1xuXG4gICAgcHVibGljIGNvbnN0cnVjdG9yIChcbiAgICAgICAgZ2F0ZXdheTogQnJvd3NlckNvbm5lY3Rpb25HYXRld2F5LFxuICAgICAgICBicm93c2VySW5mbzogYW55LFxuICAgICAgICBwZXJtYW5lbnQ6IGJvb2xlYW4sXG4gICAgICAgIGFsbG93TXVsdGlwbGVXaW5kb3dzID0gZmFsc2UsXG4gICAgICAgIHRlc3RTY2hlZHVsaW5nID0gZmFsc2VcbiAgICApIHtcbiAgICAgICAgc3VwZXIoKTtcblxuICAgICAgICB0aGlzLkhFQVJUQkVBVF9USU1FT1VUID0gSEVBUlRCRUFUX1RJTUVPVVQ7XG4gICAgICAgIHRoaXMuQlJPV1NFUl9SRVNUQVJUX1RJTUVPVVQgPSBCUk9XU0VSX1JFU1RBUlRfVElNRU9VVDtcblxuICAgICAgICB0aGlzLmlkID0gQnJvd3NlckNvbm5lY3Rpb24uX2dlbmVyYXRlSWQoKTtcbiAgICAgICAgdGhpcy5qb2JRdWV1ZSA9IFtdO1xuICAgICAgICB0aGlzLmluaXRTY3JpcHRzUXVldWUgPSBbXTtcbiAgICAgICAgdGhpcy5icm93c2VyQ29ubmVjdGlvbkdhdGV3YXkgPSBnYXRld2F5O1xuICAgICAgICB0aGlzLmRpc2Nvbm5lY3Rpb25Qcm9taXNlID0gbnVsbDtcbiAgICAgICAgdGhpcy50ZXN0UnVuQWJvcnRlZCA9IGZhbHNlO1xuICAgICAgICB0aGlzLmlzRmlyc3QgPSB0cnVlO1xuXG4gICAgICAgIHRoaXMuYnJvd3NlckluZm8gPSBicm93c2VySW5mbztcbiAgICAgICAgdGhpcy5icm93c2VySW5mby51c2VyQWdlbnRQcm92aWRlck1ldGFJbmZvID0gJyc7XG5cbiAgICAgICAgdGhpcy5wcm92aWRlciA9IGJyb3dzZXJJbmZvLnByb3ZpZGVyO1xuXG4gICAgICAgIHRoaXMucGVybWFuZW50ICAgICAgICAgICAgPSBwZXJtYW5lbnQ7XG4gICAgICAgIHRoaXMuc3RhdHVzICAgICAgICAgICAgICAgPSBCcm93c2VyQ29ubmVjdGlvblN0YXR1cy51bmluaXRpYWxpemVkO1xuICAgICAgICB0aGlzLmlkbGUgICAgICAgICAgICAgICAgID0gdHJ1ZTtcbiAgICAgICAgdGhpcy5oZWFydGJlYXRUaW1lb3V0ICAgICA9IG51bGw7XG4gICAgICAgIHRoaXMucGVuZGluZ1Rlc3RSdW5VcmwgICAgPSBudWxsO1xuICAgICAgICB0aGlzLmFsbG93TXVsdGlwbGVXaW5kb3dzID0gYWxsb3dNdWx0aXBsZVdpbmRvd3M7XG4gICAgICAgIHRoaXMudGVzdFNjaGVkdWxpbmcgPSB0ZXN0U2NoZWR1bGluZztcblxuICAgICAgICB0aGlzLnVybCA9IGAke2dhdGV3YXkuZG9tYWlufS9icm93c2VyL2Nvbm5lY3QvJHt0aGlzLmlkfWA7XG4gICAgICAgIHRoaXMuaWRsZVVybCA9IGAke2dhdGV3YXkuZG9tYWlufS9icm93c2VyL2lkbGUvJHt0aGlzLmlkfWA7XG4gICAgICAgIHRoaXMuZm9yY2VkSWRsZVVybCA9IGAke2dhdGV3YXkuZG9tYWlufS9icm93c2VyL2lkbGUtZm9yY2VkLyR7dGhpcy5pZH1gO1xuICAgICAgICB0aGlzLmluaXRTY3JpcHRVcmwgPSBgJHtnYXRld2F5LmRvbWFpbn0vYnJvd3Nlci9pbml0LXNjcmlwdC8ke3RoaXMuaWR9YDtcblxuICAgICAgICB0aGlzLmhlYXJ0YmVhdFJlbGF0aXZlVXJsID0gYC9icm93c2VyL2hlYXJ0YmVhdC8ke3RoaXMuaWR9YDtcbiAgICAgICAgdGhpcy5zdGF0dXNSZWxhdGl2ZVVybCA9IGAvYnJvd3Nlci9zdGF0dXMvJHt0aGlzLmlkfWA7XG4gICAgICAgIHRoaXMuc3RhdHVzRG9uZVJlbGF0aXZlVXJsID0gYC9icm93c2VyL3N0YXR1cy1kb25lLyR7dGhpcy5pZH1gO1xuICAgICAgICB0aGlzLmFjdGl2ZVdpbmRvd0lkVXJsID0gYC9icm93c2VyL2FjdGl2ZS13aW5kb3ctaWQvJHt0aGlzLmlkfWA7XG5cbiAgICAgICAgdGhpcy5oZWFydGJlYXRVcmwgPSBgJHtnYXRld2F5LmRvbWFpbn0ke3RoaXMuaGVhcnRiZWF0UmVsYXRpdmVVcmx9YDtcbiAgICAgICAgdGhpcy5zdGF0dXNVcmwgPSBgJHtnYXRld2F5LmRvbWFpbn0ke3RoaXMuc3RhdHVzUmVsYXRpdmVVcmx9YDtcbiAgICAgICAgdGhpcy5zdGF0dXNEb25lVXJsID0gYCR7Z2F0ZXdheS5kb21haW59JHt0aGlzLnN0YXR1c0RvbmVSZWxhdGl2ZVVybH1gO1xuXG4gICAgICAgIHRoaXMub24oJ2Vycm9yJywgKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5fZm9yY2VJZGxlKCk7XG4gICAgICAgICAgICB0aGlzLmNsb3NlKCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGNvbm5lY3Rpb25zW3RoaXMuaWRdID0gdGhpcztcblxuICAgICAgICB0aGlzLmJyb3dzZXJDb25uZWN0aW9uR2F0ZXdheS5zdGFydFNlcnZpbmdDb25uZWN0aW9uKHRoaXMpO1xuXG4gICAgICAgIHByb2Nlc3MubmV4dFRpY2soKCkgPT4gdGhpcy5fcnVuQnJvd3NlcigpKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHN0YXRpYyBfZ2VuZXJhdGVJZCAoKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIG5hbm9pZCg3KTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF9ydW5Ccm93c2VyICgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMucHJvdmlkZXIub3BlbkJyb3dzZXIoXG4gICAgICAgICAgICAgICAgdGhpcy5pZCxcbiAgICAgICAgICAgICAgICB0aGlzLnVybCxcbiAgICAgICAgICAgICAgICB0aGlzLmJyb3dzZXJJbmZvLmJyb3dzZXJOYW1lLFxuICAgICAgICAgICAgICAgIHRoaXMuYWxsb3dNdWx0aXBsZVdpbmRvd3NcbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIGlmICh0aGlzLnN0YXR1cyAhPT0gQnJvd3NlckNvbm5lY3Rpb25TdGF0dXMucmVhZHkpXG4gICAgICAgICAgICAgICAgYXdhaXQgcHJvbWlzaWZ5RXZlbnQodGhpcywgJ3JlYWR5Jyk7XG5cbiAgICAgICAgICAgIHRoaXMuc3RhdHVzID0gQnJvd3NlckNvbm5lY3Rpb25TdGF0dXMub3BlbmVkO1xuICAgICAgICAgICAgdGhpcy5lbWl0KCdvcGVuZWQnKTtcbiAgICAgICAgfVxuICAgICAgICBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICB0aGlzLmVtaXQoJ2Vycm9yJywgbmV3IEdlbmVyYWxFcnJvcihcbiAgICAgICAgICAgICAgICBSVU5USU1FX0VSUk9SUy51bmFibGVUb09wZW5Ccm93c2VyLFxuICAgICAgICAgICAgICAgIHRoaXMuYnJvd3NlckluZm8ucHJvdmlkZXJOYW1lICsgJzonICsgdGhpcy5icm93c2VySW5mby5icm93c2VyTmFtZSxcbiAgICAgICAgICAgICAgICBlcnIuc3RhY2tcbiAgICAgICAgICAgICkpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBfY2xvc2VCcm93c2VyICgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgaWYgKCF0aGlzLmlkbGUpIGF3YWl0IHByb21pc2lmeUV2ZW50KHRoaXMsICdpZGxlJyk7XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMucHJvdmlkZXIuY2xvc2VCcm93c2VyKHRoaXMuaWQpO1xuICAgICAgICB9XG4gICAgICAgIGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgIC8vIE5PVEU6IEEgd2FybmluZyB3b3VsZCBiZSByZWFsbHkgbmljZSBoZXJlLCBidXQgaXQgY2FuJ3QgYmUgZG9uZSB3aGlsZSBsb2cgaXMgc3RvcmVkIGluIGEgdGFzay5cbiAgICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1jb25zb2xlXG4gICAgICAgICAgICBjb25zb2xlLmxvZyhgRXJyb3IgY2FwdHVyZWQgd2hpbGUgY2xvc2luZyB0aGUgYnJvd3NlcjogJHtpbnNwZWN0KGVyciwgeyBkZXB0aDogMCB9KX1gKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgX2ZvcmNlSWRsZSAoKTogdm9pZCB7XG4gICAgICAgIGlmICghdGhpcy5pZGxlKSB7XG4gICAgICAgICAgICB0aGlzLmlkbGUgPSB0cnVlO1xuXG4gICAgICAgICAgICB0aGlzLmVtaXQoJ2lkbGUnKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgX2NyZWF0ZUJyb3dzZXJEaXNjb25uZWN0ZWRFcnJvciAoKTogR2VuZXJhbEVycm9yIHtcbiAgICAgICAgcmV0dXJuIG5ldyBHZW5lcmFsRXJyb3IoXG4gICAgICAgICAgICBSVU5USU1FX0VSUk9SUy5icm93c2VyRGlzY29ubmVjdGVkLFxuICAgICAgICAgICAgdGhpcy51c2VyQWdlbnRcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIF93YWl0Rm9ySGVhcnRiZWF0ICgpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5oZWFydGJlYXRUaW1lb3V0ID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tY29uc29sZVxuICAgICAgICAgICAgY29uc29sZS5sb2coYEhlYXJ0IGJlYXQgbGFwc2VkIHRyeWluZyB0byBkaXNjb25uZWN0YCk7XG4gICAgICAgICAgICBjb25zdCBlcnIgPSB0aGlzLl9jcmVhdGVCcm93c2VyRGlzY29ubmVjdGVkRXJyb3IoKTtcblxuICAgICAgICAgICAgdGhpcy5zdGF0dXMgICAgICAgICA9IEJyb3dzZXJDb25uZWN0aW9uU3RhdHVzLmRpc2Nvbm5lY3RlZDtcbiAgICAgICAgICAgIHRoaXMudGVzdFJ1bkFib3J0ZWQgPSB0cnVlO1xuXG4gICAgICAgICAgICB0aGlzLmVtaXQoJ2Rpc2Nvbm5lY3RlZCcsIGVycik7XG5cbiAgICAgICAgICAgIHRoaXMuX3Jlc3RhcnRCcm93c2VyT25EaXNjb25uZWN0KGVycik7XG4gICAgICAgIH0sIHRoaXMuSEVBUlRCRUFUX1RJTUVPVVQpO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX2dldFRlc3RSdW5VcmwgKG5lZWRQb3BOZXh0OiBib29sZWFuKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICAgICAgaWYgKG5lZWRQb3BOZXh0IHx8ICF0aGlzLnBlbmRpbmdUZXN0UnVuVXJsKVxuICAgICAgICAgICAgdGhpcy5wZW5kaW5nVGVzdFJ1blVybCA9IGF3YWl0IHRoaXMuX3BvcE5leHRUZXN0UnVuVXJsKCk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMucGVuZGluZ1Rlc3RSdW5VcmwgYXMgc3RyaW5nO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX3BvcE5leHRUZXN0UnVuVXJsICgpOiBQcm9taXNlPHN0cmluZyB8IG51bGw+IHtcbiAgICAgICAgY29uc3QgaXNaZXJvID0gdGhpcy5jdXJyZW50Sm9iXG4gICAgICAgICAgICA/IHRoaXMuY3VycmVudEpvYi5xdWV1ZWRUZXN0UnVucyA9PT0gMFxuICAgICAgICAgICAgOiBmYWxzZTtcblxuICAgICAgICBpZiAodGhpcy50ZXN0U2NoZWR1bGluZyAmJiBpc1plcm8pIHtcbiAgICAgICAgICAgIGNvbnN0IGNKb2IgPSB0aGlzLmN1cnJlbnRKb2I7XG4gICAgICAgICAgICBsZXQgaXNEb25lID0gZmFsc2U7XG5cbiAgICAgICAgICAgIHNldEludGVydmFsKCgpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoIWlzRG9uZSAmJiBjSm9iLnRvdGFsID09PSBjSm9iLnRvdGFsR2l2ZW4pIHtcbiAgICAgICAgICAgICAgICAgICAgaXNEb25lID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jbG9zZSgpO1xuICAgICAgICAgICAgICAgICAgICBjSm9iLmVtaXQoJ2RvbmUnKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LCAxMDAwKTtcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG5cbiAgICAgICAgd2hpbGUgKHRoaXMuaGFzUXVldWVkSm9icyAmJiAhdGhpcy5jdXJyZW50Sm9iLmhhc1F1ZXVlZFRlc3RSdW5zKVxuICAgICAgICAgICAgdGhpcy5qb2JRdWV1ZS5zaGlmdCgpO1xuXG4gICAgICAgIGxldCBpc1Jlc3RhcnRIYXBwZW5lZCA9IGZhbHNlO1xuXG4gICAgICAgIGlmICh0aGlzLnRlc3RTY2hlZHVsaW5nICYmIHRoaXMuY3VycmVudEpvYikge1xuICAgICAgICAgICAgY29uc3QgcXVldWVMZW5ndGggPSB0aGlzLmN1cnJlbnRKb2IucXVldWVkVGVzdFJ1bnM7XG4gICAgICAgICAgICAvLyBjb25zb2xlLmxvZyhgQ3VycmVudCBqb2JDb250cm9sbGVyIGxlbmd0aDogJHtxdWV1ZUxlbmd0aH1gKTtcblxuICAgICAgICAgICAgLy8gU3Bhd24gdXAgYSBuZXcgYnJvd3NlciBvbiBldmVyeSBuZXcgcG9sbGluZy5cbiAgICAgICAgICAgIGlmICghdGhpcy5pc0ZpcnN0ICYmIHRoaXMuaGFzUXVldWVkSm9icyAmJiBxdWV1ZUxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICBjb25zdCB0ZXN0UnVuQ29udHJvbGxlciA9IGF3YWl0IHRoaXMuY3VycmVudEpvYi5wb3BUZXN0O1xuXG4gICAgICAgICAgICAgICAgaWYgKHRlc3RSdW5Db250cm9sbGVyICE9PSBudWxsKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuc3RhdHVzID0gQnJvd3NlckNvbm5lY3Rpb25TdGF0dXMuZGlzY29ubmVjdGVkO1xuICAgICAgICAgICAgICAgICAgICBjbGVhclRpbWVvdXQodGhpcy5oZWFydGJlYXRUaW1lb3V0IGFzIE5vZGVKUy5UaW1lb3V0KTtcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5fcmVzdGFydEJyb3dzZXIoKTtcbiAgICAgICAgICAgICAgICAgICAgaXNSZXN0YXJ0SGFwcGVuZWQgPSB0cnVlO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5jdXJyZW50Sm9iLnNldFRlc3RVUkwoXG4gICAgICAgICAgICAgICAgICAgICAgICB0ZXN0UnVuQ29udHJvbGxlcixcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXNcbiAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRoaXMuaXNGaXJzdCA9IGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gQ29uZGl0aW9uIGZvciBjaGVja2luZyBub24tbnVsbCB1cmxzXG4gICAgICAgIGNvbnN0IHVybCA9IHRoaXMuaGFzUXVldWVkSm9ic1xuICAgICAgICAgICAgPyBhd2FpdCB0aGlzLmN1cnJlbnRKb2IucG9wTmV4dFRlc3RSdW5VcmwodGhpcylcbiAgICAgICAgICAgIDogbnVsbDtcblxuICAgICAgICAvLyBjb25zb2xlLmxvZyhgSXMgcmVzdGFydGVkOiAke2lzUmVzdGFydEhhcHBlbmVkfSAke3VybH1gKTtcbiAgICAgICAgaWYgKHRoaXMudGVzdFNjaGVkdWxpbmcgJiYgdXJsID09PSBudWxsICYmIGlzUmVzdGFydEhhcHBlbmVkKSB7XG4gICAgICAgICAgICB0aGlzLnN0YXR1cyA9IEJyb3dzZXJDb25uZWN0aW9uU3RhdHVzLmRpc2Nvbm5lY3RlZDtcbiAgICAgICAgICAgIHRoaXMuX2Nsb3NlQnJvd3NlcigpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHVybDtcbiAgICB9XG5cbiAgICBwdWJsaWMgc3RhdGljIGdldEJ5SWQgKGlkOiBzdHJpbmcpOiBCcm93c2VyQ29ubmVjdGlvbiB8IG51bGwge1xuICAgICAgICByZXR1cm4gY29ubmVjdGlvbnNbaWRdIHx8IG51bGw7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBfcmVzdGFydEJyb3dzZXIgKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICB0aGlzLnN0YXR1cyA9IEJyb3dzZXJDb25uZWN0aW9uU3RhdHVzLnVuaW5pdGlhbGl6ZWQ7XG5cbiAgICAgICAgdGhpcy5fZm9yY2VJZGxlKCk7XG5cbiAgICAgICAgbGV0IHJlc29sdmVUaW1lb3V0OiBGdW5jdGlvbiB8IG51bGwgPSBudWxsO1xuICAgICAgICBsZXQgaXNUaW1lb3V0RXhwaXJlZCA9IGZhbHNlO1xuICAgICAgICBsZXQgdGltZW91dDogTm9kZUpTLlRpbWVvdXQgfCBudWxsID0gbnVsbDtcblxuICAgICAgICBjb25zdCByZXN0YXJ0UHJvbWlzZSA9IHRoaXMuX2Nsb3NlQnJvd3NlcigpLnRoZW4oKCkgPT5cbiAgICAgICAgICAgIHRoaXMuX3J1bkJyb3dzZXIoKVxuICAgICAgICApO1xuXG4gICAgICAgIGNvbnN0IHRpbWVvdXRQcm9taXNlID0gbmV3IFByb21pc2UocmVzb2x2ZSA9PiB7XG4gICAgICAgICAgICByZXNvbHZlVGltZW91dCA9IHJlc29sdmU7XG5cbiAgICAgICAgICAgIHRpbWVvdXQgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgICAgICBpc1RpbWVvdXRFeHBpcmVkID0gdHJ1ZTtcblxuICAgICAgICAgICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgICAgIH0sIHRoaXMuQlJPV1NFUl9SRVNUQVJUX1RJTUVPVVQpO1xuICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gUHJvbWlzZS5yYWNlKFtyZXN0YXJ0UHJvbWlzZSwgdGltZW91dFByb21pc2VdKS50aGVuKCgpID0+IHtcbiAgICAgICAgICAgIGNsZWFyVGltZW91dCh0aW1lb3V0IGFzIE5vZGVKUy5UaW1lb3V0KTtcblxuICAgICAgICAgICAgaWYgKGlzVGltZW91dEV4cGlyZWQpXG4gICAgICAgICAgICAgICAgdGhpcy5lbWl0KCdlcnJvcicsIHRoaXMuX2NyZWF0ZUJyb3dzZXJEaXNjb25uZWN0ZWRFcnJvcigpKTtcbiAgICAgICAgICAgIGVsc2UgKHJlc29sdmVUaW1lb3V0IGFzIEZ1bmN0aW9uKSgpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwcml2YXRlIF9yZXN0YXJ0QnJvd3Nlck9uRGlzY29ubmVjdCAoZXJyOiBFcnJvcik6IHZvaWQge1xuICAgICAgICBsZXQgcmVzb2x2ZUZuOiBGdW5jdGlvbiB8IG51bGwgPSBudWxsO1xuICAgICAgICBsZXQgcmVqZWN0Rm46IEZ1bmN0aW9uIHwgbnVsbCA9IG51bGw7XG5cbiAgICAgICAgdGhpcy5kaXNjb25uZWN0aW9uUHJvbWlzZSA9IG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgICAgIHJlc29sdmVGbiA9IHJlc29sdmU7XG5cbiAgICAgICAgICAgIHJlamVjdEZuID0gKCkgPT4ge1xuICAgICAgICAgICAgICAgIHJlamVjdChlcnIpO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICAgICAgKHJlamVjdEZuIGFzIEZ1bmN0aW9uKSgpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pXG4gICAgICAgICAgICAudGhlbigoKSA9PiB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3Jlc3RhcnRCcm93c2VyKCk7XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLmNhdGNoKGUgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMuZW1pdCgnZXJyb3InLCBlKTtcbiAgICAgICAgICAgIH0pIGFzIERpc2Nvbm5lY3Rpb25Qcm9taXNlPHZvaWQ+O1xuXG4gICAgICAgIHRoaXMuZGlzY29ubmVjdGlvblByb21pc2UucmVzb2x2ZSA9IChyZXNvbHZlRm4gYXMgdW5rbm93bikgYXMgRnVuY3Rpb247XG4gICAgICAgIHRoaXMuZGlzY29ubmVjdGlvblByb21pc2UucmVqZWN0ID0gKHJlamVjdEZuIGFzIHVua25vd24pIGFzIEZ1bmN0aW9uO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBwcm9jZXNzRGlzY29ubmVjdGlvbiAoXG4gICAgICAgIGRpc2Nvbm5lY3Rpb25UaHJlc2hvbGRFeGNlZWRlZWQ6IGJvb2xlYW5cbiAgICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgY29uc3QgeyByZXNvbHZlLCByZWplY3QgfSA9IHRoaXNcbiAgICAgICAgICAgIC5kaXNjb25uZWN0aW9uUHJvbWlzZSBhcyBEaXNjb25uZWN0aW9uUHJvbWlzZTx2b2lkPjtcblxuICAgICAgICBpZiAoZGlzY29ubmVjdGlvblRocmVzaG9sZEV4Y2VlZGVlZCkgcmVqZWN0KCk7XG4gICAgICAgIGVsc2UgcmVzb2x2ZSgpO1xuICAgIH1cblxuICAgIHB1YmxpYyBhZGRXYXJuaW5nICguLi5hcmdzOiBhbnlbXSk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy5jdXJyZW50Sm9iKSB0aGlzLmN1cnJlbnRKb2Iud2FybmluZ0xvZy5hZGRXYXJuaW5nKC4uLmFyZ3MpO1xuICAgIH1cblxuICAgIHB1YmxpYyBzZXRQcm92aWRlck1ldGFJbmZvIChzdHI6IHN0cmluZyk6IHZvaWQge1xuICAgICAgICB0aGlzLmJyb3dzZXJJbmZvLnVzZXJBZ2VudFByb3ZpZGVyTWV0YUluZm8gPSBzdHI7XG4gICAgfVxuXG4gICAgcHVibGljIGdldCB1c2VyQWdlbnQgKCk6IHN0cmluZyB7XG4gICAgICAgIGxldCB1c2VyQWdlbnQgPSB0aGlzLmJyb3dzZXJJbmZvLnBhcnNlZFVzZXJBZ2VudC5wcmV0dHlVc2VyQWdlbnQ7XG5cbiAgICAgICAgaWYgKHRoaXMuYnJvd3NlckluZm8udXNlckFnZW50UHJvdmlkZXJNZXRhSW5mbylcbiAgICAgICAgICAgIHVzZXJBZ2VudCArPSBgICgke3RoaXMuYnJvd3NlckluZm8udXNlckFnZW50UHJvdmlkZXJNZXRhSW5mb30pYDtcblxuICAgICAgICByZXR1cm4gdXNlckFnZW50O1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXQgaGFzUXVldWVkSm9icyAoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiAhIXRoaXMuam9iUXVldWUubGVuZ3RoO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXQgY3VycmVudEpvYiAoKTogYW55IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuam9iUXVldWVbMF07XG4gICAgfVxuXG4gICAgLy8gQVBJXG4gICAgcHVibGljIHJ1bkluaXRTY3JpcHQgKGNvZGU6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nIHwgdW5rbm93bj4ge1xuICAgICAgICByZXR1cm4gbmV3IFByb21pc2UocmVzb2x2ZSA9PlxuICAgICAgICAgICAgdGhpcy5pbml0U2NyaXB0c1F1ZXVlLnB1c2goeyBjb2RlLCByZXNvbHZlIH0pXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogYWRkSm9iIGlzIGFwcGVuZGluZyBqb2IgdG8gdGhlIGpvYlF1ZXVlIGFuZCBlYWNoXG4gICAgICogam9iIGhhcyBtdWx0aXBsZSB0ZXN0cyBmdW5jdGlvbnMgaW4gaXQgZm9yIGV4ZWN1dGlvbi5cbiAgICAgKlxuICAgICAqIEByZXR1cm5zIHt1bmRlZmluZWR9XG4gICAgICovXG4gICAgcHVibGljIGFkZEpvYiAoam9iOiBhbnkpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5qb2JRdWV1ZS5wdXNoKGpvYik7XG4gICAgfVxuXG4gICAgcHVibGljIHJlbW92ZUpvYiAoam9iOiBhbnkpOiB2b2lkIHtcbiAgICAgICAgcmVtb3ZlKHRoaXMuam9iUXVldWUsIGpvYik7XG4gICAgfVxuXG4gICAgcHVibGljIGNsb3NlICgpOiB2b2lkIHtcbiAgICAgICAgaWYgKHRoaXMuc3RhdHVzID09PSBCcm93c2VyQ29ubmVjdGlvblN0YXR1cy5jbG9zaW5nIHx8IHRoaXMuc3RhdHVzID09PSBCcm93c2VyQ29ubmVjdGlvblN0YXR1cy5jbG9zZWQpXG4gICAgICAgICAgICByZXR1cm47XG5cbiAgICAgICAgdGhpcy5zdGF0dXMgPSBCcm93c2VyQ29ubmVjdGlvblN0YXR1cy5jbG9zaW5nO1xuXG4gICAgICAgIHRoaXMuX2Nsb3NlQnJvd3NlcigpLnRoZW4oKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5icm93c2VyQ29ubmVjdGlvbkdhdGV3YXkuc3RvcFNlcnZpbmdDb25uZWN0aW9uKHRoaXMpO1xuICAgICAgICAgICAgY2xlYXJUaW1lb3V0KHRoaXMuaGVhcnRiZWF0VGltZW91dCBhcyBOb2RlSlMuVGltZW91dCk7XG5cbiAgICAgICAgICAgIGRlbGV0ZSBjb25uZWN0aW9uc1t0aGlzLmlkXTtcblxuICAgICAgICAgICAgdGhpcy5zdGF0dXMgPSBCcm93c2VyQ29ubmVjdGlvblN0YXR1cy5jbG9zZWQ7XG5cbiAgICAgICAgICAgIHRoaXMuZW1pdCgnY2xvc2VkJyk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHB1YmxpYyBlc3RhYmxpc2ggKHVzZXJBZ2VudDogc3RyaW5nKTogdm9pZCB7XG4gICAgICAgIHRoaXMuc3RhdHVzICAgICAgICAgICAgICAgICAgICAgID0gQnJvd3NlckNvbm5lY3Rpb25TdGF0dXMucmVhZHk7XG4gICAgICAgIHRoaXMuYnJvd3NlckluZm8ucGFyc2VkVXNlckFnZW50ID0gcGFyc2VVc2VyQWdlbnQodXNlckFnZW50KTtcblxuICAgICAgICB0aGlzLl93YWl0Rm9ySGVhcnRiZWF0KCk7XG4gICAgICAgIHRoaXMuZW1pdCgncmVhZHknKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgaGVhcnRiZWF0ICgpOiBIZWFydGJlYXRTdGF0dXNSZXN1bHQge1xuICAgICAgICBjbGVhclRpbWVvdXQodGhpcy5oZWFydGJlYXRUaW1lb3V0IGFzIE5vZGVKUy5UaW1lb3V0KTtcbiAgICAgICAgdGhpcy5fd2FpdEZvckhlYXJ0YmVhdCgpO1xuXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBjb2RlOiB0aGlzLnN0YXR1cyA9PT0gQnJvd3NlckNvbm5lY3Rpb25TdGF0dXMuY2xvc2luZyA/IEhlYXJ0YmVhdFN0YXR1cy5jbG9zaW5nIDogSGVhcnRiZWF0U3RhdHVzLm9rLFxuICAgICAgICAgICAgdXJsOiAgdGhpcy5zdGF0dXMgPT09IEJyb3dzZXJDb25uZWN0aW9uU3RhdHVzLmNsb3NpbmcgPyB0aGlzLmlkbGVVcmwgOiAnJ1xuICAgICAgICB9O1xuICAgIH1cblxuICAgIHB1YmxpYyByZW5kZXJJZGxlUGFnZSAoKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIE11c3RhY2hlLnJlbmRlcihJRExFX1BBR0VfVEVNUExBVEUgYXMgc3RyaW5nLCB7XG4gICAgICAgICAgICB1c2VyQWdlbnQ6ICAgICAgdGhpcy51c2VyQWdlbnQsXG4gICAgICAgICAgICBzdGF0dXNVcmw6ICAgICAgdGhpcy5zdGF0dXNVcmwsXG4gICAgICAgICAgICBoZWFydGJlYXRVcmw6ICAgdGhpcy5oZWFydGJlYXRVcmwsXG4gICAgICAgICAgICBpbml0U2NyaXB0VXJsOiAgdGhpcy5pbml0U2NyaXB0VXJsLFxuICAgICAgICAgICAgcmV0cnlUZXN0UGFnZXM6ICEhdGhpcy5icm93c2VyQ29ubmVjdGlvbkdhdGV3YXkucmV0cnlUZXN0UGFnZXNcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHVibGljIGdldEluaXRTY3JpcHQgKCk6IEluaXRTY3JpcHQge1xuICAgICAgICBjb25zdCBpbml0U2NyaXB0UHJvbWlzZSA9IHRoaXMuaW5pdFNjcmlwdHNRdWV1ZVswXTtcblxuICAgICAgICByZXR1cm4geyBjb2RlOiBpbml0U2NyaXB0UHJvbWlzZSA/IGluaXRTY3JpcHRQcm9taXNlLmNvZGUgOiBudWxsIH07XG4gICAgfVxuXG4gICAgcHVibGljIGhhbmRsZUluaXRTY3JpcHRSZXN1bHQgKGRhdGE6IHN0cmluZyk6IHZvaWQge1xuICAgICAgICBjb25zdCBpbml0U2NyaXB0UHJvbWlzZSA9IHRoaXMuaW5pdFNjcmlwdHNRdWV1ZS5zaGlmdCgpO1xuXG4gICAgICAgIGlmIChpbml0U2NyaXB0UHJvbWlzZSkgaW5pdFNjcmlwdFByb21pc2UucmVzb2x2ZShKU09OLnBhcnNlKGRhdGEpKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgaXNIZWFkbGVzc0Jyb3dzZXIgKCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gdGhpcy5wcm92aWRlci5pc0hlYWRsZXNzQnJvd3Nlcih0aGlzLmlkKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgcmVwb3J0Sm9iUmVzdWx0IChzdGF0dXM6IHN0cmluZywgZGF0YTogYW55KTogUHJvbWlzZTxhbnk+IHtcbiAgICAgICAgYXdhaXQgdGhpcy5wcm92aWRlci5yZXBvcnRKb2JSZXN1bHQodGhpcy5pZCwgc3RhdHVzLCBkYXRhKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgZ2V0U3RhdHVzIChpc1Rlc3REb25lOiBib29sZWFuKTogUHJvbWlzZTxCcm93c2VyQ29ubmVjdGlvblN0YXR1c1Jlc3VsdD4ge1xuICAgICAgICBpZiAoIXRoaXMuaWRsZSAmJiAhaXNUZXN0RG9uZSkge1xuICAgICAgICAgICAgLy8gY29uc29sZS5sb2coYFN0YXR1cyBpZGxlIGlzIHNldCBmb3IgdGhlIHRlc3QgcnVuYCk7XG4gICAgICAgICAgICB0aGlzLmlkbGUgPSB0cnVlO1xuICAgICAgICAgICAgdGhpcy5lbWl0KCdpZGxlJyk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGhpcy5zdGF0dXMgPT09IEJyb3dzZXJDb25uZWN0aW9uU3RhdHVzLm9wZW5lZCkge1xuICAgICAgICAgICAgY29uc3QgdGVzdFJ1blVybCA9IGF3YWl0IHRoaXMuX2dldFRlc3RSdW5VcmwoaXNUZXN0RG9uZSB8fCB0aGlzLnRlc3RSdW5BYm9ydGVkKTtcblxuICAgICAgICAgICAgdGhpcy50ZXN0UnVuQWJvcnRlZCA9IGZhbHNlO1xuXG4gICAgICAgICAgICBpZiAodGVzdFJ1blVybCkge1xuICAgICAgICAgICAgICAgIHRoaXMuaWRsZSA9IGZhbHNlO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHsgY21kOiBDT01NQU5ELnJ1biwgdXJsOiB0ZXN0UnVuVXJsIH07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4geyBjbWQ6IENPTU1BTkQuaWRsZSwgdXJsOiB0aGlzLmlkbGVVcmwgfTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0IGFjdGl2ZVdpbmRvd0lkICgpOiBudWxsIHwgc3RyaW5nIHtcbiAgICAgICAgcmV0d