UNPKG

matrix-react-sdk

Version:
330 lines (320 loc) 50.7 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.VoiceBroadcastRecordingEvent = exports.VoiceBroadcastRecording = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _logger = require("matrix-js-sdk/src/logger"); var _matrix = require("matrix-js-sdk/src/matrix"); var _ = require(".."); var _ContentMessages = require("../../ContentMessages"); var _createVoiceMessageContent = require("../../utils/createVoiceMessageContent"); var _dispatcher = _interopRequireDefault(require("../../dispatcher/dispatcher")); var _VoiceBroadcastChunkEvents = require("../utils/VoiceBroadcastChunkEvents"); var _RelationsHelper = require("../../events/RelationsHelper"); var _connection = require("../../utils/connection"); var _notifications = require("../../utils/notifications"); var _BackgroundAudio = require("../../audio/BackgroundAudio"); /* 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 VoiceBroadcastRecordingEvent = exports.VoiceBroadcastRecordingEvent = /*#__PURE__*/function (VoiceBroadcastRecordingEvent) { VoiceBroadcastRecordingEvent["StateChanged"] = "liveness_changed"; VoiceBroadcastRecordingEvent["TimeLeftChanged"] = "time_left_changed"; return VoiceBroadcastRecordingEvent; }({}); class VoiceBroadcastRecording extends _matrix.TypedEventEmitter { constructor(infoEvent, client, initialState) { super(); (0, _defineProperty2.default)(this, "state", void 0); (0, _defineProperty2.default)(this, "recorder", null); (0, _defineProperty2.default)(this, "dispatcherRef", void 0); (0, _defineProperty2.default)(this, "chunkEvents", new _VoiceBroadcastChunkEvents.VoiceBroadcastChunkEvents()); (0, _defineProperty2.default)(this, "chunkRelationHelper", void 0); (0, _defineProperty2.default)(this, "maxLength", void 0); (0, _defineProperty2.default)(this, "timeLeft", void 0); (0, _defineProperty2.default)(this, "toRetry", []); (0, _defineProperty2.default)(this, "reconnectedListener", void 0); (0, _defineProperty2.default)(this, "roomId", void 0); (0, _defineProperty2.default)(this, "infoEventId", void 0); (0, _defineProperty2.default)(this, "backgroundAudio", new _BackgroundAudio.BackgroundAudio()); /** * Broadcast chunks have a sequence number to bring them in the correct order and to know if a message is missing. * This variable holds the last sequence number. * Starts with 0 because there is no chunk at the beginning of a broadcast. * Will be incremented when a chunk message is created. */ (0, _defineProperty2.default)(this, "sequence", 0); (0, _defineProperty2.default)(this, "onChunkEvent", event => { if (!event.getId() && !event.getTxnId() || event.getContent()?.msgtype !== _matrix.MsgType.Audio // don't add non-audio event ) { return; } this.chunkEvents.addEvent(event); }); /** * Retries failed actions on reconnect. */ (0, _defineProperty2.default)(this, "onReconnect", async () => { // Do nothing if not in connection_error state. if (this.state !== "connection_error") return; // Copy the array, so that it is possible to remove elements from it while iterating over the original. const toRetryCopy = [...this.toRetry]; for (const retryFn of this.toRetry) { try { await retryFn(); // Successfully retried. Remove from array copy. toRetryCopy.splice(toRetryCopy.indexOf(retryFn), 1); } catch { // The current retry callback failed. Stop the loop. break; } } this.toRetry = toRetryCopy; if (this.toRetry.length === 0) { // Everything has been successfully retried. Recover from error state to paused. await this.pause(); } }); (0, _defineProperty2.default)(this, "toggle", async () => { if (this.getState() === _.VoiceBroadcastInfoState.Paused) return this.resume(); if ([_.VoiceBroadcastInfoState.Started, _.VoiceBroadcastInfoState.Resumed].includes(this.getState())) { return this.pause(); } }); (0, _defineProperty2.default)(this, "onBeforeRedaction", () => { if (this.getState() !== _.VoiceBroadcastInfoState.Stopped) { this.setState(_.VoiceBroadcastInfoState.Stopped); // destroy cleans up everything this.destroy(); } }); (0, _defineProperty2.default)(this, "onAction", payload => { if (payload.action !== "call_state") return; // pause on any call action this.pause(); }); (0, _defineProperty2.default)(this, "onCurrentChunkLengthUpdated", currentChunkLength => { this.setTimeLeft(this.maxLength - this.chunkEvents.getLengthSeconds() - currentChunkLength); }); (0, _defineProperty2.default)(this, "onChunkRecorded", async chunk => { const uploadAndSendFn = async () => { const { url, file } = await this.uploadFile(chunk); await this.sendVoiceMessage(chunk, url, file); }; await this.callWithRetry(uploadAndSendFn); }); this.infoEvent = infoEvent; this.client = client; this.maxLength = (0, _.getMaxBroadcastLength)(); this.timeLeft = this.maxLength; this.infoEventId = this.determineEventIdFromInfoEvent(); this.roomId = this.determineRoomIdFromInfoEvent(); if (initialState) { this.state = initialState; } else { this.state = this.determineInitialStateFromInfoEvent(); } // TODO Michael W: listen for state updates this.infoEvent.on(_matrix.MatrixEventEvent.BeforeRedaction, this.onBeforeRedaction); this.dispatcherRef = _dispatcher.default.register(this.onAction); this.chunkRelationHelper = this.initialiseChunkEventRelation(); this.reconnectedListener = (0, _connection.createReconnectedListener)(this.onReconnect); this.client.on(_matrix.ClientEvent.Sync, this.reconnectedListener); } initialiseChunkEventRelation() { const relationsHelper = new _RelationsHelper.RelationsHelper(this.infoEvent, _matrix.RelationType.Reference, _matrix.EventType.RoomMessage, this.client); relationsHelper.on(_RelationsHelper.RelationsHelperEvent.Add, this.onChunkEvent); relationsHelper.emitFetchCurrent().catch(err => { _logger.logger.warn("error fetching server side relation for voice broadcast chunks", err); // fall back to local events relationsHelper.emitCurrent(); }); return relationsHelper; } determineEventIdFromInfoEvent() { const infoEventId = this.infoEvent.getId(); if (!infoEventId) { throw new Error("Cannot create broadcast for info event without Id."); } return infoEventId; } determineRoomIdFromInfoEvent() { const roomId = this.infoEvent.getRoomId(); if (!roomId) { throw new Error(`Cannot create broadcast for unknown room (info event ${this.infoEventId})`); } return roomId; } /** * Determines the initial broadcast state. * Checks all related events. If one has the "stopped" state → stopped, else started. */ determineInitialStateFromInfoEvent() { const room = this.client.getRoom(this.roomId); const relations = room?.getUnfilteredTimelineSet()?.relations?.getChildEventsForEvent(this.infoEventId, _matrix.RelationType.Reference, _.VoiceBroadcastInfoEventType); const relatedEvents = relations?.getRelations(); return !relatedEvents?.find(event => { return event.getContent()?.state === _.VoiceBroadcastInfoState.Stopped; }) ? _.VoiceBroadcastInfoState.Started : _.VoiceBroadcastInfoState.Stopped; } getTimeLeft() { return this.timeLeft; } async setTimeLeft(timeLeft) { if (timeLeft <= 0) { // time is up - stop the recording return await this.stop(); } // do never increase time left; no action if equals if (timeLeft >= this.timeLeft) return; this.timeLeft = timeLeft; this.emit(VoiceBroadcastRecordingEvent.TimeLeftChanged, timeLeft); } async start() { return this.getRecorder().start(); } async stop() { if (this.state === _.VoiceBroadcastInfoState.Stopped) return; this.setState(_.VoiceBroadcastInfoState.Stopped); await this.stopRecorder(); await this.sendInfoStateEvent(_.VoiceBroadcastInfoState.Stopped); } async pause() { // stopped or already paused recordings cannot be paused if ([_.VoiceBroadcastInfoState.Stopped, _.VoiceBroadcastInfoState.Paused].includes(this.state)) return; this.setState(_.VoiceBroadcastInfoState.Paused); await this.stopRecorder(); await this.sendInfoStateEvent(_.VoiceBroadcastInfoState.Paused); } async resume() { if (this.state !== _.VoiceBroadcastInfoState.Paused) return; this.setState(_.VoiceBroadcastInfoState.Resumed); await this.getRecorder().start(); await this.sendInfoStateEvent(_.VoiceBroadcastInfoState.Resumed); } getState() { return this.state; } getRecorder() { if (!this.recorder) { this.recorder = (0, _.createVoiceBroadcastRecorder)(); this.recorder.on(_.VoiceBroadcastRecorderEvent.ChunkRecorded, this.onChunkRecorded); this.recorder.on(_.VoiceBroadcastRecorderEvent.CurrentChunkLengthUpdated, this.onCurrentChunkLengthUpdated); } return this.recorder; } async destroy() { if (this.recorder) { this.recorder.stop(); this.recorder.destroy(); } this.infoEvent.off(_matrix.MatrixEventEvent.BeforeRedaction, this.onBeforeRedaction); this.removeAllListeners(); _dispatcher.default.unregister(this.dispatcherRef); this.chunkEvents = new _VoiceBroadcastChunkEvents.VoiceBroadcastChunkEvents(); this.chunkRelationHelper.destroy(); this.client.off(_matrix.ClientEvent.Sync, this.reconnectedListener); } setState(state) { this.state = state; this.emit(VoiceBroadcastRecordingEvent.StateChanged, this.state); } /** * This function is called on connection errors. * It sets the connection error state and stops the recorder. */ async onConnectionError() { this.playConnectionErrorAudioNotification().catch(() => { // Error logged in playConnectionErrorAudioNotification(). }); await this.stopRecorder(false); this.setState("connection_error"); } async playConnectionErrorAudioNotification() { if ((0, _notifications.localNotificationsAreSilenced)(this.client)) { return; } await this.backgroundAudio.pickFormatAndPlay("./media/error", ["mp3", "ogg"]); } async uploadFile(chunk) { return (0, _ContentMessages.uploadFile)(this.client, this.roomId, new Blob([chunk.buffer], { type: this.getRecorder().contentType })); } async sendVoiceMessage(chunk, url, file) { /** * Increment the last sequence number and use it for this message. * Done outside of the sendMessageFn to get a scoped value. * Also see {@link VoiceBroadcastRecording.sequence}. */ const sequence = ++this.sequence; const sendMessageFn = async () => { const content = (0, _createVoiceMessageContent.createVoiceMessageContent)(url, this.getRecorder().contentType, Math.round(chunk.length * 1000), chunk.buffer.length, file); content["m.relates_to"] = { rel_type: _matrix.RelationType.Reference, event_id: this.infoEventId }; content["io.element.voice_broadcast_chunk"] = { sequence }; await this.client.sendMessage(this.roomId, content); }; await this.callWithRetry(sendMessageFn); } /** * Sends an info state event with given state. * On error stores a resend function and setState(state) in {@link toRetry} and * sets the broadcast state to connection_error. */ async sendInfoStateEvent(state) { const sendEventFn = async () => { await this.client.sendStateEvent(this.roomId, _.VoiceBroadcastInfoEventType, { device_id: this.client.getDeviceId(), state, last_chunk_sequence: this.sequence, ["m.relates_to"]: { rel_type: _matrix.RelationType.Reference, event_id: this.infoEventId } }, this.client.getSafeUserId()); }; await this.callWithRetry(sendEventFn); } /** * Calls the function. * On failure adds it to the retry list and triggers connection error. * {@link toRetry} * {@link onConnectionError} */ async callWithRetry(retryAbleFn) { try { await retryAbleFn(); } catch { this.toRetry.push(retryAbleFn); this.onConnectionError(); } } async stopRecorder(emit = true) { if (!this.recorder) { return; } try { const lastChunk = await this.recorder.stop(); if (lastChunk && emit) { await this.onChunkRecorded(lastChunk); } } catch (err) { _logger.logger.warn("error stopping voice broadcast recorder", err); } } } exports.VoiceBroadcastRecording = VoiceBroadcastRecording; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbG9nZ2VyIiwicmVxdWlyZSIsIl9tYXRyaXgiLCJfIiwiX0NvbnRlbnRNZXNzYWdlcyIsIl9jcmVhdGVWb2ljZU1lc3NhZ2VDb250ZW50IiwiX2Rpc3BhdGNoZXIiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwiX1ZvaWNlQnJvYWRjYXN0Q2h1bmtFdmVudHMiLCJfUmVsYXRpb25zSGVscGVyIiwiX2Nvbm5lY3Rpb24iLCJfbm90aWZpY2F0aW9ucyIsIl9CYWNrZ3JvdW5kQXVkaW8iLCJWb2ljZUJyb2FkY2FzdFJlY29yZGluZ0V2ZW50IiwiZXhwb3J0cyIsIlZvaWNlQnJvYWRjYXN0UmVjb3JkaW5nIiwiVHlwZWRFdmVudEVtaXR0ZXIiLCJjb25zdHJ1Y3RvciIsImluZm9FdmVudCIsImNsaWVudCIsImluaXRpYWxTdGF0ZSIsIl9kZWZpbmVQcm9wZXJ0eTIiLCJkZWZhdWx0IiwiVm9pY2VCcm9hZGNhc3RDaHVua0V2ZW50cyIsIkJhY2tncm91bmRBdWRpbyIsImV2ZW50IiwiZ2V0SWQiLCJnZXRUeG5JZCIsImdldENvbnRlbnQiLCJtc2d0eXBlIiwiTXNnVHlwZSIsIkF1ZGlvIiwiY2h1bmtFdmVudHMiLCJhZGRFdmVudCIsInN0YXRlIiwidG9SZXRyeUNvcHkiLCJ0b1JldHJ5IiwicmV0cnlGbiIsInNwbGljZSIsImluZGV4T2YiLCJsZW5ndGgiLCJwYXVzZSIsImdldFN0YXRlIiwiVm9pY2VCcm9hZGNhc3RJbmZvU3RhdGUiLCJQYXVzZWQiLCJyZXN1bWUiLCJTdGFydGVkIiwiUmVzdW1lZCIsImluY2x1ZGVzIiwiU3RvcHBlZCIsInNldFN0YXRlIiwiZGVzdHJveSIsInBheWxvYWQiLCJhY3Rpb24iLCJjdXJyZW50Q2h1bmtMZW5ndGgiLCJzZXRUaW1lTGVmdCIsIm1heExlbmd0aCIsImdldExlbmd0aFNlY29uZHMiLCJjaHVuayIsInVwbG9hZEFuZFNlbmRGbiIsInVybCIsImZpbGUiLCJ1cGxvYWRGaWxlIiwic2VuZFZvaWNlTWVzc2FnZSIsImNhbGxXaXRoUmV0cnkiLCJnZXRNYXhCcm9hZGNhc3RMZW5ndGgiLCJ0aW1lTGVmdCIsImluZm9FdmVudElkIiwiZGV0ZXJtaW5lRXZlbnRJZEZyb21JbmZvRXZlbnQiLCJyb29tSWQiLCJkZXRlcm1pbmVSb29tSWRGcm9tSW5mb0V2ZW50IiwiZGV0ZXJtaW5lSW5pdGlhbFN0YXRlRnJvbUluZm9FdmVudCIsIm9uIiwiTWF0cml4RXZlbnRFdmVudCIsIkJlZm9yZVJlZGFjdGlvbiIsIm9uQmVmb3JlUmVkYWN0aW9uIiwiZGlzcGF0Y2hlclJlZiIsImRpcyIsInJlZ2lzdGVyIiwib25BY3Rpb24iLCJjaHVua1JlbGF0aW9uSGVscGVyIiwiaW5pdGlhbGlzZUNodW5rRXZlbnRSZWxhdGlvbiIsInJlY29ubmVjdGVkTGlzdGVuZXIiLCJjcmVhdGVSZWNvbm5lY3RlZExpc3RlbmVyIiwib25SZWNvbm5lY3QiLCJDbGllbnRFdmVudCIsIlN5bmMiLCJyZWxhdGlvbnNIZWxwZXIiLCJSZWxhdGlvbnNIZWxwZXIiLCJSZWxhdGlvblR5cGUiLCJSZWZlcmVuY2UiLCJFdmVudFR5cGUiLCJSb29tTWVzc2FnZSIsIlJlbGF0aW9uc0hlbHBlckV2ZW50IiwiQWRkIiwib25DaHVua0V2ZW50IiwiZW1pdEZldGNoQ3VycmVudCIsImNhdGNoIiwiZXJyIiwibG9nZ2VyIiwid2FybiIsImVtaXRDdXJyZW50IiwiRXJyb3IiLCJnZXRSb29tSWQiLCJyb29tIiwiZ2V0Um9vbSIsInJlbGF0aW9ucyIsImdldFVuZmlsdGVyZWRUaW1lbGluZVNldCIsImdldENoaWxkRXZlbnRzRm9yRXZlbnQiLCJWb2ljZUJyb2FkY2FzdEluZm9FdmVudFR5cGUiLCJyZWxhdGVkRXZlbnRzIiwiZ2V0UmVsYXRpb25zIiwiZmluZCIsImdldFRpbWVMZWZ0Iiwic3RvcCIsImVtaXQiLCJUaW1lTGVmdENoYW5nZWQiLCJzdGFydCIsImdldFJlY29yZGVyIiwic3RvcFJlY29yZGVyIiwic2VuZEluZm9TdGF0ZUV2ZW50IiwicmVjb3JkZXIiLCJjcmVhdGVWb2ljZUJyb2FkY2FzdFJlY29yZGVyIiwiVm9pY2VCcm9hZGNhc3RSZWNvcmRlckV2ZW50IiwiQ2h1bmtSZWNvcmRlZCIsIm9uQ2h1bmtSZWNvcmRlZCIsIkN1cnJlbnRDaHVua0xlbmd0aFVwZGF0ZWQiLCJvbkN1cnJlbnRDaHVua0xlbmd0aFVwZGF0ZWQiLCJvZmYiLCJyZW1vdmVBbGxMaXN0ZW5lcnMiLCJ1bnJlZ2lzdGVyIiwiU3RhdGVDaGFuZ2VkIiwib25Db25uZWN0aW9uRXJyb3IiLCJwbGF5Q29ubmVjdGlvbkVycm9yQXVkaW9Ob3RpZmljYXRpb24iLCJsb2NhbE5vdGlmaWNhdGlvbnNBcmVTaWxlbmNlZCIsImJhY2tncm91bmRBdWRpbyIsInBpY2tGb3JtYXRBbmRQbGF5IiwiQmxvYiIsImJ1ZmZlciIsInR5cGUiLCJjb250ZW50VHlwZSIsInNlcXVlbmNlIiwic2VuZE1lc3NhZ2VGbiIsImNvbnRlbnQiLCJjcmVhdGVWb2ljZU1lc3NhZ2VDb250ZW50IiwiTWF0aCIsInJvdW5kIiwicmVsX3R5cGUiLCJldmVudF9pZCIsInNlbmRNZXNzYWdlIiwic2VuZEV2ZW50Rm4iLCJzZW5kU3RhdGVFdmVudCIsImRldmljZV9pZCIsImdldERldmljZUlkIiwibGFzdF9jaHVua19zZXF1ZW5jZSIsImdldFNhZmVVc2VySWQiLCJyZXRyeUFibGVGbiIsInB1c2giLCJsYXN0Q2h1bmsiXSwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdm9pY2UtYnJvYWRjYXN0L21vZGVscy9Wb2ljZUJyb2FkY2FzdFJlY29yZGluZy50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuQ29weXJpZ2h0IDIwMjQgTmV3IFZlY3RvciBMdGQuXG5Db3B5cmlnaHQgMjAyMiBUaGUgTWF0cml4Lm9yZyBGb3VuZGF0aW9uIEMuSS5DLlxuXG5TUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQUdQTC0zLjAtb25seSBPUiBHUEwtMy4wLW9ubHlcblBsZWFzZSBzZWUgTElDRU5TRSBmaWxlcyBpbiB0aGUgcmVwb3NpdG9yeSByb290IGZvciBmdWxsIGRldGFpbHMuXG4qL1xuXG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvbG9nZ2VyXCI7XG5pbXBvcnQge1xuICAgIENsaWVudEV2ZW50LFxuICAgIENsaWVudEV2ZW50SGFuZGxlck1hcCxcbiAgICBFdmVudFR5cGUsXG4gICAgTWF0cml4Q2xpZW50LFxuICAgIE1hdHJpeEV2ZW50LFxuICAgIE1hdHJpeEV2ZW50RXZlbnQsXG4gICAgTXNnVHlwZSxcbiAgICBSZWxhdGlvblR5cGUsXG4gICAgVHlwZWRFdmVudEVtaXR0ZXIsXG59IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9tYXRyaXhcIjtcbmltcG9ydCB7IEF1ZGlvQ29udGVudCwgRW5jcnlwdGVkRmlsZSB9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy90eXBlc1wiO1xuXG5pbXBvcnQge1xuICAgIENodW5rUmVjb3JkZWRQYXlsb2FkLFxuICAgIGNyZWF0ZVZvaWNlQnJvYWRjYXN0UmVjb3JkZXIsXG4gICAgZ2V0TWF4QnJvYWRjYXN0TGVuZ3RoLFxuICAgIFZvaWNlQnJvYWRjYXN0SW5mb0V2ZW50Q29udGVudCxcbiAgICBWb2ljZUJyb2FkY2FzdEluZm9FdmVudFR5cGUsXG4gICAgVm9pY2VCcm9hZGNhc3RJbmZvU3RhdGUsXG4gICAgVm9pY2VCcm9hZGNhc3RSZWNvcmRlcixcbiAgICBWb2ljZUJyb2FkY2FzdFJlY29yZGVyRXZlbnQsXG59IGZyb20gXCIuLlwiO1xuaW1wb3J0IHsgdXBsb2FkRmlsZSB9IGZyb20gXCIuLi8uLi9Db250ZW50TWVzc2FnZXNcIjtcbmltcG9ydCB7IGNyZWF0ZVZvaWNlTWVzc2FnZUNvbnRlbnQgfSBmcm9tIFwiLi4vLi4vdXRpbHMvY3JlYXRlVm9pY2VNZXNzYWdlQ29udGVudFwiO1xuaW1wb3J0IHsgSURlc3Ryb3lhYmxlIH0gZnJvbSBcIi4uLy4uL3V0aWxzL0lEZXN0cm95YWJsZVwiO1xuaW1wb3J0IGRpcyBmcm9tIFwiLi4vLi4vZGlzcGF0Y2hlci9kaXNwYXRjaGVyXCI7XG5pbXBvcnQgeyBBY3Rpb25QYXlsb2FkIH0gZnJvbSBcIi4uLy4uL2Rpc3BhdGNoZXIvcGF5bG9hZHNcIjtcbmltcG9ydCB7IFZvaWNlQnJvYWRjYXN0Q2h1bmtFdmVudHMgfSBmcm9tIFwiLi4vdXRpbHMvVm9pY2VCcm9hZGNhc3RDaHVua0V2ZW50c1wiO1xuaW1wb3J0IHsgUmVsYXRpb25zSGVscGVyLCBSZWxhdGlvbnNIZWxwZXJFdmVudCB9IGZyb20gXCIuLi8uLi9ldmVudHMvUmVsYXRpb25zSGVscGVyXCI7XG5pbXBvcnQgeyBjcmVhdGVSZWNvbm5lY3RlZExpc3RlbmVyIH0gZnJvbSBcIi4uLy4uL3V0aWxzL2Nvbm5lY3Rpb25cIjtcbmltcG9ydCB7IGxvY2FsTm90aWZpY2F0aW9uc0FyZVNpbGVuY2VkIH0gZnJvbSBcIi4uLy4uL3V0aWxzL25vdGlmaWNhdGlvbnNcIjtcbmltcG9ydCB7IEJhY2tncm91bmRBdWRpbyB9IGZyb20gXCIuLi8uLi9hdWRpby9CYWNrZ3JvdW5kQXVkaW9cIjtcblxuZXhwb3J0IGVudW0gVm9pY2VCcm9hZGNhc3RSZWNvcmRpbmdFdmVudCB7XG4gICAgU3RhdGVDaGFuZ2VkID0gXCJsaXZlbmVzc19jaGFuZ2VkXCIsXG4gICAgVGltZUxlZnRDaGFuZ2VkID0gXCJ0aW1lX2xlZnRfY2hhbmdlZFwiLFxufVxuXG5leHBvcnQgdHlwZSBWb2ljZUJyb2FkY2FzdFJlY29yZGluZ1N0YXRlID0gVm9pY2VCcm9hZGNhc3RJbmZvU3RhdGUgfCBcImNvbm5lY3Rpb25fZXJyb3JcIjtcblxuaW50ZXJmYWNlIEV2ZW50TWFwIHtcbiAgICBbVm9pY2VCcm9hZGNhc3RSZWNvcmRpbmdFdmVudC5TdGF0ZUNoYW5nZWRdOiAoc3RhdGU6IFZvaWNlQnJvYWRjYXN0UmVjb3JkaW5nU3RhdGUpID0+IHZvaWQ7XG4gICAgW1ZvaWNlQnJvYWRjYXN0UmVjb3JkaW5nRXZlbnQuVGltZUxlZnRDaGFuZ2VkXTogKHRpbWVMZWZ0OiBudW1iZXIpID0+IHZvaWQ7XG59XG5cbmV4cG9ydCBjbGFzcyBWb2ljZUJyb2FkY2FzdFJlY29yZGluZ1xuICAgIGV4dGVuZHMgVHlwZWRFdmVudEVtaXR0ZXI8Vm9pY2VCcm9hZGNhc3RSZWNvcmRpbmdFdmVudCwgRXZlbnRNYXA+XG4gICAgaW1wbGVtZW50cyBJRGVzdHJveWFibGVcbntcbiAgICBwcml2YXRlIHN0YXRlOiBWb2ljZUJyb2FkY2FzdFJlY29yZGluZ1N0YXRlO1xuICAgIHByaXZhdGUgcmVjb3JkZXI6IFZvaWNlQnJvYWRjYXN0UmVjb3JkZXIgfCBudWxsID0gbnVsbDtcbiAgICBwcml2YXRlIGRpc3BhdGNoZXJSZWY6IHN0cmluZztcbiAgICBwcml2YXRlIGNodW5rRXZlbnRzID0gbmV3IFZvaWNlQnJvYWRjYXN0Q2h1bmtFdmVudHMoKTtcbiAgICBwcml2YXRlIGNodW5rUmVsYXRpb25IZWxwZXI6IFJlbGF0aW9uc0hlbHBlcjtcbiAgICBwcml2YXRlIG1heExlbmd0aDogbnVtYmVyO1xuICAgIHByaXZhdGUgdGltZUxlZnQ6IG51bWJlcjtcbiAgICBwcml2YXRlIHRvUmV0cnk6IEFycmF5PCgpID0+IFByb21pc2U8dm9pZD4+ID0gW107XG4gICAgcHJpdmF0ZSByZWNvbm5lY3RlZExpc3RlbmVyOiBDbGllbnRFdmVudEhhbmRsZXJNYXBbQ2xpZW50RXZlbnQuU3luY107XG4gICAgcHJpdmF0ZSByb29tSWQ6IHN0cmluZztcbiAgICBwcml2YXRlIGluZm9FdmVudElkOiBzdHJpbmc7XG4gICAgcHJpdmF0ZSBiYWNrZ3JvdW5kQXVkaW8gPSBuZXcgQmFja2dyb3VuZEF1ZGlvKCk7XG5cbiAgICAvKipcbiAgICAgKiBCcm9hZGNhc3QgY2h1bmtzIGhhdmUgYSBzZXF1ZW5jZSBudW1iZXIgdG8gYnJpbmcgdGhlbSBpbiB0aGUgY29ycmVjdCBvcmRlciBhbmQgdG8ga25vdyBpZiBhIG1lc3NhZ2UgaXMgbWlzc2luZy5cbiAgICAgKiBUaGlzIHZhcmlhYmxlIGhvbGRzIHRoZSBsYXN0IHNlcXVlbmNlIG51bWJlci5cbiAgICAgKiBTdGFydHMgd2l0aCAwIGJlY2F1c2UgdGhlcmUgaXMgbm8gY2h1bmsgYXQgdGhlIGJlZ2lubmluZyBvZiBhIGJyb2FkY2FzdC5cbiAgICAgKiBXaWxsIGJlIGluY3JlbWVudGVkIHdoZW4gYSBjaHVuayBtZXNzYWdlIGlzIGNyZWF0ZWQuXG4gICAgICovXG4gICAgcHJpdmF0ZSBzZXF1ZW5jZSA9IDA7XG5cbiAgICBwdWJsaWMgY29uc3RydWN0b3IoXG4gICAgICAgIHB1YmxpYyByZWFkb25seSBpbmZvRXZlbnQ6IE1hdHJpeEV2ZW50LFxuICAgICAgICBwcml2YXRlIGNsaWVudDogTWF0cml4Q2xpZW50LFxuICAgICAgICBpbml0aWFsU3RhdGU/OiBWb2ljZUJyb2FkY2FzdEluZm9TdGF0ZSxcbiAgICApIHtcbiAgICAgICAgc3VwZXIoKTtcbiAgICAgICAgdGhpcy5tYXhMZW5ndGggPSBnZXRNYXhCcm9hZGNhc3RMZW5ndGgoKTtcbiAgICAgICAgdGhpcy50aW1lTGVmdCA9IHRoaXMubWF4TGVuZ3RoO1xuICAgICAgICB0aGlzLmluZm9FdmVudElkID0gdGhpcy5kZXRlcm1pbmVFdmVudElkRnJvbUluZm9FdmVudCgpO1xuICAgICAgICB0aGlzLnJvb21JZCA9IHRoaXMuZGV0ZXJtaW5lUm9vbUlkRnJvbUluZm9FdmVudCgpO1xuXG4gICAgICAgIGlmIChpbml0aWFsU3RhdGUpIHtcbiAgICAgICAgICAgIHRoaXMuc3RhdGUgPSBpbml0aWFsU3RhdGU7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLnN0YXRlID0gdGhpcy5kZXRlcm1pbmVJbml0aWFsU3RhdGVGcm9tSW5mb0V2ZW50KCk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBUT0RPIE1pY2hhZWwgVzogbGlzdGVuIGZvciBzdGF0ZSB1cGRhdGVzXG5cbiAgICAgICAgdGhpcy5pbmZvRXZlbnQub24oTWF0cml4RXZlbnRFdmVudC5CZWZvcmVSZWRhY3Rpb24sIHRoaXMub25CZWZvcmVSZWRhY3Rpb24pO1xuICAgICAgICB0aGlzLmRpc3BhdGNoZXJSZWYgPSBkaXMucmVnaXN0ZXIodGhpcy5vbkFjdGlvbik7XG4gICAgICAgIHRoaXMuY2h1bmtSZWxhdGlvbkhlbHBlciA9IHRoaXMuaW5pdGlhbGlzZUNodW5rRXZlbnRSZWxhdGlvbigpO1xuICAgICAgICB0aGlzLnJlY29ubmVjdGVkTGlzdGVuZXIgPSBjcmVhdGVSZWNvbm5lY3RlZExpc3RlbmVyKHRoaXMub25SZWNvbm5lY3QpO1xuICAgICAgICB0aGlzLmNsaWVudC5vbihDbGllbnRFdmVudC5TeW5jLCB0aGlzLnJlY29ubmVjdGVkTGlzdGVuZXIpO1xuICAgIH1cblxuICAgIHByaXZhdGUgaW5pdGlhbGlzZUNodW5rRXZlbnRSZWxhdGlvbigpOiBSZWxhdGlvbnNIZWxwZXIge1xuICAgICAgICBjb25zdCByZWxhdGlvbnNIZWxwZXIgPSBuZXcgUmVsYXRpb25zSGVscGVyKFxuICAgICAgICAgICAgdGhpcy5pbmZvRXZlbnQsXG4gICAgICAgICAgICBSZWxhdGlvblR5cGUuUmVmZXJlbmNlLFxuICAgICAgICAgICAgRXZlbnRUeXBlLlJvb21NZXNzYWdlLFxuICAgICAgICAgICAgdGhpcy5jbGllbnQsXG4gICAgICAgICk7XG4gICAgICAgIHJlbGF0aW9uc0hlbHBlci5vbihSZWxhdGlvbnNIZWxwZXJFdmVudC5BZGQsIHRoaXMub25DaHVua0V2ZW50KTtcblxuICAgICAgICByZWxhdGlvbnNIZWxwZXIuZW1pdEZldGNoQ3VycmVudCgpLmNhdGNoKChlcnIpID0+IHtcbiAgICAgICAgICAgIGxvZ2dlci53YXJuKFwiZXJyb3IgZmV0Y2hpbmcgc2VydmVyIHNpZGUgcmVsYXRpb24gZm9yIHZvaWNlIGJyb2FkY2FzdCBjaHVua3NcIiwgZXJyKTtcbiAgICAgICAgICAgIC8vIGZhbGwgYmFjayB0byBsb2NhbCBldmVudHNcbiAgICAgICAgICAgIHJlbGF0aW9uc0hlbHBlci5lbWl0Q3VycmVudCgpO1xuICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gcmVsYXRpb25zSGVscGVyO1xuICAgIH1cblxuICAgIHByaXZhdGUgb25DaHVua0V2ZW50ID0gKGV2ZW50OiBNYXRyaXhFdmVudCk6IHZvaWQgPT4ge1xuICAgICAgICBpZiAoXG4gICAgICAgICAgICAoIWV2ZW50LmdldElkKCkgJiYgIWV2ZW50LmdldFR4bklkKCkpIHx8XG4gICAgICAgICAgICBldmVudC5nZXRDb250ZW50KCk/Lm1zZ3R5cGUgIT09IE1zZ1R5cGUuQXVkaW8gLy8gZG9uJ3QgYWRkIG5vbi1hdWRpbyBldmVudFxuICAgICAgICApIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuY2h1bmtFdmVudHMuYWRkRXZlbnQoZXZlbnQpO1xuICAgIH07XG5cbiAgICBwcml2YXRlIGRldGVybWluZUV2ZW50SWRGcm9tSW5mb0V2ZW50KCk6IHN0cmluZyB7XG4gICAgICAgIGNvbnN0IGluZm9FdmVudElkID0gdGhpcy5pbmZvRXZlbnQuZ2V0SWQoKTtcblxuICAgICAgICBpZiAoIWluZm9FdmVudElkKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDYW5ub3QgY3JlYXRlIGJyb2FkY2FzdCBmb3IgaW5mbyBldmVudCB3aXRob3V0IElkLlwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBpbmZvRXZlbnRJZDtcbiAgICB9XG5cbiAgICBwcml2YXRlIGRldGVybWluZVJvb21JZEZyb21JbmZvRXZlbnQoKTogc3RyaW5nIHtcbiAgICAgICAgY29uc3Qgcm9vbUlkID0gdGhpcy5pbmZvRXZlbnQuZ2V0Um9vbUlkKCk7XG5cbiAgICAgICAgaWYgKCFyb29tSWQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgQ2Fubm90IGNyZWF0ZSBicm9hZGNhc3QgZm9yIHVua25vd24gcm9vbSAoaW5mbyBldmVudCAke3RoaXMuaW5mb0V2ZW50SWR9KWApO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHJvb21JZDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBEZXRlcm1pbmVzIHRoZSBpbml0aWFsIGJyb2FkY2FzdCBzdGF0ZS5cbiAgICAgKiBDaGVja3MgYWxsIHJlbGF0ZWQgZXZlbnRzLiBJZiBvbmUgaGFzIHRoZSBcInN0b3BwZWRcIiBzdGF0ZSDihpIgc3RvcHBlZCwgZWxzZSBzdGFydGVkLlxuICAgICAqL1xuICAgIHByaXZhdGUgZGV0ZXJtaW5lSW5pdGlhbFN0YXRlRnJvbUluZm9FdmVudCgpOiBWb2ljZUJyb2FkY2FzdFJlY29yZGluZ1N0YXRlIHtcbiAgICAgICAgY29uc3Qgcm9vbSA9IHRoaXMuY2xpZW50LmdldFJvb20odGhpcy5yb29tSWQpO1xuICAgICAgICBjb25zdCByZWxhdGlvbnMgPSByb29tXG4gICAgICAgICAgICA/LmdldFVuZmlsdGVyZWRUaW1lbGluZVNldCgpXG4gICAgICAgICAgICA/LnJlbGF0aW9ucz8uZ2V0Q2hpbGRFdmVudHNGb3JFdmVudCh0aGlzLmluZm9FdmVudElkLCBSZWxhdGlvblR5cGUuUmVmZXJlbmNlLCBWb2ljZUJyb2FkY2FzdEluZm9FdmVudFR5cGUpO1xuICAgICAgICBjb25zdCByZWxhdGVkRXZlbnRzID0gcmVsYXRpb25zPy5nZXRSZWxhdGlvbnMoKTtcbiAgICAgICAgcmV0dXJuICFyZWxhdGVkRXZlbnRzPy5maW5kKChldmVudDogTWF0cml4RXZlbnQpID0+IHtcbiAgICAgICAgICAgIHJldHVybiBldmVudC5nZXRDb250ZW50KCk/LnN0YXRlID09PSBWb2ljZUJyb2FkY2FzdEluZm9TdGF0ZS5TdG9wcGVkO1xuICAgICAgICB9KVxuICAgICAgICAgICAgPyBWb2ljZUJyb2FkY2FzdEluZm9TdGF0ZS5TdGFydGVkXG4gICAgICAgICAgICA6IFZvaWNlQnJvYWRjYXN0SW5mb1N0YXRlLlN0b3BwZWQ7XG4gICAgfVxuXG4gICAgcHVibGljIGdldFRpbWVMZWZ0KCk6IG51bWJlciB7XG4gICAgICAgIHJldHVybiB0aGlzLnRpbWVMZWZ0O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJldHJpZXMgZmFpbGVkIGFjdGlvbnMgb24gcmVjb25uZWN0LlxuICAgICAqL1xuICAgIHByaXZhdGUgb25SZWNvbm5lY3QgPSBhc3luYyAoKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgICAgIC8vIERvIG5vdGhpbmcgaWYgbm90IGluIGNvbm5lY3Rpb25fZXJyb3Igc3RhdGUuXG4gICAgICAgIGlmICh0aGlzLnN0YXRlICE9PSBcImNvbm5lY3Rpb25fZXJyb3JcIikgcmV0dXJuO1xuXG4gICAgICAgIC8vIENvcHkgdGhlIGFycmF5LCBzbyB0aGF0IGl0IGlzIHBvc3NpYmxlIHRvIHJlbW92ZSBlbGVtZW50cyBmcm9tIGl0IHdoaWxlIGl0ZXJhdGluZyBvdmVyIHRoZSBvcmlnaW5hbC5cbiAgICAgICAgY29uc3QgdG9SZXRyeUNvcHkgPSBbLi4udGhpcy50b1JldHJ5XTtcblxuICAgICAgICBmb3IgKGNvbnN0IHJldHJ5Rm4gb2YgdGhpcy50b1JldHJ5KSB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIGF3YWl0IHJldHJ5Rm4oKTtcbiAgICAgICAgICAgICAgICAvLyBTdWNjZXNzZnVsbHkgcmV0cmllZC4gUmVtb3ZlIGZyb20gYXJyYXkgY29weS5cbiAgICAgICAgICAgICAgICB0b1JldHJ5Q29weS5zcGxpY2UodG9SZXRyeUNvcHkuaW5kZXhPZihyZXRyeUZuKSwgMSk7XG4gICAgICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICAgICAgICAvLyBUaGUgY3VycmVudCByZXRyeSBjYWxsYmFjayBmYWlsZWQuIFN0b3AgdGhlIGxvb3AuXG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnRvUmV0cnkgPSB0b1JldHJ5Q29weTtcblxuICAgICAgICBpZiAodGhpcy50b1JldHJ5Lmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgLy8gRXZlcnl0aGluZyBoYXMgYmVlbiBzdWNjZXNzZnVsbHkgcmV0cmllZC4gUmVjb3ZlciBmcm9tIGVycm9yIHN0YXRlIHRvIHBhdXNlZC5cbiAgICAgICAgICAgIGF3YWl0IHRoaXMucGF1c2UoKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBwcml2YXRlIGFzeW5jIHNldFRpbWVMZWZ0KHRpbWVMZWZ0OiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgaWYgKHRpbWVMZWZ0IDw9IDApIHtcbiAgICAgICAgICAgIC8vIHRpbWUgaXMgdXAgLSBzdG9wIHRoZSByZWNvcmRpbmdcbiAgICAgICAgICAgIHJldHVybiBhd2FpdCB0aGlzLnN0b3AoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGRvIG5ldmVyIGluY3JlYXNlIHRpbWUgbGVmdDsgbm8gYWN0aW9uIGlmIGVxdWFsc1xuICAgICAgICBpZiAodGltZUxlZnQgPj0gdGhpcy50aW1lTGVmdCkgcmV0dXJuO1xuXG4gICAgICAgIHRoaXMudGltZUxlZnQgPSB0aW1lTGVmdDtcbiAgICAgICAgdGhpcy5lbWl0KFZvaWNlQnJvYWRjYXN0UmVjb3JkaW5nRXZlbnQuVGltZUxlZnRDaGFuZ2VkLCB0aW1lTGVmdCk7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHN0YXJ0KCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRSZWNvcmRlcigpLnN0YXJ0KCk7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHN0b3AoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGlmICh0aGlzLnN0YXRlID09PSBWb2ljZUJyb2FkY2FzdEluZm9TdGF0ZS5TdG9wcGVkKSByZXR1cm47XG5cbiAgICAgICAgdGhpcy5zZXRTdGF0ZShWb2ljZUJyb2FkY2FzdEluZm9TdGF0ZS5TdG9wcGVkKTtcbiAgICAgICAgYXdhaXQgdGhpcy5zdG9wUmVjb3JkZXIoKTtcbiAgICAgICAgYXdhaXQgdGhpcy5zZW5kSW5mb1N0YXRlRXZlbnQoVm9pY2VCcm9hZGNhc3RJbmZvU3RhdGUuU3RvcHBlZCk7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHBhdXNlKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICAvLyBzdG9wcGVkIG9yIGFscmVhZHkgcGF1c2VkIHJlY29yZGluZ3MgY2Fubm90IGJlIHBhdXNlZFxuICAgICAgICBpZiAoXG4gICAgICAgICAgICAoXG4gICAgICAgICAgICAgICAgW1ZvaWNlQnJvYWRjYXN0SW5mb1N0YXRlLlN0b3BwZWQsIFZvaWNlQnJvYWRjYXN0SW5mb1N0YXRlLlBhdXNlZF0gYXMgVm9pY2VCcm9hZGNhc3RSZWNvcmRpbmdTdGF0ZVtdXG4gICAgICAgICAgICApLmluY2x1ZGVzKHRoaXMuc3RhdGUpXG4gICAgICAgIClcbiAgICAgICAgICAgIHJldHVybjtcblxuICAgICAgICB0aGlzLnNldFN0YXRlKFZvaWNlQnJvYWRjYXN0SW5mb1N0YXRlLlBhdXNlZCk7XG4gICAgICAgIGF3YWl0IHRoaXMuc3RvcFJlY29yZGVyKCk7XG4gICAgICAgIGF3YWl0IHRoaXMuc2VuZEluZm9TdGF0ZUV2ZW50KFZvaWNlQnJvYWRjYXN0SW5mb1N0YXRlLlBhdXNlZCk7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHJlc3VtZSgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgaWYgKHRoaXMuc3RhdGUgIT09IFZvaWNlQnJvYWRjYXN0SW5mb1N0YXRlLlBhdXNlZCkgcmV0dXJuO1xuXG4gICAgICAgIHRoaXMuc2V0U3RhdGUoVm9pY2VCcm9hZGNhc3RJbmZvU3RhdGUuUmVzdW1lZCk7XG4gICAgICAgIGF3YWl0IHRoaXMuZ2V0UmVjb3JkZXIoKS5zdGFydCgpO1xuICAgICAgICBhd2FpdCB0aGlzLnNlbmRJbmZvU3RhdGVFdmVudChWb2ljZUJyb2FkY2FzdEluZm9TdGF0ZS5SZXN1bWVkKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgdG9nZ2xlID0gYXN5bmMgKCk6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgICAgICBpZiAodGhpcy5nZXRTdGF0ZSgpID09PSBWb2ljZUJyb2FkY2FzdEluZm9TdGF0ZS5QYXVzZWQpIHJldHVybiB0aGlzLnJlc3VtZSgpO1xuXG4gICAgICAgIGlmIChcbiAgICAgICAgICAgIChcbiAgICAgICAgICAgICAgICBbVm9pY2VCcm9hZGNhc3RJbmZvU3RhdGUuU3RhcnRlZCwgVm9pY2VCcm9hZGNhc3RJbmZvU3RhdGUuUmVzdW1lZF0gYXMgVm9pY2VCcm9hZGNhc3RSZWNvcmRpbmdTdGF0ZVtdXG4gICAgICAgICAgICApLmluY2x1ZGVzKHRoaXMuZ2V0U3RhdGUoKSlcbiAgICAgICAgKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5wYXVzZSgpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHB1YmxpYyBnZXRTdGF0ZSgpOiBWb2ljZUJyb2FkY2FzdFJlY29yZGluZ1N0YXRlIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc3RhdGU7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBnZXRSZWNvcmRlcigpOiBWb2ljZUJyb2FkY2FzdFJlY29yZGVyIHtcbiAgICAgICAgaWYgKCF0aGlzLnJlY29yZGVyKSB7XG4gICAgICAgICAgICB0aGlzLnJlY29yZGVyID0gY3JlYXRlVm9pY2VCcm9hZGNhc3RSZWNvcmRlcigpO1xuICAgICAgICAgICAgdGhpcy5yZWNvcmRlci5vbihWb2ljZUJyb2FkY2FzdFJlY29yZGVyRXZlbnQuQ2h1bmtSZWNvcmRlZCwgdGhpcy5vbkNodW5rUmVjb3JkZWQpO1xuICAgICAgICAgICAgdGhpcy5yZWNvcmRlci5vbihWb2ljZUJyb2FkY2FzdFJlY29yZGVyRXZlbnQuQ3VycmVudENodW5rTGVuZ3RoVXBkYXRlZCwgdGhpcy5vbkN1cnJlbnRDaHVua0xlbmd0aFVwZGF0ZWQpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRoaXMucmVjb3JkZXI7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIGRlc3Ryb3koKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGlmICh0aGlzLnJlY29yZGVyKSB7XG4gICAgICAgICAgICB0aGlzLnJlY29yZGVyLnN0b3AoKTtcbiAgICAgICAgICAgIHRoaXMucmVjb3JkZXIuZGVzdHJveSgpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5pbmZvRXZlbnQub2ZmKE1hdHJpeEV2ZW50RXZlbnQuQmVmb3JlUmVkYWN0aW9uLCB0aGlzLm9uQmVmb3JlUmVkYWN0aW9uKTtcbiAgICAgICAgdGhpcy5yZW1vdmVBbGxMaXN0ZW5lcnMoKTtcbiAgICAgICAgZGlzLnVucmVnaXN0ZXIodGhpcy5kaXNwYXRjaGVyUmVmKTtcbiAgICAgICAgdGhpcy5jaHVua0V2ZW50cyA9IG5ldyBWb2ljZUJyb2FkY2FzdENodW5rRXZlbnRzKCk7XG4gICAgICAgIHRoaXMuY2h1bmtSZWxhdGlvbkhlbHBlci5kZXN0cm95KCk7XG4gICAgICAgIHRoaXMuY2xpZW50Lm9mZihDbGllbnRFdmVudC5TeW5jLCB0aGlzLnJlY29ubmVjdGVkTGlzdGVuZXIpO1xuICAgIH1cblxuICAgIHByaXZhdGUgb25CZWZvcmVSZWRhY3Rpb24gPSAoKTogdm9pZCA9PiB7XG4gICAgICAgIGlmICh0aGlzLmdldFN0YXRlKCkgIT09IFZvaWNlQnJvYWRjYXN0SW5mb1N0YXRlLlN0b3BwZWQpIHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoVm9pY2VCcm9hZGNhc3RJbmZvU3RhdGUuU3RvcHBlZCk7XG4gICAgICAgICAgICAvLyBkZXN0cm95IGNsZWFucyB1cCBldmVyeXRoaW5nXG4gICAgICAgICAgICB0aGlzLmRlc3Ryb3koKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBwcml2YXRlIG9uQWN0aW9uID0gKHBheWxvYWQ6IEFjdGlvblBheWxvYWQpOiB2b2lkID0+IHtcbiAgICAgICAgaWYgKHBheWxvYWQuYWN0aW9uICE9PSBcImNhbGxfc3RhdGVcIikgcmV0dXJuO1xuXG4gICAgICAgIC8vIHBhdXNlIG9uIGFueSBjYWxsIGFjdGlvblxuICAgICAgICB0aGlzLnBhdXNlKCk7XG4gICAgfTtcblxuICAgIHByaXZhdGUgc2V0U3RhdGUoc3RhdGU6IFZvaWNlQnJvYWRjYXN0UmVjb3JkaW5nU3RhdGUpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5zdGF0ZSA9IHN0YXRlO1xuICAgICAgICB0aGlzLmVtaXQoVm9pY2VCcm9hZGNhc3RSZWNvcmRpbmdFdmVudC5TdGF0ZUNoYW5nZWQsIHRoaXMuc3RhdGUpO1xuICAgIH1cblxuICAgIHByaXZhdGUgb25DdXJyZW50Q2h1bmtMZW5ndGhVcGRhdGVkID0gKGN1cnJlbnRDaHVua0xlbmd0aDogbnVtYmVyKTogdm9pZCA9PiB7XG4gICAgICAgIHRoaXMuc2V0VGltZUxlZnQodGhpcy5tYXhMZW5ndGggLSB0aGlzLmNodW5rRXZlbnRzLmdldExlbmd0aFNlY29uZHMoKSAtIGN1cnJlbnRDaHVua0xlbmd0aCk7XG4gICAgfTtcblxuICAgIHByaXZhdGUgb25DaHVua1JlY29yZGVkID0gYXN5bmMgKGNodW5rOiBDaHVua1JlY29yZGVkUGF5bG9hZCk6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgICAgICBjb25zdCB1cGxvYWRBbmRTZW5kRm4gPSBhc3luYyAoKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgICAgICAgICBjb25zdCB7IHVybCwgZmlsZSB9ID0gYXdhaXQgdGhpcy51cGxvYWRGaWxlKGNodW5rKTtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuc2VuZFZvaWNlTWVzc2FnZShjaHVuaywgdXJsLCBmaWxlKTtcbiAgICAgICAgfTtcblxuICAgICAgICBhd2FpdCB0aGlzLmNhbGxXaXRoUmV0cnkodXBsb2FkQW5kU2VuZEZuKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogVGhpcyBmdW5jdGlvbiBpcyBjYWxsZWQgb24gY29ubmVjdGlvbiBlcnJvcnMuXG4gICAgICogSXQgc2V0cyB0aGUgY29ubmVjdGlvbiBlcnJvciBzdGF0ZSBhbmQgc3RvcHMgdGhlIHJlY29yZGVyLlxuICAgICAqL1xuICAgIHByaXZhdGUgYXN5bmMgb25Db25uZWN0aW9uRXJyb3IoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHRoaXMucGxheUNvbm5lY3Rpb25FcnJvckF1ZGlvTm90aWZpY2F0aW9uKCkuY2F0Y2goKCkgPT4ge1xuICAgICAgICAgICAgLy8gRXJyb3IgbG9nZ2VkIGluIHBsYXlDb25uZWN0aW9uRXJyb3JBdWRpb05vdGlmaWNhdGlvbigpLlxuICAgICAgICB9KTtcbiAgICAgICAgYXdhaXQgdGhpcy5zdG9wUmVjb3JkZXIoZmFsc2UpO1xuICAgICAgICB0aGlzLnNldFN0YXRlKFwiY29ubmVjdGlvbl9lcnJvclwiKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIHBsYXlDb25uZWN0aW9uRXJyb3JBdWRpb05vdGlmaWNhdGlvbigpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgaWYgKGxvY2FsTm90aWZpY2F0aW9uc0FyZVNpbGVuY2VkKHRoaXMuY2xpZW50KSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgYXdhaXQgdGhpcy5iYWNrZ3JvdW5kQXVkaW8ucGlja0Zvcm1hdEFuZFBsYXkoXCIuL21lZGlhL2Vycm9yXCIsIFtcIm1wM1wiLCBcIm9nZ1wiXSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyB1cGxvYWRGaWxlKGNodW5rOiBDaHVua1JlY29yZGVkUGF5bG9hZCk6IFJldHVyblR5cGU8dHlwZW9mIHVwbG9hZEZpbGU+IHtcbiAgICAgICAgcmV0dXJuIHVwbG9hZEZpbGUoXG4gICAgICAgICAgICB0aGlzLmNsaWVudCxcbiAgICAgICAgICAgIHRoaXMucm9vbUlkLFxuICAgICAgICAgICAgbmV3IEJsb2IoW2NodW5rLmJ1ZmZlcl0sIHtcbiAgICAgICAgICAgICAgICB0eXBlOiB0aGlzLmdldFJlY29yZGVyKCkuY29udGVudFR5cGUsXG4gICAgICAgICAgICB9KSxcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIHNlbmRWb2ljZU1lc3NhZ2UoY2h1bms6IENodW5rUmVjb3JkZWRQYXlsb2FkLCB1cmw/OiBzdHJpbmcsIGZpbGU/OiBFbmNyeXB0ZWRGaWxlKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBJbmNyZW1lbnQgdGhlIGxhc3Qgc2VxdWVuY2UgbnVtYmVyIGFuZCB1c2UgaXQgZm9yIHRoaXMgbWVzc2FnZS5cbiAgICAgICAgICogRG9uZSBvdXRzaWRlIG9mIHRoZSBzZW5kTWVzc2FnZUZuIHRvIGdldCBhIHNjb3BlZCB2YWx1ZS5cbiAgICAgICAgICogQWxzbyBzZWUge0BsaW5rIFZvaWNlQnJvYWRjYXN0UmVjb3JkaW5nLnNlcXVlbmNlfS5cbiAgICAgICAgICovXG4gICAgICAgIGNvbnN0IHNlcXVlbmNlID0gKyt0aGlzLnNlcXVlbmNlO1xuXG4gICAgICAgIGNvbnN0IHNlbmRNZXNzYWdlRm4gPSBhc3luYyAoKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgICAgICAgICBjb25zdCBjb250ZW50ID0gY3JlYXRlVm9pY2VNZXNzYWdlQ29udGVudChcbiAgICAgICAgICAgICAgICB1cmwsXG4gICAgICAgICAgICAgICAgdGhpcy5nZXRSZWNvcmRlcigpLmNvbnRlbnRUeXBlLFxuICAgICAgICAgICAgICAgIE1hdGgucm91bmQoY2h1bmsubGVuZ3RoICogMTAwMCksXG4gICAgICAgICAgICAgICAgY2h1bmsuYnVmZmVyLmxlbmd0aCxcbiAgICAgICAgICAgICAgICBmaWxlLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGNvbnRlbnRbXCJtLnJlbGF0ZXNfdG9cIl0gPSB7XG4gICAgICAgICAgICAgICAgcmVsX3R5cGU6IFJlbGF0aW9uVHlwZS5SZWZlcmVuY2UsXG4gICAgICAgICAgICAgICAgZXZlbnRfaWQ6IHRoaXMuaW5mb0V2ZW50SWQsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgKDxBdWRpb0NvbnRlbnQ+Y29udGVudClbXCJpby5lbGVtZW50LnZvaWNlX2Jyb2FkY2FzdF9jaHVua1wiXSA9IHtcbiAgICAgICAgICAgICAgICBzZXF1ZW5jZSxcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIGF3YWl0IHRoaXMuY2xpZW50LnNlbmRNZXNzYWdlKHRoaXMucm9vbUlkLCBjb250ZW50KTtcbiAgICAgICAgfTtcblxuICAgICAgICBhd2FpdCB0aGlzLmNhbGxXaXRoUmV0cnkoc2VuZE1lc3NhZ2VGbik7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2VuZHMgYW4gaW5mbyBzdGF0ZSBldmVudCB3aXRoIGdpdmVuIHN0YXRlLlxuICAgICAqIE9uIGVycm9yIHN0b3JlcyBhIHJlc2VuZCBmdW5jdGlvbiBhbmQgc2V0U3RhdGUoc3RhdGUpIGluIHtAbGluayB0b1JldHJ5fSBhbmRcbiAgICAgKiBzZXRzIHRoZSBicm9hZGNhc3Qgc3RhdGUgdG8gY29ubmVjdGlvbl9lcnJvci5cbiAgICAgKi9cbiAgICBwcml2YXRlIGFzeW5jIHNlbmRJbmZvU3RhdGVFdmVudChzdGF0ZTogVm9pY2VCcm9hZGNhc3RJbmZvU3RhdGUpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgY29uc3Qgc2VuZEV2ZW50Rm4gPSBhc3luYyAoKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLmNsaWVudC5zZW5kU3RhdGVFdmVudChcbiAgICAgICAgICAgICAgICB0aGlzLnJvb21JZCxcbiAgICAgICAgICAgICAgICBWb2ljZUJyb2FkY2FzdEluZm9FdmVudFR5cGUsXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBkZXZpY2VfaWQ6IHRoaXMuY2xpZW50LmdldERldmljZUlkKCksXG4gICAgICAgICAgICAgICAgICAgIHN0YXRlLFxuICAgICAgICAgICAgICAgICAgICBsYXN0X2NodW5rX3NlcXVlbmNlOiB0aGlzLnNlcXVlbmNlLFxuICAgICAgICAgICAgICAgICAgICBbXCJtLnJlbGF0ZXNfdG9cIl06IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlbF90eXBlOiBSZWxhdGlvblR5cGUuUmVmZXJlbmNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnRfaWQ6IHRoaXMuaW5mb0V2ZW50SWQsXG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgfSBhcyBWb2ljZUJyb2FkY2FzdEluZm9FdmVudENvbnRlbnQsXG4gICAgICAgICAgICAgICAgdGhpcy5jbGllbnQuZ2V0U2FmZVVzZXJJZCgpLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgfTtcblxuICAgICAgICBhd2FpdCB0aGlzLmNhbGxXaXRoUmV0cnkoc2VuZEV2ZW50Rm4pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENhbGxzIHRoZSBmdW5jdGlvbi5cbiAgICAgKiBPbiBmYWlsdXJlIGFkZHMgaXQgdG8gdGhlIHJldHJ5IGxpc3QgYW5kIHRyaWdnZXJzIGNvbm5lY3Rpb24gZXJyb3IuXG4gICAgICoge0BsaW5rIHRvUmV0cnl9XG4gICAgICoge0BsaW5rIG9uQ29ubmVjdGlvbkVycm9yfVxuICAgICAqL1xuICAgIHByaXZhdGUgYXN5bmMgY2FsbFdpdGhSZXRyeShyZXRyeUFibGVGbjogKCkgPT4gUHJvbWlzZTx2b2lkPik6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgYXdhaXQgcmV0cnlBYmxlRm4oKTtcbiAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgICB0aGlzLnRvUmV0cnkucHVzaChyZXRyeUFibGVGbik7XG4gICAgICAgICAgICB0aGlzLm9uQ29ubmVjdGlvbkVycm9yKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIHN0b3BSZWNvcmRlcihlbWl0ID0gdHJ1ZSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBpZiAoIXRoaXMucmVjb3JkZXIpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCBsYXN0Q2h1bmsgPSBhd2FpdCB0aGlzLnJlY29yZGVyLnN0b3AoKTtcbiAgICAgICAgICAgIGlmIChsYXN0Q2h1bmsgJiYgZW1pdCkge1xuICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMub25DaHVua1JlY29yZGVkKGxhc3RDaHVuayk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgbG9nZ2VyLndhcm4oXCJlcnJvciBzdG9wcGluZyB2b2ljZSBicm9hZGNhc3QgcmVjb3JkZXJcIiwgZXJyKTtcbiAgICAgICAgfVxuICAgIH1cbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7QUFRQSxJQUFBQSxPQUFBLEdBQUFDLE9BQUE7QUFDQSxJQUFBQyxPQUFBLEdBQUFELE9BQUE7QUFhQSxJQUFBRSxDQUFBLEdBQUFGLE9BQUE7QUFVQSxJQUFBRyxnQkFBQSxHQUFBSCxPQUFBO0FBQ0EsSUFBQUksMEJBQUEsR0FBQUosT0FBQTtBQUVBLElBQUFLLFdBQUEsR0FBQUMsc0JBQUEsQ0FBQU4sT0FBQTtBQUVBLElBQUFPLDBCQUFBLEdBQUFQLE9BQUE7QUFDQSxJQUFBUSxnQkFBQSxHQUFBUixPQUFBO0FBQ0EsSUFBQVMsV0FBQSxHQUFBVCxPQUFBO0FBQ0EsSUFBQVUsY0FBQSxHQUFBVixPQUFBO0FBQ0EsSUFBQVcsZ0JBQUEsR0FBQVgsT0FBQTtBQXpDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQU5BLElBMkNZWSw0QkFBNEIsR0FBQUMsT0FBQSxDQUFBRCw0QkFBQSwwQkFBNUJBLDRCQUE0QjtFQUE1QkEsNEJBQTRCO0VBQTVCQSw0QkFBNEI7RUFBQSxPQUE1QkEsNEJBQTRCO0FBQUE7QUFZakMsTUFBTUUsdUJBQXVCLFNBQ3hCQyx5QkFBaUIsQ0FFN0I7RUFzQldDLFdBQVdBLENBQ0VDLFNBQXNCLEVBQzlCQyxNQUFvQixFQUM1QkMsWUFBc0MsRUFDeEM7SUFDRSxLQUFLLENBQUMsQ0FBQztJQUFDLElBQUFDLGdCQUFBLENBQUFDLE9BQUE7SUFBQSxJQUFBRCxnQkFBQSxDQUFBQyxPQUFBLG9CQXpCc0MsSUFBSTtJQUFBLElBQUFE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