testcafe
Version:
Automated browser testing for the modern web development stack.
146 lines • 19.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 child_process_1 = require("child_process");
const debug_1 = __importDefault(require("debug"));
const promisify_event_1 = __importDefault(require("promisify-event"));
const pinkie_1 = __importDefault(require("pinkie"));
const promisified_functions_1 = require("../../promisified-functions");
const commands_1 = __importDefault(require("./commands"));
const WORKER_PATH = require.resolve('./worker');
const WORKER_STDIO_CONFIG = ['ignore', 'pipe', 'pipe', 'ipc'];
const DEBUG_LOGGER = debug_1.default('testcafe:utils:temp-directory:cleanup-process');
class CleanupProcess {
constructor() {
this.worker = null;
this.initialized = false;
this.initPromise = pinkie_1.default.resolve(void 0);
this.errorPromise = null;
this.messageCounter = 0;
this.pendingResponses = {};
}
_sendMessage(id, msg) {
return pinkie_1.default.race([
promisified_functions_1.sendMessageToChildProcess(this.worker, Object.assign({ id }, msg)),
this._waitProcessError()
]);
}
_onResponse(response) {
const pendingResponse = this.pendingResponses[response.id];
if (response.error) {
if (pendingResponse)
pendingResponse.control.reject(response.error);
else
this.pendingResponses[response.id] = pinkie_1.default.reject(response.error);
}
else if (pendingResponse)
pendingResponse.control.resolve();
else
this.pendingResponses[response.id] = pinkie_1.default.resolve();
}
async _waitResponse(id) {
if (!this.pendingResponses[id]) {
const promiseControl = {};
this.pendingResponses[id] = new pinkie_1.default((resolve, reject) => {
Object.assign(promiseControl, { resolve, reject });
});
this.pendingResponses[id].control = promiseControl;
}
try {
await this.pendingResponses[id];
}
finally {
delete this.pendingResponses[id];
}
}
async _waitResponseForMessage(msg) {
const currentId = this.messageCounter;
this.messageCounter++;
await this._sendMessage(currentId, msg);
await this._waitResponse(currentId);
}
_waitProcessExit() {
return promisify_event_1.default(this.worker, 'exit')
.then(exitCode => pinkie_1.default.reject(new Error(`Worker process terminated with code ${exitCode}`)));
}
_waitProcessError() {
if (this.errorPromise)
return this.errorPromise;
this.errorPromise = promisify_event_1.default(this.worker, 'error');
this.errorPromise.then(() => {
this.errorPromise = null;
});
return this.errorPromise;
}
_setupWorkerEventHandlers() {
this.worker.on('message', message => this._onResponse(message));
this.worker.stdout.on('data', data => DEBUG_LOGGER('Worker process stdout:\n', String(data)));
this.worker.stderr.on('data', data => DEBUG_LOGGER('Worker process stderr:\n', String(data)));
}
_unrefWorkerProcess() {
this.worker.unref();
this.worker.stdout.unref();
this.worker.stderr.unref();
const channel = this.worker.channel || this.worker._channel;
channel.unref();
}
_handleProcessError(error) {
this.initialized = false;
DEBUG_LOGGER(error);
}
init() {
this.initPromise = this.initPromise
.then(async (initialized) => {
if (initialized !== void 0)
return initialized;
this.worker = child_process_1.spawn(process.argv[0], [WORKER_PATH], { detached: true, stdio: WORKER_STDIO_CONFIG });
this._setupWorkerEventHandlers();
this._unrefWorkerProcess();
const exitPromise = this._waitProcessExit();
try {
await pinkie_1.default.race([
this._waitResponseForMessage({ command: commands_1.default.init }),
this._waitProcessError(),
exitPromise
]);
this.initialized = true;
exitPromise.catch(error => this._handleProcessError(error));
this.worker.on('error', error => this._handleProcessError(error));
}
catch (e) {
DEBUG_LOGGER('Failed to start cleanup process');
DEBUG_LOGGER(e);
this.initialized = false;
}
return this.initialized;
});
return this.initPromise;
}
async addDirectory(path) {
if (!this.initialized)
return;
try {
await this._waitResponseForMessage({ command: commands_1.default.add, path });
}
catch (e) {
DEBUG_LOGGER(`Failed to add the ${path} directory to cleanup process`);
DEBUG_LOGGER(e);
}
}
async removeDirectory(path) {
if (!this.initialized)
return;
try {
await this._waitResponseForMessage({ command: commands_1.default.remove, path });
}
catch (e) {
DEBUG_LOGGER(`Failed to remove the ${path} directory in cleanup process`);
DEBUG_LOGGER(e);
}
}
}
exports.default = new CleanupProcess();
module.exports = exports.default;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvdXRpbHMvdGVtcC1kaXJlY3RvcnkvY2xlYW51cC1wcm9jZXNzL2luZGV4LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsaURBQXNDO0FBQ3RDLGtEQUEwQjtBQUMxQixzRUFBNkM7QUFDN0Msb0RBQTZCO0FBQzdCLHVFQUF3RTtBQUN4RSwwREFBa0M7QUFHbEMsTUFBTSxXQUFXLEdBQVcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQztBQUN4RCxNQUFNLG1CQUFtQixHQUFHLENBQUMsUUFBUSxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsS0FBSyxDQUFDLENBQUM7QUFFOUQsTUFBTSxZQUFZLEdBQUcsZUFBSyxDQUFDLCtDQUErQyxDQUFDLENBQUM7QUFFNUUsTUFBTSxjQUFjO0lBQ2hCO1FBQ0ksSUFBSSxDQUFDLE1BQU0sR0FBUyxJQUFJLENBQUM7UUFDekIsSUFBSSxDQUFDLFdBQVcsR0FBSSxLQUFLLENBQUM7UUFDMUIsSUFBSSxDQUFDLFdBQVcsR0FBSSxnQkFBTyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO1FBQzVDLElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxDQUFDO1FBRXpCLElBQUksQ0FBQyxjQUFjLEdBQUcsQ0FBQyxDQUFDO1FBRXhCLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxFQUFFLENBQUM7SUFDL0IsQ0FBQztJQUVELFlBQVksQ0FBRSxFQUFFLEVBQUUsR0FBRztRQUNqQixPQUFPLGdCQUFPLENBQUMsSUFBSSxDQUFDO1lBQ2hCLGlEQUF5QixDQUFDLElBQUksQ0FBQyxNQUFNLGtCQUFJLEVBQUUsSUFBSyxHQUFHLEVBQUc7WUFDdEQsSUFBSSxDQUFDLGlCQUFpQixFQUFFO1NBQzNCLENBQUMsQ0FBQztJQUNQLENBQUM7SUFFRCxXQUFXLENBQUUsUUFBUTtRQUNqQixNQUFNLGVBQWUsR0FB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WUFBWSxDQUFDLHFCQUFxQixJQUFJLCtCQUErQixDQUFDLENBQUM7WUFDdkUsWUFBWSxDQUFDLENBQUMsQ0FBQyxDQUFDO1NBQ25CO0lBQ0wsQ0FBQztJQUVELEtBQUssQ0FBQyxlQUFlLENBQUUsSUFBSTtRQUN2QixJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVc7WUFDakIsT0FBTztRQUVYLElBQUk7WUFDQSxNQUFNLElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxFQUFFLE9BQU8sRUFBRSxrQkFBUSxDQUFDLE1BQU0sRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO1NBQzFFO1FBQ0QsT0FBTyxDQUFDLEVBQUU7WUFDTixZQUFZLENBQUMsd0JBQXdCLElBQUksK0JBQStCLENBQUMsQ0FBQztZQUMxRSxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUM7U0FDbkI7SUFDTCxDQUFDO0NBQ0o7QUFFRCxrQkFBZSxJQUFJLGNBQWMsRUFBRSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgc3Bhd24gfSBmcm9tICdjaGlsZF9wcm9jZXNzJztcbmltcG9ydCBkZWJ1ZyBmcm9tICdkZWJ1Zyc7XG5pbXBvcnQgcHJvbWlzaWZ5RXZlbnQgZnJvbSAncHJvbWlzaWZ5LWV2ZW50JztcbmltcG9ydCBQcm9taXNlIGZyb20gJ3BpbmtpZSc7XG5pbXBvcnQgeyBzZW5kTWVzc2FnZVRvQ2hpbGRQcm9jZXNzIH0gZnJvbSAnLi4vLi4vcHJvbWlzaWZpZWQtZnVuY3Rpb25zJztcbmltcG9ydCBDT01NQU5EUyBmcm9tICcuL2NvbW1hbmRzJztcblxuXG5jb25zdCBXT1JLRVJfUEFUSCAgICAgICAgID0gcmVxdWlyZS5yZXNvbHZlKCcuL3dvcmtlcicpO1xuY29uc3QgV09SS0VSX1NURElPX0NPTkZJRyA9IFsnaWdub3JlJywgJ3BpcGUnLCAncGlwZScsICdpcGMnXTtcblxuY29uc3QgREVCVUdfTE9HR0VSID0gZGVidWcoJ3Rlc3RjYWZlOnV0aWxzOnRlbXAtZGlyZWN0b3J5OmNsZWFudXAtcHJvY2VzcycpO1xuXG5jbGFzcyBDbGVhbnVwUHJvY2VzcyB7XG4gICAgY29uc3RydWN0b3IgKCkge1xuICAgICAgICB0aGlzLndvcmtlciAgICAgICA9IG51bGw7XG4gICAgICAgIHRoaXMuaW5pdGlhbGl6ZWQgID0gZmFsc2U7XG4gICAgICAgIHRoaXMuaW5pdFByb21pc2UgID0gUHJvbWlzZS5yZXNvbHZlKHZvaWQgMCk7XG4gICAgICAgIHRoaXMuZXJyb3JQcm9taXNlID0gbnVsbDtcblxuICAgICAgICB0aGlzLm1lc3NhZ2VDb3VudGVyID0gMDtcblxuICAgICAgICB0aGlzLnBlbmRpbmdSZXNwb25zZXMgPSB7fTtcbiAgICB9XG5cbiAgICBfc2VuZE1lc3NhZ2UgKGlkLCBtc2cpIHtcbiAgICAgICAgcmV0dXJuIFByb21pc2UucmFjZShbXG4gICAgICAgICAgICBzZW5kTWVzc2FnZVRvQ2hpbGRQcm9jZXNzKHRoaXMud29ya2VyLCB7IGlkLCAuLi5tc2cgfSksXG4gICAgICAgICAgICB0aGlzLl93YWl0UHJvY2Vzc0Vycm9yKClcbiAgICAgICAgXSk7XG4gICAgfVxuXG4gICAgX29uUmVzcG9uc2UgKHJlc3BvbnNlKSB7XG4gICAgICAgIGNvbnN0IHBlbmRpbmdSZXNwb25zZSA9IHRoaXMucGVuZGluZ1Jlc3BvbnNlc1tyZXNwb25zZS5pZF07XG5cbiAgICAgICAgaWYgKHJlc3BvbnNlLmVycm9yKSB7XG4gICAgICAgICAgICBpZiAocGVuZGluZ1Jlc3BvbnNlKVxuICAgICAgICAgICAgICAgIHBlbmRpbmdSZXNwb25zZS5jb250cm9sLnJlamVjdChyZXNwb25zZS5lcnJvcik7XG4gICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgdGhpcy5wZW5kaW5nUmVzcG9uc2VzW3Jlc3BvbnNlLmlkXSA9IFByb21pc2UucmVqZWN0KHJlc3BvbnNlLmVycm9yKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChwZW5kaW5nUmVzcG9uc2UpXG4gICAgICAgICAgICBwZW5kaW5nUmVzcG9uc2UuY29udHJvbC5yZXNvbHZlKCk7XG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIHRoaXMucGVuZGluZ1Jlc3BvbnNlc1tyZXNwb25zZS5pZF0gPSBQcm9taXNlLnJlc29sdmUoKTtcbiAgICB9XG5cbiAgICBhc3luYyBfd2FpdFJlc3BvbnNlIChpZCkge1xuICAgICAgICBpZiAoIXRoaXMucGVuZGluZ1Jlc3BvbnNlc1tpZF0pIHtcbiAgICAgICAgICAgIGNvbnN0IHByb21pc2VDb250cm9sID0ge307XG5cbiAgICAgICAgICAgIHRoaXMucGVuZGluZ1Jlc3BvbnNlc1tpZF0gPSBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgICAgICAgICAgT2JqZWN0LmFzc2lnbihwcm9taXNlQ29udHJvbCwgeyByZXNvbHZlLCByZWplY3QgfSk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgdGhpcy5wZW5kaW5nUmVzcG9uc2VzW2lkXS5jb250cm9sID0gcHJvbWlzZUNvbnRyb2w7XG4gICAgICAgIH1cblxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5wZW5kaW5nUmVzcG9uc2VzW2lkXTtcbiAgICAgICAgfVxuICAgICAgICBmaW5hbGx5IHtcbiAgICAgICAgICAgIGRlbGV0ZSB0aGlzLnBlbmRpbmdSZXNwb25zZXNbaWRdO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgYXN5bmMgX3dhaXRSZXNwb25zZUZvck1lc3NhZ2UgKG1zZykge1xuICAgICAgICBjb25zdCBjdXJyZW50SWQgPSB0aGlzLm1lc3NhZ2VDb3VudGVyO1xuXG4gICAgICAgIHRoaXMubWVzc2FnZUNvdW50ZXIrKztcblxuICAgICAgICBhd2FpdCB0aGlzLl9zZW5kTWVzc2FnZShjdXJyZW50SWQsIG1zZyk7XG4gICAgICAgIGF3YWl0IHRoaXMuX3dhaXRSZXNwb25zZShjdXJyZW50SWQpO1xuICAgIH1cblxuICAgIF93YWl0UHJvY2Vzc0V4aXQgKCkge1xuICAgICAgICByZXR1cm4gcHJvbWlzaWZ5RXZlbnQodGhpcy53b3JrZXIsICdleGl0JylcbiAgICAgICAgICAgIC50aGVuKGV4aXRDb2RlID0+IFByb21pc2UucmVqZWN0KG5ldyBFcnJvcihgV29ya2VyIHByb2Nlc3MgdGVybWluYXRlZCB3aXRoIGNvZGUgJHtleGl0Q29kZX1gKSkpO1xuICAgIH1cblxuICAgIF93YWl0UHJvY2Vzc0Vycm9yICgpIHtcbiAgICAgICAgaWYgKHRoaXMuZXJyb3JQcm9taXNlKVxuICAgICAgICAgICAgcmV0dXJuIHRoaXMuZXJyb3JQcm9taXNlO1xuXG4gICAgICAgIHRoaXMuZXJyb3JQcm9taXNlID0gcHJvbWlzaWZ5RXZlbnQodGhpcy53b3JrZXIsICdlcnJvcicpO1xuXG4gICAgICAgIHRoaXMuZXJyb3JQcm9taXNlLnRoZW4oKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5lcnJvclByb21pc2UgPSBudWxsO1xuICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gdGhpcy5lcnJvclByb21pc2U7XG4gICAgfVxuXG4gICAgX3NldHVwV29ya2VyRXZlbnRIYW5kbGVycyAoKSB7XG4gICAgICAgIHRoaXMud29ya2VyLm9uKCdtZXNzYWdlJywgbWVzc2FnZSA9PiB0aGlzLl9vblJlc3BvbnNlKG1lc3NhZ2UpKTtcblxuICAgICAgICB0aGlzLndvcmtlci5zdGRvdXQub24oJ2RhdGEnLCBkYXRhID0+IERFQlVHX0xPR0dFUignV29ya2VyIHByb2Nlc3Mgc3Rkb3V0OlxcbicsIFN0cmluZyhkYXRhKSkpO1xuICAgICAgICB0aGlzLndvcmtlci5zdGRlcnIub24oJ2RhdGEnLCBkYXRhID0+IERFQlVHX0xPR0dFUignV29ya2VyIHByb2Nlc3Mgc3RkZXJyOlxcbicsIFN0cmluZyhkYXRhKSkpO1xuICAgIH1cblxuICAgIF91bnJlZldvcmtlclByb2Nlc3MgKCkge1xuICAgICAgICB0aGlzLndvcmtlci51bnJlZigpO1xuICAgICAgICB0aGlzLndvcmtlci5zdGRvdXQudW5yZWYoKTtcbiAgICAgICAgdGhpcy53b3JrZXIuc3RkZXJyLnVucmVmKCk7XG5cbiAgICAgICAgY29uc3QgY2hhbm5lbCA9IHRoaXMud29ya2VyLmNoYW5uZWwgfHwgdGhpcy53b3JrZXIuX2NoYW5uZWw7XG5cbiAgICAgICAgY2hhbm5lbC51bnJlZigpO1xuICAgIH1cblxuICAgIF9oYW5kbGVQcm9jZXNzRXJyb3IgKGVycm9yKSB7XG4gICAgICAgIHRoaXMuaW5pdGlhbGl6ZWQgPSBmYWxzZTtcblxuICAgICAgICBERUJVR19MT0dHRVIoZXJyb3IpO1xuICAgIH1cblxuICAgIGluaXQgKCkge1xuICAgICAgICB0aGlzLmluaXRQcm9taXNlID0gdGhpcy5pbml0UHJvbWlzZVxuICAgICAgICAgICAgLnRoZW4oYXN5bmMgaW5pdGlhbGl6ZWQgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChpbml0aWFsaXplZCAhPT0gdm9pZCAwKVxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gaW5pdGlhbGl6ZWQ7XG5cbiAgICAgICAgICAgICAgICB0aGlzLndvcmtlciA9IHNwYXduKHByb2Nlc3MuYXJndlswXSwgW1dPUktFUl9QQVRIXSwgeyBkZXRhY2hlZDogdHJ1ZSwgc3RkaW86IFdPUktFUl9TVERJT19DT05GSUcgfSk7XG5cbiAgICAgICAgICAgICAgICB0aGlzLl9zZXR1cFdvcmtlckV2ZW50SGFuZGxlcnMoKTtcbiAgICAgICAgICAgICAgICB0aGlzLl91bnJlZldvcmtlclByb2Nlc3MoKTtcblxuICAgICAgICAgICAgICAgIGNvbnN0IGV4aXRQcm9taXNlID0gdGhpcy5fd2FpdFByb2Nlc3NFeGl0KCk7XG5cbiAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICBhd2FpdCBQcm9taXNlLnJhY2UoW1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5fd2FpdFJlc3BvbnNlRm9yTWVzc2FnZSh7IGNvbW1hbmQ6IENPTU1BTkRTLmluaXQgfSksXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLl93YWl0UHJvY2Vzc0Vycm9yKCksXG4gICAgICAgICAgICAgICAgICAgICAgICBleGl0UHJvbWlzZVxuICAgICAgICAgICAgICAgICAgICBdKTtcblxuICAgICAgICAgICAgICAgICAgICB0aGlzLmluaXRpYWxpemVkID0gdHJ1ZTtcblxuICAgICAgICAgICAgICAgICAgICBleGl0UHJvbWlzZS5jYXRjaChlcnJvciA9PiB0aGlzLl9oYW5kbGVQcm9jZXNzRXJyb3IoZXJyb3IpKTtcblxuICAgICAgICAgICAgICAgICAgICB0aGlzLndvcmtlci5vbignZXJyb3InLCBlcnJvciA9PiB0aGlzLl9oYW5kbGVQcm9jZXNzRXJyb3IoZXJyb3IpKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICAgICAgREVCVUdfTE9HR0VSKCdGYWlsZWQgdG8gc3RhcnQgY2xlYW51cCBwcm9jZXNzJyk7XG4gICAgICAgICAgICAgICAgICAgIERFQlVHX0xPR0dFUihlKTtcblxuICAgICAgICAgICAgICAgICAgICB0aGlzLmluaXRpYWxpemVkID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuaW5pdGlhbGl6ZWQ7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gdGhpcy5pbml0UHJvbWlzZTtcbiAgICB9XG5cbiAgICBhc3luYyBhZGREaXJlY3RvcnkgKHBhdGgpIHtcbiAgICAgICAgaWYgKCF0aGlzLmluaXRpYWxpemVkKVxuICAgICAgICAgICAgcmV0dXJuO1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLl93YWl0UmVzcG9uc2VGb3JNZXNzYWdlKHsgY29tbWFuZDogQ09NTUFORFMuYWRkLCBwYXRoIH0pO1xuICAgICAgICB9XG4gICAgICAgIGNhdGNoIChlKSB7XG4gICAgICAgICAgICBERUJVR19MT0dHRVIoYEZhaWxlZCB0byBhZGQgdGhlICR7cGF0aH0gZGlyZWN0b3J5IHRvIGNsZWFudXAgcHJvY2Vzc2ApO1xuICAgICAgICAgICAgREVCVUdfTE9HR0VSKGUpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgYXN5bmMgcmVtb3ZlRGlyZWN0b3J5IChwYXRoKSB7XG4gICAgICAgIGlmICghdGhpcy5pbml0aWFsaXplZClcbiAgICAgICAgICAgIHJldHVybjtcblxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5fd2FpdFJlc3BvbnNlRm9yTWVzc2FnZSh7IGNvbW1hbmQ6IENPTU1BTkRTLnJlbW92ZSwgcGF0aCB9KTtcbiAgICAgICAgfVxuICAgICAgICBjYXRjaCAoZSkge1xuICAgICAgICAgICAgREVCVUdfTE9HR0VSKGBGYWlsZWQgdG8gcmVtb3ZlIHRoZSAke3BhdGh9IGRpcmVjdG9yeSBpbiBjbGVhbnVwIHByb2Nlc3NgKTtcbiAgICAgICAgICAgIERFQlVHX0xPR0dFUihlKTtcbiAgICAgICAgfVxuICAgIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgbmV3IENsZWFudXBQcm9jZXNzKCk7XG4iXX0=