testcafe
Version:
Automated browser testing for the modern web development stack.
204 lines • 29.5 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 net_1 = require("net");
const promisify_event_1 = __importDefault(require("promisify-event"));
const events_1 = __importDefault(require("events"));
const delay_1 = __importDefault(require("../../../../../../utils/delay"));
const client_functions_1 = require("../../../../utils/client-functions");
const commands_1 = __importDefault(require("./commands"));
const CONNECTION_TIMEOUT = 30000;
const CONNECTION_RETRY_DELAY = 300;
const MAX_RESIZE_RETRY_COUNT = 2;
const HEADER_SEPARATOR = ':';
module.exports = class MarionetteClient {
constructor(port = 2828, runtimeInfo, host = '127.0.0.1') {
this.currentPacketNumber = 1;
this.events = new events_1.default();
this.port = port;
this.host = host;
this.socket = new net_1.Socket();
this.buffer = Buffer.alloc(0);
this.getPacketPromise = Promise.resolve();
this.sendPacketPromise = Promise.resolve();
this._runtimeInfo = runtimeInfo;
this._windowHandles = {};
this.protocolInfo = {
applicationType: '',
marionetteProtocol: '',
};
this.sessionInfo = null;
}
get activeWindowId() {
return this._runtimeInfo.activeWindowId;
}
async _attemptToConnect(port, host) {
this.socket.connect(port, host);
const connectionPromise = Promise.race([
(0, promisify_event_1.default)(this.socket, 'connect'),
(0, promisify_event_1.default)(this.socket, 'error'),
]);
return await connectionPromise
.then(() => true)
.catch(() => {
this.socket.removeAllListeners('connect');
return (0, delay_1.default)(CONNECTION_RETRY_DELAY);
});
}
async _connectSocket(port, host) {
const connectionStartTime = Date.now();
let connected = await this._attemptToConnect(port, host);
while (!connected && Date.now() - connectionStartTime < CONNECTION_TIMEOUT)
connected = await this._attemptToConnect(port, host);
if (!connected)
throw new Error('Unable to connect');
this.socket.on('data', data => this._handleNewData(data));
}
async _writeSocket(message) {
if (!this.socket.write(message))
await (0, promisify_event_1.default)(this.socket, 'drain');
}
_handleNewData(data) {
if (!data)
return;
this.buffer = Buffer.concat([this.buffer, data]);
this.events.emit('new-data');
}
_getPacket() {
this.getPacketPromise = this.getPacketPromise.then(async () => {
let headerEndIndex = this.buffer.indexOf(HEADER_SEPARATOR);
while (headerEndIndex < 0) {
await (0, promisify_event_1.default)(this.events, 'new-data');
headerEndIndex = this.buffer.indexOf(HEADER_SEPARATOR);
}
const packet = {
length: NaN,
body: null,
};
packet.length = parseInt(this.buffer.toString('utf8', 0, headerEndIndex), 10) || 0;
const bodyStartIndex = headerEndIndex + HEADER_SEPARATOR.length;
const bodyEndIndex = bodyStartIndex + packet.length;
if (packet.length) {
while (this.buffer.length < bodyEndIndex)
await (0, promisify_event_1.default)(this.events, 'new-data');
packet.body = JSON.parse(this.buffer.toString('utf8', bodyStartIndex, bodyEndIndex));
}
this.buffer = this.buffer.slice(bodyEndIndex);
return packet;
});
return this.getPacketPromise;
}
_sendPacket(payload) {
this.sendPacketPromise = this.sendPacketPromise.then(async () => {
const body = [0, this.currentPacketNumber++, payload.command, payload.parameters];
const serialized = JSON.stringify(body);
const message = Buffer.byteLength(serialized, 'utf8') + HEADER_SEPARATOR + serialized;
this._writeSocket(message);
});
return this.sendPacketPromise;
}
_throwMarionetteError(error) {
throw new Error(`${error.error}${error.message ? ': ' + error.message : ''}`);
}
async _switchToWindow(windowHandle) {
await this._getResponse({
command: commands_1.default.switchToWindow,
parameters: { handle: windowHandle },
});
}
async _getActiveWindowHandle() {
const windowHandles = await this._getResponse({
command: commands_1.default.getWindowHandles,
});
for (const handle of windowHandles) {
await this._switchToWindow(handle);
const title = await this._getResponse({ command: commands_1.default.getTitle });
if (title.value.includes(this.activeWindowId))
return handle;
}
return null;
}
async _ensureActiveWindow() {
let handle = this._windowHandles[this.activeWindowId];
if (handle) {
await this._switchToWindow(handle);
return;
}
handle = await this._getActiveWindowHandle();
if (handle)
this._windowHandles[this.activeWindowId] = handle;
}
async _request(packet) {
await this._ensureActiveWindow();
return this._getResponse(packet);
}
async _getResponse(packet) {
const packetNumber = this.currentPacketNumber;
await this._sendPacket(packet);
let responsePacket = await this._getPacket();
while (!responsePacket.body || responsePacket.body[1] !== packetNumber)
responsePacket = await this._getPacket();
if (responsePacket.body[2])
this._throwMarionetteError(responsePacket.body[2]);
return responsePacket.body[3];
}
async _getScreenshotRawData(fullPage = false) {
return await this._request({
command: commands_1.default.takeScreenshot,
parameters: {
full: fullPage,
hash: false,
scroll: false,
},
});
}
async connect() {
await this._connectSocket(this.port, this.host);
const infoPacket = await this._getPacket();
this.protocolInfo = {
applicationType: infoPacket.body.applicationType,
marionetteProtocol: infoPacket.body.marionetteProtocol,
};
this.sessionInfo = await this._getResponse({ command: commands_1.default.newSession });
}
dispose() {
this.socket.end();
this.buffer = null;
}
async executeScript(code) {
return await this._request({
command: commands_1.default.executeScript,
parameters: { script: `return (${code})()` },
});
}
async getScreenshotData(fullPage) {
const frameData = await this._getScreenshotRawData(fullPage);
return Buffer.from(frameData.value, 'base64');
}
async setWindowSize(width, height) {
let { value: pageRect } = await this.executeScript(client_functions_1.GET_WINDOW_DIMENSIONS_INFO_SCRIPT);
let attemptCounter = 0;
while (attemptCounter++ < MAX_RESIZE_RETRY_COUNT && (pageRect.width !== width || pageRect.height !== height)) {
const currentRect = await this._request({ command: commands_1.default.getWindowRect });
await this._request({
command: commands_1.default.setWindowRect,
parameters: {
x: currentRect.x,
y: currentRect.y,
width: width + (currentRect.width - pageRect.width),
height: height + (currentRect.height - pageRect.height),
},
});
({ value: pageRect } = await this.executeScript(client_functions_1.GET_WINDOW_DIMENSIONS_INFO_SCRIPT));
}
}
async quit() {
await this._request({ command: commands_1.default.quit });
}
// NOTE: This method is empty because of the code structure
async closeBrowserChildWindow() {
}
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYnJvd3Nlci9wcm92aWRlci9idWlsdC1pbi9kZWRpY2F0ZWQvZmlyZWZveC9tYXJpb25ldHRlLWNsaWVudC9pbmRleC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLDZCQUE2QjtBQUM3QixzRUFBNkM7QUFDN0Msb0RBQWtDO0FBQ2xDLDBFQUFrRDtBQUNsRCx5RUFBdUY7QUFDdkYsMERBQWtDO0FBR2xDLE1BQU0sa0JBQWtCLEdBQU8sS0FBSyxDQUFDO0FBQ3JDLE1BQU0sc0JBQXNCLEdBQUcsR0FBRyxDQUFDO0FBQ25DLE1BQU0sc0JBQXNCLEdBQUcsQ0FBQyxDQUFDO0FBQ2pDLE1BQU0sZ0JBQWdCLEdBQVMsR0FBRyxDQUFDO0FBRW5DLE1BQU0sQ0FBQyxPQUFPLEdBQUcsTUFBTSxnQkFBZ0I7SUFDbkMsWUFBYSxJQUFJLEdBQUcsSUFBSSxFQUFFLFdBQVcsRUFBRSxJQUFJLEdBQUcsV0FBVztRQUNyRCxJQUFJLENBQUMsbUJBQW1CLEdBQUcsQ0FBQyxDQUFDO1FBQzdCLElBQUksQ0FBQyxNQUFNLEdBQWdCLElBQUksZ0JBQVksRUFBRSxDQUFDO1FBQzlDLElBQUksQ0FBQyxJQUFJLEdBQWtCLElBQUksQ0FBQztRQUNoQyxJQUFJLENBQUMsSUFBSSxHQUFrQixJQUFJLENBQUM7UUFDaEMsSUFBSSxDQUFDLE1BQU0sR0FBZ0IsSUFBSSxZQUFNLEVBQUUsQ0FBQztRQUN4QyxJQUFJLENBQUMsTUFBTSxHQUFnQixNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQzNDLElBQUksQ0FBQyxnQkFBZ0IsR0FBTSxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDN0MsSUFBSSxDQUFDLGlCQUFpQixHQUFLLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUU3QyxJQUFJLENBQUMsWUFBWSxHQUFLLFdBQVcsQ0FBQztR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TSxHQUFHLENBQUMsV0FBVyxDQUFDLE1BQU0sR0FBRyxRQUFRLENBQUMsTUFBTSxDQUFDO2lCQUMxRDthQUNKLENBQUMsQ0FBQztZQUVILENBQUMsRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLEdBQUcsTUFBTSxJQUFJLENBQUMsYUFBYSxDQUFDLG9EQUFpQyxDQUFDLENBQUMsQ0FBQztTQUN2RjtJQUNMLENBQUM7SUFFRCxLQUFLLENBQUMsSUFBSTtRQUNOLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxFQUFFLE9BQU8sRUFBRSxrQkFBUSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7SUFDcEQsQ0FBQztJQUVELDJEQUEyRDtJQUMzRCxLQUFLLENBQUMsdUJBQXVCO0lBQzdCLENBQUM7Q0FDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgU29ja2V0IH0gZnJvbSAnbmV0JztcbmltcG9ydCBwcm9taXNpZnlFdmVudCBmcm9tICdwcm9taXNpZnktZXZlbnQnO1xuaW1wb3J0IEV2ZW50RW1pdHRlciBmcm9tICdldmVudHMnO1xuaW1wb3J0IGRlbGF5IGZyb20gJy4uLy4uLy4uLy4uLy4uLy4uL3V0aWxzL2RlbGF5JztcbmltcG9ydCB7IEdFVF9XSU5ET1dfRElNRU5TSU9OU19JTkZPX1NDUklQVCB9IGZyb20gJy4uLy4uLy4uLy4uL3V0aWxzL2NsaWVudC1mdW5jdGlvbnMnO1xuaW1wb3J0IENPTU1BTkRTIGZyb20gJy4vY29tbWFuZHMnO1xuXG5cbmNvbnN0IENPTk5FQ1RJT05fVElNRU9VVCAgICAgPSAzMDAwMDtcbmNvbnN0IENPTk5FQ1RJT05fUkVUUllfREVMQVkgPSAzMDA7XG5jb25zdCBNQVhfUkVTSVpFX1JFVFJZX0NPVU5UID0gMjtcbmNvbnN0IEhFQURFUl9TRVBBUkFUT1IgICAgICAgPSAnOic7XG5cbm1vZHVsZS5leHBvcnRzID0gY2xhc3MgTWFyaW9uZXR0ZUNsaWVudCB7XG4gICAgY29uc3RydWN0b3IgKHBvcnQgPSAyODI4LCBydW50aW1lSW5mbywgaG9zdCA9ICcxMjcuMC4wLjEnKSB7XG4gICAgICAgIHRoaXMuY3VycmVudFBhY2tldE51bWJlciA9IDE7XG4gICAgICAgIHRoaXMuZXZlbnRzICAgICAgICAgICAgICA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcbiAgICAgICAgdGhpcy5wb3J0ICAgICAgICAgICAgICAgID0gcG9ydDtcbiAgICAgICAgdGhpcy5ob3N0ICAgICAgICAgICAgICAgID0gaG9zdDtcbiAgICAgICAgdGhpcy5zb2NrZXQgICAgICAgICAgICAgID0gbmV3IFNvY2tldCgpO1xuICAgICAgICB0aGlzLmJ1ZmZlciAgICAgICAgICAgICAgPSBCdWZmZXIuYWxsb2MoMCk7XG4gICAgICAgIHRoaXMuZ2V0UGFja2V0UHJvbWlzZSAgICA9IFByb21pc2UucmVzb2x2ZSgpO1xuICAgICAgICB0aGlzLnNlbmRQYWNrZXRQcm9taXNlICAgPSBQcm9taXNlLnJlc29sdmUoKTtcblxuICAgICAgICB0aGlzLl9ydW50aW1lSW5mbyAgID0gcnVudGltZUluZm87XG4gICAgICAgIHRoaXMuX3dpbmRvd0hhbmRsZXMgPSB7fTtcblxuICAgICAgICB0aGlzLnByb3RvY29sSW5mbyA9IHtcbiAgICAgICAgICAgIGFwcGxpY2F0aW9uVHlwZTogICAgJycsXG4gICAgICAgICAgICBtYXJpb25ldHRlUHJvdG9jb2w6ICcnLFxuICAgICAgICB9O1xuXG4gICAgICAgIHRoaXMuc2Vzc2lvbkluZm8gPSBudWxsO1xuICAgIH1cblxuICAgIGdldCBhY3RpdmVXaW5kb3dJZCAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9ydW50aW1lSW5mby5hY3RpdmVXaW5kb3dJZDtcbiAgICB9XG5cbiAgICBhc3luYyBfYXR0ZW1wdFRvQ29ubmVjdCAocG9ydCwgaG9zdCkge1xuICAgICAgICB0aGlzLnNvY2tldC5jb25uZWN0KHBvcnQsIGhvc3QpO1xuXG4gICAgICAgIGNvbnN0IGNvbm5lY3Rpb25Qcm9taXNlID0gUHJvbWlzZS5yYWNlKFtcbiAgICAgICAgICAgIHByb21pc2lmeUV2ZW50KHRoaXMuc29ja2V0LCAnY29ubmVjdCcpLFxuICAgICAgICAgICAgcHJvbWlzaWZ5RXZlbnQodGhpcy5zb2NrZXQsICdlcnJvcicpLFxuICAgICAgICBdKTtcblxuICAgICAgICByZXR1cm4gYXdhaXQgY29ubmVjdGlvblByb21pc2VcbiAgICAgICAgICAgIC50aGVuKCgpID0+IHRydWUpXG4gICAgICAgICAgICAuY2F0Y2goKCkgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMuc29ja2V0LnJlbW92ZUFsbExpc3RlbmVycygnY29ubmVjdCcpO1xuICAgICAgICAgICAgICAgIHJldHVybiBkZWxheShDT05ORUNUSU9OX1JFVFJZX0RFTEFZKTtcbiAgICAgICAgICAgIH0pO1xuICAgIH1cblxuICAgIGFzeW5jIF9jb25uZWN0U29ja2V0IChwb3J0LCBob3N0KSB7XG4gICAgICAgIGNvbnN0IGNvbm5lY3Rpb25TdGFydFRpbWUgPSBEYXRlLm5vdygpO1xuXG4gICAgICAgIGxldCBjb25uZWN0ZWQgPSBhd2FpdCB0aGlzLl9hdHRlbXB0VG9Db25uZWN0KHBvcnQsIGhvc3QpO1xuXG4gICAgICAgIHdoaWxlICghY29ubmVjdGVkICYmIERhdGUubm93KCkgLSBjb25uZWN0aW9uU3RhcnRUaW1lIDwgQ09OTkVDVElPTl9USU1FT1VUKVxuICAgICAgICAgICAgY29ubmVjdGVkID0gYXdhaXQgdGhpcy5fYXR0ZW1wdFRvQ29ubmVjdChwb3J0LCBob3N0KTtcblxuICAgICAgICBpZiAoIWNvbm5lY3RlZClcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignVW5hYmxlIHRvIGNvbm5lY3QnKTtcblxuICAgICAgICB0aGlzLnNvY2tldC5vbignZGF0YScsIGRhdGEgPT4gdGhpcy5faGFuZGxlTmV3RGF0YShkYXRhKSk7XG4gICAgfVxuXG4gICAgYXN5bmMgX3dyaXRlU29ja2V0IChtZXNzYWdlKSB7XG4gICAgICAgIGlmICghdGhpcy5zb2NrZXQud3JpdGUobWVzc2FnZSkpXG4gICAgICAgICAgICBhd2FpdCBwcm9taXNpZnlFdmVudCh0aGlzLnNvY2tldCwgJ2RyYWluJyk7XG4gICAgfVxuXG4gICAgX2hhbmRsZU5ld0RhdGEgKGRhdGEpIHtcbiAgICAgICAgaWYgKCFkYXRhKVxuICAgICAgICAgICAgcmV0dXJuO1xuXG4gICAgICAgIHRoaXMuYnVmZmVyID0gQnVmZmVyLmNvbmNhdChbdGhpcy5idWZmZXIsIGRhdGFdKTtcblxuICAgICAgICB0aGlzLmV2ZW50cy5lbWl0KCduZXctZGF0YScpO1xuICAgIH1cblxuICAgIF9nZXRQYWNrZXQgKCkge1xuICAgICAgICB0aGlzLmdldFBhY2tldFByb21pc2UgPSB0aGlzLmdldFBhY2tldFByb21pc2UudGhlbihhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICBsZXQgaGVhZGVyRW5kSW5kZXggPSB0aGlzLmJ1ZmZlci5pbmRleE9mKEhFQURFUl9TRVBBUkFUT1IpO1xuXG4gICAgICAgICAgICB3aGlsZSAoaGVhZGVyRW5kSW5kZXggPCAwKSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgcHJvbWlzaWZ5RXZlbnQodGhpcy5ldmVudHMsICduZXctZGF0YScpO1xuXG4gICAgICAgICAgICAgICAgaGVhZGVyRW5kSW5kZXggPSB0aGlzLmJ1ZmZlci5pbmRleE9mKEhFQURFUl9TRVBBUkFUT1IpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjb25zdCBwYWNrZXQgPSB7XG4gICAgICAgICAgICAgICAgbGVuZ3RoOiBOYU4sXG4gICAgICAgICAgICAgICAgYm9keTogICBudWxsLFxuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgcGFja2V0Lmxlbmd0aCA9IHBhcnNlSW50KHRoaXMuYnVmZmVyLnRvU3RyaW5nKCd1dGY4JywgMCwgaGVhZGVyRW5kSW5kZXgpLCAxMCkgfHwgMDtcblxuICAgICAgICAgICAgY29uc3QgYm9keVN0YXJ0SW5kZXggPSBoZWFkZXJFbmRJbmRleCArIEhFQURFUl9TRVBBUkFUT1IubGVuZ3RoO1xuICAgICAgICAgICAgY29uc3QgYm9keUVuZEluZGV4ICAgPSBib2R5U3RhcnRJbmRleCArIHBhY2tldC5sZW5ndGg7XG5cbiAgICAgICAgICAgIGlmIChwYWNrZXQubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgd2hpbGUgKHRoaXMuYnVmZmVyLmxlbmd0aCA8IGJvZHlFbmRJbmRleClcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgcHJvbWlzaWZ5RXZlbnQodGhpcy5ldmVudHMsICduZXctZGF0YScpO1xuXG4gICAgICAgICAgICAgICAgcGFja2V0LmJvZHkgPSBKU09OLnBhcnNlKHRoaXMuYnVmZmVyLnRvU3RyaW5nKCd1dGY4JywgYm9keVN0YXJ0SW5kZXgsIGJvZHlFbmRJbmRleCkpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB0aGlzLmJ1ZmZlciA9IHRoaXMuYnVmZmVyLnNsaWNlKGJvZHlFbmRJbmRleCk7XG5cbiAgICAgICAgICAgIHJldHVybiBwYWNrZXQ7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiB0aGlzLmdldFBhY2tldFByb21pc2U7XG4gICAgfVxuXG4gICAgX3NlbmRQYWNrZXQgKHBheWxvYWQpIHtcbiAgICAgICAgdGhpcy5zZW5kUGFja2V0UHJvbWlzZSA9IHRoaXMuc2VuZFBhY2tldFByb21pc2UudGhlbihhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBib2R5ICAgICAgID0gWzAsIHRoaXMuY3VycmVudFBhY2tldE51bWJlcisrLCBwYXlsb2FkLmNvbW1hbmQsIHBheWxvYWQucGFyYW1ldGVyc107XG4gICAgICAgICAgICBjb25zdCBzZXJpYWxpemVkID0gSlNPTi5zdHJpbmdpZnkoYm9keSk7XG4gICAgICAgICAgICBjb25zdCBtZXNzYWdlICAgID0gQnVmZmVyLmJ5dGVMZW5ndGgoc2VyaWFsaXplZCwgJ3V0ZjgnKSArIEhFQURFUl9TRVBBUkFUT1IgKyBzZXJpYWxpemVkO1xuXG4gICAgICAgICAgICB0aGlzLl93cml0ZVNvY2tldChtZXNzYWdlKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMuc2VuZFBhY2tldFByb21pc2U7XG4gICAgfVxuXG4gICAgX3Rocm93TWFyaW9uZXR0ZUVycm9yIChlcnJvcikge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYCR7ZXJyb3IuZXJyb3J9JHtlcnJvci5tZXNzYWdlID8gJzogJyArIGVycm9yLm1lc3NhZ2UgOiAnJ31gKTtcbiAgICB9XG5cbiAgICBhc3luYyBfc3dpdGNoVG9XaW5kb3cgKHdpbmRvd0hhbmRsZSkge1xuICAgICAgICBhd2FpdCB0aGlzLl9nZXRSZXNwb25zZSh7XG4gICAgICAgICAgICBjb21tYW5kOiAgICBDT01NQU5EUy5zd2l0Y2hUb1dpbmRvdyxcbiAgICAgICAgICAgIHBhcmFtZXRlcnM6IHsgaGFuZGxlOiB3aW5kb3dIYW5kbGUgfSxcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgYXN5bmMgX2dldEFjdGl2ZVdpbmRvd0hhbmRsZSAoKSB7XG4gICAgICAgIGNvbnN0IHdpbmRvd0hhbmRsZXMgPSBhd2FpdCB0aGlzLl9nZXRSZXNwb25zZSh7XG4gICAgICAgICAgICBjb21tYW5kOiBDT01NQU5EUy5nZXRXaW5kb3dIYW5kbGVzLFxuICAgICAgICB9KTtcblxuICAgICAgICBmb3IgKGNvbnN0IGhhbmRsZSBvZiB3aW5kb3dIYW5kbGVzKSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLl9zd2l0Y2hUb1dpbmRvdyhoYW5kbGUpO1xuXG4gICAgICAgICAgICBjb25zdCB0aXRsZSA9IGF3YWl0IHRoaXMuX2dldFJlc3BvbnNlKHsgY29tbWFuZDogQ09NTUFORFMuZ2V0VGl0bGUgfSk7XG5cbiAgICAgICAgICAgIGlmICh0aXRsZS52YWx1ZS5pbmNsdWRlcyh0aGlzLmFjdGl2ZVdpbmRvd0lkKSlcbiAgICAgICAgICAgICAgICByZXR1cm4gaGFuZGxlO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgYXN5bmMgX2Vuc3VyZUFjdGl2ZVdpbmRvdyAoKSB7XG4gICAgICAgIGxldCBoYW5kbGUgPSB0aGlzLl93aW5kb3dIYW5kbGVzW3RoaXMuYWN0aXZlV2luZG93SWRdO1xuXG4gICAgICAgIGlmIChoYW5kbGUpIHtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuX3N3aXRjaFRvV2luZG93KGhhbmRsZSk7XG5cbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGhhbmRsZSA9IGF3YWl0IHRoaXMuX2dldEFjdGl2ZVdpbmRvd0hhbmRsZSgpO1xuXG4gICAgICAgIGlmIChoYW5kbGUpXG4gICAgICAgICAgICB0aGlzLl93aW5kb3dIYW5kbGVzW3RoaXMuYWN0aXZlV2luZG93SWRdID0gaGFuZGxlO1xuICAgIH1cblxuICAgIGFzeW5jIF9yZXF1ZXN0IChwYWNrZXQpIHtcbiAgICAgICAgYXdhaXQgdGhpcy5fZW5zdXJlQWN0aXZlV2luZG93KCk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMuX2dldFJlc3BvbnNlKHBhY2tldCk7XG4gICAgfVxuXG4gICAgYXN5bmMgX2dldFJlc3BvbnNlIChwYWNrZXQpIHtcbiAgICAgICAgY29uc3QgcGFja2V0TnVtYmVyID0gdGhpcy5jdXJyZW50UGFja2V0TnVtYmVyO1xuXG4gICAgICAgIGF3YWl0IHRoaXMuX3NlbmRQYWNrZXQocGFja2V0KTtcblxuICAgICAgICBsZXQgcmVzcG9uc2VQYWNrZXQgPSBhd2FpdCB0aGlzLl9nZXRQYWNrZXQoKTtcblxuICAgICAgICB3aGlsZSAoIXJlc3BvbnNlUGFja2V0LmJvZHkgfHwgcmVzcG9uc2VQYWNrZXQuYm9keVsxXSAhPT0gcGFja2V0TnVtYmVyKVxuICAgICAgICAgICAgcmVzcG9uc2VQYWNrZXQgPSBhd2FpdCB0aGlzLl9nZXRQYWNrZXQoKTtcblxuICAgICAgICBpZiAocmVzcG9uc2VQYWNrZXQuYm9keVsyXSlcbiAgICAgICAgICAgIHRoaXMuX3Rocm93TWFyaW9uZXR0ZUVycm9yKHJlc3BvbnNlUGFja2V0LmJvZHlbMl0pO1xuXG4gICAgICAgIHJldHVybiByZXNwb25zZVBhY2tldC5ib2R5WzNdO1xuICAgIH1cblxuICAgIGFzeW5jIF9nZXRTY3JlZW5zaG90UmF3RGF0YSAoZnVsbFBhZ2UgPSBmYWxzZSkge1xuICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5fcmVxdWVzdCh7XG4gICAgICAgICAgICBjb21tYW5kOiAgICBDT01NQU5EUy50YWtlU2NyZWVuc2hvdCxcbiAgICAgICAgICAgIHBhcmFtZXRlcnM6IHtcbiAgICAgICAgICAgICAgICBmdWxsOiAgIGZ1bGxQYWdlLFxuICAgICAgICAgICAgICAgIGhhc2g6ICAgZmFsc2UsXG4gICAgICAgICAgICAgICAgc2Nyb2xsOiBmYWxzZSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIGFzeW5jIGNvbm5lY3QgKCkge1xuICAgICAgICBhd2FpdCB0aGlzLl9jb25uZWN0U29ja2V0KHRoaXMucG9ydCwgdGhpcy5ob3N0KTtcblxuICAgICAgICBjb25zdCBpbmZvUGFja2V0ID0gYXdhaXQgdGhpcy5fZ2V0UGFja2V0KCk7XG5cbiAgICAgICAgdGhpcy5wcm90b2NvbEluZm8gPSB7XG4gICAgICAgICAgICBhcHBsaWNhdGlvblR5cGU6ICAgIGluZm9QYWNrZXQuYm9keS5hcHBsaWNhdGlvblR5cGUsXG4gICAgICAgICAgICBtYXJpb25ldHRlUHJvdG9jb2w6IGluZm9QYWNrZXQuYm9keS5tYXJpb25ldHRlUHJvdG9jb2wsXG4gICAgICAgIH07XG5cbiAgICAgICAgdGhpcy5zZXNzaW9uSW5mbyA9IGF3YWl0IHRoaXMuX2dldFJlc3BvbnNlKHsgY29tbWFuZDogQ09NTUFORFMubmV3U2Vzc2lvbiB9KTtcbiAgICB9XG5cbiAgICBkaXNwb3NlICgpIHtcbiAgICAgICAgdGhpcy5zb2NrZXQuZW5kKCk7XG4gICAgICAgIHRoaXMuYnVmZmVyID0gbnVsbDtcbiAgICB9XG5cbiAgICBhc3luYyBleGVjdXRlU2NyaXB0IChjb2RlKSB7XG4gICAgICAgIHJldHVybiBhd2FpdCB0aGlzLl9yZXF1ZXN0KHtcbiAgICAgICAgICAgIGNvbW1hbmQ6ICAgIENPTU1BTkRTLmV4ZWN1dGVTY3JpcHQsXG4gICAgICAgICAgICBwYXJhbWV0ZXJzOiB7IHNjcmlwdDogYHJldHVybiAoJHtjb2RlfSkoKWAgfSxcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgYXN5bmMgZ2V0U2NyZWVuc2hvdERhdGEgKGZ1bGxQYWdlKSB7XG4gICAgICAgIGNvbnN0IGZyYW1lRGF0YSA9IGF3YWl0IHRoaXMuX2dldFNjcmVlbnNob3RSYXdEYXRhKGZ1bGxQYWdlKTtcblxuICAgICAgICByZXR1cm4gQnVmZmVyLmZyb20oZnJhbWVEYXRhLnZhbHVlLCAnYmFzZTY0Jyk7XG4gICAgfVxuXG4gICAgYXN5bmMgc2V0V2luZG93U2l6ZSAod2lkdGgsIGhlaWdodCkge1xuICAgICAgICBsZXQgeyB2YWx1ZTogcGFnZVJlY3QgfSA9IGF3YWl0IHRoaXMuZXhlY3V0ZVNjcmlwdChHRVRfV0lORE9XX0RJTUVOU0lPTlNfSU5GT19TQ1JJUFQpO1xuICAgICAgICBsZXQgYXR0ZW1wdENvdW50ZXIgICAgICA9IDA7XG5cbiAgICAgICAgd2hpbGUgKGF0dGVtcHRDb3VudGVyKysgPCBNQVhfUkVTSVpFX1JFVFJZX0NPVU5UICYmIChwYWdlUmVjdC53aWR0aCAhPT0gd2lkdGggfHwgcGFnZVJlY3QuaGVpZ2h0ICE9PSBoZWlnaHQpKSB7XG4gICAgICAgICAgICBjb25zdCBjdXJyZW50UmVjdCA9IGF3YWl0IHRoaXMuX3JlcXVlc3QoeyBjb21tYW5kOiBDT01NQU5EUy5nZXRXaW5kb3dSZWN0IH0pO1xuXG4gICAgICAgICAgICBhd2FpdCB0aGlzLl9yZXF1ZXN0KHtcbiAgICAgICAgICAgICAgICBjb21tYW5kOiBDT01NQU5EUy5zZXRXaW5kb3dSZWN0LFxuXG4gICAgICAgICAgICAgICAgcGFyYW1ldGVyczoge1xuICAgICAgICAgICAgICAgICAgICB4OiAgICAgIGN1cnJlbnRSZWN0LngsXG4gICAgICAgICAgICAgICAgICAgIHk6ICAgICAgY3VycmVudFJlY3QueSxcbiAgICAgICAgICAgICAgICAgICAgd2lkdGg6ICB3aWR0aCArIChjdXJyZW50UmVjdC53aWR0aCAtIHBhZ2VSZWN0LndpZHRoKSxcbiAgICAgICAgICAgICAgICAgICAgaGVpZ2h0OiBoZWlnaHQgKyAoY3VycmVudFJlY3QuaGVpZ2h0IC0gcGFnZVJlY3QuaGVpZ2h0KSxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICh7IHZhbHVlOiBwYWdlUmVjdCB9ID0gYXdhaXQgdGhpcy5leGVjdXRlU2NyaXB0KEdFVF9XSU5ET1dfRElNRU5TSU9OU19JTkZPX1NDUklQVCkpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgYXN5bmMgcXVpdCAoKSB7XG4gICAgICAgIGF3YWl0IHRoaXMuX3JlcXVlc3QoeyBjb21tYW5kOiBDT01NQU5EUy5xdWl0IH0pO1xuICAgIH1cblxuICAgIC8vIE5PVEU6IFRoaXMgbWV0aG9kIGlzIGVtcHR5IGJlY2F1c2Ugb2YgdGhlIGNvZGUgc3RydWN0dXJlXG4gICAgYXN5bmMgY2xvc2VCcm93c2VyQ2hpbGRXaW5kb3cgKCkge1xuICAgIH1cbn07XG5cbiJdfQ==