matrix-react-sdk
Version:
SDK for matrix.org using React
497 lines • 75 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.VoiceBroadcastPlaybackState = exports.VoiceBroadcastPlaybackEvent = exports.VoiceBroadcastPlayback = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _matrix = require("matrix-js-sdk/src/matrix");
var _matrixWidgetApi = require("matrix-widget-api");
var _logger = require("matrix-js-sdk/src/logger");
var _utils = require("matrix-js-sdk/src/utils");
var _Playback = require("../../audio/Playback");
var _PlaybackManager = require("../../audio/PlaybackManager");
var _AsyncStore = require("../../stores/AsyncStore");
var _MediaEventHelper = require("../../utils/MediaEventHelper");
var _ = require("..");
var _RelationsHelper = require("../../events/RelationsHelper");
var _VoiceBroadcastChunkEvents = require("../utils/VoiceBroadcastChunkEvents");
var _determineVoiceBroadcastLiveness = require("../utils/determineVoiceBroadcastLiveness");
var _languageHandler = require("../../languageHandler");
/*
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 VoiceBroadcastPlaybackState = exports.VoiceBroadcastPlaybackState = /*#__PURE__*/function (VoiceBroadcastPlaybackState) {
VoiceBroadcastPlaybackState["Paused"] = "pause";
VoiceBroadcastPlaybackState["Playing"] = "playing";
VoiceBroadcastPlaybackState["Stopped"] = "stopped";
VoiceBroadcastPlaybackState["Buffering"] = "buffering";
VoiceBroadcastPlaybackState["Error"] = "error";
return VoiceBroadcastPlaybackState;
}({});
let VoiceBroadcastPlaybackEvent = exports.VoiceBroadcastPlaybackEvent = /*#__PURE__*/function (VoiceBroadcastPlaybackEvent) {
VoiceBroadcastPlaybackEvent["TimesChanged"] = "times_changed";
VoiceBroadcastPlaybackEvent["LivenessChanged"] = "liveness_changed";
VoiceBroadcastPlaybackEvent["StateChanged"] = "state_changed";
VoiceBroadcastPlaybackEvent["InfoStateChanged"] = "info_state_changed";
return VoiceBroadcastPlaybackEvent;
}({});
class VoiceBroadcastPlayback extends _matrix.TypedEventEmitter {
constructor(infoEvent, client, recordings) {
super();
(0, _defineProperty2.default)(this, "state", VoiceBroadcastPlaybackState.Stopped);
(0, _defineProperty2.default)(this, "chunkEvents", new _VoiceBroadcastChunkEvents.VoiceBroadcastChunkEvents());
/** @var Map: event Id → undecryptable event */
(0, _defineProperty2.default)(this, "utdChunkEvents", new Map());
(0, _defineProperty2.default)(this, "playbacks", new Map());
(0, _defineProperty2.default)(this, "currentlyPlaying", null);
/** @var total duration of all chunks in milliseconds */
(0, _defineProperty2.default)(this, "duration", 0);
/** @var current playback position in milliseconds */
(0, _defineProperty2.default)(this, "position", 0);
(0, _defineProperty2.default)(this, "liveData", new _matrixWidgetApi.SimpleObservable());
(0, _defineProperty2.default)(this, "liveness", "not-live");
// set via addInfoEvent() in constructor
(0, _defineProperty2.default)(this, "infoState", void 0);
(0, _defineProperty2.default)(this, "lastInfoEvent", void 0);
// set via setUpRelationsHelper() in constructor
(0, _defineProperty2.default)(this, "chunkRelationHelper", void 0);
(0, _defineProperty2.default)(this, "infoRelationHelper", void 0);
(0, _defineProperty2.default)(this, "skipToNext", void 0);
(0, _defineProperty2.default)(this, "skipToDeferred", void 0);
(0, _defineProperty2.default)(this, "addChunkEvent", async event => {
if (!event.getId() && !event.getTxnId()) {
// skip events without id and txn id
return false;
}
if (event.isDecryptionFailure()) {
this.onChunkEventDecryptionFailure(event);
return false;
}
if (event.getContent()?.msgtype !== _matrix.MsgType.Audio) {
// skip non-audio event
return false;
}
this.chunkEvents.addEvent(event);
this.setDuration(this.chunkEvents.getLength());
if (this.getState() === VoiceBroadcastPlaybackState.Buffering) {
await this.startOrPlayNext();
}
return true;
});
(0, _defineProperty2.default)(this, "onChunkEventDecryptionFailure", event => {
const eventId = event.getId();
if (!eventId) {
// This should not happen, as the existence of the Id is checked before the call.
// Log anyway and return.
_logger.logger.warn("Broadcast chunk decryption failure for event without Id", {
broadcast: this.infoEvent.getId()
});
return;
}
if (!this.utdChunkEvents.has(eventId)) {
event.once(_matrix.MatrixEventEvent.Decrypted, this.onChunkEventDecrypted);
}
this.utdChunkEvents.set(eventId, event);
this.setError();
});
(0, _defineProperty2.default)(this, "onChunkEventDecrypted", async event => {
const eventId = event.getId();
if (!eventId) {
// This should not happen, as the existence of the Id is checked before the call.
// Log anyway and return.
_logger.logger.warn("Broadcast chunk decrypted for event without Id", {
broadcast: this.infoEvent.getId()
});
return;
}
this.utdChunkEvents.delete(eventId);
await this.addChunkEvent(event);
if (this.utdChunkEvents.size === 0) {
// no more UTD events, recover from error to paused
this.setState(VoiceBroadcastPlaybackState.Paused);
}
});
(0, _defineProperty2.default)(this, "startOrPlayNext", async () => {
if (this.currentlyPlaying) {
return this.playNext();
}
return await this.start();
});
(0, _defineProperty2.default)(this, "addInfoEvent", event => {
if (this.lastInfoEvent && this.lastInfoEvent.getTs() >= event.getTs()) {
// Only handle newer events
return;
}
const state = event.getContent()?.state;
if (!Object.values(_.VoiceBroadcastInfoState).includes(state)) {
// Do not handle unknown voice broadcast states
return;
}
this.lastInfoEvent = event;
this.setInfoState(state);
});
(0, _defineProperty2.default)(this, "onBeforeRedaction", () => {
if (this.getState() !== VoiceBroadcastPlaybackState.Stopped) {
this.stop();
// destroy cleans up everything
this.destroy();
}
});
(0, _defineProperty2.default)(this, "onPlaybackPositionUpdate", (event, position) => {
if (event !== this.currentlyPlaying) return;
const newPosition = this.chunkEvents.getLengthTo(event) + position * 1000; // observable sends seconds
// do not jump backwards - this can happen when transiting from one to another chunk
if (newPosition < this.position) return;
this.setPosition(newPosition);
});
(0, _defineProperty2.default)(this, "onPlaybackStateChange", async (event, newState) => {
if (event !== this.currentlyPlaying) return;
if (newState !== _Playback.PlaybackState.Stopped) return;
await this.playNext();
this.unloadPlayback(event);
});
this.infoEvent = infoEvent;
this.client = client;
this.recordings = recordings;
this.addInfoEvent(this.infoEvent);
this.infoEvent.on(_matrix.MatrixEventEvent.BeforeRedaction, this.onBeforeRedaction);
this.setUpRelationsHelper();
}
async setUpRelationsHelper() {
this.infoRelationHelper = new _RelationsHelper.RelationsHelper(this.infoEvent, _matrix.RelationType.Reference, _.VoiceBroadcastInfoEventType, this.client);
this.infoRelationHelper.getCurrent().forEach(this.addInfoEvent);
if (this.infoState !== _.VoiceBroadcastInfoState.Stopped) {
// Only required if not stopped. Stopped is the final state.
this.infoRelationHelper.on(_RelationsHelper.RelationsHelperEvent.Add, this.addInfoEvent);
try {
await this.infoRelationHelper.emitFetchCurrent();
} catch (err) {
_logger.logger.warn("error fetching server side relation for voice broadcast info", err);
// fall back to local events
this.infoRelationHelper.emitCurrent();
}
}
this.chunkRelationHelper = new _RelationsHelper.RelationsHelper(this.infoEvent, _matrix.RelationType.Reference, _matrix.EventType.RoomMessage, this.client);
this.chunkRelationHelper.on(_RelationsHelper.RelationsHelperEvent.Add, this.addChunkEvent);
try {
// TODO Michael W: only fetch events if needed, blocked by PSF-1708
await this.chunkRelationHelper.emitFetchCurrent();
} catch (err) {
_logger.logger.warn("error fetching server side relation for voice broadcast chunks", err);
// fall back to local events
this.chunkRelationHelper.emitCurrent();
}
}
async tryLoadPlayback(chunkEvent) {
try {
return await this.loadPlayback(chunkEvent);
} catch (err) {
_logger.logger.warn("Unable to load broadcast playback", {
message: err.message,
broadcastId: this.infoEvent.getId(),
chunkId: chunkEvent.getId()
});
this.setError();
}
}
async loadPlayback(chunkEvent) {
const eventId = chunkEvent.getId();
if (!eventId) {
throw new Error("Broadcast chunk event without Id occurred");
}
const helper = new _MediaEventHelper.MediaEventHelper(chunkEvent);
const blob = await helper.sourceBlob.value;
const buffer = await blob.arrayBuffer();
const playback = _PlaybackManager.PlaybackManager.instance.createPlaybackInstance(buffer);
await playback.prepare();
playback.clockInfo.populatePlaceholdersFrom(chunkEvent);
this.playbacks.set(eventId, playback);
playback.on(_AsyncStore.UPDATE_EVENT, state => this.onPlaybackStateChange(chunkEvent, state));
playback.clockInfo.liveData.onUpdate(([position]) => {
this.onPlaybackPositionUpdate(chunkEvent, position);
});
}
unloadPlayback(event) {
const playback = this.playbacks.get(event.getId());
if (!playback) return;
playback.destroy();
this.playbacks.delete(event.getId());
}
setDuration(duration) {
if (this.duration === duration) return;
this.duration = duration;
this.emitTimesChanged();
this.liveData.update([this.timeSeconds, this.durationSeconds]);
}
setPosition(position) {
if (this.position === position) return;
this.position = position;
this.emitTimesChanged();
this.liveData.update([this.timeSeconds, this.durationSeconds]);
}
emitTimesChanged() {
this.emit(VoiceBroadcastPlaybackEvent.TimesChanged, {
duration: this.durationSeconds,
position: this.timeSeconds,
timeLeft: this.timeLeftSeconds
});
}
async playNext() {
if (!this.currentlyPlaying) return;
const next = this.chunkEvents.getNext(this.currentlyPlaying);
if (next) {
return this.playEvent(next);
}
if (this.getInfoState() === _.VoiceBroadcastInfoState.Stopped && this.chunkEvents.getSequenceForEvent(this.currentlyPlaying) === this.lastChunkSequence) {
this.stop();
} else {
// No more chunks available, although the broadcast is not finished → enter buffering state.
this.setState(VoiceBroadcastPlaybackState.Buffering);
}
}
/**
* @returns {number} The last chunk sequence from the latest info event.
* Falls back to the length of received chunks if the info event does not provide the number.
*/
get lastChunkSequence() {
return this.lastInfoEvent.getContent()?.last_chunk_sequence || this.chunkEvents.getNumberOfEvents();
}
async playEvent(event) {
this.setState(VoiceBroadcastPlaybackState.Playing);
this.currentlyPlaying = event;
const playback = await this.tryGetOrLoadPlaybackForEvent(event);
playback?.play();
}
async tryGetOrLoadPlaybackForEvent(event) {
try {
return await this.getOrLoadPlaybackForEvent(event);
} catch (err) {
_logger.logger.warn("Unable to load broadcast playback", {
message: err.message,
broadcastId: this.infoEvent.getId(),
chunkId: event.getId()
});
this.setError();
}
}
async getOrLoadPlaybackForEvent(event) {
const eventId = event.getId();
if (!eventId) {
throw new Error("Broadcast chunk event without Id occurred");
}
if (!this.playbacks.has(eventId)) {
// set to buffering while loading the chunk data
const currentState = this.getState();
this.setState(VoiceBroadcastPlaybackState.Buffering);
await this.loadPlayback(event);
this.setState(currentState);
}
const playback = this.playbacks.get(eventId);
if (!playback) {
throw new Error(`Unable to find playback for event ${event.getId()}`);
}
// try to load the playback for the next event for a smooth(er) playback
const nextEvent = this.chunkEvents.getNext(event);
if (nextEvent) this.tryLoadPlayback(nextEvent);
return playback;
}
getCurrentPlayback() {
if (!this.currentlyPlaying) return;
return this.playbacks.get(this.currentlyPlaying.getId());
}
getLiveness() {
return this.liveness;
}
setLiveness(liveness) {
if (this.liveness === liveness) return;
this.liveness = liveness;
this.emit(VoiceBroadcastPlaybackEvent.LivenessChanged, liveness);
}
get currentState() {
return _Playback.PlaybackState.Playing;
}
get timeSeconds() {
return this.position / 1000;
}
get durationSeconds() {
return this.duration / 1000;
}
get timeLeftSeconds() {
// Sometimes the meta data and the audio files are a little bit out of sync.
// Be sure it never returns a negative value.
return Math.max(0, Math.round(this.durationSeconds) - this.timeSeconds);
}
async skipTo(timeSeconds) {
this.skipToNext = timeSeconds;
if (this.skipToDeferred) {
// Skip to position is already in progress. Return the promise for that.
return this.skipToDeferred.promise;
}
this.skipToDeferred = (0, _utils.defer)();
while (this.skipToNext !== undefined) {
// Skip to position until skipToNext is undefined.
// skipToNext can be set if skipTo is called while already skipping.
const skipToNext = this.skipToNext;
this.skipToNext = undefined;
await this.doSkipTo(skipToNext);
}
this.skipToDeferred.resolve();
this.skipToDeferred = undefined;
}
async doSkipTo(timeSeconds) {
const time = timeSeconds * 1000;
const event = this.chunkEvents.findByTime(time);
if (!event) {
_logger.logger.warn("voice broadcast chunk event to skip to not found");
return;
}
const currentPlayback = this.getCurrentPlayback();
const skipToPlayback = await this.tryGetOrLoadPlaybackForEvent(event);
const currentPlaybackEvent = this.currentlyPlaying;
if (!skipToPlayback) {
_logger.logger.warn("voice broadcast chunk to skip to not found", event);
return;
}
this.currentlyPlaying = event;
if (currentPlayback && currentPlaybackEvent && currentPlayback !== skipToPlayback) {
// only stop and unload the playback here without triggering other effects, e.g. play next
currentPlayback.off(_AsyncStore.UPDATE_EVENT, this.onPlaybackStateChange);
await currentPlayback.stop();
currentPlayback.on(_AsyncStore.UPDATE_EVENT, this.onPlaybackStateChange);
this.unloadPlayback(currentPlaybackEvent);
}
const offsetInChunk = time - this.chunkEvents.getLengthTo(event);
await skipToPlayback.skipTo(offsetInChunk / 1000);
if (this.state === VoiceBroadcastPlaybackState.Playing && !skipToPlayback.isPlaying) {
await skipToPlayback.play();
}
this.setPosition(time);
}
async start() {
if (this.state === VoiceBroadcastPlaybackState.Playing) return;
const currentRecording = this.recordings.getCurrent();
if (currentRecording && currentRecording.getState() !== _.VoiceBroadcastInfoState.Stopped) {
const shouldStopRecording = await (0, _.showConfirmListenBroadcastStopCurrentDialog)();
if (!shouldStopRecording) {
// keep recording
return;
}
await this.recordings.getCurrent()?.stop();
}
const chunkEvents = this.chunkEvents.getEvents();
const toPlay = this.getInfoState() === _.VoiceBroadcastInfoState.Stopped ? chunkEvents[0] // start at the beginning for an ended voice broadcast
: chunkEvents[chunkEvents.length - 1]; // start at the current chunk for an ongoing voice broadcast
if (toPlay) {
return this.playEvent(toPlay);
}
this.setState(VoiceBroadcastPlaybackState.Buffering);
}
stop() {
// error is a final state
if (this.getState() === VoiceBroadcastPlaybackState.Error) return;
this.setState(VoiceBroadcastPlaybackState.Stopped);
this.getCurrentPlayback()?.stop();
this.currentlyPlaying = null;
this.setPosition(0);
}
pause() {
// error is a final state
if (this.getState() === VoiceBroadcastPlaybackState.Error) return;
// stopped voice broadcasts cannot be paused
if (this.getState() === VoiceBroadcastPlaybackState.Stopped) return;
this.setState(VoiceBroadcastPlaybackState.Paused);
this.getCurrentPlayback()?.pause();
}
resume() {
// error is a final state
if (this.getState() === VoiceBroadcastPlaybackState.Error) return;
if (!this.currentlyPlaying) {
// no playback to resume, start from the beginning
this.start();
return;
}
this.setState(VoiceBroadcastPlaybackState.Playing);
this.getCurrentPlayback()?.play();
}
/**
* Toggles the playback:
* stopped → playing
* playing → paused
* paused → playing
*/
async toggle() {
// error is a final state
if (this.getState() === VoiceBroadcastPlaybackState.Error) return;
if (this.state === VoiceBroadcastPlaybackState.Stopped) {
await this.start();
return;
}
if (this.state === VoiceBroadcastPlaybackState.Paused) {
this.resume();
return;
}
this.pause();
}
getState() {
return this.state;
}
setState(state) {
if (this.state === state) {
return;
}
this.state = state;
this.emit(VoiceBroadcastPlaybackEvent.StateChanged, state, this);
}
/**
* Set error state. Stop current playback, if any.
*/
setError() {
this.setState(VoiceBroadcastPlaybackState.Error);
this.getCurrentPlayback()?.stop();
this.currentlyPlaying = null;
this.setPosition(0);
}
getInfoState() {
return this.infoState;
}
setInfoState(state) {
if (this.infoState === state) {
return;
}
this.infoState = state;
this.emit(VoiceBroadcastPlaybackEvent.InfoStateChanged, state);
this.setLiveness((0, _determineVoiceBroadcastLiveness.determineVoiceBroadcastLiveness)(this.infoState));
}
get errorMessage() {
if (this.getState() !== VoiceBroadcastPlaybackState.Error) return "";
if (this.utdChunkEvents.size) return (0, _languageHandler._t)("voice_broadcast|failed_decrypt");
return (0, _languageHandler._t)("voice_broadcast|failed_generic");
}
destroy() {
for (const [, utdEvent] of this.utdChunkEvents) {
utdEvent.off(_matrix.MatrixEventEvent.Decrypted, this.onChunkEventDecrypted);
}
this.utdChunkEvents.clear();
this.chunkRelationHelper.destroy();
this.infoRelationHelper.destroy();
this.removeAllListeners();
this.chunkEvents = new _VoiceBroadcastChunkEvents.VoiceBroadcastChunkEvents();
this.playbacks.forEach(p => p.destroy());
this.playbacks = new Map();
}
}
exports.VoiceBroadcastPlayback = VoiceBroadcastPlayback;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbWF0cml4IiwicmVxdWlyZSIsIl9tYXRyaXhXaWRnZXRBcGkiLCJfbG9nZ2VyIiwiX3V0aWxzIiwiX1BsYXliYWNrIiwiX1BsYXliYWNrTWFuYWdlciIsIl9Bc3luY1N0b3JlIiwiX01lZGlhRXZlbnRIZWxwZXIiLCJfIiwiX1JlbGF0aW9uc0hlbHBlciIsIl9Wb2ljZUJyb2FkY2FzdENodW5rRXZlbnRzIiwiX2RldGVybWluZVZvaWNlQnJvYWRjYXN0TGl2ZW5lc3MiLCJfbGFuZ3VhZ2VIYW5kbGVyIiwiVm9pY2VCcm9hZGNhc3RQbGF5YmFja1N0YXRlIiwiZXhwb3J0cyIsIlZvaWNlQnJvYWRjYXN0UGxheWJhY2tFdmVudCIsIlZvaWNlQnJvYWRjYXN0UGxheWJhY2siLCJUeXBlZEV2ZW50RW1pdHRlciIsImNvbnN0cnVjdG9yIiwiaW5mb0V2ZW50IiwiY2xpZW50IiwicmVjb3JkaW5ncyIsIl9kZWZpbmVQcm9wZXJ0eTIiLCJkZWZhdWx0IiwiU3RvcHBlZCIsIlZvaWNlQnJvYWRjYXN0Q2h1bmtFdmVudHMiLCJNYXAiLCJTaW1wbGVPYnNlcnZhYmxlIiwiZXZlbnQiLCJnZXRJZCIsImdldFR4bklkIiwiaXNEZWNyeXB0aW9uRmFpbHVyZSIsIm9uQ2h1bmtFdmVudERlY3J5cHRpb25GYWlsdXJlIiwiZ2V0Q29udGVudCIsIm1zZ3R5cGUiLCJNc2dUeXBlIiwiQXVkaW8iLCJjaHVua0V2ZW50cyIsImFkZEV2ZW50Iiwic2V0RHVyYXRpb24iLCJnZXRMZW5ndGgiLCJnZXRTdGF0ZSIsIkJ1ZmZlcmluZyIsInN0YXJ0T3JQbGF5TmV4dCIsImV2ZW50SWQiLCJsb2dnZXIiLCJ3YXJuIiwiYnJvYWRjYXN0IiwidXRkQ2h1bmtFdmVudHMiLCJoYXMiLCJvbmNlIiwiTWF0cml4RXZlbnRFdmVudCIsIkRlY3J5cHRlZCIsIm9uQ2h1bmtFdmVudERlY3J5cHRlZCIsInNldCIsInNldEVycm9yIiwiZGVsZXRlIiwiYWRkQ2h1bmtFdmVudCIsInNpemUiLCJzZXRTdGF0ZSIsIlBhdXNlZCIsImN1cnJlbnRseVBsYXlpbmciLCJwbGF5TmV4dCIsInN0YXJ0IiwibGFzdEluZm9FdmVudCIsImdldFRzIiwic3RhdGUiLCJPYmplY3QiLCJ2YWx1ZXMiLCJWb2ljZUJyb2FkY2FzdEluZm9TdGF0ZSIsImluY2x1ZGVzIiwic2V0SW5mb1N0YXRlIiwic3RvcCIsImRlc3Ryb3kiLCJwb3NpdGlvbiIsIm5ld1Bvc2l0aW9uIiwiZ2V0TGVuZ3RoVG8iLCJzZXRQb3NpdGlvbiIsIm5ld1N0YXRlIiwiUGxheWJhY2tTdGF0ZSIsInVubG9hZFBsYXliYWNrIiwiYWRkSW5mb0V2ZW50Iiwib24iLCJCZWZvcmVSZWRhY3Rpb24iLCJvbkJlZm9yZVJlZGFjdGlvbiIsInNldFVwUmVsYXRpb25zSGVscGVyIiwiaW5mb1JlbGF0aW9uSGVscGVyIiwiUmVsYXRpb25zSGVscGVyIiwiUmVsYXRpb25UeXBlIiwiUmVmZXJlbmNlIiwiVm9pY2VCcm9hZGNhc3RJbmZvRXZlbnRUeXBlIiwiZ2V0Q3VycmVudCIsImZvckVhY2giLCJpbmZvU3RhdGUiLCJSZWxhdGlvbnNIZWxwZXJFdmVudCIsIkFkZCIsImVtaXRGZXRjaEN1cnJlbnQiLCJlcnIiLCJlbWl0Q3VycmVudCIsImNodW5rUmVsYXRpb25IZWxwZXIiLCJFdmVudFR5cGUiLCJSb29tTWVzc2FnZSIsInRyeUxvYWRQbGF5YmFjayIsImNodW5rRXZlbnQiLCJsb2FkUGxheWJhY2siLCJtZXNzYWdlIiwiYnJvYWRjYXN0SWQiLCJjaHVua0lkIiwiRXJyb3IiLCJoZWxwZXIiLCJNZWRpYUV2ZW50SGVscGVyIiwiYmxvYiIsInNvdXJjZUJsb2IiLCJ2YWx1ZSIsImJ1ZmZlciIsImFycmF5QnVmZmVyIiwicGxheWJhY2siLCJQbGF5YmFja01hbmFnZXIiLCJpbnN0YW5jZSIsImNyZWF0ZVBsYXliYWNrSW5zdGFuY2UiLCJwcmVwYXJlIiwiY2xvY2tJbmZvIiwicG9wdWxhdGVQbGFjZWhvbGRlcnNGcm9tIiwicGxheWJhY2tzIiwiVVBEQVRFX0VWRU5UIiwib25QbGF5YmFja1N0YXRlQ2hhbmdlIiwibGl2ZURhdGEiLCJvblVwZGF0ZSIsIm9uUGxheWJhY2tQb3NpdGlvblVwZGF0ZSIsImdldCIsImR1cmF0aW9uIiwiZW1pdFRpbWVzQ2hhbmdlZCIsInVwZGF0ZSIsInRpbWVTZWNvbmRzIiwiZHVyYXRpb25TZWNvbmRzIiwiZW1pdCIsIlRpbWVzQ2hhbmdlZCIsInRpbWVMZWZ0IiwidGltZUxlZnRTZWNvbmRzIiwibmV4dCIsImdldE5leHQiLCJwbGF5RXZlbnQiLCJnZXRJbmZvU3RhdGUiLCJnZXRTZXF1ZW5jZUZvckV2ZW50IiwibGFzdENodW5rU2VxdWVuY2UiLCJsYXN0X2NodW5rX3NlcXVlbmNlIiwiZ2V0TnVtYmVyT2ZFdmVudHMiLCJQbGF5aW5nIiwidHJ5R2V0T3JMb2FkUGxheWJhY2tGb3JFdmVudCIsInBsYXkiLCJnZXRPckxvYWRQbGF5YmFja0ZvckV2ZW50IiwiY3VycmVudFN0YXRlIiwibmV4dEV2ZW50IiwiZ2V0Q3VycmVudFBsYXliYWNrIiwiZ2V0TGl2ZW5lc3MiLCJsaXZlbmVzcyIsInNldExpdmVuZXNzIiwiTGl2ZW5lc3NDaGFuZ2VkIiwiTWF0aCIsIm1heCIsInJvdW5kIiwic2tpcFRvIiwic2tpcFRvTmV4dCIsInNraXBUb0RlZmVycmVkIiwicHJvbWlzZSIsImRlZmVyIiwidW5kZWZpbmVkIiwiZG9Ta2lwVG8iLCJyZXNvbHZlIiwidGltZSIsImZpbmRCeVRpbWUiLCJjdXJyZW50UGxheWJhY2siLCJza2lwVG9QbGF5YmFjayIsImN1cnJlbnRQbGF5YmFja0V2ZW50Iiwib2ZmIiwib2Zmc2V0SW5DaHVuayIsImlzUGxheWluZyIsImN1cnJlbnRSZWNvcmRpbmciLCJzaG91bGRTdG9wUmVjb3JkaW5nIiwic2hvd0NvbmZpcm1MaXN0ZW5Ccm9hZGNhc3RTdG9wQ3VycmVudERpYWxvZyIsImdldEV2ZW50cyIsInRvUGxheSIsImxlbmd0aCIsInBhdXNlIiwicmVzdW1lIiwidG9nZ2xlIiwiU3RhdGVDaGFuZ2VkIiwiSW5mb1N0YXRlQ2hhbmdlZCIsImRldGVybWluZVZvaWNlQnJvYWRjYXN0TGl2ZW5lc3MiLCJlcnJvck1lc3NhZ2UiLCJfdCIsInV0ZEV2ZW50IiwiY2xlYXIiLCJyZW1vdmVBbGxMaXN0ZW5lcnMiLCJwIl0sInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3ZvaWNlLWJyb2FkY2FzdC9tb2RlbHMvVm9pY2VCcm9hZGNhc3RQbGF5YmFjay50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuQ29weXJpZ2h0IDIwMjQgTmV3IFZlY3RvciBMdGQuXG5Db3B5cmlnaHQgMjAyMiBUaGUgTWF0cml4Lm9yZyBGb3VuZGF0aW9uIEMuSS5DLlxuXG5TUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQUdQTC0zLjAtb25seSBPUiBHUEwtMy4wLW9ubHlcblBsZWFzZSBzZWUgTElDRU5TRSBmaWxlcyBpbiB0aGUgcmVwb3NpdG9yeSByb290IGZvciBmdWxsIGRldGFpbHMuXG4qL1xuXG5pbXBvcnQge1xuICAgIEV2ZW50VHlwZSxcbiAgICBNYXRyaXhDbGllbnQsXG4gICAgTWF0cml4RXZlbnQsXG4gICAgTWF0cml4RXZlbnRFdmVudCxcbiAgICBNc2dUeXBlLFxuICAgIFJlbGF0aW9uVHlwZSxcbiAgICBUeXBlZEV2ZW50RW1pdHRlcixcbn0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL21hdHJpeFwiO1xuaW1wb3J0IHsgU2ltcGxlT2JzZXJ2YWJsZSB9IGZyb20gXCJtYXRyaXgtd2lkZ2V0LWFwaVwiO1xuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL2xvZ2dlclwiO1xuaW1wb3J0IHsgZGVmZXIsIElEZWZlcnJlZCB9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy91dGlsc1wiO1xuXG5pbXBvcnQgeyBQbGF5YmFjaywgUGxheWJhY2tJbnRlcmZhY2UsIFBsYXliYWNrU3RhdGUgfSBmcm9tIFwiLi4vLi4vYXVkaW8vUGxheWJhY2tcIjtcbmltcG9ydCB7IFBsYXliYWNrTWFuYWdlciB9IGZyb20gXCIuLi8uLi9hdWRpby9QbGF5YmFja01hbmFnZXJcIjtcbmltcG9ydCB7IFVQREFURV9FVkVOVCB9IGZyb20gXCIuLi8uLi9zdG9yZXMvQXN5bmNTdG9yZVwiO1xuaW1wb3J0IHsgTWVkaWFFdmVudEhlbHBlciB9IGZyb20gXCIuLi8uLi91dGlscy9NZWRpYUV2ZW50SGVscGVyXCI7XG5pbXBvcnQgeyBJRGVzdHJveWFibGUgfSBmcm9tIFwiLi4vLi4vdXRpbHMvSURlc3Ryb3lhYmxlXCI7XG5pbXBvcnQge1xuICAgIFZvaWNlQnJvYWRjYXN0TGl2ZW5lc3MsXG4gICAgVm9pY2VCcm9hZGNhc3RJbmZvRXZlbnRUeXBlLFxuICAgIFZvaWNlQnJvYWRjYXN0SW5mb1N0YXRlLFxuICAgIFZvaWNlQnJvYWRjYXN0SW5mb0V2ZW50Q29udGVudCxcbiAgICBWb2ljZUJyb2FkY2FzdFJlY29yZGluZ3NTdG9yZSxcbiAgICBzaG93Q29uZmlybUxpc3RlbkJyb2FkY2FzdFN0b3BDdXJyZW50RGlhbG9nLFxufSBmcm9tIFwiLi5cIjtcbmltcG9ydCB7IFJlbGF0aW9uc0hlbHBlciwgUmVsYXRpb25zSGVscGVyRXZlbnQgfSBmcm9tIFwiLi4vLi4vZXZlbnRzL1JlbGF0aW9uc0hlbHBlclwiO1xuaW1wb3J0IHsgVm9pY2VCcm9hZGNhc3RDaHVua0V2ZW50cyB9IGZyb20gXCIuLi91dGlscy9Wb2ljZUJyb2FkY2FzdENodW5rRXZlbnRzXCI7XG5pbXBvcnQgeyBkZXRlcm1pbmVWb2ljZUJyb2FkY2FzdExpdmVuZXNzIH0gZnJvbSBcIi4uL3V0aWxzL2RldGVybWluZVZvaWNlQnJvYWRjYXN0TGl2ZW5lc3NcIjtcbmltcG9ydCB7IF90IH0gZnJvbSBcIi4uLy4uL2xhbmd1YWdlSGFuZGxlclwiO1xuXG5leHBvcnQgZW51bSBWb2ljZUJyb2FkY2FzdFBsYXliYWNrU3RhdGUge1xuICAgIFBhdXNlZCA9IFwicGF1c2VcIixcbiAgICBQbGF5aW5nID0gXCJwbGF5aW5nXCIsXG4gICAgU3RvcHBlZCA9IFwic3RvcHBlZFwiLFxuICAgIEJ1ZmZlcmluZyA9IFwiYnVmZmVyaW5nXCIsXG4gICAgRXJyb3IgPSBcImVycm9yXCIsXG59XG5cbmV4cG9ydCBlbnVtIFZvaWNlQnJvYWRjYXN0UGxheWJhY2tFdmVudCB7XG4gICAgVGltZXNDaGFuZ2VkID0gXCJ0aW1lc19jaGFuZ2VkXCIsXG4gICAgTGl2ZW5lc3NDaGFuZ2VkID0gXCJsaXZlbmVzc19jaGFuZ2VkXCIsXG4gICAgU3RhdGVDaGFuZ2VkID0gXCJzdGF0ZV9jaGFuZ2VkXCIsXG4gICAgSW5mb1N0YXRlQ2hhbmdlZCA9IFwiaW5mb19zdGF0ZV9jaGFuZ2VkXCIsXG59XG5cbmV4cG9ydCB0eXBlIFZvaWNlQnJvYWRjYXN0UGxheWJhY2tUaW1lcyA9IHtcbiAgICBkdXJhdGlvbjogbnVtYmVyO1xuICAgIHBvc2l0aW9uOiBudW1iZXI7XG4gICAgdGltZUxlZnQ6IG51bWJlcjtcbn07XG5cbmludGVyZmFjZSBFdmVudE1hcCB7XG4gICAgW1ZvaWNlQnJvYWRjYXN0UGxheWJhY2tFdmVudC5UaW1lc0NoYW5nZWRdOiAodGltZXM6IFZvaWNlQnJvYWRjYXN0UGxheWJhY2tUaW1lcykgPT4gdm9pZDtcbiAgICBbVm9pY2VCcm9hZGNhc3RQbGF5YmFja0V2ZW50LkxpdmVuZXNzQ2hhbmdlZF06IChsaXZlbmVzczogVm9pY2VCcm9hZGNhc3RMaXZlbmVzcykgPT4gdm9pZDtcbiAgICBbVm9pY2VCcm9hZGNhc3RQbGF5YmFja0V2ZW50LlN0YXRlQ2hhbmdlZF06IChcbiAgICAgICAgc3RhdGU6IFZvaWNlQnJvYWRjYXN0UGxheWJhY2tTdGF0ZSxcbiAgICAgICAgcGxheWJhY2s6IFZvaWNlQnJvYWRjYXN0UGxheWJhY2ssXG4gICAgKSA9PiB2b2lkO1xuICAgIFtWb2ljZUJyb2FkY2FzdFBsYXliYWNrRXZlbnQuSW5mb1N0YXRlQ2hhbmdlZF06IChzdGF0ZTogVm9pY2VCcm9hZGNhc3RJbmZvU3RhdGUpID0+IHZvaWQ7XG59XG5cbmV4cG9ydCBjbGFzcyBWb2ljZUJyb2FkY2FzdFBsYXliYWNrXG4gICAgZXh0ZW5kcyBUeXBlZEV2ZW50RW1pdHRlcjxWb2ljZUJyb2FkY2FzdFBsYXliYWNrRXZlbnQsIEV2ZW50TWFwPlxuICAgIGltcGxlbWVudHMgSURlc3Ryb3lhYmxlLCBQbGF5YmFja0ludGVyZmFjZVxue1xuICAgIHByaXZhdGUgc3RhdGUgPSBWb2ljZUJyb2FkY2FzdFBsYXliYWNrU3RhdGUuU3RvcHBlZDtcbiAgICBwcml2YXRlIGNodW5rRXZlbnRzID0gbmV3IFZvaWNlQnJvYWRjYXN0Q2h1bmtFdmVudHMoKTtcbiAgICAvKiogQHZhciBNYXA6IGV2ZW50IElkIOKGkiB1bmRlY3J5cHRhYmxlIGV2ZW50ICovXG4gICAgcHJpdmF0ZSB1dGRDaHVua0V2ZW50czogTWFwPHN0cmluZywgTWF0cml4RXZlbnQ+ID0gbmV3IE1hcCgpO1xuICAgIHByaXZhdGUgcGxheWJhY2tzID0gbmV3IE1hcDxzdHJpbmcsIFBsYXliYWNrPigpO1xuICAgIHByaXZhdGUgY3VycmVudGx5UGxheWluZzogTWF0cml4RXZlbnQgfCBudWxsID0gbnVsbDtcbiAgICAvKiogQHZhciB0b3RhbCBkdXJhdGlvbiBvZiBhbGwgY2h1bmtzIGluIG1pbGxpc2Vjb25kcyAqL1xuICAgIHByaXZhdGUgZHVyYXRpb24gPSAwO1xuICAgIC8qKiBAdmFyIGN1cnJlbnQgcGxheWJhY2sgcG9zaXRpb24gaW4gbWlsbGlzZWNvbmRzICovXG4gICAgcHJpdmF0ZSBwb3NpdGlvbiA9IDA7XG4gICAgcHVibGljIHJlYWRvbmx5IGxpdmVEYXRhID0gbmV3IFNpbXBsZU9ic2VydmFibGU8bnVtYmVyW10+KCk7XG4gICAgcHJpdmF0ZSBsaXZlbmVzczogVm9pY2VCcm9hZGNhc3RMaXZlbmVzcyA9IFwibm90LWxpdmVcIjtcblxuICAgIC8vIHNldCB2aWEgYWRkSW5mb0V2ZW50KCkgaW4gY29uc3RydWN0b3JcbiAgICBwcml2YXRlIGluZm9TdGF0ZSE6IFZvaWNlQnJvYWRjYXN0SW5mb1N0YXRlO1xuICAgIHByaXZhdGUgbGFzdEluZm9FdmVudCE6IE1hdHJpeEV2ZW50O1xuXG4gICAgLy8gc2V0IHZpYSBzZXRVcFJlbGF0aW9uc0hlbHBlcigpIGluIGNvbnN0cnVjdG9yXG4gICAgcHJpdmF0ZSBjaHVua1JlbGF0aW9uSGVscGVyITogUmVsYXRpb25zSGVscGVyO1xuICAgIHByaXZhdGUgaW5mb1JlbGF0aW9uSGVscGVyITogUmVsYXRpb25zSGVscGVyO1xuXG4gICAgcHJpdmF0ZSBza2lwVG9OZXh0PzogbnVtYmVyO1xuICAgIHByaXZhdGUgc2tpcFRvRGVmZXJyZWQ/OiBJRGVmZXJyZWQ8dm9pZD47XG5cbiAgICBwdWJsaWMgY29uc3RydWN0b3IoXG4gICAgICAgIHB1YmxpYyByZWFkb25seSBpbmZvRXZlbnQ6IE1hdHJpeEV2ZW50LFxuICAgICAgICBwcml2YXRlIGNsaWVudDogTWF0cml4Q2xpZW50LFxuICAgICAgICBwcml2YXRlIHJlY29yZGluZ3M6IFZvaWNlQnJvYWRjYXN0UmVjb3JkaW5nc1N0b3JlLFxuICAgICkge1xuICAgICAgICBzdXBlcigpO1xuICAgICAgICB0aGlzLmFkZEluZm9FdmVudCh0aGlzLmluZm9FdmVudCk7XG4gICAgICAgIHRoaXMuaW5mb0V2ZW50Lm9uKE1hdHJpeEV2ZW50RXZlbnQuQmVmb3JlUmVkYWN0aW9uLCB0aGlzLm9uQmVmb3JlUmVkYWN0aW9uKTtcbiAgICAgICAgdGhpcy5zZXRVcFJlbGF0aW9uc0hlbHBlcigpO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgc2V0VXBSZWxhdGlvbnNIZWxwZXIoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHRoaXMuaW5mb1JlbGF0aW9uSGVscGVyID0gbmV3IFJlbGF0aW9uc0hlbHBlcihcbiAgICAgICAgICAgIHRoaXMuaW5mb0V2ZW50LFxuICAgICAgICAgICAgUmVsYXRpb25UeXBlLlJlZmVyZW5jZSxcbiAgICAgICAgICAgIFZvaWNlQnJvYWRjYXN0SW5mb0V2ZW50VHlwZSxcbiAgICAgICAgICAgIHRoaXMuY2xpZW50LFxuICAgICAgICApO1xuICAgICAgICB0aGlzLmluZm9SZWxhdGlvbkhlbHBlci5nZXRDdXJyZW50KCkuZm9yRWFjaCh0aGlzLmFkZEluZm9FdmVudCk7XG5cbiAgICAgICAgaWYgKHRoaXMuaW5mb1N0YXRlICE9PSBWb2ljZUJyb2FkY2FzdEluZm9TdGF0ZS5TdG9wcGVkKSB7XG4gICAgICAgICAgICAvLyBPbmx5IHJlcXVpcmVkIGlmIG5vdCBzdG9wcGVkLiBTdG9wcGVkIGlzIHRoZSBmaW5hbCBzdGF0ZS5cbiAgICAgICAgICAgIHRoaXMuaW5mb1JlbGF0aW9uSGVscGVyLm9uKFJlbGF0aW9uc0hlbHBlckV2ZW50LkFkZCwgdGhpcy5hZGRJbmZvRXZlbnQpO1xuXG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMuaW5mb1JlbGF0aW9uSGVscGVyLmVtaXRGZXRjaEN1cnJlbnQoKTtcbiAgICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgICAgIGxvZ2dlci53YXJuKFwiZXJyb3IgZmV0Y2hpbmcgc2VydmVyIHNpZGUgcmVsYXRpb24gZm9yIHZvaWNlIGJyb2FkY2FzdCBpbmZvXCIsIGVycik7XG4gICAgICAgICAgICAgICAgLy8gZmFsbCBiYWNrIHRvIGxvY2FsIGV2ZW50c1xuICAgICAgICAgICAgICAgIHRoaXMuaW5mb1JlbGF0aW9uSGVscGVyLmVtaXRDdXJyZW50KCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmNodW5rUmVsYXRpb25IZWxwZXIgPSBuZXcgUmVsYXRpb25zSGVscGVyKFxuICAgICAgICAgICAgdGhpcy5pbmZvRXZlbnQsXG4gICAgICAgICAgICBSZWxhdGlvblR5cGUuUmVmZXJlbmNlLFxuICAgICAgICAgICAgRXZlbnRUeXBlLlJvb21NZXNzYWdlLFxuICAgICAgICAgICAgdGhpcy5jbGllbnQsXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMuY2h1bmtSZWxhdGlvbkhlbHBlci5vbihSZWxhdGlvbnNIZWxwZXJFdmVudC5BZGQsIHRoaXMuYWRkQ2h1bmtFdmVudCk7XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIC8vIFRPRE8gTWljaGFlbCBXOiBvbmx5IGZldGNoIGV2ZW50cyBpZiBuZWVkZWQsIGJsb2NrZWQgYnkgUFNGLTE3MDhcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuY2h1bmtSZWxhdGlvbkhlbHBlci5lbWl0RmV0Y2hDdXJyZW50KCk7XG4gICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgbG9nZ2VyLndhcm4oXCJlcnJvciBmZXRjaGluZyBzZXJ2ZXIgc2lkZSByZWxhdGlvbiBmb3Igdm9pY2UgYnJvYWRjYXN0IGNodW5rc1wiLCBlcnIpO1xuICAgICAgICAgICAgLy8gZmFsbCBiYWNrIHRvIGxvY2FsIGV2ZW50c1xuICAgICAgICAgICAgdGhpcy5jaHVua1JlbGF0aW9uSGVscGVyLmVtaXRDdXJyZW50KCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIGFkZENodW5rRXZlbnQgPSBhc3luYyAoZXZlbnQ6IE1hdHJpeEV2ZW50KTogUHJvbWlzZTxib29sZWFuPiA9PiB7XG4gICAgICAgIGlmICghZXZlbnQuZ2V0SWQoKSAmJiAhZXZlbnQuZ2V0VHhuSWQoKSkge1xuICAgICAgICAgICAgLy8gc2tpcCBldmVudHMgd2l0aG91dCBpZCBhbmQgdHhuIGlkXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoZXZlbnQuaXNEZWNyeXB0aW9uRmFpbHVyZSgpKSB7XG4gICAgICAgICAgICB0aGlzLm9uQ2h1bmtFdmVudERlY3J5cHRpb25GYWlsdXJlKGV2ZW50KTtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChldmVudC5nZXRDb250ZW50KCk/Lm1zZ3R5cGUgIT09IE1zZ1R5cGUuQXVkaW8pIHtcbiAgICAgICAgICAgIC8vIHNraXAgbm9uLWF1ZGlvIGV2ZW50XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmNodW5rRXZlbnRzLmFkZEV2ZW50KGV2ZW50KTtcbiAgICAgICAgdGhpcy5zZXREdXJhdGlvbih0aGlzLmNodW5rRXZlbnRzLmdldExlbmd0aCgpKTtcblxuICAgICAgICBpZiAodGhpcy5nZXRTdGF0ZSgpID09PSBWb2ljZUJyb2FkY2FzdFBsYXliYWNrU3RhdGUuQnVmZmVyaW5nKSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLnN0YXJ0T3JQbGF5TmV4dCgpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfTtcblxuICAgIHByaXZhdGUgb25DaHVua0V2ZW50RGVjcnlwdGlvbkZhaWx1cmUgPSAoZXZlbnQ6IE1hdHJpeEV2ZW50KTogdm9pZCA9PiB7XG4gICAgICAgIGNvbnN0IGV2ZW50SWQgPSBldmVudC5nZXRJZCgpO1xuXG4gICAgICAgIGlmICghZXZlbnRJZCkge1xuICAgICAgICAgICAgLy8gVGhpcyBzaG91bGQgbm90IGhhcHBlbiwgYXMgdGhlIGV4aXN0ZW5jZSBvZiB0aGUgSWQgaXMgY2hlY2tlZCBiZWZvcmUgdGhlIGNhbGwuXG4gICAgICAgICAgICAvLyBMb2cgYW55d2F5IGFuZCByZXR1cm4uXG4gICAgICAgICAgICBsb2dnZXIud2FybihcIkJyb2FkY2FzdCBjaHVuayBkZWNyeXB0aW9uIGZhaWx1cmUgZm9yIGV2ZW50IHdpdGhvdXQgSWRcIiwge1xuICAgICAgICAgICAgICAgIGJyb2FkY2FzdDogdGhpcy5pbmZvRXZlbnQuZ2V0SWQoKSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCF0aGlzLnV0ZENodW5rRXZlbnRzLmhhcyhldmVudElkKSkge1xuICAgICAgICAgICAgZXZlbnQub25jZShNYXRyaXhFdmVudEV2ZW50LkRlY3J5cHRlZCwgdGhpcy5vbkNodW5rRXZlbnREZWNyeXB0ZWQpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy51dGRDaHVua0V2ZW50cy5zZXQoZXZlbnRJZCwgZXZlbnQpO1xuICAgICAgICB0aGlzLnNldEVycm9yKCk7XG4gICAgfTtcblxuICAgIHByaXZhdGUgb25DaHVua0V2ZW50RGVjcnlwdGVkID0gYXN5bmMgKGV2ZW50OiBNYXRyaXhFdmVudCk6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgICAgICBjb25zdCBldmVudElkID0gZXZlbnQuZ2V0SWQoKTtcblxuICAgICAgICBpZiAoIWV2ZW50SWQpIHtcbiAgICAgICAgICAgIC8vIFRoaXMgc2hvdWxkIG5vdCBoYXBwZW4sIGFzIHRoZSBleGlzdGVuY2Ugb2YgdGhlIElkIGlzIGNoZWNrZWQgYmVmb3JlIHRoZSBjYWxsLlxuICAgICAgICAgICAgLy8gTG9nIGFueXdheSBhbmQgcmV0dXJuLlxuICAgICAgICAgICAgbG9nZ2VyLndhcm4oXCJCcm9hZGNhc3QgY2h1bmsgZGVjcnlwdGVkIGZvciBldmVudCB3aXRob3V0IElkXCIsIHsgYnJvYWRjYXN0OiB0aGlzLmluZm9FdmVudC5nZXRJZCgpIH0pO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy51dGRDaHVua0V2ZW50cy5kZWxldGUoZXZlbnRJZCk7XG4gICAgICAgIGF3YWl0IHRoaXMuYWRkQ2h1bmtFdmVudChldmVudCk7XG5cbiAgICAgICAgaWYgKHRoaXMudXRkQ2h1bmtFdmVudHMuc2l6ZSA9PT0gMCkge1xuICAgICAgICAgICAgLy8gbm8gbW9yZSBVVEQgZXZlbnRzLCByZWNvdmVyIGZyb20gZXJyb3IgdG8gcGF1c2VkXG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKFZvaWNlQnJvYWRjYXN0UGxheWJhY2tTdGF0ZS5QYXVzZWQpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHByaXZhdGUgc3RhcnRPclBsYXlOZXh0ID0gYXN5bmMgKCk6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgICAgICBpZiAodGhpcy5jdXJyZW50bHlQbGF5aW5nKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5wbGF5TmV4dCgpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGF3YWl0IHRoaXMuc3RhcnQoKTtcbiAgICB9O1xuXG4gICAgcHJpdmF0ZSBhZGRJbmZvRXZlbnQgPSAoZXZlbnQ6IE1hdHJpeEV2ZW50KTogdm9pZCA9PiB7XG4gICAgICAgIGlmICh0aGlzLmxhc3RJbmZvRXZlbnQgJiYgdGhpcy5sYXN0SW5mb0V2ZW50LmdldFRzKCkgPj0gZXZlbnQuZ2V0VHMoKSkge1xuICAgICAgICAgICAgLy8gT25seSBoYW5kbGUgbmV3ZXIgZXZlbnRzXG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBzdGF0ZSA9IGV2ZW50LmdldENvbnRlbnQoKT8uc3RhdGU7XG5cbiAgICAgICAgaWYgKCFPYmplY3QudmFsdWVzKFZvaWNlQnJvYWRjYXN0SW5mb1N0YXRlKS5pbmNsdWRlcyhzdGF0ZSkpIHtcbiAgICAgICAgICAgIC8vIERvIG5vdCBoYW5kbGUgdW5rbm93biB2b2ljZSBicm9hZGNhc3Qgc3RhdGVzXG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmxhc3RJbmZvRXZlbnQgPSBldmVudDtcbiAgICAgICAgdGhpcy5zZXRJbmZvU3RhdGUoc3RhdGUpO1xuICAgIH07XG5cbiAgICBwcml2YXRlIG9uQmVmb3JlUmVkYWN0aW9uID0gKCk6IHZvaWQgPT4ge1xuICAgICAgICBpZiAodGhpcy5nZXRTdGF0ZSgpICE9PSBWb2ljZUJyb2FkY2FzdFBsYXliYWNrU3RhdGUuU3RvcHBlZCkge1xuICAgICAgICAgICAgdGhpcy5zdG9wKCk7XG4gICAgICAgICAgICAvLyBkZXN0cm95IGNsZWFucyB1cCBldmVyeXRoaW5nXG4gICAgICAgICAgICB0aGlzLmRlc3Ryb3koKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBwcml2YXRlIGFzeW5jIHRyeUxvYWRQbGF5YmFjayhjaHVua0V2ZW50OiBNYXRyaXhFdmVudCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgcmV0dXJuIGF3YWl0IHRoaXMubG9hZFBsYXliYWNrKGNodW5rRXZlbnQpO1xuICAgICAgICB9IGNhdGNoIChlcnI6IGFueSkge1xuICAgICAgICAgICAgbG9nZ2VyLndhcm4oXCJVbmFibGUgdG8gbG9hZCBicm9hZGNhc3QgcGxheWJhY2tcIiwge1xuICAgICAgICAgICAgICAgIG1lc3NhZ2U6IGVyci5tZXNzYWdlLFxuICAgICAgICAgICAgICAgIGJyb2FkY2FzdElkOiB0aGlzLmluZm9FdmVudC5nZXRJZCgpLFxuICAgICAgICAgICAgICAgIGNodW5rSWQ6IGNodW5rRXZlbnQuZ2V0SWQoKSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgdGhpcy5zZXRFcnJvcigpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBsb2FkUGxheWJhY2soY2h1bmtFdmVudDogTWF0cml4RXZlbnQpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgY29uc3QgZXZlbnRJZCA9IGNodW5rRXZlbnQuZ2V0SWQoKTtcblxuICAgICAgICBpZiAoIWV2ZW50SWQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkJyb2FkY2FzdCBjaHVuayBldmVudCB3aXRob3V0IElkIG9jY3VycmVkXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgaGVscGVyID0gbmV3IE1lZGlhRXZlbnRIZWxwZXIoY2h1bmtFdmVudCk7XG4gICAgICAgIGNvbnN0IGJsb2IgPSBhd2FpdCBoZWxwZXIuc291cmNlQmxvYi52YWx1ZTtcbiAgICAgICAgY29uc3QgYnVmZmVyID0gYXdhaXQgYmxvYi5hcnJheUJ1ZmZlcigpO1xuICAgICAgICBjb25zdCBwbGF5YmFjayA9IFBsYXliYWNrTWFuYWdlci5pbnN0YW5jZS5jcmVhdGVQbGF5YmFja0luc3RhbmNlKGJ1ZmZlcik7XG4gICAgICAgIGF3YWl0IHBsYXliYWNrLnByZXBhcmUoKTtcbiAgICAgICAgcGxheWJhY2suY2xvY2tJbmZvLnBvcHVsYXRlUGxhY2Vob2xkZXJzRnJvbShjaHVua0V2ZW50KTtcbiAgICAgICAgdGhpcy5wbGF5YmFja3Muc2V0KGV2ZW50SWQsIHBsYXliYWNrKTtcbiAgICAgICAgcGxheWJhY2sub24oVVBEQVRFX0VWRU5ULCAoc3RhdGUpID0+IHRoaXMub25QbGF5YmFja1N0YXRlQ2hhbmdlKGNodW5rRXZlbnQsIHN0YXRlKSk7XG4gICAgICAgIHBsYXliYWNrLmNsb2NrSW5mby5saXZlRGF0YS5vblVwZGF0ZSgoW3Bvc2l0aW9uXSkgPT4ge1xuICAgICAgICAgICAgdGhpcy5vblBsYXliYWNrUG9zaXRpb25VcGRhdGUoY2h1bmtFdmVudCwgcG9zaXRpb24pO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHVubG9hZFBsYXliYWNrKGV2ZW50OiBNYXRyaXhFdmVudCk6IHZvaWQge1xuICAgICAgICBjb25zdCBwbGF5YmFjayA9IHRoaXMucGxheWJhY2tzLmdldChldmVudC5nZXRJZCgpISk7XG4gICAgICAgIGlmICghcGxheWJhY2spIHJldHVybjtcblxuICAgICAgICBwbGF5YmFjay5kZXN0cm95KCk7XG4gICAgICAgIHRoaXMucGxheWJhY2tzLmRlbGV0ZShldmVudC5nZXRJZCgpISk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBvblBsYXliYWNrUG9zaXRpb25VcGRhdGUgPSAoZXZlbnQ6IE1hdHJpeEV2ZW50LCBwb3NpdGlvbjogbnVtYmVyKTogdm9pZCA9PiB7XG4gICAgICAgIGlmIChldmVudCAhPT0gdGhpcy5jdXJyZW50bHlQbGF5aW5nKSByZXR1cm47XG5cbiAgICAgICAgY29uc3QgbmV3UG9zaXRpb24gPSB0aGlzLmNodW5rRXZlbnRzLmdldExlbmd0aFRvKGV2ZW50KSArIHBvc2l0aW9uICogMTAwMDsgLy8gb2JzZXJ2YWJsZSBzZW5kcyBzZWNvbmRzXG5cbiAgICAgICAgLy8gZG8gbm90IGp1bXAgYmFja3dhcmRzIC0gdGhpcyBjYW4gaGFwcGVuIHdoZW4gdHJhbnNpdGluZyBmcm9tIG9uZSB0byBhbm90aGVyIGNodW5rXG4gICAgICAgIGlmIChuZXdQb3NpdGlvbiA8IHRoaXMucG9zaXRpb24pIHJldHVybjtcblxuICAgICAgICB0aGlzLnNldFBvc2l0aW9uKG5ld1Bvc2l0aW9uKTtcbiAgICB9O1xuXG4gICAgcHJpdmF0ZSBzZXREdXJhdGlvbihkdXJhdGlvbjogbnVtYmVyKTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLmR1cmF0aW9uID09PSBkdXJhdGlvbikgcmV0dXJuO1xuXG4gICAgICAgIHRoaXMuZHVyYXRpb24gPSBkdXJhdGlvbjtcbiAgICAgICAgdGhpcy5lbWl0VGltZXNDaGFuZ2VkKCk7XG4gICAgICAgIHRoaXMubGl2ZURhdGEudXBkYXRlKFt0aGlzLnRpbWVTZWNvbmRzLCB0aGlzLmR1cmF0aW9uU2Vjb25kc10pO1xuICAgIH1cblxuICAgIHByaXZhdGUgc2V0UG9zaXRpb24ocG9zaXRpb246IG51bWJlcik6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy5wb3NpdGlvbiA9PT0gcG9zaXRpb24pIHJldHVybjtcblxuICAgICAgICB0aGlzLnBvc2l0aW9uID0gcG9zaXRpb247XG4gICAgICAgIHRoaXMuZW1pdFRpbWVzQ2hhbmdlZCgpO1xuICAgICAgICB0aGlzLmxpdmVEYXRhLnVwZGF0ZShbdGhpcy50aW1lU2Vjb25kcywgdGhpcy5kdXJhdGlvblNlY29uZHNdKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGVtaXRUaW1lc0NoYW5nZWQoKTogdm9pZCB7XG4gICAgICAgIHRoaXMuZW1pdChWb2ljZUJyb2FkY2FzdFBsYXliYWNrRXZlbnQuVGltZXNDaGFuZ2VkLCB7XG4gICAgICAgICAgICBkdXJhdGlvbjogdGhpcy5kdXJhdGlvblNlY29uZHMsXG4gICAgICAgICAgICBwb3NpdGlvbjogdGhpcy50aW1lU2Vjb25kcyxcbiAgICAgICAgICAgIHRpbWVMZWZ0OiB0aGlzLnRpbWVMZWZ0U2Vjb25kcyxcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBvblBsYXliYWNrU3RhdGVDaGFuZ2UgPSBhc3luYyAoZXZlbnQ6IE1hdHJpeEV2ZW50LCBuZXdTdGF0ZTogUGxheWJhY2tTdGF0ZSk6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgICAgICBpZiAoZXZlbnQgIT09IHRoaXMuY3VycmVudGx5UGxheWluZykgcmV0dXJuO1xuICAgICAgICBpZiAobmV3U3RhdGUgIT09IFBsYXliYWNrU3RhdGUuU3RvcHBlZCkgcmV0dXJuO1xuXG4gICAgICAgIGF3YWl0IHRoaXMucGxheU5leHQoKTtcbiAgICAgICAgdGhpcy51bmxvYWRQbGF5YmFjayhldmVudCk7XG4gICAgfTtcblxuICAgIHByaXZhdGUgYXN5bmMgcGxheU5leHQoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGlmICghdGhpcy5jdXJyZW50bHlQbGF5aW5nKSByZXR1cm47XG5cbiAgICAgICAgY29uc3QgbmV4dCA9IHRoaXMuY2h1bmtFdmVudHMuZ2V0TmV4dCh0aGlzLmN1cnJlbnRseVBsYXlpbmcpO1xuXG4gICAgICAgIGlmIChuZXh0KSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5wbGF5RXZlbnQobmV4dCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoXG4gICAgICAgICAgICB0aGlzLmdldEluZm9TdGF0ZSgpID09PSBWb2ljZUJyb2FkY2FzdEluZm9TdGF0ZS5TdG9wcGVkICYmXG4gICAgICAgICAgICB0aGlzLmNodW5rRXZlbnRzLmdldFNlcXVlbmNlRm9yRXZlbnQodGhpcy5jdXJyZW50bHlQbGF5aW5nKSA9PT0gdGhpcy5sYXN0Q2h1bmtTZXF1ZW5jZVxuICAgICAgICApIHtcbiAgICAgICAgICAgIHRoaXMuc3RvcCgpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gTm8gbW9yZSBjaHVua3MgYXZhaWxhYmxlLCBhbHRob3VnaCB0aGUgYnJvYWRjYXN0IGlzIG5vdCBmaW5pc2hlZCDihpIgZW50ZXIgYnVmZmVyaW5nIHN0YXRlLlxuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZShWb2ljZUJyb2FkY2FzdFBsYXliYWNrU3RhdGUuQnVmZmVyaW5nKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEByZXR1cm5zIHtudW1iZXJ9IFRoZSBsYXN0IGNodW5rIHNlcXVlbmNlIGZyb20gdGhlIGxhdGVzdCBpbmZvIGV2ZW50LlxuICAgICAqICAgICAgICAgICAgICAgICAgIEZhbGxzIGJhY2sgdG8gdGhlIGxlbmd0aCBvZiByZWNlaXZlZCBjaHVua3MgaWYgdGhlIGluZm8gZXZlbnQgZG9lcyBub3QgcHJvdmlkZSB0aGUgbnVtYmVyLlxuICAgICAqL1xuICAgIHByaXZhdGUgZ2V0IGxhc3RDaHVua1NlcXVlbmNlKCk6IG51bWJlciB7XG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICB0aGlzLmxhc3RJbmZvRXZlbnQuZ2V0Q29udGVudDxWb2ljZUJyb2FkY2FzdEluZm9FdmVudENvbnRlbnQ+KCk/Lmxhc3RfY2h1bmtfc2VxdWVuY2UgfHxcbiAgICAgICAgICAgIHRoaXMuY2h1bmtFdmVudHMuZ2V0TnVtYmVyT2ZFdmVudHMoKVxuICAgICAgICApO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgcGxheUV2ZW50KGV2ZW50OiBNYXRyaXhFdmVudCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICB0aGlzLnNldFN0YXRlKFZvaWNlQnJvYWRjYXN0UGxheWJhY2tTdGF0ZS5QbGF5aW5nKTtcbiAgICAgICAgdGhpcy5jdXJyZW50bHlQbGF5aW5nID0gZXZlbnQ7XG4gICAgICAgIGNvbnN0IHBsYXliYWNrID0gYXdhaXQgdGhpcy50cnlHZXRPckxvYWRQbGF5YmFja0ZvckV2ZW50KGV2ZW50KTtcbiAgICAgICAgcGxheWJhY2s/LnBsYXkoKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIHRyeUdldE9yTG9hZFBsYXliYWNrRm9yRXZlbnQoZXZlbnQ6IE1hdHJpeEV2ZW50KTogUHJvbWlzZTxQbGF5YmFjayB8IHVuZGVmaW5lZD4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgcmV0dXJuIGF3YWl0IHRoaXMuZ2V0T3JMb2FkUGxheWJhY2tGb3JFdmVudChldmVudCk7XG4gICAgICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICAgICAgICBsb2dnZXIud2FybihcIlVuYWJsZSB0byBsb2FkIGJyb2FkY2FzdCBwbGF5YmFja1wiLCB7XG4gICAgICAgICAgICAgICAgbWVzc2FnZTogZXJyLm1lc3NhZ2UsXG4gICAgICAgICAgICAgICAgYnJvYWRjYXN0SWQ6IHRoaXMuaW5mb0V2ZW50LmdldElkKCksXG4gICAgICAgICAgICAgICAgY2h1bmtJZDogZXZlbnQuZ2V0SWQoKSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgdGhpcy5zZXRFcnJvcigpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBnZXRPckxvYWRQbGF5YmFja0ZvckV2ZW50KGV2ZW50OiBNYXRyaXhFdmVudCk6IFByb21pc2U8UGxheWJhY2sgfCB1bmRlZmluZWQ+IHtcbiAgICAgICAgY29uc3QgZXZlbnRJZCA9IGV2ZW50LmdldElkKCk7XG5cbiAgICAgICAgaWYgKCFldmVudElkKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJCcm9hZGNhc3QgY2h1bmsgZXZlbnQgd2l0aG91dCBJZCBvY2N1cnJlZFwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghdGhpcy5wbGF5YmFja3MuaGFzKGV2ZW50SWQpKSB7XG4gICAgICAgICAgICAvLyBzZXQgdG8gYnVmZmVyaW5nIHdoaWxlIGxvYWRpbmcgdGhlIGNodW5rIGRhdGFcbiAgICAgICAgICAgIGNvbnN0IGN1cnJlbnRTdGF0ZSA9IHRoaXMuZ2V0U3RhdGUoKTtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoVm9pY2VCcm9hZGNhc3RQbGF5YmFja1N0YXRlLkJ1ZmZlcmluZyk7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLmxvYWRQbGF5YmFjayhldmVudCk7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKGN1cnJlbnRTdGF0ZSk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBwbGF5YmFjayA9IHRoaXMucGxheWJhY2tzLmdldChldmVudElkKTtcblxuICAgICAgICBpZiAoIXBsYXliYWNrKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFVuYWJsZSB0byBmaW5kIHBsYXliYWNrIGZvciBldmVudCAke2V2ZW50LmdldElkKCl9YCk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyB0cnkgdG8gbG9hZCB0aGUgcGxheWJhY2sgZm9yIHRoZSBuZXh0IGV2ZW50IGZvciBhIHNtb290aChlcikgcGxheWJhY2tcbiAgICAgICAgY29uc3QgbmV4dEV2ZW50ID0gdGhpcy5jaHVua0V2ZW50cy5nZXROZXh0KGV2ZW50KTtcbiAgICAgICAgaWYgKG5leHRFdmVudCkgdGhpcy50cnlMb2FkUGxheWJhY2sobmV4dEV2ZW50KTtcblxuICAgICAgICByZXR1cm4gcGxheWJhY2s7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBnZXRDdXJyZW50UGxheWJhY2soKTogUGxheWJhY2sgfCB1bmRlZmluZWQge1xuICAgICAgICBpZiAoIXRoaXMuY3VycmVudGx5UGxheWluZykgcmV0dXJuO1xuICAgICAgICByZXR1cm4gdGhpcy5wbGF5YmFja3MuZ2V0KHRoaXMuY3VycmVudGx5UGxheWluZy5nZXRJZCgpISk7XG4gICAgfVxuXG4gICAgcHVibGljIGdldExpdmVuZXNzKCk6IFZvaWNlQnJvYWRjYXN0TGl2ZW5lc3Mge1xuICAgICAgICByZXR1cm4gdGhpcy5saXZlbmVzcztcbiAgICB9XG5cbiAgICBwcml2YXRlIHNldExpdmVuZXNzKGxpdmVuZXNzOiBWb2ljZUJyb2FkY2FzdExpdmVuZXNzKTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLmxpdmVuZXNzID09PSBsaXZlbmVzcykgcmV0dXJuO1xuXG4gICAgICAgIHRoaXMubGl2ZW5lc3MgPSBsaXZlbmVzcztcbiAgICAgICAgdGhpcy5lbWl0KFZvaWNlQnJvYWRjYXN0UGxheWJhY2tFdmVudC5MaXZlbmVzc0NoYW5nZWQsIGxpdmVuZXNzKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0IGN1cnJlbnRTdGF0ZSgpOiBQbGF5YmFja1N0YXRlIHtcbiAgICAgICAgcmV0dXJuIFBsYXliYWNrU3RhdGUuUGxheWluZztcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0IHRpbWVTZWNvbmRzKCk6IG51bWJlciB7XG4gICAgICAgIHJldHVybiB0aGlzLnBvc2l0aW9uIC8gMTAwMDtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0IGR1cmF0aW9uU2Vjb25kcygpOiBudW1iZXIge1xuICAgICAgICByZXR1cm4gdGhpcy5kdXJhdGlvbiAvIDEwMDA7XG4gICAgfVxuXG4gICAgcHVibGljIGdldCB0aW1lTGVmdFNlY29uZHMoKTogbnVtYmVyIHtcbiAgICAgICAgLy8gU29tZXRpbWVzIHRoZSBtZXRhIGRhdGEgYW5kIHRoZSBhdWRpbyBmaWxlcyBhcmUgYSBsaXR0bGUgYml0IG91dCBvZiBzeW5jLlxuICAgICAgICAvLyBCZSBzdXJlIGl0IG5ldmVyIHJldHVybnMgYSBuZWdhdGl2ZSB2YWx1ZS5cbiAgICAgICAgcmV0dXJuIE1hdGgubWF4KDAsIE1hdGgucm91bmQodGhpcy5kdXJhdGlvblNlY29uZHMpIC0gdGhpcy50aW1lU2Vjb25kcyk7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHNraXBUbyh0aW1lU2Vjb25kczogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHRoaXMuc2tpcFRvTmV4dCA9IHRpbWVTZWNvbmRzO1xuXG4gICAgICAgIGlmICh0aGlzLnNraXBUb0RlZmVycmVkKSB7XG4gICAgICAgICAgICAvLyBTa2lwIHRvIHBvc2l0aW9uIGlzIGFscmVhZHkgaW4gcHJvZ3Jlc3MuIFJldHVybiB0aGUgcHJvbWlzZSBmb3IgdGhhdC5cbiAgICAgICAgICAgIHJldHVybiB0aGlzLnNraXBUb0RlZmVycmVkLnByb21pc2U7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNraXBUb0RlZmVycmVkID0gZGVmZXIoKTtcblxuICAgICAgICB3aGlsZSAodGhpcy5za2lwVG9OZXh0ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIC8vIFNraXAgdG8gcG9zaXRpb24gdW50aWwgc2tpcFRvTmV4dCBpcyB1bmRlZmluZWQuXG4gICAgICAgICAgICAvLyBza2lwVG9OZXh0IGNhbiBiZSBzZXQgaWYgc2tpcFRvIGlzIGNhbGxlZCB3aGlsZSBhbHJlYWR5IHNraXBwaW5nLlxuICAgICAgICAgICAgY29uc3Qgc2tpcFRvTmV4dCA9IHRoaXMuc2tpcFRvTmV4dDtcbiAgICAgICAgICAgIHRoaXMuc2tpcFRvTmV4dCA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuZG9Ta2lwVG8oc2tpcFRvTmV4dCk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNraXBUb0RlZmVycmVkLnJlc29sdmUoKTtcbiAgICAgICAgdGhpcy5za2lwVG9EZWZlcnJlZCA9IHVuZGVmaW5lZDtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIGRvU2tpcFRvKHRpbWVTZWNvbmRzOiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgY29uc3QgdGltZSA9IHRpbWVTZWNvbmRzICogMTAwMDtcbiAgICAgICAgY29uc3QgZXZlbnQgPSB0aGlzLmNodW5rRXZlbnRzLmZpbmRCeVRpbWUodGltZSk7XG5cbiAgICAgICAgaWYgKCFldmVudCkge1xuICAgICAgICAgICAgbG9nZ2VyLndhcm4oXCJ2b2ljZSBicm9hZGNhc3QgY2h1bmsgZXZlbnQgdG8gc2tpcCB0byBub3QgZm91bmRcIik7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBjdXJyZW50UGxheWJhY2sgPSB0aGlzLmdldEN1cnJlbnRQbGF5YmFjaygpO1xuICAgICAgICBjb25zdCBza2lwVG9QbGF5YmFjayA9IGF3YWl0IHRoaXMudHJ5R2V0T3JMb2FkUGxheWJhY2tGb3JFdmVudChldmVudCk7XG4gICAgICAgIGNvbnN0IGN1cnJlbnRQbGF5YmFja0V2ZW50ID0gdGhpcy5jdXJyZW50bHlQbGF5aW5nO1xuXG4gICAgICAgIGlmICghc2tpcFRvUGxheWJhY2spIHtcbiAgICAgICAgICAgIGxvZ2dlci53YXJuKFwidm9pY2UgYnJvYWRjYXN0IGNodW5rIHRvIHNraXAgdG8gbm90IGZvdW5kXCIsIGV2ZW50KTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuY3VycmVudGx5UGxheWluZyA9IGV2ZW50O1xuXG4gICAgICAgIGlmIChjdXJyZW50UGxheWJhY2sgJiYgY3VycmVudFBsYXliYWNrRXZlbnQgJiYgY3VycmVudFBsYXliYWNrICE9PSBza2lwVG9QbGF5YmFjaykge1xuICAgICAgICAgICAgLy8gb25seSBzdG9wIGFuZCB1bmxvYWQgdGhlIHBsYXliYWNrIGhlcmUgd2l0aG91dCB0cmlnZ2VyaW5nIG90aGVyIGVmZmVjdHMsIGUuZy4gcGxheSBuZXh0XG4gICAgICAgICAgICBjdXJyZW50UGxheWJhY2sub2ZmKFVQREFURV9FVkVOVCwgdGhpcy5vblBsYXliYWNrU3RhdGVDaGFuZ2UpO1xuICAgICAgICAgICAgYXdhaXQgY3VycmVudFBsYXliYWNrLnN0b3AoKTtcbiAgICAgICAgICAgIGN1cnJlbnRQbGF5YmFjay5vbihVUERBVEVfRVZFTlQsIHRoaXMub25QbGF5YmFja1N0YXRlQ2hhbmdlKTtcbiAgICAgICAgICAgIHRoaXMudW5sb2FkUGxheWJhY2soY3VycmVudFBsYXliYWNrRXZlbnQpO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3Qgb2Zmc2V0SW5DaHVuayA9IHRpbWUgLSB0aGlzLmNodW5rRXZlbnRzLmdldExlbmd0aFRvKGV2ZW50KTtcbiAgICAgICAgYXdhaXQgc2tpcFRvUGxheWJhY2suc2tpcFRvKG9mZnNldEluQ2h1bmsgLyAxMDAwKTtcblxuICAgICAgICBpZiAodGhpcy5zdGF0ZSA9PT0gVm9pY2VCcm9hZGNhc3RQbGF5YmFja1N0YXRlLlBsYXlpbmcgJiYgIXNraXBUb1BsYXliYWNrLmlzUGxheWluZykge1xuICAgICAgICAgICAgYXdhaXQgc2tpcFRvUGxheWJhY2sucGxheSgpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5zZXRQb3NpdGlvbih0aW1lKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgc3RhcnQoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGlmICh0aGlzLnN0YXRlID09PSBWb2ljZUJyb2FkY2FzdFBsYXliYWNrU3RhdGUuUGxheWluZykgcmV0dXJuO1xuXG4gICAgICAgIGNvbnN0IGN1cnJlbnRSZWNvcmRpbmcgPSB0aGlzLnJlY29yZGluZ3MuZ2V0Q3VycmVudCgpO1xuXG4gICAgICAgIGlmIChjdXJyZW50UmVjb3JkaW5nICYmIGN1cnJlbnRSZWNvcmRpbmcuZ2V0U3RhdGUoKSAhPT0gVm9pY2VCcm9hZGNhc3RJbmZvU3RhdGUuU3RvcHBlZCkge1xuICAgICAgICAgICAgY29uc3Qgc2hvdWxkU3RvcFJlY29yZGluZyA9IGF3YWl0IHNob3dDb25maXJtTGlzdGVuQnJvYWRjYXN0U3RvcEN1cnJlbnREaWFsb2coKTtcblxuICAgICAgICAgICAgaWYgKCFzaG91bGRTdG9wUmVjb3JkaW5nKSB7XG4gICAgICAgICAgICAgICAgLy8ga2VlcCByZWNvcmRpbmdcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGF3YWl0IHRoaXMucmVjb3JkaW5ncy5nZXRDdXJyZW50KCk/LnN0b3AoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGNodW5rRXZlbnRzID0gdGhpcy5jaHVua0V2ZW50cy5nZXRFdmVudHMoKTtcblxuICAgICAgICBjb25zdCB0b1BsYXkgPVxuICAgICAgICAgICAgdGhpcy5nZXRJbmZvU3RhdGUoKSA9PT0gVm9pY2VCcm9hZGNhc3RJbmZvU3RhdGUuU3RvcHBlZFxuICAgICAgICAgICAgICAgID8gY2h1bmtFdmVudHNbMF0gLy8gc3RhcnQgYXQgdGhlIGJlZ2lubmluZyBmb3IgYW4gZW5kZWQgdm9pY2UgYnJvYWRjYXN0XG4gICAgICAgICAgICAgICAgOiBjaHVua0V2ZW50c1tjaHVua0V2ZW50cy5sZW5ndGggLSAxXTsgLy8gc3RhcnQgYXQgdGhlIGN1cnJlbnQgY2h1bmsgZm9yIGFuIG9uZ29pbmcgdm9pY2UgYnJvYWRjYXN0XG5cbiAgICAgICAgaWYgKHRvUGxheSkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMucGxheUV2ZW50KHRvUGxheSk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNldFN0YXRlKFZvaWNlQnJvYWRjYXN0UGxheWJhY2tTdGF0ZS5CdWZmZXJpbmcpO1xuICAgIH1cblxuICAgIHB1YmxpYyBzdG9wKCk6IHZvaWQge1xuICAgICAgICAvLyBlcnJvciBpcyBhIGZpbmFsIHN0YXRlXG4gICAgICAgIGlmICh0aGlzLmdldFN0YXRlKCkgPT09IFZvaWNlQnJvYWRjYXN0UGxheWJhY2tTdGF0ZS5FcnJvcikgcmV0dXJuO1xuXG4gICAgICAgIHRoaXMuc2V0U3RhdGUoVm9pY2VCcm9hZGNhc3RQbGF5YmFja1N0YXRlLlN0b3BwZWQpO1xuICAgICAgICB0aGlzLmdldEN1cnJlbnRQbGF5YmFjaygpPy5zdG9wKCk7XG4gICAgICAgIHRoaXMuY3VycmVudGx5UGxheWluZyA9IG51bGw7XG4gICAgICAgIHRoaXMuc2V0UG9zaXRpb24oMCk7XG4gICAgfVxuXG4gICAgcHVibGljIHBhdXNlKCk6IHZvaWQge1xuICAgICAgICAvLyBlcnJvciBpcyBhIGZpbmFsIHN0YXRlXG4gICAgICAgIGlmICh0aGlzLmdldFN0YXRlKCkgPT09IFZvaWNlQnJvYWRjYXN0UGxheWJhY2tTdGF0ZS5FcnJvcikgcmV0dXJuO1xuXG4gICAgICAgIC8vIHN0b3BwZWQgdm9pY2UgYnJvYWRjYXN0cyBjYW5ub3QgYmUgcGF1c2VkXG4gICAgICAgIGlmICh0aGlzLmdldFN0YXRlKCkgPT09IFZvaWNlQnJvYWRjYXN0UGxheWJhY2tTdGF0ZS5TdG9wcGVkKSByZXR1cm47XG5cbiAgICAgICAgdGhpcy5zZXRTdGF0ZShWb2ljZUJyb2FkY2FzdFBsYXliYWNrU3RhdGUuUGF1c2VkKTtcbiAgICAgICAgdGhpcy5nZXRDdXJyZW50UGxheWJhY2soKT8ucGF1c2UoKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgcmVzdW1lKCk6IHZvaWQge1xuICAgICAgICAvLyBlcnJvciBpcyBhIGZpbmFsIHN0YXRlXG4gICAgICAgIGlmICh0aGlzLmdldFN0YXRlKCkgPT09IFZvaWNlQnJvYWRjYXN0UGxheWJhY2tTdGF0ZS5FcnJvcikgcmV0dXJuO1xuXG4gICAgICAgIGlmICghdGhpcy5jdXJyZW50bHlQbGF5aW5nKSB7XG4gICAgICAgICAgICAvLyBubyBwbGF5YmFjayB0byByZXN1bWUsIHN0YXJ0IGZyb20gdGhlIGJlZ2lubmluZ1xuICAgICAgICAgICAgdGhpcy5zdGFydCgpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5zZXRTdGF0ZShWb2ljZUJyb2FkY2FzdFBsYXliYWNrU3RhdGUuUGxheWluZyk7XG4gICAgICAgIHRoaXMuZ2V0Q3VycmVudFBsYXliYWNrKCk/LnBsYXkoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBUb2dnbGVzIHRoZSBwbGF5YmFjazpcbiAgICAgKiBzdG9wcGVkIOKGkiBwbGF5aW5nXG4gICAgICogcGxheWluZyDihpIgcGF1c2VkXG4gICAgICogcGF1c2VkIOKGkiBwbGF5aW5nXG4gICAgICovXG4gICAgcHVibGljIGFzeW5jIHRvZ2dsZSgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgLy8gZXJyb3IgaXMgYSBmaW5hbCBzdGF0ZVxuICAgICAgICBpZiAodGhpcy5nZXRTdGF0ZSgpID09PSBWb2ljZUJyb2FkY2FzdFBsYXliYWNrU3RhdGUuRXJyb3IpIHJldHVybjtcblxuICAgICAgICBpZiAodGhpcy5zdGF0ZSA9PT0gVm9pY2VCcm9hZGNhc3RQbGF5YmFja1N0YXRlLlN0b3BwZWQpIHtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuc3RhcnQoKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0aGlzLnN0YXRlID09PSBWb2ljZUJyb2FkY2FzdFBsYXliYWNrU3RhdGUuUGF1c2VkKSB7XG4gICAgICAgICAgICB0aGlzLnJlc3VtZSgpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5wYXVzZSgpO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXRTdGF0ZSgpOiBWb2ljZUJyb2FkY2FzdFBsYXliYWNrU3RhdGUge1xuICAgICAgICByZXR1cm4gdGhpcy5zdGF0ZTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHNldFN0YXRlKHN0YXRlOiBWb2ljZUJyb2FkY2FzdFBsYXliYWNrU3RhdGUpOiB2b2lkIHtcbiAgICAgICAgaWYgKHRoaXMuc3RhdGUgPT09IHN0YXRlKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnN0YXRlID0gc3RhdGU7XG4gICAgICAgIHRoaXMuZW1pdChWb2ljZUJyb2FkY2FzdFBsYXliYWNrRXZlbnQuU3RhdGVDaGFuZ2VkLCBzdGF0ZSwgdGhpcyk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2V0IGVycm9yIHN0YXRlLiBTdG9wIGN1cnJlbnQgcGxheWJhY2ssIGlmIGFueS5cbiAgICAgKi9cbiAgICBwcml2YXRlIHNldEVycm9yKCk6IHZvaWQge1xuICAgICAgICB0aGlzLnNldFN0YXRlKFZvaWNlQnJvYWRjYXN0UGxheWJhY2tTdGF0ZS5FcnJvcik7XG4gICAgICAgIHRoaXMuZ2V0Q3VycmVudFBsYXliYWNrKCk/LnN0b3AoKTtcbiAgICAgICAgdGhpcy5jdXJyZW50bHlQbGF5aW5nID0gbnVsbDtcbiAgICAgICAgdGhpcy5zZXRQb3NpdGlvbigwKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0SW5mb1N0YXRlKCk6IFZvaWNlQnJvYWRjYXN0SW5mb1N0YXRlIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuaW5mb1N0YXRlO1xuICAgIH1cblxuICAgIHByaXZhdGUgc2V0SW5mb1N0YXRlKHN0YXRlOiBWb2ljZUJyb2FkY2FzdEluZm9TdGF0ZSk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy5pbmZvU3RhdGUgPT09IHN0YXRlKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmluZm9TdGF0ZSA9IHN0YXRlO1xuICAgICAgICB0aGlzLmVtaXQoVm9pY2VCcm9hZGNhc3RQbGF5YmFja0V2ZW50LkluZm9TdGF0ZUNoYW5nZWQsIHN0YXRlKTtcbiAgICAgICAgdGhpcy5zZXRMaXZlbmVzcyhkZXRlcm1pbmVWb2ljZUJyb2FkY2FzdExpdmVuZXNzKHRoaXMuaW5mb1N0YXRlKSk7XG4gICAgfVxuXG4gICAgcHVibGljIGdldCBlcnJvck1lc3NhZ2UoKTogc3RyaW5nIHtcbiAgICAgICAgaWYgKHRoaXMuZ2V0U3RhdGUoKSAhPT0gVm9pY2VCcm9hZGNhc3RQbGF5YmFja1N0YXRlLkVycm9yKSByZXR1cm4gXCJcIjtcbiAgICAgICAgaWYgKHRoaXMudXRkQ2h1bmtFdmVudHMuc2l6ZSkgcmV0dXJuIF90KFwidm9pY2VfYnJvYWRjYXN0fGZhaWxlZF9kZWNyeXB0XCIpO1xuICAgICAgICByZXR1cm4gX3QoXCJ2b2ljZV9icm9hZGNhc3R8ZmFpbGVkX2dlbmVyaWNcIik7XG4gICAgfVxuXG4gICAgcHVibGljIGRlc3Ryb3koKTogdm9pZCB7XG4gICAgICAgIGZvciAoY29uc3QgWywgdXRkRXZlbnRdIG9mIHRoaXMudXRkQ2h1bmtFdmVudHMpIHtcbiAgICAgICAgICAgIHV0ZEV2ZW50Lm9mZihNYXRyaXhFdmVudEV2ZW50LkRlY3J5cHRlZCwgdGhpcy5vbkNodW5rRXZlbnREZWNyeXB0ZWQpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy51dGRDaHVua0V2ZW50cy5jbGVhcigpO1xuXG4gICAgICAgIHRoaXMuY2h1bmtSZWxhdGlvbkhlbHBlci5kZXN0cm95KCk7XG4gICAgICAgIHRoaXMuaW5mb1JlbGF0aW9uSGVscGVyLmRlc3Ryb3koKTtcbiAgICAgICAgdGhpcy5yZW1vdmVBbGxMaXN0ZW5lcnMoKTtcblxuICAgICAgICB0aGlzLmNodW5rRXZlbnRzID0gbmV3IFZvaWNlQnJvYWRjYXN0Q2h1bmtFdmVudHMoKTtcbiAgICAgICAgdGhpcy5wbGF5YmFja3MuZm9yRWFjaCgocCkgPT4gcC5kZXN0cm95KCkpO1xuICAgICAgICB0aGlzLnBsYXliYWNrcyA9IG5ldyBNYXA8c3RyaW5nLCBQbGF5YmFjaz4oKTtcbiAgICB9XG59XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7O0FBUUEsSUFBQUEsT0FBQSxHQUFBQyxPQUFBO0FBU0EsSUFBQUMsZ0JBQUEsR0FBQUQsT0FBQTtBQUNBLElBQUFFLE9BQUEsR0FBQUYsT0FBQTtBQUNBLElBQUFHLE1BQUEsR0FBQUgsT0FBQTtBQUVBLElBQUFJLFNBQUEsR0FBQUosT0FBQTtBQUNBLElBQUFLLGdCQUFBLEdBQUFMLE9BQUE7QUFDQSxJQUFBTSxXQUFBLEdBQUFOLE9BQUE7QUFDQSxJQUFBTyxpQkFBQSxHQUFBUCxPQUFBO0FBRUEsSUFBQVEsQ0FBQSxHQUFBUixPQUFBO0FBUUEsSUFBQVMsZ0JBQUEsR0FBQVQsT0FBQTtBQUNBLElBQUFVLDBCQUFBLEdBQUFWLE9BQUE7QUFDQSxJQUFBVyxnQ0FBQSxHQUFBWCxPQUFBO0FBQ0EsSUFBQVksZ0JBQUEsR0FBQVosT0FBQTtBQXJDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQU5BLElBdUNZYSwyQkFBMkIsR0FBQUMsT0FBQSxDQUFBRCwyQkFBQSwwQkFBM0JBLDJCQUEyQjtFQUEzQkEsMkJBQTJCO0VBQTNC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