UNPKG

matrix-react-sdk

Version:
245 lines (235 loc) 31.5 kB
"use strict"; 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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