UNPKG

matrix-react-sdk

Version:
155 lines (147 loc) 20.8 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.createVoiceBroadcastRecorder = exports.VoiceBroadcastRecorderEvent = exports.VoiceBroadcastRecorder = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _lodash = require("lodash"); var _logger = require("matrix-js-sdk/src/logger"); var _matrix = require("matrix-js-sdk/src/matrix"); var _ = require(".."); var _VoiceRecording = require("../../audio/VoiceRecording"); var _arrays = require("../../utils/arrays"); var _Singleflight = require("../../utils/Singleflight"); /* Copyright 2024 New Vector Ltd. Copyright 2022 The Matrix.org Foundation C.I.C. SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only Please see LICENSE files in the repository root for full details. */ let VoiceBroadcastRecorderEvent = exports.VoiceBroadcastRecorderEvent = /*#__PURE__*/function (VoiceBroadcastRecorderEvent) { VoiceBroadcastRecorderEvent["ChunkRecorded"] = "chunk_recorded"; VoiceBroadcastRecorderEvent["CurrentChunkLengthUpdated"] = "current_chunk_length_updated"; return VoiceBroadcastRecorderEvent; }({}); // char sequence of "OpusHead" const OpusHead = [79, 112, 117, 115, 72, 101, 97, 100]; // char sequence of "OpusTags" const OpusTags = [79, 112, 117, 115, 84, 97, 103, 115]; /** * This class provides the function to seamlessly record fixed length chunks. * Subscribe with on(VoiceBroadcastRecordingEvents.ChunkRecorded, (payload: ChunkRecordedPayload) => {}) * to retrieve chunks while recording. */ class VoiceBroadcastRecorder extends _matrix.TypedEventEmitter { constructor(voiceRecording, targetChunkLength) { super(); (0, _defineProperty2.default)(this, "opusHead", void 0); (0, _defineProperty2.default)(this, "opusTags", void 0); (0, _defineProperty2.default)(this, "chunkBuffer", new Uint8Array(0)); // position of the previous chunk in seconds (0, _defineProperty2.default)(this, "previousChunkEndTimePosition", 0); // current chunk length in seconds (0, _defineProperty2.default)(this, "currentChunkLength", 0); (0, _defineProperty2.default)(this, "onDataAvailable", data => { const dataArray = new Uint8Array(data); // extract the part, that contains the header type info const headerType = Array.from(dataArray.slice(28, 36)); if ((0, _lodash.isEqual)(OpusHead, headerType)) { // data seems to be an "OpusHead" header this.opusHead = dataArray; return; } if ((0, _lodash.isEqual)(OpusTags, headerType)) { // data seems to be an "OpusTags" header this.opusTags = dataArray; return; } this.setCurrentChunkLength(this.voiceRecording.recorderSeconds - this.previousChunkEndTimePosition); this.handleData(dataArray); }); this.voiceRecording = voiceRecording; this.targetChunkLength = targetChunkLength; this.voiceRecording.onDataAvailable = this.onDataAvailable; } async start() { await this.voiceRecording.start(); this.voiceRecording.liveData.onUpdate(data => { this.setCurrentChunkLength(data.timeSeconds - this.previousChunkEndTimePosition); }); } /** * Stops the recording and returns the remaining chunk (if any). */ async stop() { try { await this.voiceRecording.stop(); } catch (e) { // Ignore if the recording raises any error. } // forget about that call, so that we can stop it again later _Singleflight.Singleflight.forgetAllFor(this.voiceRecording); const chunk = this.extractChunk(); this.currentChunkLength = 0; this.previousChunkEndTimePosition = 0; return chunk; } get contentType() { return this.voiceRecording.contentType; } setCurrentChunkLength(currentChunkLength) { if (this.currentChunkLength === currentChunkLength) return; this.currentChunkLength = currentChunkLength; this.emit(VoiceBroadcastRecorderEvent.CurrentChunkLengthUpdated, currentChunkLength); } getCurrentChunkLength() { return this.currentChunkLength; } handleData(data) { this.chunkBuffer = (0, _arrays.concat)(this.chunkBuffer, data); this.emitChunkIfTargetLengthReached(); } emitChunkIfTargetLengthReached() { if (this.getCurrentChunkLength() >= this.targetChunkLength) { this.emitAndResetChunk(); } } /** * Extracts the current chunk and resets the buffer. */ extractChunk() { if (this.chunkBuffer.length === 0) { return null; } if (!this.opusHead || !this.opusTags) { _logger.logger.warn("Broadcast chunk cannot be extracted. OpusHead or OpusTags is missing."); return null; } const currentRecorderTime = this.voiceRecording.recorderSeconds; const payload = { buffer: (0, _arrays.concat)(this.opusHead, this.opusTags, this.chunkBuffer), length: this.getCurrentChunkLength() }; this.chunkBuffer = new Uint8Array(0); this.setCurrentChunkLength(0); this.previousChunkEndTimePosition = currentRecorderTime; return payload; } emitAndResetChunk() { if (this.chunkBuffer.length === 0) { return; } this.emit(VoiceBroadcastRecorderEvent.ChunkRecorded, this.extractChunk()); } destroy() { this.removeAllListeners(); this.voiceRecording.destroy(); } } exports.VoiceBroadcastRecorder = VoiceBroadcastRecorder; const createVoiceBroadcastRecorder = () => { const voiceRecording = new _VoiceRecording.VoiceRecording(); voiceRecording.disableMaxLength(); return new VoiceBroadcastRecorder(voiceRecording, (0, _.getChunkLength)()); }; exports.createVoiceBroadcastRecorder = createVoiceBroadcastRecorder; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbG9kYXNoIiwicmVxdWlyZSIsIl9sb2dnZXIiLCJfbWF0cml4IiwiXyIsIl9Wb2ljZVJlY29yZGluZyIsIl9hcnJheXMiLCJfU2luZ2xlZmxpZ2h0IiwiVm9pY2VCcm9hZGNhc3RSZWNvcmRlckV2ZW50IiwiZXhwb3J0cyIsIk9wdXNIZWFkIiwiT3B1c1RhZ3MiLCJWb2ljZUJyb2FkY2FzdFJlY29yZGVyIiwiVHlwZWRFdmVudEVtaXR0ZXIiLCJjb25zdHJ1Y3RvciIsInZvaWNlUmVjb3JkaW5nIiwidGFyZ2V0Q2h1bmtMZW5ndGgiLCJfZGVmaW5lUHJvcGVydHkyIiwiZGVmYXVsdCIsIlVpbnQ4QXJyYXkiLCJkYXRhIiwiZGF0YUFycmF5IiwiaGVhZGVyVHlwZSIsIkFycmF5IiwiZnJvbSIsInNsaWNlIiwiaXNFcXVhbCIsIm9wdXNIZWFkIiwib3B1c1RhZ3MiLCJzZXRDdXJyZW50Q2h1bmtMZW5ndGgiLCJyZWNvcmRlclNlY29uZHMiLCJwcmV2aW91c0NodW5rRW5kVGltZVBvc2l0aW9uIiwiaGFuZGxlRGF0YSIsIm9uRGF0YUF2YWlsYWJsZSIsInN0YXJ0IiwibGl2ZURhdGEiLCJvblVwZGF0ZSIsInRpbWVTZWNvbmRzIiwic3RvcCIsImUiLCJTaW5nbGVmbGlnaHQiLCJmb3JnZXRBbGxGb3IiLCJjaHVuayIsImV4dHJhY3RDaHVuayIsImN1cnJlbnRDaHVua0xlbmd0aCIsImNvbnRlbnRUeXBlIiwiZW1pdCIsIkN1cnJlbnRDaHVua0xlbmd0aFVwZGF0ZWQiLCJnZXRDdXJyZW50Q2h1bmtMZW5ndGgiLCJjaHVua0J1ZmZlciIsImNvbmNhdCIsImVtaXRDaHVua0lmVGFyZ2V0TGVuZ3RoUmVhY2hlZCIsImVtaXRBbmRSZXNldENodW5rIiwibGVuZ3RoIiwibG9nZ2VyIiwid2FybiIsImN1cnJlbnRSZWNvcmRlclRpbWUiLCJwYXlsb2FkIiwiYnVmZmVyIiwiQ2h1bmtSZWNvcmRlZCIsImRlc3Ryb3kiLCJyZW1vdmVBbGxMaXN0ZW5lcnMiLCJjcmVhdGVWb2ljZUJyb2FkY2FzdFJlY29yZGVyIiwiVm9pY2VSZWNvcmRpbmciLCJkaXNhYmxlTWF4TGVuZ3RoIiwiZ2V0Q2h1bmtMZW5ndGgiXSwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdm9pY2UtYnJvYWRjYXN0L2F1ZGlvL1ZvaWNlQnJvYWRjYXN0UmVjb3JkZXIudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLypcbkNvcHlyaWdodCAyMDI0IE5ldyBWZWN0b3IgTHRkLlxuQ29weXJpZ2h0IDIwMjIgVGhlIE1hdHJpeC5vcmcgRm91bmRhdGlvbiBDLkkuQy5cblxuU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFHUEwtMy4wLW9ubHkgT1IgR1BMLTMuMC1vbmx5XG5QbGVhc2Ugc2VlIExJQ0VOU0UgZmlsZXMgaW4gdGhlIHJlcG9zaXRvcnkgcm9vdCBmb3IgZnVsbCBkZXRhaWxzLlxuKi9cblxuaW1wb3J0IHsgaXNFcXVhbCB9IGZyb20gXCJsb2Rhc2hcIjtcbmltcG9ydCB7IE9wdGlvbmFsIH0gZnJvbSBcIm1hdHJpeC1ldmVudHMtc2RrXCI7XG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvbG9nZ2VyXCI7XG5pbXBvcnQgeyBUeXBlZEV2ZW50RW1pdHRlciB9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9tYXRyaXhcIjtcblxuaW1wb3J0IHsgZ2V0Q2h1bmtMZW5ndGggfSBmcm9tIFwiLi5cIjtcbmltcG9ydCB7IElSZWNvcmRpbmdVcGRhdGUsIFZvaWNlUmVjb3JkaW5nIH0gZnJvbSBcIi4uLy4uL2F1ZGlvL1ZvaWNlUmVjb3JkaW5nXCI7XG5pbXBvcnQgeyBjb25jYXQgfSBmcm9tIFwiLi4vLi4vdXRpbHMvYXJyYXlzXCI7XG5pbXBvcnQgeyBJRGVzdHJveWFibGUgfSBmcm9tIFwiLi4vLi4vdXRpbHMvSURlc3Ryb3lhYmxlXCI7XG5pbXBvcnQgeyBTaW5nbGVmbGlnaHQgfSBmcm9tIFwiLi4vLi4vdXRpbHMvU2luZ2xlZmxpZ2h0XCI7XG5cbmV4cG9ydCBlbnVtIFZvaWNlQnJvYWRjYXN0UmVjb3JkZXJFdmVudCB7XG4gICAgQ2h1bmtSZWNvcmRlZCA9IFwiY2h1bmtfcmVjb3JkZWRcIixcbiAgICBDdXJyZW50Q2h1bmtMZW5ndGhVcGRhdGVkID0gXCJjdXJyZW50X2NodW5rX2xlbmd0aF91cGRhdGVkXCIsXG59XG5cbmludGVyZmFjZSBFdmVudE1hcCB7XG4gICAgW1ZvaWNlQnJvYWRjYXN0UmVjb3JkZXJFdmVudC5DaHVua1JlY29yZGVkXTogKGNodW5rOiBDaHVua1JlY29yZGVkUGF5bG9hZCkgPT4gdm9pZDtcbiAgICBbVm9pY2VCcm9hZGNhc3RSZWNvcmRlckV2ZW50LkN1cnJlbnRDaHVua0xlbmd0aFVwZGF0ZWRdOiAobGVuZ3RoOiBudW1iZXIpID0+IHZvaWQ7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ2h1bmtSZWNvcmRlZFBheWxvYWQge1xuICAgIGJ1ZmZlcjogVWludDhBcnJheTtcbiAgICBsZW5ndGg6IG51bWJlcjtcbn1cblxuLy8gY2hhciBzZXF1ZW5jZSBvZiBcIk9wdXNIZWFkXCJcbmNvbnN0IE9wdXNIZWFkID0gWzc5LCAxMTIsIDExNywgMTE1LCA3MiwgMTAxLCA5NywgMTAwXTtcblxuLy8gY2hhciBzZXF1ZW5jZSBvZiBcIk9wdXNUYWdzXCJcbmNvbnN0IE9wdXNUYWdzID0gWzc5LCAxMTIsIDExNywgMTE1LCA4NCwgOTcsIDEwMywgMTE1XTtcblxuLyoqXG4gKiBUaGlzIGNsYXNzIHByb3ZpZGVzIHRoZSBmdW5jdGlvbiB0byBzZWFtbGVzc2x5IHJlY29yZCBmaXhlZCBsZW5ndGggY2h1bmtzLlxuICogU3Vic2NyaWJlIHdpdGggb24oVm9pY2VCcm9hZGNhc3RSZWNvcmRpbmdFdmVudHMuQ2h1bmtSZWNvcmRlZCwgKHBheWxvYWQ6IENodW5rUmVjb3JkZWRQYXlsb2FkKSA9PiB7fSlcbiAqIHRvIHJldHJpZXZlIGNodW5rcyB3aGlsZSByZWNvcmRpbmcuXG4gKi9cbmV4cG9ydCBjbGFzcyBWb2ljZUJyb2FkY2FzdFJlY29yZGVyXG4gICAgZXh0ZW5kcyBUeXBlZEV2ZW50RW1pdHRlcjxWb2ljZUJyb2FkY2FzdFJlY29yZGVyRXZlbnQsIEV2ZW50TWFwPlxuICAgIGltcGxlbWVudHMgSURlc3Ryb3lhYmxlXG57XG4gICAgcHJpdmF0ZSBvcHVzSGVhZD86IFVpbnQ4QXJyYXk7XG4gICAgcHJpdmF0ZSBvcHVzVGFncz86IFVpbnQ4QXJyYXk7XG4gICAgcHJpdmF0ZSBjaHVua0J1ZmZlciA9IG5ldyBVaW50OEFycmF5KDApO1xuICAgIC8vIHBvc2l0aW9uIG9mIHRoZSBwcmV2aW91cyBjaHVuayBpbiBzZWNvbmRzXG4gICAgcHJpdmF0ZSBwcmV2aW91c0NodW5rRW5kVGltZVBvc2l0aW9uID0gMDtcbiAgICAvLyBjdXJyZW50IGNodW5rIGxlbmd0aCBpbiBzZWNvbmRzXG4gICAgcHJpdmF0ZSBjdXJyZW50Q2h1bmtMZW5ndGggPSAwO1xuXG4gICAgcHVibGljIGNvbnN0cnVjdG9yKFxuICAgICAgICBwcml2YXRlIHZvaWNlUmVjb3JkaW5nOiBWb2ljZVJlY29yZGluZyxcbiAgICAgICAgcHVibGljIHJlYWRvbmx5IHRhcmdldENodW5rTGVuZ3RoOiBudW1iZXIsXG4gICAgKSB7XG4gICAgICAgIHN1cGVyKCk7XG4gICAgICAgIHRoaXMudm9pY2VSZWNvcmRpbmcub25EYXRhQXZhaWxhYmxlID0gdGhpcy5vbkRhdGFBdmFpbGFibGU7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHN0YXJ0KCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCB0aGlzLnZvaWNlUmVjb3JkaW5nLnN0YXJ0KCk7XG4gICAgICAgIHRoaXMudm9pY2VSZWNvcmRpbmcubGl2ZURhdGEub25VcGRhdGUoKGRhdGE6IElSZWNvcmRpbmdVcGRhdGUpID0+IHtcbiAgICAgICAgICAgIHRoaXMuc2V0Q3VycmVudENodW5rTGVuZ3RoKGRhdGEudGltZVNlY29uZHMgLSB0aGlzLnByZXZpb3VzQ2h1bmtFbmRUaW1lUG9zaXRpb24pO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTdG9wcyB0aGUgcmVjb3JkaW5nIGFuZCByZXR1cm5zIHRoZSByZW1haW5pbmcgY2h1bmsgKGlmIGFueSkuXG4gICAgICovXG4gICAgcHVibGljIGFzeW5jIHN0b3AoKTogUHJvbWlzZTxPcHRpb25hbDxDaHVua1JlY29yZGVkUGF5bG9hZD4+IHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMudm9pY2VSZWNvcmRpbmcuc3RvcCgpO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAvLyBJZ25vcmUgaWYgdGhlIHJlY29yZGluZyByYWlzZXMgYW55IGVycm9yLlxuICAgICAgICB9XG5cbiAgICAgICAgLy8gZm9yZ2V0IGFib3V0IHRoYXQgY2FsbCwgc28gdGhhdCB3ZSBjYW4gc3RvcCBpdCBhZ2FpbiBsYXRlclxuICAgICAgICBTaW5nbGVmbGlnaHQuZm9yZ2V0QWxsRm9yKHRoaXMudm9pY2VSZWNvcmRpbmcpO1xuICAgICAgICBjb25zdCBjaHVuayA9IHRoaXMuZXh0cmFjdENodW5rKCk7XG4gICAgICAgIHRoaXMuY3VycmVudENodW5rTGVuZ3RoID0gMDtcbiAgICAgICAgdGhpcy5wcmV2aW91c0NodW5rRW5kVGltZVBvc2l0aW9uID0gMDtcbiAgICAgICAgcmV0dXJuIGNodW5rO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXQgY29udGVudFR5cGUoKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIHRoaXMudm9pY2VSZWNvcmRpbmcuY29udGVudFR5cGU7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBzZXRDdXJyZW50Q2h1bmtMZW5ndGgoY3VycmVudENodW5rTGVuZ3RoOiBudW1iZXIpOiB2b2lkIHtcbiAgICAgICAgaWYgKHRoaXMuY3VycmVudENodW5rTGVuZ3RoID09PSBjdXJyZW50Q2h1bmtMZW5ndGgpIHJldHVybjtcblxuICAgICAgICB0aGlzLmN1cnJlbnRDaHVua0xlbmd0aCA9IGN1cnJlbnRDaHVua0xlbmd0aDtcbiAgICAgICAgdGhpcy5lbWl0KFZvaWNlQnJvYWRjYXN0UmVjb3JkZXJFdmVudC5DdXJyZW50Q2h1bmtMZW5ndGhVcGRhdGVkLCBjdXJyZW50Q2h1bmtMZW5ndGgpO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXRDdXJyZW50Q2h1bmtMZW5ndGgoKTogbnVtYmVyIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuY3VycmVudENodW5rTGVuZ3RoO1xuICAgIH1cblxuICAgIHByaXZhdGUgb25EYXRhQXZhaWxhYmxlID0gKGRhdGE6IEFycmF5QnVmZmVyKTogdm9pZCA9PiB7XG4gICAgICAgIGNvbnN0IGRhdGFBcnJheSA9IG5ldyBVaW50OEFycmF5KGRhdGEpO1xuXG4gICAgICAgIC8vIGV4dHJhY3QgdGhlIHBhcnQsIHRoYXQgY29udGFpbnMgdGhlIGhlYWRlciB0eXBlIGluZm9cbiAgICAgICAgY29uc3QgaGVhZGVyVHlwZSA9IEFycmF5LmZyb20oZGF0YUFycmF5LnNsaWNlKDI4LCAzNikpO1xuXG4gICAgICAgIGlmIChpc0VxdWFsKE9wdXNIZWFkLCBoZWFkZXJUeXBlKSkge1xuICAgICAgICAgICAgLy8gZGF0YSBzZWVtcyB0byBiZSBhbiBcIk9wdXNIZWFkXCIgaGVhZGVyXG4gICAgICAgICAgICB0aGlzLm9wdXNIZWFkID0gZGF0YUFycmF5O1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGlzRXF1YWwoT3B1c1RhZ3MsIGhlYWRlclR5cGUpKSB7XG4gICAgICAgICAgICAvLyBkYXRhIHNlZW1zIHRvIGJlIGFuIFwiT3B1c1RhZ3NcIiBoZWFkZXJcbiAgICAgICAgICAgIHRoaXMub3B1c1RhZ3MgPSBkYXRhQXJyYXk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNldEN1cnJlbnRDaHVua0xlbmd0aCh0aGlzLnZvaWNlUmVjb3JkaW5nLnJlY29yZGVyU2Vjb25kcyEgLSB0aGlzLnByZXZpb3VzQ2h1bmtFbmRUaW1lUG9zaXRpb24pO1xuICAgICAgICB0aGlzLmhhbmRsZURhdGEoZGF0YUFycmF5KTtcbiAgICB9O1xuXG4gICAgcHJpdmF0ZSBoYW5kbGVEYXRhKGRhdGE6IFVpbnQ4QXJyYXkpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5jaHVua0J1ZmZlciA9IGNvbmNhdCh0aGlzLmNodW5rQnVmZmVyLCBkYXRhKTtcbiAgICAgICAgdGhpcy5lbWl0Q2h1bmtJZlRhcmdldExlbmd0aFJlYWNoZWQoKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGVtaXRDaHVua0lmVGFyZ2V0TGVuZ3RoUmVhY2hlZCgpOiB2b2lkIHtcbiAgICAgICAgaWYgKHRoaXMuZ2V0Q3VycmVudENodW5rTGVuZ3RoKCkgPj0gdGhpcy50YXJnZXRDaHVua0xlbmd0aCkge1xuICAgICAgICAgICAgdGhpcy5lbWl0QW5kUmVzZXRDaHVuaygpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRXh0cmFjdHMgdGhlIGN1cnJlbnQgY2h1bmsgYW5kIHJlc2V0cyB0aGUgYnVmZmVyLlxuICAgICAqL1xuICAgIHByaXZhdGUgZXh0cmFjdENodW5rKCk6IE9wdGlvbmFsPENodW5rUmVjb3JkZWRQYXlsb2FkPiB7XG4gICAgICAgIGlmICh0aGlzLmNodW5rQnVmZmVyLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIXRoaXMub3B1c0hlYWQgfHwgIXRoaXMub3B1c1RhZ3MpIHtcbiAgICAgICAgICAgIGxvZ2dlci53YXJuKFwiQnJvYWRjYXN0IGNodW5rIGNhbm5vdCBiZSBleHRyYWN0ZWQuIE9wdXNIZWFkIG9yIE9wdXNUYWdzIGlzIG1pc3NpbmcuXCIpO1xuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBjdXJyZW50UmVjb3JkZXJUaW1lID0gdGhpcy52b2ljZVJlY29yZGluZy5yZWNvcmRlclNlY29uZHMhO1xuICAgICAgICBjb25zdCBwYXlsb2FkOiBDaHVua1JlY29yZGVkUGF5bG9hZCA9IHtcbiAgICAgICAgICAgIGJ1ZmZlcjogY29uY2F0KHRoaXMub3B1c0hlYWQhLCB0aGlzLm9wdXNUYWdzISwgdGhpcy5jaHVua0J1ZmZlciksXG4gICAgICAgICAgICBsZW5ndGg6IHRoaXMuZ2V0Q3VycmVudENodW5rTGVuZ3RoKCksXG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuY2h1bmtCdWZmZXIgPSBuZXcgVWludDhBcnJheSgwKTtcbiAgICAgICAgdGhpcy5zZXRDdXJyZW50Q2h1bmtMZW5ndGgoMCk7XG4gICAgICAgIHRoaXMucHJldmlvdXNDaHVua0VuZFRpbWVQb3NpdGlvbiA9IGN1cnJlbnRSZWNvcmRlclRpbWU7XG4gICAgICAgIHJldHVybiBwYXlsb2FkO1xuICAgIH1cblxuICAgIHByaXZhdGUgZW1pdEFuZFJlc2V0Q2h1bmsoKTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLmNodW5rQnVmZmVyLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5lbWl0KFZvaWNlQnJvYWRjYXN0UmVjb3JkZXJFdmVudC5DaHVua1JlY29yZGVkLCB0aGlzLmV4dHJhY3RDaHVuaygpISk7XG4gICAgfVxuXG4gICAgcHVibGljIGRlc3Ryb3koKTogdm9pZCB7XG4gICAgICAgIHRoaXMucmVtb3ZlQWxsTGlzdGVuZXJzKCk7XG4gICAgICAgIHRoaXMudm9pY2VSZWNvcmRpbmcuZGVzdHJveSgpO1xuICAgIH1cbn1cblxuZXhwb3J0IGNvbnN0IGNyZWF0ZVZvaWNlQnJvYWRjYXN0UmVjb3JkZXIgPSAoKTogVm9pY2VCcm9hZGNhc3RSZWNvcmRlciA9PiB7XG4gICAgY29uc3Qgdm9pY2VSZWNvcmRpbmcgPSBuZXcgVm9pY2VSZWNvcmRpbmcoKTtcbiAgICB2b2ljZVJlY29yZGluZy5kaXNhYmxlTWF4TGVuZ3RoKCk7XG4gICAgcmV0dXJuIG5ldyBWb2ljZUJyb2FkY2Fz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