UNPKG

testcafe

Version:

Automated browser testing for the modern web development stack.

153 lines 19.3 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const debug_1 = __importDefault(require("debug")); const child_process_1 = require("child_process"); const lodash_1 = require("lodash"); const async_event_emitter_1 = __importDefault(require("../utils/async-event-emitter")); const delay_1 = __importDefault(require("../utils/delay")); const DEBUG_LOGGER_PREFIX = 'testcafe:video-recorder:process:'; const DEFAULT_OPTIONS = { // NOTE: use to force stdin and stdout formats 'f': 'image2pipe', // NOTE: don't ask confirmation for rewriting the output file 'y': true, // NOTE: use the time when a frame is read from the source as its timestamp // IMPORTANT: must be specified before configuring the source 'use_wallclock_as_timestamps': 1, // NOTE: use stdin as a source 'i': 'pipe:0', // NOTE: use the H.264 video codec 'c:v': 'libx264', // NOTE: use the 'ultrafast' compression preset 'preset': 'ultrafast', // NOTE: use the yuv420p pixel format (the most widely supported) 'pix_fmt': 'yuv420p', // NOTE: scale input frames to make the frame height divisible by 2 (yuv420p's requirement) 'vf': 'scale=trunc(iw/2)*2:trunc(ih/2)*2', // NOTE: set the frame rate to 30 in the output video (the most widely supported) 'r': 30, }; const FFMPEG_START_DELAY = 500; const DELAY_AFTER_EMPTY_FRAME = 20; class VideoRecorder extends async_event_emitter_1.default { constructor(basePath, ffmpegPath, connection, customOptions) { super(); this.debugLogger = (0, debug_1.default)(DEBUG_LOGGER_PREFIX + connection.id); this.customOptions = customOptions; this.videoPath = basePath; this.connection = connection; this.ffmpegPath = ffmpegPath; this.ffmpegProcess = null; this.ffmpegStdoutBuf = ''; this.ffmpegStderrBuf = ''; this.ffmpegClosingPromise = null; this.disposed = false; this.closed = false; this.optionsList = this._getOptionsList(); this.capturingPromise = null; } static _filterOption([key, value]) { if (value === true) return ['-' + key]; return ['-' + key, value]; } _setupFFMPEGBuffers() { this.ffmpegProcess.stdout.on('data', data => { this.ffmpegStdoutBuf += String(data); }); this.ffmpegProcess.stderr.on('data', data => { this.ffmpegStderrBuf += String(data); }); } _getChildProcessPromise() { return new Promise((resolve, reject) => { this.ffmpegProcess.on('exit', resolve); this.ffmpegProcess.on('error', reject); }); } _getOptionsList() { const optionsObject = Object.assign({}, DEFAULT_OPTIONS, this.customOptions); const optionsList = (0, lodash_1.flatten)(Object.entries(optionsObject).map(VideoRecorder._filterOption)); optionsList.push(this.videoPath); return optionsList; } get active() { return !this.closed && !this.disposed; } async _addFrame(frameData) { const writingFinished = this.ffmpegProcess.stdin.write(frameData); if (!writingFinished) await new Promise(r => this.ffmpegProcess.stdin.once('drain', r)); } async _capture() { while (this.active) { try { const frame = await this.connection.provider.getVideoFrameData(this.connection.id); if (frame) { await this.emit('frame'); await this._addFrame(frame); } else await (0, delay_1.default)(DELAY_AFTER_EMPTY_FRAME); } catch (error) { this.debugLogger(error); } } } async _startCapturing() { await this.connection.provider.startCapturingVideo(this.connection.id); } async _stopCapturing() { await this.connection.provider.stopCapturingVideo(this.connection.id); } async init() { this.ffmpegProcess = (0, child_process_1.spawn)(this.ffmpegPath, this.optionsList, { stdio: 'pipe' }); this._setupFFMPEGBuffers(); this.ffmpegClosingPromise = this ._getChildProcessPromise() .then(code => { this.closed = true; this.disposed = true; if (code) { this.debugLogger(code); this.debugLogger(this.ffmpegStdoutBuf); this.debugLogger(this.ffmpegStderrBuf); } }) .catch(error => { this.closed = true; this.disposed = true; this.debugLogger(error); this.debugLogger(this.ffmpegStdoutBuf); this.debugLogger(this.ffmpegStderrBuf); }); await (0, delay_1.default)(FFMPEG_START_DELAY); } async dispose() { if (this.disposed) return; this.disposed = true; this.ffmpegProcess.stdin.end(); await this.ffmpegClosingPromise; } async startCapturing() { await this._startCapturing(); this.capturingPromise = this._capture(); await this.once('frame'); } async finishCapturing() { if (this.closed) return; this.closed = true; await this._stopCapturing(); await this.capturingPromise; await this.dispose(); } } exports.default = VideoRecorder; module.exports = exports.default; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvY2Vzcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy92aWRlby1yZWNvcmRlci9wcm9jZXNzLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsa0RBQTBCO0FBQzFCLGlEQUFzQztBQUN0QyxtQ0FBaUM7QUFDakMsdUZBQXdEO0FBQ3hELDJEQUFtQztBQUduQyxNQUFNLG1CQUFtQixHQUFHLGtDQUFrQyxDQUFDO0FBRS9ELE1BQU0sZUFBZSxHQUFHO0lBRXBCLDhDQUE4QztJQUM5QyxHQUFHLEVBQUUsWUFBWTtJQUVqQiw2REFBNkQ7SUFDN0QsR0FBRyxFQUFFLElBQUk7SUFFVCwyRUFBMkU7SUFDM0UsNkRBQTZEO0lBQzdELDZCQUE2QixFQUFFLENBQUM7SUFFaEMsOEJBQThCO0lBQzlCLEdBQUcsRUFBRSxRQUFRO0lBRWIsa0NBQWtDO0lBQ2xDLEtBQUssRUFBRSxTQUFTO0lBRWhCLCtDQUErQztJQUMvQyxRQUFRLEVBQUUsV0FBVztJQUVyQixpRUFBaUU7SUFDakUsU0FBUyxFQUFFLFNBQVM7SUFFcEIsMkZBQTJGO0lBQzNGLElBQUksRUFBRSxtQ0FBbUM7SUFFekMsaUZBQWlGO0lBQ2pGLEdBQUcsRUFBRSxFQUFFO0NBQ1YsQ0FBQztBQUVGLE1BQU0sa0JBQWtCLEdBQUcsR0FBRyxDQUFDO0FBRS9CLE1BQU0sdUJBQXVCLEdBQUcsRUFBRSxDQUFDO0FBRW5DLE1BQXFCLGFBQWMsU0FBUSw2QkFBWTtJQUNuRCxZQUFhLFFBQVEsRUFBRSxVQUFVLEVBQUUsVUFBVSxFQUFFLGFBQWE7UUFDeEQsS0FBSyxFQUFFLENBQUM7UUFFUixJQUFJLENBQUMsV0FBVyxHQUFHLElBQUEsZUFBSyxFQUFDLG1CQUFtQixHQUFHLFVBQVUsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUU5RCxJQUFJLENBQUMsYUFBYSxHQUFHLGFBQWEsQ0FBQztRQUNuQyxJQUFJLENBQUMsU0FBUyxHQUFPLFFBQVEsQ0FBQztRQUM5QixJQUFJLENBQUMsVUFBVSxHQUFNLFVBQVUsQ0FBQztRQUNoQyxJQUFJLENBQUMsVUFBVSxHQUFNLFVBQVUsQ0FBQztRQUNoQyxJQUFJLENBQUMsYUFBYSxHQUFHLElBQUksQ0FBQztRQUUxQixJQUFJLENBQUMsZUFBZSxHQUFHLEVBQUUsQ0FBQztRQUMxQixJQUFJLENBQUMsZUFBZSxHQUFHLEVBQUUsQ0FBQztRQUUxQixJQUFJLENBQUMsb0JBQW9CLEdBQUcsSUFBSSxDQUFDO1FBRWpDLElBQUksQ0FBQyxRQUFRLEdBQUcsS0FBSyxDQUFDO1FBQ3RCLElBQUksQ0FBQyxNQUFNLEdBQUcsS0FBSyxDQUFDO1FBRXBCLElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO1FBRTFDLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxJQUFJLENBQUM7SUFDakMsQ0FBQztJQUVELE1BQU0sQ0FBQyxhQUFhLENBQUUsQ0FBQyxHQUFHLEVBQUUsS0FBSyxDQUFDO1FBQzlCLElBQUksS0FBSyxLQUFLLElBQUk7WUFDZCxPQUFPLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FBQyxDQUFDO1FBRXZCLE9BQU8sQ0FBQyxHQUFHLEdBQUcsR0FBRyxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBQzlCLENBQUM7SUFFRCxtQkFBbUI7UUFDZixJQUFJLENBQUMsYUFBYSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxFQUFFO1lBQ3hDLElBQUksQ0FBQyxlQUFlLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3pDLENBQUMsQ0FBQyxDQUFDO1FBRUgsSUFBSSxDQUFDLGFBQWEsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsRUFBRTtZQUN4QyxJQUFJLENBQUMsZUFBZSxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUN6QyxDQUFDLENBQUMsQ0FBQztJQUNQLENBQUM7SUFFRCx1QkFBdUI7UUFDbkIsT0FBTyxJQUFJLE9BQU8sQ0FBQyxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRTtZQUNuQyxJQUFJLENBQUMsYUFBYSxDQUFDLEVBQUUsQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUM7WUFDdkMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1FBQzNDLENBQUMsQ0FBQyxDQUFDO0lBQ1AsQ0FBQztJQUVELGVBQWU7UUFDWCxNQUFNLGFBQWEsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDLEVBQUUsRUFBRSxlQUFlLEVBQUUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBRTdFLE1BQU0sV0FBVyxHQUFHLElBQUEsZ0JBQU8sRUFBQyxNQUFNLENBQUMsT0FBTyxDQUFDLGFBQWEsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxhQUFhLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQztRQUU1RixXQUFXLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUVqQyxPQUFPLFdBQVcsQ0FBQztJQUN2QixDQUFDO0lBRUQsSUFBSSxNQUFNO1FBQ04sT0FBTyxDQUFDLElBQUksQ0FBQyxNQUFNLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDO0lBQzFDLENBQUM7SUFFRCxLQUFLLENBQUMsU0FBUyxDQUFFLFNBQVM7UUFDdEIsTUFBTSxlQUFlLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBRWxFLElBQUksQ0FBQyxlQUFlO1lBQ2hCLE1BQU0sSUFBSSxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDMUUsQ0FBQztJQUVELEtBQUssQ0FBQyxRQUFRO1FBQ1YsT0FBTyxJQUFJLENBQUMsTUFBTSxFQUFFO1lBQ2hCLElBQUk7Z0JBQ0EsTUFBTSxLQUFLLEdBQUcsTUFBTSxJQUFJLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQyxDQUFDO2dCQUVuRixJQUFJLEtBQUssRUFBRTtvQkFDUCxNQUFNLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7b0JBQ3pCLE1BQU0sSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQztpQkFDL0I7O29CQUVHLE1BQU0sSUFBQSxlQUFLLEVBQUMsdUJBQXVCLENBQUMsQ0FBQzthQUM1QztZQUNELE9BQU8sS0FBSyxFQUFFO2dCQUNWLElBQUksQ0FBQyxXQUFXLENBQUMsS0FBSyxDQUFDLENBQUM7YUFDM0I7U0FDSjtJQUNMLENBQUM7SUFFRCxLQUFLLENBQUMsZUFBZTtRQUNqQixNQUFNLElBQUksQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLG1CQUFtQixDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDM0UsQ0FBQztJQUVELEtBQUssQ0FBQyxjQUFjO1FBQ2hCLE1BQU0sSUFBSSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUMxRSxDQUFDO0lBRUQsS0FBSyxDQUFDLElBQUk7UUFDTixJQUFJLENBQUMsYUFBYSxHQUFHLElBQUEscUJBQUssRUFBQyxJQUFJLENBQUMsVUFBVSxFQUFFLElBQUksQ0FBQyxXQUFXLEVBQUUsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztRQUVqRixJQUFJLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztRQUUzQixJQUFJLENBQUMsb0JBQW9CLEdBQUcsSUFBSTthQUMzQix1QkFBdUIsRUFBRTthQUN6QixJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUU7WUFDVCxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQztZQUNuQixJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQztZQUVyQixJQUFJLElBQUksRUFBRTtnQkFDTixJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUN2QixJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQztnQkFDdkMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLENBQUM7YUFDMUM7UUFDTCxDQUFDLENBQUM7YUFDRCxLQUFLLENBQUMsS0FBSyxDQUFDLEVBQUU7WUFDWCxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQztZQUNuQixJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQztZQUVyQixJQUFJLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQ3hCLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxDQUFDO1lBQ3ZDLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxDQUFDO1FBQzNDLENBQUMsQ0FBQyxDQUFDO1FBRVAsTUFBTSxJQUFBLGVBQUssRUFBQyxrQkFBa0IsQ0FBQyxDQUFDO0lBQ3BDLENBQUM7SUFFRCxLQUFLLENBQUMsT0FBTztRQUNULElBQUksSUFBSSxDQUFDLFFBQVE7WUFDYixPQUFPO1FBRVgsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUM7UUFDckIsSUFBSSxDQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLENBQUM7UUFFL0IsTUFBTSxJQUFJLENBQUMsb0JBQW9CLENBQUM7SUFDcEMsQ0FBQztJQUVELEtBQUssQ0FBQyxjQUFjO1FBQ2hCLE1BQU0sSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO1FBRTdCLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7UUFFeEMsTUFBTSxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQzdCLENBQUM7SUFFRCxLQUFLLENBQUMsZUFBZTtRQUNqQixJQUFJLElBQUksQ0FBQyxNQUFNO1lBQ1gsT0FBTztRQUVYLElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDO1FBRW5CLE1BQU0sSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO1FBQzVCLE1BQU0sSUFBSSxDQUFDLGdCQUFnQixDQUFDO1FBQzVCLE1BQU0sSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBQ3pCLENBQUM7Q0FDSjtBQXpKRCxnQ0F5SkMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgZGVidWcgZnJvbSAnZGVidWcnO1xuaW1wb3J0IHsgc3Bhd24gfSBmcm9tICdjaGlsZF9wcm9jZXNzJztcbmltcG9ydCB7IGZsYXR0ZW4gfSBmcm9tICdsb2Rhc2gnO1xuaW1wb3J0IEFzeW5jRW1pdHRlciBmcm9tICcuLi91dGlscy9hc3luYy1ldmVudC1lbWl0dGVyJztcbmltcG9ydCBkZWxheSBmcm9tICcuLi91dGlscy9kZWxheSc7XG5cblxuY29uc3QgREVCVUdfTE9HR0VSX1BSRUZJWCA9ICd0ZXN0Y2FmZTp2aWRlby1yZWNvcmRlcjpwcm9jZXNzOic7XG5cbmNvbnN0IERFRkFVTFRfT1BUSU9OUyA9IHtcblxuICAgIC8vIE5PVEU6IHVzZSB0byBmb3JjZSBzdGRpbiBhbmQgc3Rkb3V0IGZvcm1hdHNcbiAgICAnZic6ICdpbWFnZTJwaXBlJyxcblxuICAgIC8vIE5PVEU6IGRvbid0IGFzayBjb25maXJtYXRpb24gZm9yIHJld3JpdGluZyB0aGUgb3V0cHV0IGZpbGVcbiAgICAneSc6IHRydWUsXG5cbiAgICAvLyBOT1RFOiB1c2UgdGhlIHRpbWUgd2hlbiBhIGZyYW1lIGlzIHJlYWQgZnJvbSB0aGUgc291cmNlIGFzIGl0cyB0aW1lc3RhbXBcbiAgICAvLyBJTVBPUlRBTlQ6IG11c3QgYmUgc3BlY2lmaWVkIGJlZm9yZSBjb25maWd1cmluZyB0aGUgc291cmNlXG4gICAgJ3VzZV93YWxsY2xvY2tfYXNfdGltZXN0YW1wcyc6IDEsXG5cbiAgICAvLyBOT1RFOiB1c2Ugc3RkaW4gYXMgYSBzb3VyY2VcbiAgICAnaSc6ICdwaXBlOjAnLFxuXG4gICAgLy8gTk9URTogdXNlIHRoZSBILjI2NCB2aWRlbyBjb2RlY1xuICAgICdjOnYnOiAnbGlieDI2NCcsXG5cbiAgICAvLyBOT1RFOiB1c2UgdGhlICd1bHRyYWZhc3QnIGNvbXByZXNzaW9uIHByZXNldFxuICAgICdwcmVzZXQnOiAndWx0cmFmYXN0JyxcblxuICAgIC8vIE5PVEU6IHVzZSB0aGUgeXV2NDIwcCBwaXhlbCBmb3JtYXQgKHRoZSBtb3N0IHdpZGVseSBzdXBwb3J0ZWQpXG4gICAgJ3BpeF9mbXQnOiAneXV2NDIwcCcsXG5cbiAgICAvLyBOT1RFOiBzY2FsZSBpbnB1dCBmcmFtZXMgdG8gbWFrZSB0aGUgZnJhbWUgaGVpZ2h0IGRpdmlzaWJsZSBieSAyICh5dXY0MjBwJ3MgcmVxdWlyZW1lbnQpXG4gICAgJ3ZmJzogJ3NjYWxlPXRydW5jKGl3LzIpKjI6dHJ1bmMoaWgvMikqMicsXG5cbiAgICAvLyBOT1RFOiBzZXQgdGhlIGZyYW1lIHJhdGUgdG8gMzAgaW4gdGhlIG91dHB1dCB2aWRlbyAodGhlIG1vc3Qgd2lkZWx5IHN1cHBvcnRlZClcbiAgICAncic6IDMwLFxufTtcblxuY29uc3QgRkZNUEVHX1NUQVJUX0RFTEFZID0gNTAwO1xuXG5jb25zdCBERUxBWV9BRlRFUl9FTVBUWV9GUkFNRSA9IDIwO1xuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBWaWRlb1JlY29yZGVyIGV4dGVuZHMgQXN5bmNFbWl0dGVyIHtcbiAgICBjb25zdHJ1Y3RvciAoYmFzZVBhdGgsIGZmbXBlZ1BhdGgsIGNvbm5lY3Rpb24sIGN1c3RvbU9wdGlvbnMpIHtcbiAgICAgICAgc3VwZXIoKTtcblxuICAgICAgICB0aGlzLmRlYnVnTG9nZ2VyID0gZGVidWcoREVCVUdfTE9HR0VSX1BSRUZJWCArIGNvbm5lY3Rpb24uaWQpO1xuXG4gICAgICAgIHRoaXMuY3VzdG9tT3B0aW9ucyA9IGN1c3RvbU9wdGlvbnM7XG4gICAgICAgIHRoaXMudmlkZW9QYXRoICAgICA9IGJhc2VQYXRoO1xuICAgICAgICB0aGlzLmNvbm5lY3Rpb24gICAgPSBjb25uZWN0aW9uO1xuICAgICAgICB0aGlzLmZmbXBlZ1BhdGggICAgPSBmZm1wZWdQYXRoO1xuICAgICAgICB0aGlzLmZmbXBlZ1Byb2Nlc3MgPSBudWxsO1xuXG4gICAgICAgIHRoaXMuZmZtcGVnU3Rkb3V0QnVmID0gJyc7XG4gICAgICAgIHRoaXMuZmZtcGVnU3RkZXJyQnVmID0gJyc7XG5cbiAgICAgICAgdGhpcy5mZm1wZWdDbG9zaW5nUHJvbWlzZSA9IG51bGw7XG5cbiAgICAgICAgdGhpcy5kaXNwb3NlZCA9IGZhbHNlO1xuICAgICAgICB0aGlzLmNsb3NlZCA9IGZhbHNlO1xuXG4gICAgICAgIHRoaXMub3B0aW9uc0xpc3QgPSB0aGlzLl9nZXRPcHRpb25zTGlzdCgpO1xuXG4gICAgICAgIHRoaXMuY2FwdHVyaW5nUHJvbWlzZSA9IG51bGw7XG4gICAgfVxuXG4gICAgc3RhdGljIF9maWx0ZXJPcHRpb24gKFtrZXksIHZhbHVlXSkge1xuICAgICAgICBpZiAodmFsdWUgPT09IHRydWUpXG4gICAgICAgICAgICByZXR1cm4gWyctJyArIGtleV07XG5cbiAgICAgICAgcmV0dXJuIFsnLScgKyBrZXksIHZhbHVlXTtcbiAgICB9XG5cbiAgICBfc2V0dXBGRk1QRUdCdWZmZXJzICgpIHtcbiAgICAgICAgdGhpcy5mZm1wZWdQcm9jZXNzLnN0ZG91dC5vbignZGF0YScsIGRhdGEgPT4ge1xuICAgICAgICAgICAgdGhpcy5mZm1wZWdTdGRvdXRCdWYgKz0gU3RyaW5nKGRhdGEpO1xuICAgICAgICB9KTtcblxuICAgICAgICB0aGlzLmZmbXBlZ1Byb2Nlc3Muc3RkZXJyLm9uKCdkYXRhJywgZGF0YSA9PiB7XG4gICAgICAgICAgICB0aGlzLmZmbXBlZ1N0ZGVyckJ1ZiArPSBTdHJpbmcoZGF0YSk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIF9nZXRDaGlsZFByb2Nlc3NQcm9taXNlICgpIHtcbiAgICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgICAgIHRoaXMuZmZtcGVnUHJvY2Vzcy5vbignZXhpdCcsIHJlc29sdmUpO1xuICAgICAgICAgICAgdGhpcy5mZm1wZWdQcm9jZXNzLm9uKCdlcnJvcicsIHJlamVjdCk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIF9nZXRPcHRpb25zTGlzdCAoKSB7XG4gICAgICAgIGNvbnN0IG9wdGlvbnNPYmplY3QgPSBPYmplY3QuYXNzaWduKHt9LCBERUZBVUxUX09QVElPTlMsIHRoaXMuY3VzdG9tT3B0aW9ucyk7XG5cbiAgICAgICAgY29uc3Qgb3B0aW9uc0xpc3QgPSBmbGF0dGVuKE9iamVjdC5lbnRyaWVzKG9wdGlvbnNPYmplY3QpLm1hcChWaWRlb1JlY29yZGVyLl9maWx0ZXJPcHRpb24pKTtcblxuICAgICAgICBvcHRpb25zTGlzdC5wdXNoKHRoaXMudmlkZW9QYXRoKTtcblxuICAgICAgICByZXR1cm4gb3B0aW9uc0xpc3Q7XG4gICAgfVxuXG4gICAgZ2V0IGFjdGl2ZSAoKSB7XG4gICAgICAgIHJldHVybiAhdGhpcy5jbG9zZWQgJiYgIXRoaXMuZGlzcG9zZWQ7XG4gICAgfVxuXG4gICAgYXN5bmMgX2FkZEZyYW1lIChmcmFtZURhdGEpIHtcbiAgICAgICAgY29uc3Qgd3JpdGluZ0ZpbmlzaGVkID0gdGhpcy5mZm1wZWdQcm9jZXNzLnN0ZGluLndyaXRlKGZyYW1lRGF0YSk7XG5cbiAgICAgICAgaWYgKCF3cml0aW5nRmluaXNoZWQpXG4gICAgICAgICAgICBhd2FpdCBuZXcgUHJvbWlzZShyID0+IHRoaXMuZmZtcGVnUHJvY2Vzcy5zdGRpbi5vbmNlKCdkcmFpbicsIHIpKTtcbiAgICB9XG5cbiAgICBhc3luYyBfY2FwdHVyZSAoKSB7XG4gICAgICAgIHdoaWxlICh0aGlzLmFjdGl2ZSkge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICBjb25zdCBmcmFtZSA9IGF3YWl0IHRoaXMuY29ubmVjdGlvbi5wcm92aWRlci5nZXRWaWRlb0ZyYW1lRGF0YSh0aGlzLmNvbm5lY3Rpb24uaWQpO1xuXG4gICAgICAgICAgICAgICAgaWYgKGZyYW1lKSB7XG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMuZW1pdCgnZnJhbWUnKTtcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5fYWRkRnJhbWUoZnJhbWUpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IGRlbGF5KERFTEFZX0FGVEVSX0VNUFRZX0ZSQU1FKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgICAgIHRoaXMuZGVidWdMb2dnZXIoZXJyb3IpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgYXN5bmMgX3N0YXJ0Q2FwdHVyaW5nICgpIHtcbiAgICAgICAgYXdhaXQgdGhpcy5jb25uZWN0aW9uLnByb3ZpZGVyLnN0YXJ0Q2FwdHVyaW5nVmlkZW8odGhpcy5jb25uZWN0aW9uLmlkKTtcbiAgICB9XG5cbiAgICBhc3luYyBfc3RvcENhcHR1cmluZyAoKSB7XG4gICAgICAgIGF3YWl0IHRoaXMuY29ubmVjdGlvbi5wcm92aWRlci5zdG9wQ2FwdHVyaW5nVmlkZW8odGhpcy5jb25uZWN0aW9uLmlkKTtcbiAgICB9XG5cbiAgICBhc3luYyBpbml0ICgpIHtcbiAgICAgICAgdGhpcy5mZm1wZWdQcm9jZXNzID0gc3Bhd24odGhpcy5mZm1wZWdQYXRoLCB0aGlzLm9wdGlvbnNMaXN0LCB7IHN0ZGlvOiAncGlwZScgfSk7XG5cbiAgICAgICAgdGhpcy5fc2V0dXBGRk1QRUdCdWZmZXJzKCk7XG5cbiAgICAgICAgdGhpcy5mZm1wZWdDbG9zaW5nUHJvbWlzZSA9IHRoaXNcbiAgICAgICAgICAgIC5fZ2V0Q2hpbGRQcm9jZXNzUHJvbWlzZSgpXG4gICAgICAgICAgICAudGhlbihjb2RlID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLmNsb3NlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgdGhpcy5kaXNwb3NlZCA9IHRydWU7XG5cbiAgICAgICAgICAgICAgICBpZiAoY29kZSkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmRlYnVnTG9nZ2VyKGNvZGUpO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmRlYnVnTG9nZ2VyKHRoaXMuZmZtcGVnU3Rkb3V0QnVmKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5kZWJ1Z0xvZ2dlcih0aGlzLmZmbXBlZ1N0ZGVyckJ1Zik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIC5jYXRjaChlcnJvciA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5jbG9zZWQgPSB0cnVlO1xuICAgICAgICAgICAgICAgIHRoaXMuZGlzcG9zZWQgPSB0cnVlO1xuXG4gICAgICAgICAgICAgICAgdGhpcy5kZWJ1Z0xvZ2dlcihlcnJvcik7XG4gICAgICAgICAgICAgICAgdGhpcy5kZWJ1Z0xvZ2dlcih0aGlzLmZmbXBlZ1N0ZG91dEJ1Zik7XG4gICAgICAgICAgICAgICAgdGhpcy5kZWJ1Z0xvZ2dlcih0aGlzLmZmbXBlZ1N0ZGVyckJ1Zik7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICBhd2FpdCBkZWxheShGRk1QRUdfU1RBUlRfREVMQVkpO1xuICAgIH1cblxuICAgIGFzeW5jIGRpc3Bvc2UgKCkge1xuICAgICAgICBpZiAodGhpcy5kaXNwb3NlZClcbiAgICAgICAgICAgIHJldHVybjtcblxuICAgICAgICB0aGlzLmRpc3Bvc2VkID0gdHJ1ZTtcbiAgICAgICAgdGhpcy5mZm1wZWdQcm9jZXNzLnN0ZGluLmVuZCgpO1xuXG4gICAgICAgIGF3YWl0IHRoaXMuZmZtcGVnQ2xvc2luZ1Byb21pc2U7XG4gICAgfVxuXG4gICAgYXN5bmMgc3RhcnRDYXB0dXJpbmcgKCkge1xuICAgICAgICBhd2FpdCB0aGlzLl9zdGFydENhcHR1cmluZygpO1xuXG4gICAgICAgIHRoaXMuY2FwdHVyaW5nUHJvbWlzZSA9IHRoaXMuX2NhcHR1cmUoKTtcblxuICAgICAgICBhd2FpdCB0aGlzLm9uY2UoJ2ZyYW1lJyk7XG4gICAgfVxuXG4gICAgYXN5bmMgZmluaXNoQ2FwdHVyaW5nICgpIHtcbiAgICAgICAgaWYgKHRoaXMuY2xvc2VkKVxuICAgICAgICAgICAgcmV0dXJuO1xuXG4gICAgICAgIHRoaXMuY2xvc2VkID0gdHJ1ZTtcblxuICAgICAgICBhd2FpdCB0aGlzLl9zdG9wQ2FwdHVyaW5nKCk7XG4gICAgICAgIGF3YWl0IHRoaXMuY2FwdHVyaW5nUHJvbWlzZTtcbiAgICAgICAgYXdhaXQgdGhpcy5kaXNwb3NlKCk7XG4gICAgfVxufVxuIl19