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