matrix-react-sdk
Version:
SDK for matrix.org using React
155 lines (147 loc) • 20.8 kB
JavaScript
"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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