matrix-react-sdk
Version:
SDK for matrix.org using React
170 lines (164 loc) • 27.5 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.CallStoreEvent = exports.CallStore = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _logger = require("matrix-js-sdk/src/logger");
var _groupCallEventHandler = require("matrix-js-sdk/src/webrtc/groupCallEventHandler");
var _matrixrtc = require("matrix-js-sdk/src/matrixrtc");
var _dispatcher = _interopRequireDefault(require("../dispatcher/dispatcher"));
var _AsyncStore = require("./AsyncStore");
var _AsyncStoreWithClient = require("./AsyncStoreWithClient");
var _WidgetStore = _interopRequireDefault(require("./WidgetStore"));
var _SettingsStore = _interopRequireDefault(require("../settings/SettingsStore"));
var _SettingLevel = require("../settings/SettingLevel");
var _Call = require("../models/Call");
/*
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 CallStoreEvent = exports.CallStoreEvent = /*#__PURE__*/function (CallStoreEvent) {
CallStoreEvent["Call"] = "call";
CallStoreEvent["ConnectedCalls"] = "connected_calls";
return CallStoreEvent;
}({});
class CallStore extends _AsyncStoreWithClient.AsyncStoreWithClient {
static get instance() {
if (!this._instance) {
this._instance = new CallStore();
this._instance.start();
}
return this._instance;
}
constructor() {
super(_dispatcher.default);
(0, _defineProperty2.default)(this, "_connectedCalls", new Set());
(0, _defineProperty2.default)(this, "calls", new Map());
// Key is room ID
(0, _defineProperty2.default)(this, "callListeners", new Map());
(0, _defineProperty2.default)(this, "onWidgets", roomId => {
if (!this.matrixClient) return;
if (roomId === null) {
// This store happened to start before the widget store was done
// loading all rooms, so we need to initialize each room again
for (const room of this.matrixClient.getRooms()) {
this.updateRoom(room);
}
} else {
const room = this.matrixClient.getRoom(roomId);
// Widget updates can arrive before the room does, empirically
if (room !== null) this.updateRoom(room);
}
});
(0, _defineProperty2.default)(this, "onGroupCall", groupCall => this.updateRoom(groupCall.room));
(0, _defineProperty2.default)(this, "onRTCSessionStart", (roomId, session) => {
this.updateRoom(session.room);
});
this.setMaxListeners(100); // One for each RoomTile
}
async onAction() {
// nothing to do
}
async onReady() {
if (!this.matrixClient) return;
// We assume that the calls present in a room are a function of room
// widgets and group calls, so we initialize the room map here and then
// update it whenever those change
for (const room of this.matrixClient.getRooms()) {
this.updateRoom(room);
}
this.matrixClient.on(_groupCallEventHandler.GroupCallEventHandlerEvent.Incoming, this.onGroupCall);
this.matrixClient.on(_groupCallEventHandler.GroupCallEventHandlerEvent.Outgoing, this.onGroupCall);
this.matrixClient.matrixRTC.on(_matrixrtc.MatrixRTCSessionManagerEvents.SessionStarted, this.onRTCSessionStart);
_WidgetStore.default.instance.on(_AsyncStore.UPDATE_EVENT, this.onWidgets);
// If the room ID of a previously connected call is still in settings at
// this time, that's a sign that we failed to disconnect from it
// properly, and need to clean up after ourselves
const uncleanlyDisconnectedRoomIds = _SettingsStore.default.getValue("activeCallRoomIds");
if (uncleanlyDisconnectedRoomIds.length) {
await Promise.all([...uncleanlyDisconnectedRoomIds.map(async uncleanlyDisconnectedRoomId => {
_logger.logger.log(`Cleaning up call state for room ${uncleanlyDisconnectedRoomId}`);
await this.getCall(uncleanlyDisconnectedRoomId)?.clean();
}), _SettingsStore.default.setValue("activeCallRoomIds", null, _SettingLevel.SettingLevel.DEVICE, [])]);
}
}
async onNotReady() {
for (const [call, listenerMap] of this.callListeners) {
// It's important that we remove the listeners before destroying the
// call, because otherwise the call's onDestroy callback would fire
// and immediately repopulate the map
for (const [event, listener] of listenerMap) call.off(event, listener);
call.destroy();
}
this.callListeners.clear();
this.calls.clear();
this._connectedCalls.clear();
if (this.matrixClient) {
this.matrixClient.off(_groupCallEventHandler.GroupCallEventHandlerEvent.Incoming, this.onGroupCall);
this.matrixClient.off(_groupCallEventHandler.GroupCallEventHandlerEvent.Outgoing, this.onGroupCall);
this.matrixClient.off(_groupCallEventHandler.GroupCallEventHandlerEvent.Ended, this.onGroupCall);
this.matrixClient.matrixRTC.off(_matrixrtc.MatrixRTCSessionManagerEvents.SessionStarted, this.onRTCSessionStart);
}
_WidgetStore.default.instance.off(_AsyncStore.UPDATE_EVENT, this.onWidgets);
}
/**
* The calls to which the user is currently connected.
*/
get connectedCalls() {
return this._connectedCalls;
}
set connectedCalls(value) {
this._connectedCalls = value;
this.emit(CallStoreEvent.ConnectedCalls, value);
// The room IDs are persisted to settings so we can detect unclean disconnects
_SettingsStore.default.setValue("activeCallRoomIds", null, _SettingLevel.SettingLevel.DEVICE, [...value].map(call => call.roomId));
}
updateRoom(room) {
if (!this.calls.has(room.roomId)) {
const call = _Call.Call.get(room);
if (call) {
const onConnectionState = state => {
if (state === _Call.ConnectionState.Connected) {
this.connectedCalls = new Set([...this.connectedCalls, call]);
} else if (state === _Call.ConnectionState.Disconnected) {
this.connectedCalls = new Set([...this.connectedCalls].filter(c => c !== call));
}
};
const onDestroy = () => {
this.calls.delete(room.roomId);
for (const [event, listener] of this.callListeners.get(call)) call.off(event, listener);
this.updateRoom(room);
};
call.on(_Call.CallEvent.ConnectionState, onConnectionState);
call.on(_Call.CallEvent.Destroy, onDestroy);
this.calls.set(room.roomId, call);
this.callListeners.set(call, new Map([[_Call.CallEvent.ConnectionState, onConnectionState], [_Call.CallEvent.Destroy, onDestroy]]));
}
this.emit(CallStoreEvent.Call, call, room.roomId);
}
}
/**
* Gets the call associated with the given room, if any.
* @param {string} roomId The room's ID.
* @returns {Call | null} The call.
*/
getCall(roomId) {
return this.calls.get(roomId) ?? null;
}
/**
* Gets the active call associated with the given room, if any.
* @param roomId The room's ID.
* @returns The active call.
*/
getActiveCall(roomId) {
const call = this.getCall(roomId);
return call !== null && this.connectedCalls.has(call) ? call : null;
}
}
exports.CallStore = CallStore;
(0, _defineProperty2.default)(CallStore, "_instance", void 0);
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbG9nZ2VyIiwicmVxdWlyZSIsIl9ncm91cENhbGxFdmVudEhhbmRsZXIiLCJfbWF0cml4cnRjIiwiX2Rpc3BhdGNoZXIiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwiX0FzeW5jU3RvcmUiLCJfQXN5bmNTdG9yZVdpdGhDbGllbnQiLCJfV2lkZ2V0U3RvcmUiLCJfU2V0dGluZ3NTdG9yZSIsIl9TZXR0aW5nTGV2ZWwiLCJfQ2FsbCIsIkNhbGxTdG9yZUV2ZW50IiwiZXhwb3J0cyIsIkNhbGxTdG9yZSIsIkFzeW5jU3RvcmVXaXRoQ2xpZW50IiwiaW5zdGFuY2UiLCJfaW5zdGFuY2UiLCJzdGFydCIsImNvbnN0cnVjdG9yIiwiZGVmYXVsdERpc3BhdGNoZXIiLCJfZGVmaW5lUHJvcGVydHkyIiwiZGVmYXVsdCIsIlNldCIsIk1hcCIsInJvb21JZCIsIm1hdHJpeENsaWVudCIsInJvb20iLCJnZXRSb29tcyIsInVwZGF0ZVJvb20iLCJnZXRSb29tIiwiZ3JvdXBDYWxsIiwic2Vzc2lvbiIsInNldE1heExpc3RlbmVycyIsIm9uQWN0aW9uIiwib25SZWFkeSIsIm9uIiwiR3JvdXBDYWxsRXZlbnRIYW5kbGVyRXZlbnQiLCJJbmNvbWluZyIsIm9uR3JvdXBDYWxsIiwiT3V0Z29pbmciLCJtYXRyaXhSVEMiLCJNYXRyaXhSVENTZXNzaW9uTWFuYWdlckV2ZW50cyIsIlNlc3Npb25TdGFydGVkIiwib25SVENTZXNzaW9uU3RhcnQiLCJXaWRnZXRTdG9yZSIsIlVQREFURV9FVkVOVCIsIm9uV2lkZ2V0cyIsInVuY2xlYW5seURpc2Nvbm5lY3RlZFJvb21JZHMiLCJTZXR0aW5nc1N0b3JlIiwiZ2V0VmFsdWUiLCJsZW5ndGgiLCJQcm9taXNlIiwiYWxsIiwibWFwIiwidW5jbGVhbmx5RGlzY29ubmVjdGVkUm9vbUlkIiwibG9nZ2VyIiwibG9nIiwiZ2V0Q2FsbCIsImNsZWFuIiwic2V0VmFsdWUiLCJTZXR0aW5nTGV2ZWwiLCJERVZJQ0UiLCJvbk5vdFJlYWR5IiwiY2FsbCIsImxpc3RlbmVyTWFwIiwiY2FsbExpc3RlbmVycyIsImV2ZW50IiwibGlzdGVuZXIiLCJvZmYiLCJkZXN0cm95IiwiY2xlYXIiLCJjYWxscyIsIl9jb25uZWN0ZWRDYWxscyIsIkVuZGVkIiwiY29ubmVjdGVkQ2FsbHMiLCJ2YWx1ZSIsImVtaXQiLCJDb25uZWN0ZWRDYWxscyIsImhhcyIsIkNhbGwiLCJnZXQiLCJvbkNvbm5lY3Rpb25TdGF0ZSIsInN0YXRlIiwiQ29ubmVjdGlvblN0YXRlIiwiQ29ubmVjdGVkIiwiRGlzY29ubmVjdGVkIiwiZmlsdGVyIiwiYyIsIm9uRGVzdHJveSIsImRlbGV0ZSIsIkNhbGxFdmVudCIsIkRlc3Ryb3kiLCJzZXQiLCJnZXRBY3RpdmVDYWxsIl0sInNvdXJjZXMiOlsiLi4vLi4vc3JjL3N0b3Jlcy9DYWxsU3RvcmUudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLypcbkNvcHlyaWdodCAyMDI0IE5ldyBWZWN0b3IgTHRkLlxuQ29weXJpZ2h0IDIwMjIgVGhlIE1hdHJpeC5vcmcgRm91bmRhdGlvbiBDLkkuQy5cblxuU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFHUEwtMy4wLW9ubHkgT1IgR1BMLTMuMC1vbmx5XG5QbGVhc2Ugc2VlIExJQ0VOU0UgZmlsZXMgaW4gdGhlIHJlcG9zaXRvcnkgcm9vdCBmb3IgZnVsbCBkZXRhaWxzLlxuKi9cblxuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL2xvZ2dlclwiO1xuaW1wb3J0IHsgR3JvdXBDYWxsRXZlbnRIYW5kbGVyRXZlbnQgfSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvd2VicnRjL2dyb3VwQ2FsbEV2ZW50SGFuZGxlclwiO1xuaW1wb3J0IHsgTWF0cml4UlRDU2Vzc2lvbiwgTWF0cml4UlRDU2Vzc2lvbk1hbmFnZXJFdmVudHMgfSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvbWF0cml4cnRjXCI7XG5cbmltcG9ydCB0eXBlIHsgR3JvdXBDYWxsLCBSb29tIH0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL21hdHJpeFwiO1xuaW1wb3J0IGRlZmF1bHREaXNwYXRjaGVyIGZyb20gXCIuLi9kaXNwYXRjaGVyL2Rpc3BhdGNoZXJcIjtcbmltcG9ydCB7IFVQREFURV9FVkVOVCB9IGZyb20gXCIuL0FzeW5jU3RvcmVcIjtcbmltcG9ydCB7IEFzeW5jU3RvcmVXaXRoQ2xpZW50IH0gZnJvbSBcIi4vQXN5bmNTdG9yZVdpdGhDbGllbnRcIjtcbmltcG9ydCBXaWRnZXRTdG9yZSBmcm9tIFwiLi9XaWRnZXRTdG9yZVwiO1xuaW1wb3J0IFNldHRpbmdzU3RvcmUgZnJvbSBcIi4uL3NldHRpbmdzL1NldHRpbmdzU3RvcmVcIjtcbmltcG9ydCB7IFNldHRpbmdMZXZlbCB9IGZyb20gXCIuLi9zZXR0aW5ncy9TZXR0aW5nTGV2ZWxcIjtcbmltcG9ydCB7IENhbGwsIENhbGxFdmVudCwgQ29ubmVjdGlvblN0YXRlIH0gZnJvbSBcIi4uL21vZGVscy9DYWxsXCI7XG5cbmV4cG9ydCBlbnVtIENhbGxTdG9yZUV2ZW50IHtcbiAgICAvLyBTaWduYWxzIGEgY2hhbmdlIGluIHRoZSBjYWxsIGFzc29jaWF0ZWQgd2l0aCBhIGdpdmVuIHJvb21cbiAgICBDYWxsID0gXCJjYWxsXCIsXG4gICAgLy8gU2lnbmFscyBhIGNoYW5nZSBpbiB0aGUgYWN0aXZlIGNhbGxzXG4gICAgQ29ubmVjdGVkQ2FsbHMgPSBcImNvbm5lY3RlZF9jYWxsc1wiLFxufVxuXG5leHBvcnQgY2xhc3MgQ2FsbFN0b3JlIGV4dGVuZHMgQXN5bmNTdG9yZVdpdGhDbGllbnQ8e30+IHtcbiAgICBwcml2YXRlIHN0YXRpYyBfaW5zdGFuY2U6IENhbGxTdG9yZTtcbiAgICBwdWJsaWMgc3RhdGljIGdldCBpbnN0YW5jZSgpOiBDYWxsU3RvcmUge1xuICAgICAgICBpZiAoIXRoaXMuX2luc3RhbmNlKSB7XG4gICAgICAgICAgICB0aGlzLl9pbnN0YW5jZSA9IG5ldyBDYWxsU3RvcmUoKTtcbiAgICAgICAgICAgIHRoaXMuX2luc3RhbmNlLnN0YXJ0KCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXMuX2luc3RhbmNlO1xuICAgIH1cblxuICAgIHByaXZhdGUgY29uc3RydWN0b3IoKSB7XG4gICAgICAgIHN1cGVyKGRlZmF1bHREaXNwYXRjaGVyKTtcbiAgICAgICAgdGhpcy5zZXRNYXhMaXN0ZW5lcnMoMTAwKTsgLy8gT25lIGZvciBlYWNoIFJvb21UaWxlXG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIGFzeW5jIG9uQWN0aW9uKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICAvLyBub3RoaW5nIHRvIGRvXG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIGFzeW5jIG9uUmVhZHkoKTogUHJvbWlzZTxhbnk+IHtcbiAgICAgICAgaWYgKCF0aGlzLm1hdHJpeENsaWVudCkgcmV0dXJuO1xuICAgICAgICAvLyBXZSBhc3N1bWUgdGhhdCB0aGUgY2FsbHMgcHJlc2VudCBpbiBhIHJvb20gYXJlIGEgZnVuY3Rpb24gb2Ygcm9vbVxuICAgICAgICAvLyB3aWRnZXRzIGFuZCBncm91cCBjYWxscywgc28gd2UgaW5pdGlhbGl6ZSB0aGUgcm9vbSBtYXAgaGVyZSBhbmQgdGhlblxuICAgICAgICAvLyB1cGRhdGUgaXQgd2hlbmV2ZXIgdGhvc2UgY2hhbmdlXG4gICAgICAgIGZvciAoY29uc3Qgcm9vbSBvZiB0aGlzLm1hdHJpeENsaWVudC5nZXRSb29tcygpKSB7XG4gICAgICAgICAgICB0aGlzLnVwZGF0ZVJvb20ocm9vbSk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5tYXRyaXhDbGllbnQub24oR3JvdXBDYWxsRXZlbnRIYW5kbGVyRXZlbnQuSW5jb21pbmcsIHRoaXMub25Hcm91cENhbGwpO1xuICAgICAgICB0aGlzLm1hdHJpeENsaWVudC5vbihHcm91cENhbGxFdmVudEhhbmRsZXJFdmVudC5PdXRnb2luZywgdGhpcy5vbkdyb3VwQ2FsbCk7XG4gICAgICAgIHRoaXMubWF0cml4Q2xpZW50Lm1hdHJpeFJUQy5vbihNYXRyaXhSVENTZXNzaW9uTWFuYWdlckV2ZW50cy5TZXNzaW9uU3RhcnRlZCwgdGhpcy5vblJUQ1Nlc3Npb25TdGFydCk7XG4gICAgICAgIFdpZGdldFN0b3JlLmluc3RhbmNlLm9uKFVQREFURV9FVkVOVCwgdGhpcy5vbldpZGdldHMpO1xuXG4gICAgICAgIC8vIElmIHRoZSByb29tIElEIG9mIGEgcHJldmlvdXNseSBjb25uZWN0ZWQgY2FsbCBpcyBzdGlsbCBpbiBzZXR0aW5ncyBhdFxuICAgICAgICAvLyB0aGlzIHRpbWUsIHRoYXQncyBhIHNpZ24gdGhhdCB3ZSBmYWlsZWQgdG8gZGlzY29ubmVjdCBmcm9tIGl0XG4gICAgICAgIC8vIHByb3Blcmx5LCBhbmQgbmVlZCB0byBjbGVhbiB1cCBhZnRlciBvdXJzZWx2ZXNcbiAgICAgICAgY29uc3QgdW5jbGVhbmx5RGlzY29ubmVjdGVkUm9vbUlkcyA9IFNldHRpbmdzU3RvcmUuZ2V0VmFsdWU8c3RyaW5nW10+KFwiYWN0aXZlQ2FsbFJvb21JZHNcIik7XG4gICAgICAgIGlmICh1bmNsZWFubHlEaXNjb25uZWN0ZWRSb29tSWRzLmxlbmd0aCkge1xuICAgICAgICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgICAgICAgICAgIC4uLnVuY2xlYW5seURpc2Nvbm5lY3RlZFJvb21JZHMubWFwKGFzeW5jICh1bmNsZWFubHlEaXNjb25uZWN0ZWRSb29tSWQpOiBQcm9taXNlPHZvaWQ+ID0+IHtcbiAgICAgICAgICAgICAgICAgICAgbG9nZ2VyLmxvZyhgQ2xlYW5pbmcgdXAgY2FsbCBzdGF0ZSBmb3Igcm9vbSAke3VuY2xlYW5seURpc2Nvbm5lY3RlZFJvb21JZH1gKTtcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5nZXRDYWxsKHVuY2xlYW5seURpc2Nvbm5lY3RlZFJvb21JZCk/LmNsZWFuKCk7XG4gICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgICAgU2V0dGluZ3NTdG9yZS5zZXRWYWx1ZShcImFjdGl2ZUNhbGxSb29tSWRzXCIsIG51bGwsIFNldHRpbmdMZXZlbC5ERVZJQ0UsIFtdKSxcbiAgICAgICAgICAgIF0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIGFzeW5jIG9uTm90UmVhZHkoKTogUHJvbWlzZTxhbnk+IHtcbiAgICAgICAgZm9yIChjb25zdCBbY2FsbCwgbGlzdGVuZXJNYXBdIG9mIHRoaXMuY2FsbExpc3RlbmVycykge1xuICAgICAgICAgICAgLy8gSXQncyBpbXBvcnRhbnQgdGhhdCB3ZSByZW1vdmUgdGhlIGxpc3RlbmVycyBiZWZvcmUgZGVzdHJveWluZyB0aGVcbiAgICAgICAgICAgIC8vIGNhbGwsIGJlY2F1c2Ugb3RoZXJ3aXNlIHRoZSBjYWxsJ3Mgb25EZXN0cm95IGNhbGxiYWNrIHdvdWxkIGZpcmVcbiAgICAgICAgICAgIC8vIGFuZCBpbW1lZGlhdGVseSByZXBvcHVsYXRlIHRoZSBtYXBcbiAgICAgICAgICAgIGZvciAoY29uc3QgW2V2ZW50LCBsaXN0ZW5lcl0gb2YgbGlzdGVuZXJNYXApIGNhbGwub2ZmKGV2ZW50LCBsaXN0ZW5lcik7XG4gICAgICAgICAgICBjYWxsLmRlc3Ryb3koKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmNhbGxMaXN0ZW5lcnMuY2xlYXIoKTtcbiAgICAgICAgdGhpcy5jYWxscy5jbGVhcigpO1xuICAgICAgICB0aGlzLl9jb25uZWN0ZWRDYWxscy5jbGVhcigpO1xuXG4gICAgICAgIGlmICh0aGlzLm1hdHJpeENsaWVudCkge1xuICAgICAgICAgICAgdGhpcy5tYXRyaXhDbGllbnQub2ZmKEdyb3VwQ2FsbEV2ZW50SGFuZGxlckV2ZW50LkluY29taW5nLCB0aGlzLm9uR3JvdXBDYWxsKTtcbiAgICAgICAgICAgIHRoaXMubWF0cml4Q2xpZW50Lm9mZihHcm91cENhbGxFdmVudEhhbmRsZXJFdmVudC5PdXRnb2luZywgdGhpcy5vbkdyb3VwQ2FsbCk7XG4gICAgICAgICAgICB0aGlzLm1hdHJpeENsaWVudC5vZmYoR3JvdXBDYWxsRXZlbnRIYW5kbGVyRXZlbnQuRW5kZWQsIHRoaXMub25Hcm91cENhbGwpO1xuICAgICAgICAgICAgdGhpcy5tYXRyaXhDbGllbnQubWF0cml4UlRDLm9mZihNYXRyaXhSVENTZXNzaW9uTWFuYWdlckV2ZW50cy5TZXNzaW9uU3RhcnRlZCwgdGhpcy5vblJUQ1Nlc3Npb25TdGFydCk7XG4gICAgICAgIH1cbiAgICAgICAgV2lkZ2V0U3RvcmUuaW5zdGFuY2Uub2ZmKFVQREFURV9FVkVOVCwgdGhpcy5vbldpZGdldHMpO1xuICAgIH1cblxuICAgIHByaXZhdGUgX2Nvbm5lY3RlZENhbGxzOiBTZXQ8Q2FsbD4gPSBuZXcgU2V0KCk7XG4gICAgLyoqXG4gICAgICogVGhlIGNhbGxzIHRvIHdoaWNoIHRoZSB1c2VyIGlzIGN1cnJlbnRseSBjb25uZWN0ZWQuXG4gICAgICovXG4gICAgcHVibGljIGdldCBjb25uZWN0ZWRDYWxscygpOiBTZXQ8Q2FsbD4ge1xuICAgICAgICByZXR1cm4gdGhpcy5fY29ubmVjdGVkQ2FsbHM7XG4gICAgfVxuICAgIHByaXZhdGUgc2V0IGNvbm5lY3RlZENhbGxzKHZhbHVlOiBTZXQ8Q2FsbD4pIHtcbiAgICAgICAgdGhpcy5fY29ubmVjdGVkQ2FsbHMgPSB2YWx1ZTtcbiAgICAgICAgdGhpcy5lbWl0KENhbGxTdG9yZUV2ZW50LkNvbm5lY3RlZENhbGxzLCB2YWx1ZSk7XG5cbiAgICAgICAgLy8gVGhlIHJvb20gSURzIGFyZSBwZXJzaXN0ZWQgdG8gc2V0dGluZ3Mgc28gd2UgY2FuIGRldGVjdCB1bmNsZWFuIGRpc2Nvbm5lY3RzXG4gICAgICAgIFNldHRpbmdzU3RvcmUuc2V0VmFsdWUoXG4gICAgICAgICAgICBcImFjdGl2ZUNhbGxSb29tSWRzXCIsXG4gICAgICAgICAgICBudWxsLFxuICAgICAgICAgICAgU2V0dGluZ0xldmVsLkRFVklDRSxcbiAgICAgICAgICAgIFsuLi52YWx1ZV0ubWFwKChjYWxsKSA9PiBjYWxsLnJvb21JZCksXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBjYWxscyA9IG5ldyBNYXA8c3RyaW5nLCBDYWxsPigpOyAvLyBLZXkgaXMgcm9vbSBJRFxuICAgIHByaXZhdGUgY2FsbExpc3RlbmVycyA9IG5ldyBNYXA8Q2FsbCwgTWFwPENhbGxFdmVudCwgKC4uLmFyZ3M6IHVua25vd25bXSkgPT4gdW5rbm93bj4+KCk7XG5cbiAgICBwcml2YXRlIHVwZGF0ZVJvb20ocm9vbTogUm9vbSk6IHZvaWQge1xuICAgICAgICBpZiAoIXRoaXMuY2FsbHMuaGFzKHJvb20ucm9vbUlkKSkge1xuICAgICAgICAgICAgY29uc3QgY2FsbCA9IENhbGwuZ2V0KHJvb20pO1xuXG4gICAgICAgICAgICBpZiAoY2FsbCkge1xuICAgICAgICAgICAgICAgIGNvbnN0IG9uQ29ubmVjdGlvblN0YXRlID0gKHN0YXRlOiBDb25uZWN0aW9uU3RhdGUpOiB2b2lkID0+IHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHN0YXRlID09PSBDb25uZWN0aW9uU3RhdGUuQ29ubmVjdGVkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmNvbm5lY3RlZENhbGxzID0gbmV3IFNldChbLi4udGhpcy5jb25uZWN0ZWRDYWxscywgY2FsbF0pO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHN0YXRlID09PSBDb25uZWN0aW9uU3RhdGUuRGlzY29ubmVjdGVkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmNvbm5lY3RlZENhbGxzID0gbmV3IFNldChbLi4udGhpcy5jb25uZWN0ZWRDYWxsc10uZmlsdGVyKChjKSA9PiBjICE9PSBjYWxsKSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIGNvbnN0IG9uRGVzdHJveSA9ICgpOiB2b2lkID0+IHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jYWxscy5kZWxldGUocm9vbS5yb29tSWQpO1xuICAgICAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IFtldmVudCwgbGlzdGVuZXJdIG9mIHRoaXMuY2FsbExpc3RlbmVycy5nZXQoY2FsbCkhKSBjYWxsLm9mZihldmVudCwgbGlzdGVuZXIpO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnVwZGF0ZVJvb20ocm9vbSk7XG4gICAgICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgICAgIGNhbGwub24oQ2FsbEV2ZW50LkNvbm5lY3Rpb25TdGF0ZSwgb25Db25uZWN0aW9uU3RhdGUpO1xuICAgICAgICAgICAgICAgIGNhbGwub24oQ2FsbEV2ZW50LkRlc3Ryb3ksIG9uRGVzdHJveSk7XG5cbiAgICAgICAgICAgICAgICB0aGlzLmNhbGxzLnNldChyb29tLnJvb21JZCwgY2FsbCk7XG4gICAgICAgICAgICAgICAgdGhpcy5jYWxsTGlzdGVuZXJzLnNldChcbiAgICAgICAgICAgICAgICAgICAgY2FsbCxcbiAgICAgICAgICAgICAgICAgICAgbmV3IE1hcDxDYWxsRXZlbnQsICguLi5hcmdzOiBhbnlbXSkgPT4gdW5rbm93bj4oW1xuICAgICAgICAgICAgICAgICAgICAgICAgW0NhbGxFdmVudC5Db25uZWN0aW9uU3RhdGUsIG9uQ29ubmVjdGlvblN0YXRlXSxcbiAgICAgICAgICAgICAgICAgICAgICAgIFtDYWxsRXZlbnQuRGVzdHJveSwgb25EZXN0cm95XSxcbiAgICAgICAgICAgICAgICAgICAgXSksXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5lbWl0KENhbGxTdG9yZUV2ZW50LkNhbGwsIGNhbGwsIHJvb20ucm9vbUlkKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldHMgdGhlIGNhbGwgYXNzb2NpYXRlZCB3aXRoIHRoZSBnaXZlbiByb29tLCBpZiBhbnkuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHJvb21JZCBUaGUgcm9vbSdzIElELlxuICAgICAqIEByZXR1cm5zIHtDYWxsIHwgbnVsbH0gVGhlIGNhbGwuXG4gICAgICovXG4gICAgcHVibGljIGdldENhbGwocm9vbUlkOiBzdHJpbmcpOiBDYWxsIHwgbnVsbCB7XG4gICAgICAgIHJldHVybiB0aGlzLmNhbGxzLmdldChyb29tSWQpID8/IG51bGw7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0cyB0aGUgYWN0aXZlIGNhbGwgYXNzb2NpYXRlZCB3aXRoIHRoZSBnaXZlbiByb29tLCBpZiBhbnkuXG4gICAgICogQHBhcmFtIHJvb21JZCBUaGUgcm9vbSdzIElELlxuICAgICAqIEByZXR1cm5zIFRoZSBhY3RpdmUgY2FsbC5cbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0QWN0aXZlQ2FsbChyb29tSWQ6IHN0cmluZyk6IENhbGwgfCBudWxsIHtcbiAgICAgICAgY29uc3QgY2FsbCA9IHRoaXMuZ2V0Q2FsbChyb29tSWQpO1xuICAgICAgICByZXR1cm4gY2FsbCAhPT0gbnVsbCAmJiB0aGlzLmNvbm5lY3RlZENhbGxzLmhhcyhjYWxsKSA/IGNhbGwgOiBudWxsO1xuICAgIH1cblxuICAgIHByaXZhdGUgb25XaWRnZXRzID0gKHJvb21JZDogc3RyaW5nIHwgbnVsbCk6IHZvaWQgPT4ge1xuICAgICAgICBpZiAoIXRoaXMubWF0cml4Q2xpZW50KSByZXR1cm47XG4gICAgICAgIGlmIChyb29tSWQgPT09IG51bGwpIHtcbiAgICAgICAgICAgIC8vIFRoaXMgc3RvcmUgaGFwcGVuZWQgdG8gc3RhcnQgYmVmb3JlIHRoZSB3aWRnZXQgc3RvcmUgd2FzIGRvbmVcbiAgICAgICAgICAgIC8vIGxvYWRpbmcgYWxsIHJvb21zLCBzbyB3ZSBuZWVkIHRvIGluaXRpYWxpemUgZWFjaCByb29tIGFnYWluXG4gICAgICAgICAgICBmb3IgKGNvbnN0IHJvb20gb2YgdGhpcy5tYXRyaXhDbGllbnQuZ2V0Um9vbXMoKSkge1xuICAgICAgICAgICAgICAgIHRoaXMudXBkYXRlUm9vbShyb29tKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNvbnN0IHJvb20gPSB0aGlzLm1hdHJpeENsaWVudC5nZXRSb29tKHJvb21JZCk7XG4gICAgICAgICAgICAvLyBXaWRnZXQgdXBkYXRlcyBjYW4gYXJyaXZlIGJlZm9yZSB0aGUgcm9vbSBkb2VzLCBlbXBpcmljYWxseVxuICAgICAgICAgICAgaWYgKHJvb20gIT09IG51bGwpIHRoaXMudXBkYXRlUm9vbShyb29tKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBwcml2YXRlIG9uR3JvdXBDYWxsID0gKGdyb3VwQ2FsbDogR3JvdXBDYWxsKTogdm9pZCA9PiB0aGlzLnVwZGF0ZVJvb20oZ3JvdXBDYWxsLnJvb20pO1xuICAgIHByaXZhdGUgb25SVENTZXNzaW9uU3RhcnQgPSAocm9vbUlkOiBzdHJpbmcsIHNlc3Npb246IE1hdHJpeFJUQ1Nlc3Npb24pOiB2b2lkID0+IHtcbiAgICAgICAgdGhpcy51cGRhdGVSb29tKHNlc3Npb24ucm9vbSk7XG4gICAgfTtcbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7QUFRQSxJQUFBQSxPQUFBLEdBQUFDLE9BQUE7QUFDQSxJQUFBQyxzQkFBQSxHQUFBRCxPQUFBO0FBQ0EsSUFBQUUsVUFBQSxHQUFBRixPQUFBO0FBR0EsSUFBQUcsV0FBQSxHQUFBQyxzQkFBQSxDQUFBSixPQUFBO0FBQ0EsSUFBQUssV0FBQSxHQUFBTCxPQUFBO0FBQ0EsSUFBQU0scUJBQUEsR0FBQU4sT0FBQTtBQUNBLElBQUFPLFlBQUEsR0FBQUgsc0JBQUEsQ0FBQUosT0FBQTtBQUNBLElBQUFRLGNBQUEsR0FBQUosc0JBQUEsQ0FBQUosT0FBQTtBQUNBLElBQUFTLGFBQUEsR0FBQVQsT0FBQTtBQUNBLElBQUFVLEtBQUEsR0FBQVYsT0FBQTtBQW5CQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQU5BLElBcUJZVyxjQUFjLEdBQUFDLE9BQUEsQ0FBQUQsY0FBQSwwQkFBZEEsY0FBYztFQUFkQSxjQUFjO0VBQWRBLGNBQWM7RUFBQSxPQUFkQSxjQUFjO0FBQUE7QUFP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