matrix-react-sdk
Version:
SDK for matrix.org using React
245 lines (235 loc) • 31.5 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _lodash = require("lodash");
var _matrix = require("matrix-js-sdk/src/matrix");
var _types = require("matrix-js-sdk/src/types");
var _logger = require("matrix-js-sdk/src/logger");
var _filterValidMDirect = require("./dm/filterValidMDirect");
/*
Copyright 2024 New Vector Ltd.
Copyright 2016-2019 , 2021 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.
*/
/**
* Class that takes a Matrix Client and flips the m.direct map
* so the operation of mapping a room ID to which user it's a DM
* with can be performed efficiently.
*
* With 'start', this can also keep itself up to date over time.
*/
class DMRoomMap {
constructor(matrixClient) {
// TODO: convert these to maps
(0, _defineProperty2.default)(this, "roomToUser", null);
(0, _defineProperty2.default)(this, "userToRooms", null);
(0, _defineProperty2.default)(this, "hasSentOutPatchDirectAccountDataPatch", void 0);
(0, _defineProperty2.default)(this, "mDirectEvent", void 0);
(0, _defineProperty2.default)(this, "onAccountData", ev => {
if (ev.getType() == _matrix.EventType.Direct) {
this.setMDirectFromContent(ev.getContent());
this.userToRooms = null;
this.roomToUser = null;
}
});
this.matrixClient = matrixClient;
// see onAccountData
this.hasSentOutPatchDirectAccountDataPatch = false;
const mDirectRawContent = matrixClient.getAccountData(_matrix.EventType.Direct)?.getContent() ?? {};
this.setMDirectFromContent(mDirectRawContent);
}
/**
* Makes and returns a new shared instance that can then be accessed
* with shared(). This returned instance is not automatically started.
*/
static makeShared(matrixClient) {
DMRoomMap.sharedInstance = new DMRoomMap(matrixClient);
return DMRoomMap.sharedInstance;
}
/**
* Set the shared instance to the instance supplied
* Used by tests
* @param inst the new shared instance
*/
static setShared(inst) {
DMRoomMap.sharedInstance = inst;
}
/**
* Returns a shared instance of the class
* that uses the singleton matrix client
* The shared instance must be started before use.
*/
static shared() {
return DMRoomMap.sharedInstance;
}
start() {
this.populateRoomToUser();
this.matrixClient.on(_matrix.ClientEvent.AccountData, this.onAccountData);
}
stop() {
this.matrixClient.removeListener(_matrix.ClientEvent.AccountData, this.onAccountData);
}
/**
* Filter m.direct content to contain only valid data and then sets it.
* Logs if invalid m.direct content occurs.
* {@link filterValidMDirect}
*
* @param content - Raw m.direct content
*/
setMDirectFromContent(content) {
const {
valid,
filteredContent
} = (0, _filterValidMDirect.filterValidMDirect)(content);
if (!valid) {
_logger.logger.warn("Invalid m.direct content occurred", content);
}
this.mDirectEvent = filteredContent;
}
/**
* some client bug somewhere is causing some DMs to be marked
* with ourself, not the other user. Fix it by guessing the other user and
* modifying userToRooms
*/
patchUpSelfDMs(userToRooms) {
const myUserId = this.matrixClient.getUserId();
const selfRoomIds = userToRooms[myUserId];
if (selfRoomIds) {
// any self-chats that should not be self-chats?
const guessedUserIdsThatChanged = selfRoomIds.map(roomId => {
const room = this.matrixClient.getRoom(roomId);
if (room) {
const userId = room.guessDMUserId();
if (userId && userId !== myUserId) {
return {
userId,
roomId
};
}
}
}).filter(ids => !!ids); //filter out
// these are actually all legit self-chats
// bail out
if (!guessedUserIdsThatChanged.length) {
return false;
}
userToRooms[myUserId] = selfRoomIds.filter(roomId => {
return !guessedUserIdsThatChanged.some(ids => ids.roomId === roomId);
});
guessedUserIdsThatChanged.forEach(({
userId,
roomId
}) => {
const roomIds = userToRooms[userId];
if (!roomIds) {
userToRooms[userId] = [roomId];
} else {
roomIds.push(roomId);
userToRooms[userId] = (0, _lodash.uniq)(roomIds);
}
});
return true;
}
return false;
}
getDMRoomsForUserId(userId) {
// Here, we return the empty list if there are no rooms,
// since the number of conversations you have with this user is zero.
return this.getUserToRooms()[userId] || [];
}
/**
* Gets the DM room which the given IDs share, if any.
* @param {string[]} ids The identifiers (user IDs and email addresses) to look for.
* @returns {Room} The DM room which all IDs given share, or falsy if no common room.
*/
getDMRoomForIdentifiers(ids) {
// TODO: [Canonical DMs] Handle lookups for email addresses.
// For now we'll pretend we only get user IDs and end up returning nothing for email addresses
let commonRooms = this.getDMRoomsForUserId(ids[0]);
for (let i = 1; i < ids.length; i++) {
const userRooms = this.getDMRoomsForUserId(ids[i]);
commonRooms = commonRooms.filter(r => userRooms.includes(r));
}
const joinedRooms = commonRooms.map(r => this.matrixClient.getRoom(r)).filter(r => r && r.getMyMembership() === _types.KnownMembership.Join);
return joinedRooms[0];
}
getUserIdForRoomId(roomId) {
if (this.roomToUser == null) {
// we lazily populate roomToUser so you can use
// this class just to call getDMRoomsForUserId
// which doesn't do very much, but is a fairly
// convenient wrapper and there's no point
// iterating through the map if getUserIdForRoomId()
// is never called.
this.populateRoomToUser();
}
// Here, we return undefined if the room is not in the map:
// the room ID you gave is not a DM room for any user.
if (this.roomToUser[roomId] === undefined) {
// no entry? if the room is an invite, look for the is_direct hint.
const room = this.matrixClient.getRoom(roomId);
if (room) {
return room.getDMInviter();
}
}
return this.roomToUser[roomId];
}
getUniqueRoomsWithIndividuals() {
if (!this.roomToUser) return {}; // No rooms means no map.
// map roomToUser to valid rooms with two participants
return Object.keys(this.roomToUser).reduce((acc, roomId) => {
const userId = this.getUserIdForRoomId(roomId);
const room = this.matrixClient.getRoom(roomId);
const hasTwoMembers = room?.getInvitedAndJoinedMemberCount() === 2;
if (userId && room && hasTwoMembers) {
acc[userId] = room;
}
return acc;
}, {});
}
/**
* @returns all room Ids from m.direct
*/
getRoomIds() {
return Object.values(this.mDirectEvent).reduce((prevRoomIds, roomIds) => {
roomIds.forEach(roomId => prevRoomIds.add(roomId));
return prevRoomIds;
}, new Set());
}
getUserToRooms() {
if (!this.userToRooms) {
const userToRooms = this.mDirectEvent;
const myUserId = this.matrixClient.getUserId();
const selfDMs = userToRooms[myUserId];
if (selfDMs?.length) {
const neededPatching = this.patchUpSelfDMs(userToRooms);
// to avoid multiple devices fighting to correct
// the account data, only try to send the corrected
// version once.
_logger.logger.warn(`Invalid m.direct account data detected (self-chats that shouldn't be), patching it up.`);
if (neededPatching && !this.hasSentOutPatchDirectAccountDataPatch) {
this.hasSentOutPatchDirectAccountDataPatch = true;
this.matrixClient.setAccountData(_matrix.EventType.Direct, userToRooms);
}
}
this.userToRooms = userToRooms;
}
return this.userToRooms;
}
populateRoomToUser() {
this.roomToUser = {};
for (const user of Object.keys(this.getUserToRooms())) {
for (const roomId of this.userToRooms[user]) {
this.roomToUser[roomId] = user;
}
}
}
}
exports.default = DMRoomMap;
(0, _defineProperty2.default)(DMRoomMap, "sharedInstance", void 0);
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbG9kYXNoIiwicmVxdWlyZSIsIl9tYXRyaXgiLCJfdHlwZXMiLCJfbG9nZ2VyIiwiX2ZpbHRlclZhbGlkTURpcmVjdCIsIkRNUm9vbU1hcCIsImNvbnN0cnVjdG9yIiwibWF0cml4Q2xpZW50IiwiX2RlZmluZVByb3BlcnR5MiIsImRlZmF1bHQiLCJldiIsImdldFR5cGUiLCJFdmVudFR5cGUiLCJEaXJlY3QiLCJzZXRNRGlyZWN0RnJvbUNvbnRlbnQiLCJnZXRDb250ZW50IiwidXNlclRvUm9vbXMiLCJyb29tVG9Vc2VyIiwiaGFzU2VudE91dFBhdGNoRGlyZWN0QWNjb3VudERhdGFQYXRjaCIsIm1EaXJlY3RSYXdDb250ZW50IiwiZ2V0QWNjb3VudERhdGEiLCJtYWtlU2hhcmVkIiwic2hhcmVkSW5zdGFuY2UiLCJzZXRTaGFyZWQiLCJpbnN0Iiwic2hhcmVkIiwic3RhcnQiLCJwb3B1bGF0ZVJvb21Ub1VzZXIiLCJvbiIsIkNsaWVudEV2ZW50IiwiQWNjb3VudERhdGEiLCJvbkFjY291bnREYXRhIiwic3RvcCIsInJlbW92ZUxpc3RlbmVyIiwiY29udGVudCIsInZhbGlkIiwiZmlsdGVyZWRDb250ZW50IiwiZmlsdGVyVmFsaWRNRGlyZWN0IiwibG9nZ2VyIiwid2FybiIsIm1EaXJlY3RFdmVudCIsInBhdGNoVXBTZWxmRE1zIiwibXlVc2VySWQiLCJnZXRVc2VySWQiLCJzZWxmUm9vbUlkcyIsImd1ZXNzZWRVc2VySWRzVGhhdENoYW5nZWQiLCJtYXAiLCJyb29tSWQiLCJyb29tIiwiZ2V0Um9vbSIsInVzZXJJZCIsImd1ZXNzRE1Vc2VySWQiLCJmaWx0ZXIiLCJpZHMiLCJsZW5ndGgiLCJzb21lIiwiZm9yRWFjaCIsInJvb21JZHMiLCJwdXNoIiwidW5pcSIsImdldERNUm9vbXNGb3JVc2VySWQiLCJnZXRVc2VyVG9Sb29tcyIsImdldERNUm9vbUZvcklkZW50aWZpZXJzIiwiY29tbW9uUm9vbXMiLCJpIiwidXNlclJvb21zIiwiciIsImluY2x1ZGVzIiwiam9pbmVkUm9vbXMiLCJnZXRNeU1lbWJlcnNoaXAiLCJLbm93bk1lbWJlcnNoaXAiLCJKb2luIiwiZ2V0VXNlcklkRm9yUm9vbUlkIiwidW5kZWZpbmVkIiwiZ2V0RE1JbnZpdGVyIiwiZ2V0VW5pcXVlUm9vbXNXaXRoSW5kaXZpZHVhbHMiLCJPYmplY3QiLCJrZXlzIiwicmVkdWNlIiwiYWNjIiwiaGFzVHdvTWVtYmVycyIsImdldEludml0ZWRBbmRKb2luZWRNZW1iZXJDb3VudCIsImdldFJvb21JZHMiLCJ2YWx1ZXMiLCJwcmV2Um9vbUlkcyIsImFkZCIsIlNldCIsInNlbGZETXMiLCJuZWVkZWRQYXRjaGluZyIsInNldEFjY291bnREYXRhIiwidXNlciIsImV4cG9ydHMiXSwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvRE1Sb29tTWFwLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qXG5Db3B5cmlnaHQgMjAyNCBOZXcgVmVjdG9yIEx0ZC5cbkNvcHlyaWdodCAyMDE2LTIwMTkgLCAyMDIxIFRoZSBNYXRyaXgub3JnIEZvdW5kYXRpb24gQy5JLkMuXG5cblNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBR1BMLTMuMC1vbmx5IE9SIEdQTC0zLjAtb25seVxuUGxlYXNlIHNlZSBMSUNFTlNFIGZpbGVzIGluIHRoZSByZXBvc2l0b3J5IHJvb3QgZm9yIGZ1bGwgZGV0YWlscy5cbiovXG5cbmltcG9ydCB7IHVuaXEgfSBmcm9tIFwibG9kYXNoXCI7XG5pbXBvcnQgeyBSb29tLCBNYXRyaXhFdmVudCwgRXZlbnRUeXBlLCBDbGllbnRFdmVudCwgTWF0cml4Q2xpZW50IH0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL21hdHJpeFwiO1xuaW1wb3J0IHsgS25vd25NZW1iZXJzaGlwIH0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL3R5cGVzXCI7XG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvbG9nZ2VyXCI7XG5pbXBvcnQgeyBPcHRpb25hbCB9IGZyb20gXCJtYXRyaXgtZXZlbnRzLXNka1wiO1xuXG5pbXBvcnQgeyBmaWx0ZXJWYWxpZE1EaXJlY3QgfSBmcm9tIFwiLi9kbS9maWx0ZXJWYWxpZE1EaXJlY3RcIjtcblxuLyoqXG4gKiBDbGFzcyB0aGF0IHRha2VzIGEgTWF0cml4IENsaWVudCBhbmQgZmxpcHMgdGhlIG0uZGlyZWN0IG1hcFxuICogc28gdGhlIG9wZXJhdGlvbiBvZiBtYXBwaW5nIGEgcm9vbSBJRCB0byB3aGljaCB1c2VyIGl0J3MgYSBETVxuICogd2l0aCBjYW4gYmUgcGVyZm9ybWVkIGVmZmljaWVudGx5LlxuICpcbiAqIFdpdGggJ3N0YXJ0JywgdGhpcyBjYW4gYWxzbyBrZWVwIGl0c2VsZiB1cCB0byBkYXRlIG92ZXIgdGltZS5cbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgRE1Sb29tTWFwIHtcbiAgICBwcml2YXRlIHN0YXRpYyBzaGFyZWRJbnN0YW5jZTogRE1Sb29tTWFwO1xuXG4gICAgLy8gVE9ETzogY29udmVydCB0aGVzZSB0byBtYXBzXG4gICAgcHJpdmF0ZSByb29tVG9Vc2VyOiB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB9IHwgbnVsbCA9IG51bGw7XG4gICAgcHJpdmF0ZSB1c2VyVG9Sb29tczogeyBba2V5OiBzdHJpbmddOiBzdHJpbmdbXSB9IHwgbnVsbCA9IG51bGw7XG4gICAgcHJpdmF0ZSBoYXNTZW50T3V0UGF0Y2hEaXJlY3RBY2NvdW50RGF0YVBhdGNoOiBib29sZWFuO1xuICAgIHByaXZhdGUgbURpcmVjdEV2ZW50ITogeyBba2V5OiBzdHJpbmddOiBzdHJpbmdbXSB9O1xuXG4gICAgcHVibGljIGNvbnN0cnVjdG9yKHByaXZhdGUgcmVhZG9ubHkgbWF0cml4Q2xpZW50OiBNYXRyaXhDbGllbnQpIHtcbiAgICAgICAgLy8gc2VlIG9uQWNjb3VudERhdGFcbiAgICAgICAgdGhpcy5oYXNTZW50T3V0UGF0Y2hEaXJlY3RBY2NvdW50RGF0YVBhdGNoID0gZmFsc2U7XG5cbiAgICAgICAgY29uc3QgbURpcmVjdFJhd0NvbnRlbnQgPSBtYXRyaXhDbGllbnQuZ2V0QWNjb3VudERhdGEoRXZlbnRUeXBlLkRpcmVjdCk/LmdldENvbnRlbnQoKSA/PyB7fTtcbiAgICAgICAgdGhpcy5zZXRNRGlyZWN0RnJvbUNvbnRlbnQobURpcmVjdFJhd0NvbnRlbnQpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIE1ha2VzIGFuZCByZXR1cm5zIGEgbmV3IHNoYXJlZCBpbnN0YW5jZSB0aGF0IGNhbiB0aGVuIGJlIGFjY2Vzc2VkXG4gICAgICogd2l0aCBzaGFyZWQoKS4gVGhpcyByZXR1cm5lZCBpbnN0YW5jZSBpcyBub3QgYXV0b21hdGljYWxseSBzdGFydGVkLlxuICAgICAqL1xuICAgIHB1YmxpYyBzdGF0aWMgbWFrZVNoYXJlZChtYXRyaXhDbGllbnQ6IE1hdHJpeENsaWVudCk6IERNUm9vbU1hcCB7XG4gICAgICAgIERNUm9vbU1hcC5zaGFyZWRJbnN0YW5jZSA9IG5ldyBETVJvb21NYXAobWF0cml4Q2xpZW50KTtcbiAgICAgICAgcmV0dXJuIERNUm9vbU1hcC5zaGFyZWRJbnN0YW5jZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZXQgdGhlIHNoYXJlZCBpbnN0YW5jZSB0byB0aGUgaW5zdGFuY2Ugc3VwcGxpZWRcbiAgICAgKiBVc2VkIGJ5IHRlc3RzXG4gICAgICogQHBhcmFtIGluc3QgdGhlIG5ldyBzaGFyZWQgaW5zdGFuY2VcbiAgICAgKi9cbiAgICBwdWJsaWMgc3RhdGljIHNldFNoYXJlZChpbnN0OiBETVJvb21NYXApOiB2b2lkIHtcbiAgICAgICAgRE1Sb29tTWFwLnNoYXJlZEluc3RhbmNlID0gaW5zdDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIGEgc2hhcmVkIGluc3RhbmNlIG9mIHRoZSBjbGFzc1xuICAgICAqIHRoYXQgdXNlcyB0aGUgc2luZ2xldG9uIG1hdHJpeCBjbGllbnRcbiAgICAgKiBUaGUgc2hhcmVkIGluc3RhbmNlIG11c3QgYmUgc3RhcnRlZCBiZWZvcmUgdXNlLlxuICAgICAqL1xuICAgIHB1YmxpYyBzdGF0aWMgc2hhcmVkKCk6IERNUm9vbU1hcCB7XG4gICAgICAgIHJldHVybiBETVJvb21NYXAuc2hhcmVkSW5zdGFuY2U7XG4gICAgfVxuXG4gICAgcHVibGljIHN0YXJ0KCk6IHZvaWQge1xuICAgICAgICB0aGlzLnBvcHVsYXRlUm9vbVRvVXNlcigpO1xuICAgICAgICB0aGlzLm1hdHJpeENsaWVudC5vbihDbGllbnRFdmVudC5BY2NvdW50RGF0YSwgdGhpcy5vbkFjY291bnREYXRhKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgc3RvcCgpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5tYXRyaXhDbGllbnQucmVtb3ZlTGlzdGVuZXIoQ2xpZW50RXZlbnQuQWNjb3VudERhdGEsIHRoaXMub25BY2NvdW50RGF0YSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRmlsdGVyIG0uZGlyZWN0IGNvbnRlbnQgdG8gY29udGFpbiBvbmx5IHZhbGlkIGRhdGEgYW5kIHRoZW4gc2V0cyBpdC5cbiAgICAgKiBMb2dzIGlmIGludmFsaWQgbS5kaXJlY3QgY29udGVudCBvY2N1cnMuXG4gICAgICoge0BsaW5rIGZpbHRlclZhbGlkTURpcmVjdH1cbiAgICAgKlxuICAgICAqIEBwYXJhbSBjb250ZW50IC0gUmF3IG0uZGlyZWN0IGNvbnRlbnRcbiAgICAgKi9cbiAgICBwcml2YXRlIHNldE1EaXJlY3RGcm9tQ29udGVudChjb250ZW50OiB1bmtub3duKTogdm9pZCB7XG4gICAgICAgIGNvbnN0IHsgdmFsaWQsIGZpbHRlcmVkQ29udGVudCB9ID0gZmlsdGVyVmFsaWRNRGlyZWN0KGNvbnRlbnQpO1xuXG4gICAgICAgIGlmICghdmFsaWQpIHtcbiAgICAgICAgICAgIGxvZ2dlci53YXJuKFwiSW52YWxpZCBtLmRpcmVjdCBjb250ZW50IG9jY3VycmVkXCIsIGNvbnRlbnQpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5tRGlyZWN0RXZlbnQgPSBmaWx0ZXJlZENvbnRlbnQ7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBvbkFjY291bnREYXRhID0gKGV2OiBNYXRyaXhFdmVudCk6IHZvaWQgPT4ge1xuICAgICAgICBpZiAoZXYuZ2V0VHlwZSgpID09IEV2ZW50VHlwZS5EaXJlY3QpIHtcbiAgICAgICAgICAgIHRoaXMuc2V0TURpcmVjdEZyb21Db250ZW50KGV2LmdldENvbnRlbnQoKSk7XG4gICAgICAgICAgICB0aGlzLnVzZXJUb1Jvb21zID0gbnVsbDtcbiAgICAgICAgICAgIHRoaXMucm9vbVRvVXNlciA9IG51bGw7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogc29tZSBjbGllbnQgYnVnIHNvbWV3aGVyZSBpcyBjYXVzaW5nIHNvbWUgRE1zIHRvIGJlIG1hcmtlZFxuICAgICAqIHdpdGggb3Vyc2VsZiwgbm90IHRoZSBvdGhlciB1c2VyLiBGaXggaXQgYnkgZ3Vlc3NpbmcgdGhlIG90aGVyIHVzZXIgYW5kXG4gICAgICogbW9kaWZ5aW5nIHVzZXJUb1Jvb21zXG4gICAgICovXG4gICAgcHJpdmF0ZSBwYXRjaFVwU2VsZkRNcyh1c2VyVG9Sb29tczogUmVjb3JkPHN0cmluZywgc3RyaW5nW10+KTogYm9vbGVhbiB7XG4gICAgICAgIGNvbnN0IG15VXNlcklkID0gdGhpcy5tYXRyaXhDbGllbnQuZ2V0VXNlcklkKCkhO1xuICAgICAgICBjb25zdCBzZWxmUm9vbUlkcyA9IHVzZXJUb1Jvb21zW215VXNlcklkXTtcbiAgICAgICAgaWYgKHNlbGZSb29tSWRzKSB7XG4gICAgICAgICAgICAvLyBhbnkgc2VsZi1jaGF0cyB0aGF0IHNob3VsZCBub3QgYmUgc2VsZi1jaGF0cz9cbiAgICAgICAgICAgIGNvbnN0IGd1ZXNzZWRVc2VySWRzVGhhdENoYW5nZWQgPSBzZWxmUm9vbUlkc1xuICAgICAgICAgICAgICAgIC5tYXAoKHJvb21JZCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCByb29tID0gdGhpcy5tYXRyaXhDbGllbnQuZ2V0Um9vbShyb29tSWQpO1xuICAgICAgICAgICAgICAgICAgICBpZiAocm9vbSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgdXNlcklkID0gcm9vbS5ndWVzc0RNVXNlcklkKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAodXNlcklkICYmIHVzZXJJZCAhPT0gbXlVc2VySWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4geyB1c2VySWQsIHJvb21JZCB9O1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAuZmlsdGVyKChpZHMpID0+ICEhaWRzKSBhcyB7IHVzZXJJZDogc3RyaW5nOyByb29tSWQ6IHN0cmluZyB9W107IC8vZmlsdGVyIG91dFxuICAgICAgICAgICAgLy8gdGhlc2UgYXJlIGFjdHVhbGx5IGFsbCBsZWdpdCBzZWxmLWNoYXRzXG4gICAgICAgICAgICAvLyBiYWlsIG91dFxuICAgICAgICAgICAgaWYgKCFndWVzc2VkVXNlcklkc1RoYXRDaGFuZ2VkLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHVzZXJUb1Jvb21zW215VXNlcklkXSA9IHNlbGZSb29tSWRzLmZpbHRlcigocm9vbUlkKSA9PiB7XG4gICAgICAgICAgICAgICAgcmV0dXJuICFndWVzc2VkVXNlcklkc1RoYXRDaGFuZ2VkLnNvbWUoKGlkcykgPT4gaWRzLnJvb21JZCA9PT0gcm9vbUlkKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgZ3Vlc3NlZFVzZXJJZHNUaGF0Q2hhbmdlZC5mb3JFYWNoKCh7IHVzZXJJZCwgcm9vbUlkIH0pID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCByb29tSWRzID0gdXNlclRvUm9vbXNbdXNlcklkXTtcbiAgICAgICAgICAgICAgICBpZiAoIXJvb21JZHMpIHtcbiAgICAgICAgICAgICAgICAgICAgdXNlclRvUm9vbXNbdXNlcklkXSA9IFtyb29tSWRdO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHJvb21JZHMucHVzaChyb29tSWQpO1xuICAgICAgICAgICAgICAgICAgICB1c2VyVG9Sb29tc1t1c2VySWRdID0gdW5pcShyb29tSWRzKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0RE1Sb29tc0ZvclVzZXJJZCh1c2VySWQ6IHN0cmluZyk6IHN0cmluZ1tdIHtcbiAgICAgICAgLy8gSGVyZSwgd2UgcmV0dXJuIHRoZSBlbXB0eSBsaXN0IGlmIHRoZXJlIGFyZSBubyByb29tcyxcbiAgICAgICAgLy8gc2luY2UgdGhlIG51bWJlciBvZiBjb252ZXJzYXRpb25zIHlvdSBoYXZlIHdpdGggdGhpcyB1c2VyIGlzIHplcm8uXG4gICAgICAgIHJldHVybiB0aGlzLmdldFVzZXJUb1Jvb21zKClbdXNlcklkXSB8fCBbXTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXRzIHRoZSBETSByb29tIHdoaWNoIHRoZSBnaXZlbiBJRHMgc2hhcmUsIGlmIGFueS5cbiAgICAgKiBAcGFyYW0ge3N0cmluZ1tdfSBpZHMgVGhlIGlkZW50aWZpZXJzICh1c2VyIElEcyBhbmQgZW1haWwgYWRkcmVzc2VzKSB0byBsb29rIGZvci5cbiAgICAgKiBAcmV0dXJucyB7Um9vbX0gVGhlIERNIHJvb20gd2hpY2ggYWxsIElEcyBnaXZlbiBzaGFyZSwgb3IgZmFsc3kgaWYgbm8gY29tbW9uIHJvb20uXG4gICAgICovXG4gICAgcHVibGljIGdldERNUm9vbUZvcklkZW50aWZpZXJzKGlkczogc3RyaW5nW10pOiBSb29tIHwgbnVsbCB7XG4gICAgICAgIC8vIFRPRE86IFtDYW5vbmljYWwgRE1zXSBIYW5kbGUgbG9va3VwcyBmb3IgZW1haWwgYWRkcmVzc2VzLlxuICAgICAgICAvLyBGb3Igbm93IHdlJ2xsIHByZXRlbmQgd2Ugb25seSBnZXQgdXNlciBJRHMgYW5kIGVuZCB1cCByZXR1cm5pbmcgbm90aGluZyBmb3IgZW1haWwgYWRkcmVzc2VzXG5cbiAgICAgICAgbGV0IGNvbW1vblJvb21zID0gdGhpcy5nZXRETVJvb21zRm9yVXNlcklkKGlkc1swXSk7XG4gICAgICAgIGZvciAobGV0IGkgPSAxOyBpIDwgaWRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBjb25zdCB1c2VyUm9vbXMgPSB0aGlzLmdldERNUm9vbXNGb3JVc2VySWQoaWRzW2ldKTtcbiAgICAgICAgICAgIGNvbW1vblJvb21zID0gY29tbW9uUm9vbXMuZmlsdGVyKChyKSA9PiB1c2VyUm9vbXMuaW5jbHVkZXMocikpO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3Qgam9pbmVkUm9vbXMgPSBjb21tb25Sb29tc1xuICAgICAgICAgICAgLm1hcCgocikgPT4gdGhpcy5tYXRyaXhDbGllbnQuZ2V0Um9vbShyKSlcbiAgICAgICAgICAgIC5maWx0ZXIoKHIpID0+IHIgJiYgci5nZXRNeU1lbWJlcnNoaXAoKSA9PT0gS25vd25NZW1iZXJzaGlwLkpvaW4pO1xuXG4gICAgICAgIHJldHVybiBqb2luZWRSb29tc1swXTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0VXNlcklkRm9yUm9vbUlkKHJvb21JZDogc3RyaW5nKTogT3B0aW9uYWw8c3RyaW5nPiB7XG4gICAgICAgIGlmICh0aGlzLnJvb21Ub1VzZXIgPT0gbnVsbCkge1xuICAgICAgICAgICAgLy8gd2UgbGF6aWx5IHBvcHVsYXRlIHJvb21Ub1VzZXIgc28geW91IGNhbiB1c2VcbiAgICAgICAgICAgIC8vIHRoaXMgY2xhc3MganVzdCB0byBjYWxsIGdldERNUm9vbXNGb3JVc2VySWRcbiAgICAgICAgICAgIC8vIHdoaWNoIGRvZXNuJ3QgZG8gdmVyeSBtdWNoLCBidXQgaXMgYSBmYWlybHlcbiAgICAgICAgICAgIC8vIGNvbnZlbmllbnQgd3JhcHBlciBhbmQgdGhlcmUncyBubyBwb2ludFxuICAgICAgICAgICAgLy8gaXRlcmF0aW5nIHRocm91Z2ggdGhlIG1hcCBpZiBnZXRVc2VySWRGb3JSb29tSWQoKVxuICAgICAgICAgICAgLy8gaXMgbmV2ZXIgY2FsbGVkLlxuICAgICAgICAgICAgdGhpcy5wb3B1bGF0ZVJvb21Ub1VzZXIoKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBIZXJlLCB3ZSByZXR1cm4gdW5kZWZpbmVkIGlmIHRoZSByb29tIGlzIG5vdCBpbiB0aGUgbWFwOlxuICAgICAgICAvLyB0aGUgcm9vbSBJRCB5b3UgZ2F2ZSBpcyBub3QgYSBETSByb29tIGZvciBhbnkgdXNlci5cbiAgICAgICAgaWYgKHRoaXMucm9vbVRvVXNlciFbcm9vbUlkXSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAvLyBubyBlbnRyeT8gaWYgdGhlIHJvb20gaXMgYW4gaW52aXRlLCBsb29rIGZvciB0aGUgaXNfZGlyZWN0IGhpbnQuXG4gICAgICAgICAgICBjb25zdCByb29tID0gdGhpcy5tYXRyaXhDbGllbnQuZ2V0Um9vbShyb29tSWQpO1xuICAgICAgICAgICAgaWYgKHJvb20pIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gcm9vbS5nZXRETUludml0ZXIoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy5yb29tVG9Vc2VyIVtyb29tSWRdO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXRVbmlxdWVSb29tc1dpdGhJbmRpdmlkdWFscygpOiB7IFt1c2VySWQ6IHN0cmluZ106IFJvb20gfSB7XG4gICAgICAgIGlmICghdGhpcy5yb29tVG9Vc2VyKSByZXR1cm4ge307IC8vIE5vIHJvb21zIG1lYW5zIG5vIG1hcC5cbiAgICAgICAgLy8gbWFwIHJvb21Ub1VzZXIgdG8gdmFsaWQgcm9vbXMgd2l0aCB0d28gcGFydGljaXBhbnRzXG4gICAgICAgIHJldHVybiBPYmplY3Qua2V5cyh0aGlzLnJvb21Ub1VzZXIpLnJlZHVjZShcbiAgICAgICAgICAgIChhY2MsIHJvb21JZDogc3RyaW5nKSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3QgdXNlcklkID0gdGhpcy5nZXRVc2VySWRGb3JSb29tSWQocm9vbUlkKTtcbiAgICAgICAgICAgICAgICBjb25zdCByb29tID0gdGhpcy5tYXRyaXhDbGllbnQuZ2V0Um9vbShyb29tSWQpO1xuICAgICAgICAgICAgICAgIGNvbnN0IGhhc1R3b01lbWJlcnMgPSByb29tPy5nZXRJbnZpdGVkQW5kSm9pbmVkTWVtYmVyQ291bnQoKSA9PT0gMjtcbiAgICAgICAgICAgICAgICBpZiAodXNlcklkICYmIHJvb20gJiYgaGFzVHdvTWVtYmVycykge1xuICAgICAgICAgICAgICAgICAgICBhY2NbdXNlcklkXSA9IHJvb207XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybiBhY2M7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge30gYXMgUmVjb3JkPHN0cmluZywgUm9vbT4sXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQHJldHVybnMgYWxsIHJvb20gSWRzIGZyb20gbS5kaXJlY3RcbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0Um9vbUlkcygpOiBTZXQ8c3RyaW5nPiB7XG4gICAgICAgIHJldHVybiBPYmplY3QudmFsdWVzKHRoaXMubURpcmVjdEV2ZW50KS5yZWR1Y2UoKHByZXZSb29tSWRzOiBTZXQ8c3RyaW5nPiwgcm9vbUlkczogc3RyaW5nW10pOiBTZXQ8c3RyaW5nPiA9PiB7XG4gICAgICAgICAgICByb29tSWRzLmZvckVhY2goKHJvb21JZCkgPT4gcHJldlJvb21JZHMuYWRkKHJvb21JZCkpO1xuICAgICAgICAgICAgcmV0dXJuIHByZXZSb29tSWRzO1xuICAgICAgICB9LCBuZXcgU2V0PHN0cmluZz4oKSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBnZXRVc2VyVG9Sb29tcygpOiB7IFtrZXk6IHN0cmluZ106IHN0cmluZ1tdIH0ge1xuICAgICAgICBpZiAoIXRoaXMudXNlclRvUm9vbXMpIHtcbiAgICAgICAgICAgIGNvbnN0IHVzZXJUb1Jvb21zID0gdGhpcy5tRGlyZWN0RXZlbnQ7XG4gICAgICAgICAgICBjb25zdCBteVVzZXJJZCA9IHRoaXMubWF0cml4Q2xpZW50LmdldFVzZXJJZCgpITtcbiAgICAgICAgICAgIGNvbnN0IHNlbGZETXMgPSB1c2VyVG9Sb29tc1tteVVzZXJJZF07XG4gICAgICAgICAgICBpZiAoc2VsZkRNcz8ubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgbmVlZGVkUGF0Y2hpbmcgPSB0aGlzLnBhdGNoVXBTZWxmRE1zKHVzZXJUb1Jvb21zKTtcbiAgICAgICAgICAgICAgICAvLyB0byBhdm9pZCBtdWx0aXBsZSBkZXZpY2VzIGZpZ2h0aW5nIHRvIGNvcnJlY3RcbiAgICAgICAgICAgICAgICAvLyB0aGUgYWNjb3VudCBkYXRhLCBvbmx5IHRyeSB0byBzZW5kIHRoZSBjb3JyZWN0ZWRcbiAgICAgICAgICAgICAgICAvLyB2ZXJzaW9uIG9uY2UuXG4gICAgICAgICAgICAgICAgbG9nZ2VyLndhcm4oYEludmFsaWQgbS5kaXJlY3QgYWNjb3VudCBkYXRhIGRldGVjdGVkIChzZWxmLWNoYXRzIHRoYXQgc2hvdWxkbid0IGJlKSwgcGF0Y2hpbmcgaXQgdXAuYCk7XG4gICAgICAgICAgICAgICAgaWYgKG5lZWRlZFBhdGNoaW5nICYmICF0aGlzLmhhc1NlbnRPdXRQYXRjaERpcmVjdEFjY291bnREYXRhUGF0Y2gpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5oYXNTZW50T3V0UGF0Y2hEaXJlY3RBY2NvdW50RGF0YVBhdGNoID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5tYXRyaXhDbGllbnQuc2V0QWNjb3VudERhdGEoRXZlbnRUeXBlLkRpcmVjdCwgdXNlclRvUm9vbXMpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMudXNlclRvUm9vbXMgPSB1c2VyVG9Sb29tcztcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy51c2VyVG9Sb29tcztcbiAgICB9XG5cbiAgICBwcml2YXRlIHBvcHVsYXRlUm9vbVRvVXNlcigpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5yb29tVG9Vc2VyID0ge307XG4gICAgICAgIGZvciAoY29uc3QgdXNlciBvZiBPYmplY3Qua2V5cyh0aGlzLmdldFVzZXJUb1Jvb21zKCkpKSB7XG4gICAgICAgICAgICBmb3IgKGNvbnN0IHJvb21JZCBvZiB0aGlzLnVzZXJUb1Jvb21zIVt1c2VyXSkge1xuICAgICAgICAgICAgICAgIHRoaXMucm9vbVRvVXNlcltyb29tSWRdID0gdXNlcjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7QUFRQSxJQUFBQSxPQUFBLEdBQUFDLE9BQUE7QUFDQSxJQUFBQyxPQUFBLEdBQUFELE9BQUE7QUFDQSxJQUFBRSxNQUFBLEdBQUFGLE9BQUE7QUFDQSxJQUFBRyxPQUFBLEdBQUFILE9BQUE7QUFHQSxJQUFBSSxtQkFBQSxHQUFBSixPQUFBO0FBZEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBVUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDZSxNQUFNSyxTQUFTLENBQUM7RUFTcEJDLFdBQVdBLENBQWtCQyxZQUEwQixFQUFFO0lBTmhFO0lBQUEsSUFBQUMsZ0JBQUEsQ0FBQUMsT0FBQSxzQkFDdUQsSUFBSTtJQUFBLElBQUFELGdCQUFBLENBQUFDLE9BQUEsdUJBQ0QsSUFBSTtJQUFBLElBQUFELGdCQUFBLENBQUFDLE9BQUE7SUFBQSxJQUFBRCxnQkFBQSxDQUFBQyxPQUFBO0lBQUEsSUFBQUQsZ0JBQUEsQ0FBQUMsT0FBQSx5QkFpRXJDQyxFQUFlLElB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