matrix-react-sdk
Version:
SDK for matrix.org using React
173 lines (162 loc) • 22.3 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.UserProfilesStore = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _logger = require("matrix-js-sdk/src/logger");
var _matrix = require("matrix-js-sdk/src/matrix");
var _LruCache = require("../utils/LruCache");
/*
Copyright 2024 New Vector Ltd.
Copyright 2023 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.
*/
const cacheSize = 500;
/**
* This store provides cached access to user profiles.
* Listens for membership events and invalidates the cache for a profile on update with different profile values.
*/
class UserProfilesStore {
constructor(client) {
(0, _defineProperty2.default)(this, "profiles", new _LruCache.LruCache(cacheSize));
(0, _defineProperty2.default)(this, "profileLookupErrors", new _LruCache.LruCache(cacheSize));
(0, _defineProperty2.default)(this, "knownProfiles", new _LruCache.LruCache(cacheSize));
/**
* Simple cache invalidation if a room membership event is received and
* at least one profile value differs from the cached one.
*/
(0, _defineProperty2.default)(this, "onRoomMembershipEvent", (event, member) => {
const profile = this.profiles.get(member.userId);
if (profile && (profile.displayname !== member.rawDisplayName || profile.avatar_url !== member.getMxcAvatarUrl())) {
this.profiles.delete(member.userId);
}
const knownProfile = this.knownProfiles.get(member.userId);
if (knownProfile && (knownProfile.displayname !== member.rawDisplayName || knownProfile.avatar_url !== member.getMxcAvatarUrl())) {
this.knownProfiles.delete(member.userId);
}
});
this.client = client;
client.on(_matrix.RoomMemberEvent.Membership, this.onRoomMembershipEvent);
}
/**
* Synchronously get a profile from the store cache.
*
* @param userId - User Id of the profile to fetch
* @returns The profile, if cached by the store.
* Null if the profile does not exist.
* Undefined if the profile is not cached by the store.
* In this case a profile can be fetched from the API via {@link fetchProfile}.
*/
getProfile(userId) {
return this.profiles.get(userId);
}
/**
* Async shortcut function that returns the profile from cache or
* or fetches it on cache miss.
*
* @param userId - User Id of the profile to get or fetch
* @returns The profile, if cached by the store or fetched from the API.
* Null if the profile does not exist or an error occurred during fetch.
*/
async getOrFetchProfile(userId, options) {
const cachedProfile = this.profiles.get(userId);
if (cachedProfile) return cachedProfile;
return this.fetchProfile(userId, options);
}
/**
* Get a profile lookup error.
*
* @param userId - User Id for which to get the lookup error
* @returns The lookup error or undefined if there was no error or the profile was not fetched.
*/
getProfileLookupError(userId) {
return this.profileLookupErrors.get(userId);
}
/**
* Synchronously get a profile from known users from the store cache.
* Known user means that at least one shared room with the user exists.
*
* @param userId - User Id of the profile to fetch
* @returns The profile, if cached by the store.
* Null if the profile does not exist.
* Undefined if the profile is not cached by the store.
* In this case a profile can be fetched from the API via {@link fetchOnlyKnownProfile}.
*/
getOnlyKnownProfile(userId) {
return this.knownProfiles.get(userId);
}
/**
* Asynchronousely fetches a profile from the API.
* Stores the result in the cache, so that next time {@link getProfile} returns this value.
*
* @param userId - User Id for which the profile should be fetched for
* @returns The profile, if found.
* Null if the profile does not exist or there was an error fetching it.
*/
async fetchProfile(userId, options) {
const profile = await this.fetchProfileFromApi(userId, options);
this.profiles.set(userId, profile);
return profile;
}
/**
* Asynchronousely fetches a profile from a known user from the API.
* Known user means that at least one shared room with the user exists.
* Stores the result in the cache, so that next time {@link getOnlyKnownProfile} returns this value.
*
* @param userId - User Id for which the profile should be fetched for
* @returns The profile, if found.
* Undefined if the user is unknown.
* Null if the profile does not exist or there was an error fetching it.
*/
async fetchOnlyKnownProfile(userId) {
// Do not look up unknown users. The test for existence in knownProfiles is a performance optimisation.
// If the user Id exists in knownProfiles we know them.
if (!this.knownProfiles.has(userId) && !this.isUserIdKnown(userId)) return undefined;
const profile = await this.fetchProfileFromApi(userId);
this.knownProfiles.set(userId, profile);
return profile;
}
flush() {
this.profiles = new _LruCache.LruCache(cacheSize);
this.profileLookupErrors = new _LruCache.LruCache(cacheSize);
this.knownProfiles = new _LruCache.LruCache(cacheSize);
}
/**
* Looks up a user profile via API.
*
* @param userId - User Id for which the profile should be fetched for
* @returns The profile information or null on errors
*/
async fetchProfileFromApi(userId, options) {
// invalidate cached profile errors
this.profileLookupErrors.delete(userId);
try {
return (await this.client.getProfileInfo(userId)) ?? null;
} catch (e) {
_logger.logger.warn(`Error retrieving profile for userId ${userId}`, e);
if (e instanceof _matrix.MatrixError) {
this.profileLookupErrors.set(userId, e);
}
if (options?.shouldThrow) {
throw e;
}
}
return null;
}
/**
* Whether at least one shared room with the userId exists.
*
* @param userId
* @returns true: at least one room shared with user identified by its Id, else false.
*/
isUserIdKnown(userId) {
return this.client.getRooms().some(room => {
return !!room.getMember(userId);
});
}
}
exports.UserProfilesStore = UserProfilesStore;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbG9nZ2VyIiwicmVxdWlyZSIsIl9tYXRyaXgiLCJfTHJ1Q2FjaGUiLCJjYWNoZVNpemUiLCJVc2VyUHJvZmlsZXNTdG9yZSIsImNvbnN0cnVjdG9yIiwiY2xpZW50IiwiX2RlZmluZVByb3BlcnR5MiIsImRlZmF1bHQiLCJMcnVDYWNoZSIsImV2ZW50IiwibWVtYmVyIiwicHJvZmlsZSIsInByb2ZpbGVzIiwiZ2V0IiwidXNlcklkIiwiZGlzcGxheW5hbWUiLCJyYXdEaXNwbGF5TmFtZSIsImF2YXRhcl91cmwiLCJnZXRNeGNBdmF0YXJVcmwiLCJkZWxldGUiLCJrbm93blByb2ZpbGUiLCJrbm93blByb2ZpbGVzIiwib24iLCJSb29tTWVtYmVyRXZlbnQiLCJNZW1iZXJzaGlwIiwib25Sb29tTWVtYmVyc2hpcEV2ZW50IiwiZ2V0UHJvZmlsZSIsImdldE9yRmV0Y2hQcm9maWxlIiwib3B0aW9ucyIsImNhY2hlZFByb2ZpbGUiLCJmZXRjaFByb2ZpbGUiLCJnZXRQcm9maWxlTG9va3VwRXJyb3IiLCJwcm9maWxlTG9va3VwRXJyb3JzIiwiZ2V0T25seUtub3duUHJvZmlsZSIsImZldGNoUHJvZmlsZUZyb21BcGkiLCJzZXQiLCJmZXRjaE9ubHlLbm93blByb2ZpbGUiLCJoYXMiLCJpc1VzZXJJZEtub3duIiwidW5kZWZpbmVkIiwiZmx1c2giLCJnZXRQcm9maWxlSW5mbyIsImUiLCJsb2dnZXIiLCJ3YXJuIiwiTWF0cml4RXJyb3IiLCJzaG91bGRUaHJvdyIsImdldFJvb21zIiwic29tZSIsInJvb20iLCJnZXRNZW1iZXIiLCJleHBvcnRzIl0sInNvdXJjZXMiOlsiLi4vLi4vc3JjL3N0b3Jlcy9Vc2VyUHJvZmlsZXNTdG9yZS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuQ29weXJpZ2h0IDIwMjQgTmV3IFZlY3RvciBMdGQuXG5Db3B5cmlnaHQgMjAyMyBUaGUgTWF0cml4Lm9yZyBGb3VuZGF0aW9uIEMuSS5DLlxuXG5TUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQUdQTC0zLjAtb25seSBPUiBHUEwtMy4wLW9ubHlcblBsZWFzZSBzZWUgTElDRU5TRSBmaWxlcyBpbiB0aGUgcmVwb3NpdG9yeSByb290IGZvciBmdWxsIGRldGFpbHMuXG4qL1xuXG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvbG9nZ2VyXCI7XG5pbXBvcnQge1xuICAgIElNYXRyaXhQcm9maWxlLFxuICAgIE1hdHJpeENsaWVudCxcbiAgICBNYXRyaXhFcnJvcixcbiAgICBNYXRyaXhFdmVudCxcbiAgICBSb29tTWVtYmVyLFxuICAgIFJvb21NZW1iZXJFdmVudCxcbn0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL21hdHJpeFwiO1xuXG5pbXBvcnQgeyBMcnVDYWNoZSB9IGZyb20gXCIuLi91dGlscy9McnVDYWNoZVwiO1xuXG5jb25zdCBjYWNoZVNpemUgPSA1MDA7XG5cbnR5cGUgU3RvcmVQcm9maWxlVmFsdWUgPSBJTWF0cml4UHJvZmlsZSB8IHVuZGVmaW5lZCB8IG51bGw7XG5cbmludGVyZmFjZSBHZXRPcHRpb25zIHtcbiAgICAvKiogV2hldGhlciBjYWxsaW5nIHRoZSBmdW5jdGlvbiBzaG91dWxkIHJhaXNlIGFuIEVycm9yLiAqL1xuICAgIHNob3VsZFRocm93OiBib29sZWFuO1xufVxuXG4vKipcbiAqIFRoaXMgc3RvcmUgcHJvdmlkZXMgY2FjaGVkIGFjY2VzcyB0byB1c2VyIHByb2ZpbGVzLlxuICogTGlzdGVucyBmb3IgbWVtYmVyc2hpcCBldmVudHMgYW5kIGludmFsaWRhdGVzIHRoZSBjYWNoZSBmb3IgYSBwcm9maWxlIG9uIHVwZGF0ZSB3aXRoIGRpZmZlcmVudCBwcm9maWxlIHZhbHVlcy5cbiAqL1xuZXhwb3J0IGNsYXNzIFVzZXJQcm9maWxlc1N0b3JlIHtcbiAgICBwcml2YXRlIHByb2ZpbGVzID0gbmV3IExydUNhY2hlPHN0cmluZywgSU1hdHJpeFByb2ZpbGUgfCBudWxsPihjYWNoZVNpemUpO1xuICAgIHByaXZhdGUgcHJvZmlsZUxvb2t1cEVycm9ycyA9IG5ldyBMcnVDYWNoZTxzdHJpbmcsIE1hdHJpeEVycm9yPihjYWNoZVNpemUpO1xuICAgIHByaXZhdGUga25vd25Qcm9maWxlcyA9IG5ldyBMcnVDYWNoZTxzdHJpbmcsIElNYXRyaXhQcm9maWxlIHwgbnVsbD4oY2FjaGVTaXplKTtcblxuICAgIHB1YmxpYyBjb25zdHJ1Y3Rvcihwcml2YXRlIGNsaWVudDogTWF0cml4Q2xpZW50KSB7XG4gICAgICAgIGNsaWVudC5vbihSb29tTWVtYmVyRXZlbnQuTWVtYmVyc2hpcCwgdGhpcy5vblJvb21NZW1iZXJzaGlwRXZlbnQpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFN5bmNocm9ub3VzbHkgZ2V0IGEgcHJvZmlsZSBmcm9tIHRoZSBzdG9yZSBjYWNoZS5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB1c2VySWQgLSBVc2VyIElkIG9mIHRoZSBwcm9maWxlIHRvIGZldGNoXG4gICAgICogQHJldHVybnMgVGhlIHByb2ZpbGUsIGlmIGNhY2hlZCBieSB0aGUgc3RvcmUuXG4gICAgICogICAgICAgICAgTnVsbCBpZiB0aGUgcHJvZmlsZSBkb2VzIG5vdCBleGlzdC5cbiAgICAgKiAgICAgICAgICBVbmRlZmluZWQgaWYgdGhlIHByb2ZpbGUgaXMgbm90IGNhY2hlZCBieSB0aGUgc3RvcmUuXG4gICAgICogICAgICAgICAgSW4gdGhpcyBjYXNlIGEgcHJvZmlsZSBjYW4gYmUgZmV0Y2hlZCBmcm9tIHRoZSBBUEkgdmlhIHtAbGluayBmZXRjaFByb2ZpbGV9LlxuICAgICAqL1xuICAgIHB1YmxpYyBnZXRQcm9maWxlKHVzZXJJZDogc3RyaW5nKTogU3RvcmVQcm9maWxlVmFsdWUge1xuICAgICAgICByZXR1cm4gdGhpcy5wcm9maWxlcy5nZXQodXNlcklkKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBBc3luYyBzaG9ydGN1dCBmdW5jdGlvbiB0aGF0IHJldHVybnMgdGhlIHByb2ZpbGUgZnJvbSBjYWNoZSBvclxuICAgICAqIG9yIGZldGNoZXMgaXQgb24gY2FjaGUgbWlzcy5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB1c2VySWQgLSBVc2VyIElkIG9mIHRoZSBwcm9maWxlIHRvIGdldCBvciBmZXRjaFxuICAgICAqIEByZXR1cm5zIFRoZSBwcm9maWxlLCBpZiBjYWNoZWQgYnkgdGhlIHN0b3JlIG9yIGZldGNoZWQgZnJvbSB0aGUgQVBJLlxuICAgICAqICAgICAgICAgIE51bGwgaWYgdGhlIHByb2ZpbGUgZG9lcyBub3QgZXhpc3Qgb3IgYW4gZXJyb3Igb2NjdXJyZWQgZHVyaW5nIGZldGNoLlxuICAgICAqL1xuICAgIHB1YmxpYyBhc3luYyBnZXRPckZldGNoUHJvZmlsZSh1c2VySWQ6IHN0cmluZywgb3B0aW9ucz86IEdldE9wdGlvbnMpOiBQcm9taXNlPElNYXRyaXhQcm9maWxlIHwgbnVsbD4ge1xuICAgICAgICBjb25zdCBjYWNoZWRQcm9maWxlID0gdGhpcy5wcm9maWxlcy5nZXQodXNlcklkKTtcblxuICAgICAgICBpZiAoY2FjaGVkUHJvZmlsZSkgcmV0dXJuIGNhY2hlZFByb2ZpbGU7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMuZmV0Y2hQcm9maWxlKHVzZXJJZCwgb3B0aW9ucyk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IGEgcHJvZmlsZSBsb29rdXAgZXJyb3IuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gdXNlcklkIC0gVXNlciBJZCBmb3Igd2hpY2ggdG8gZ2V0IHRoZSBsb29rdXAgZXJyb3JcbiAgICAgKiBAcmV0dXJucyBUaGUgbG9va3VwIGVycm9yIG9yIHVuZGVmaW5lZCBpZiB0aGVyZSB3YXMgbm8gZXJyb3Igb3IgdGhlIHByb2ZpbGUgd2FzIG5vdCBmZXRjaGVkLlxuICAgICAqL1xuICAgIHB1YmxpYyBnZXRQcm9maWxlTG9va3VwRXJyb3IodXNlcklkOiBzdHJpbmcpOiBNYXRyaXhFcnJvciB8IHVuZGVmaW5lZCB7XG4gICAgICAgIHJldHVybiB0aGlzLnByb2ZpbGVMb29rdXBFcnJvcnMuZ2V0KHVzZXJJZCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU3luY2hyb25vdXNseSBnZXQgYSBwcm9maWxlIGZyb20ga25vd24gdXNlcnMgZnJvbSB0aGUgc3RvcmUgY2FjaGUuXG4gICAgICogS25vd24gdXNlciBtZWFucyB0aGF0IGF0IGxlYXN0IG9uZSBzaGFyZWQgcm9vbSB3aXRoIHRoZSB1c2VyIGV4aXN0cy5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB1c2VySWQgLSBVc2VyIElkIG9mIHRoZSBwcm9maWxlIHRvIGZldGNoXG4gICAgICogQHJldHVybnMgVGhlIHByb2ZpbGUsIGlmIGNhY2hlZCBieSB0aGUgc3RvcmUuXG4gICAgICogICAgICAgICAgTnVsbCBpZiB0aGUgcHJvZmlsZSBkb2VzIG5vdCBleGlzdC5cbiAgICAgKiAgICAgICAgICBVbmRlZmluZWQgaWYgdGhlIHByb2ZpbGUgaXMgbm90IGNhY2hlZCBieSB0aGUgc3RvcmUuXG4gICAgICogICAgICAgICAgSW4gdGhpcyBjYXNlIGEgcHJvZmlsZSBjYW4gYmUgZmV0Y2hlZCBmcm9tIHRoZSBBUEkgdmlhIHtAbGluayBmZXRjaE9ubHlLbm93blByb2ZpbGV9LlxuICAgICAqL1xuICAgIHB1YmxpYyBnZXRPbmx5S25vd25Qcm9maWxlKHVzZXJJZDogc3RyaW5nKTogU3RvcmVQcm9maWxlVmFsdWUge1xuICAgICAgICByZXR1cm4gdGhpcy5rbm93blByb2ZpbGVzLmdldCh1c2VySWQpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEFzeW5jaHJvbm91c2VseSBmZXRjaGVzIGEgcHJvZmlsZSBmcm9tIHRoZSBBUEkuXG4gICAgICogU3RvcmVzIHRoZSByZXN1bHQgaW4gdGhlIGNhY2hlLCBzbyB0aGF0IG5leHQgdGltZSB7QGxpbmsgZ2V0UHJvZmlsZX0gcmV0dXJucyB0aGlzIHZhbHVlLlxuICAgICAqXG4gICAgICogQHBhcmFtIHVzZXJJZCAtIFVzZXIgSWQgZm9yIHdoaWNoIHRoZSBwcm9maWxlIHNob3VsZCBiZSBmZXRjaGVkIGZvclxuICAgICAqIEByZXR1cm5zIFRoZSBwcm9maWxlLCBpZiBmb3VuZC5cbiAgICAgKiAgICAgICAgICBOdWxsIGlmIHRoZSBwcm9maWxlIGRvZXMgbm90IGV4aXN0IG9yIHRoZXJlIHdhcyBhbiBlcnJvciBmZXRjaGluZyBpdC5cbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgZmV0Y2hQcm9maWxlKHVzZXJJZDogc3RyaW5nLCBvcHRpb25zPzogR2V0T3B0aW9ucyk6IFByb21pc2U8SU1hdHJpeFByb2ZpbGUgfCBudWxsPiB7XG4gICAgICAgIGNvbnN0IHByb2ZpbGUgPSBhd2FpdCB0aGlzLmZldGNoUHJvZmlsZUZyb21BcGkodXNlcklkLCBvcHRpb25zKTtcbiAgICAgICAgdGhpcy5wcm9maWxlcy5zZXQodXNlcklkLCBwcm9maWxlKTtcbiAgICAgICAgcmV0dXJuIHByb2ZpbGU7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQXN5bmNocm9ub3VzZWx5IGZldGNoZXMgYSBwcm9maWxlIGZyb20gYSBrbm93biB1c2VyIGZyb20gdGhlIEFQSS5cbiAgICAgKiBLbm93biB1c2VyIG1lYW5zIHRoYXQgYXQgbGVhc3Qgb25lIHNoYXJlZCByb29tIHdpdGggdGhlIHVzZXIgZXhpc3RzLlxuICAgICAqIFN0b3JlcyB0aGUgcmVzdWx0IGluIHRoZSBjYWNoZSwgc28gdGhhdCBuZXh0IHRpbWUge0BsaW5rIGdldE9ubHlLbm93blByb2ZpbGV9IHJldHVybnMgdGhpcyB2YWx1ZS5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB1c2VySWQgLSBVc2VyIElkIGZvciB3aGljaCB0aGUgcHJvZmlsZSBzaG91bGQgYmUgZmV0Y2hlZCBmb3JcbiAgICAgKiBAcmV0dXJucyBUaGUgcHJvZmlsZSwgaWYgZm91bmQuXG4gICAgICogICAgICAgICAgVW5kZWZpbmVkIGlmIHRoZSB1c2VyIGlzIHVua25vd24uXG4gICAgICogICAgICAgICAgTnVsbCBpZiB0aGUgcHJvZmlsZSBkb2VzIG5vdCBleGlzdCBvciB0aGVyZSB3YXMgYW4gZXJyb3IgZmV0Y2hpbmcgaXQuXG4gICAgICovXG4gICAgcHVibGljIGFzeW5jIGZldGNoT25seUtub3duUHJvZmlsZSh1c2VySWQ6IHN0cmluZyk6IFByb21pc2U8U3RvcmVQcm9maWxlVmFsdWU+IHtcbiAgICAgICAgLy8gRG8gbm90IGxvb2sgdXAgdW5rbm93biB1c2Vycy4gVGhlIHRlc3QgZm9yIGV4aXN0ZW5jZSBpbiBrbm93blByb2ZpbGVzIGlzIGEgcGVyZm9ybWFuY2Ugb3B0aW1pc2F0aW9uLlxuICAgICAgICAvLyBJZiB0aGUgdXNlciBJZCBleGlzdHMgaW4ga25vd25Qcm9maWxlcyB3ZSBrbm93IHRoZW0uXG4gICAgICAgIGlmICghdGhpcy5rbm93blByb2ZpbGVzLmhhcyh1c2VySWQpICYmICF0aGlzLmlzVXNlcklkS25vd24odXNlcklkKSkgcmV0dXJuIHVuZGVmaW5lZDtcblxuICAgICAgICBjb25zdCBwcm9maWxlID0gYXdhaXQgdGhpcy5mZXRjaFByb2ZpbGVGcm9tQXBpKHVzZXJJZCk7XG4gICAgICAgIHRoaXMua25vd25Qcm9maWxlcy5zZXQodXNlcklkLCBwcm9maWxlKTtcbiAgICAgICAgcmV0dXJuIHByb2ZpbGU7XG4gICAgfVxuXG4gICAgcHVibGljIGZsdXNoKCk6IHZvaWQge1xuICAgICAgICB0aGlzLnByb2ZpbGVzID0gbmV3IExydUNhY2hlPHN0cmluZywgSU1hdHJpeFByb2ZpbGUgfCBudWxsPihjYWNoZVNpemUpO1xuICAgICAgICB0aGlzLnByb2ZpbGVMb29rdXBFcnJvcnMgPSBuZXcgTHJ1Q2FjaGU8c3RyaW5nLCBNYXRyaXhFcnJvcj4oY2FjaGVTaXplKTtcbiAgICAgICAgdGhpcy5rbm93blByb2ZpbGVzID0gbmV3IExydUNhY2hlPHN0cmluZywgSU1hdHJpeFByb2ZpbGUgfCBudWxsPihjYWNoZVNpemUpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIExvb2tzIHVwIGEgdXNlciBwcm9maWxlIHZpYSBBUEkuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gdXNlcklkIC0gVXNlciBJZCBmb3Igd2hpY2ggdGhlIHByb2ZpbGUgc2hvdWxkIGJlIGZldGNoZWQgZm9yXG4gICAgICogQHJldHVybnMgVGhlIHByb2ZpbGUgaW5mb3JtYXRpb24gb3IgbnVsbCBvbiBlcnJvcnNcbiAgICAgKi9cbiAgICBwcml2YXRlIGFzeW5jIGZldGNoUHJvZmlsZUZyb21BcGkodXNlcklkOiBzdHJpbmcsIG9wdGlvbnM/OiBHZXRPcHRpb25zKTogUHJvbWlzZTxJTWF0cml4UHJvZmlsZSB8IG51bGw+IHtcbiAgICAgICAgLy8gaW52YWxpZGF0ZSBjYWNoZWQgcHJvZmlsZSBlcnJvcnNcbiAgICAgICAgdGhpcy5wcm9maWxlTG9va3VwRXJyb3JzLmRlbGV0ZSh1c2VySWQpO1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICByZXR1cm4gKGF3YWl0IHRoaXMuY2xpZW50LmdldFByb2ZpbGVJbmZvKHVzZXJJZCkpID8/IG51bGw7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIGxvZ2dlci53YXJuKGBFcnJvciByZXRyaWV2aW5nIHByb2ZpbGUgZm9yIHVzZXJJZCAke3VzZXJJZH1gLCBlKTtcblxuICAgICAgICAgICAgaWYgKGUgaW5zdGFuY2VvZiBNYXRyaXhFcnJvcikge1xuICAgICAgICAgICAgICAgIHRoaXMucHJvZmlsZUxvb2t1cEVycm9ycy5zZXQodXNlcklkLCBlKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKG9wdGlvbnM/LnNob3VsZFRocm93KSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFdoZXRoZXIgYXQgbGVhc3Qgb25lIHNoYXJlZCByb29tIHdpdGggdGhlIHVzZXJJZCBleGlzdHMuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gdXNlcklkXG4gICAgICogQHJldHVybnMgdHJ1ZTogYXQgbGVhc3Qgb25lIHJvb20gc2hhcmVkIHdpdGggdXNlciBpZGVudGlmaWVkIGJ5IGl0cyBJZCwgZWxzZSBmYWxzZS5cbiAgICAgKi9cbiAgICBwcml2YXRlIGlzVXNlcklkS25vd24odXNlcklkOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuY2xpZW50LmdldFJvb21zKCkuc29tZSgocm9vbSkgPT4ge1xuICAgICAgICAgICAgcmV0dXJuICEhcm9vbS5nZXRNZW1iZXIodXNlcklkKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2ltcGxlIGNhY2hlIGludmFsaWRhdGlvbiBpZiBhIHJvb20gbWVtYmVyc2hpcCBldmVudCBpcyByZWNlaXZlZCBhbmRcbiAgICAgKiBhdCBsZWFzdCBvbmUgcHJvZmlsZSB2YWx1ZSBkaWZmZXJzIGZyb20gdGhlIGNhY2hlZCBvbmUuXG4gICAgICovXG4gICAgcHJpdmF0ZSBvblJvb21NZW1iZXJzaGlwRXZlbnQgPSAoZXZlbnQ6IE1hdHJpeEV2ZW50LCBtZW1iZXI6IFJvb21NZW1iZXIpOiB2b2lkID0+IHtcbiAgICAgICAgY29uc3QgcHJvZmlsZSA9IHRoaXMucHJvZmlsZXMuZ2V0KG1lbWJlci51c2VySWQpO1xuXG4gICAgICAgIGlmIChcbiAgICAgICAgICAgIHByb2ZpbGUgJiZcbiAgICAgICAgICAgIChwcm9maWxlLmRpc3BsYXluYW1lICE9PSBtZW1iZXIucmF3RGlzcGxheU5hbWUgfHwgcHJvZmlsZS5hdmF0YXJfdXJsICE9PSBtZW1iZXIuZ2V0TXhjQXZhdGFyVXJsKCkpXG4gICAgICAgICkge1xuICAgICAgICAgICAgdGhpcy5wcm9maWxlcy5kZWxldGUobWVtYmVyLnVzZXJJZCk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBrbm93blByb2ZpbGUgPSB0aGlzLmtub3duUHJvZmlsZXMuZ2V0KG1lbWJlci51c2VySWQpO1xuXG4gICAgICAgIGlmIChcbiAgICAgICAgICAgIGtub3duUHJvZmlsZSAmJlxuICAgICAgICAgICAgKGtub3duUHJvZmlsZS5kaXNwbGF5bmFtZSAhPT0gbWVtYmVyLnJhd0Rpc3BsYXlOYW1lIHx8IGtub3duUHJvZmlsZS5hdmF0YXJfdXJsICE9PSBtZW1iZXIuZ2V0TXhjQXZhdGFyVXJsKCkpXG4gICAgICAgICkge1xuICAgICAgICAgICAgdGhpcy5rbm93blByb2ZpbGVzLmRlbGV0ZShtZW1iZXIudXNlcklkKTtcbiAgICAgICAgfVxuICAgIH07XG59XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7O0FBUUEsSUFBQUEsT0FBQSxHQUFBQyxPQUFBO0FBQ0EsSUFBQUMsT0FBQSxHQUFBRCxPQUFBO0FBU0EsSUFBQUUsU0FBQSxHQUFBRixPQUFBO0FBbEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQWNBLE1BQU1HLFNBQVMsR0FBRyxHQUFHO0FBU3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ08sTUFBTUMsaUJBQWlCLENBQUM7RUFLcEJDLFdBQVdBLENBQVNDLE1BQW9CLEVBQUU7SUFBQSxJQUFBQyxnQkFBQSxDQUFBQyxPQUFBLG9CQUo5QixJQUFJQyxrQkFBUSxDQUFnQ04sU0FBUyxDQUFDO0lBQUEsSUFBQUksZ0JBQUEsQ0FBQUMsT0FBQSwrQkFDM0MsSUFBSUMsa0JBQVEsQ0FBc0JOLFNBQVMsQ0FBQztJQUFBLElBQUFJLGdCQUFBLENBQUFDLE9BQUEseUJBQ2xELElBQUlDLGtCQUFRLENBQWdDTixTQUFTLENBQUM7SUEwSTlFO0FBQ0o7QUFDQTtBQUNBO0lBSEksSUFBQUksZ0JBQUEsQ0FBQUMsT0FBQSxpQ0FJZ0MsQ0FBQ0UsS0FBa0IsRUFBRUMsTUFBa0IsS0FBVztNQUM5RSxNQUFNQyxPQUFPLEdBQUcsSUFBSSxDQUFDQyxRQUFRLENBQUNDLEdBQUcsQ0FBQ0gsTUFBTSxDQUFDSSxNQUFNLENBQUM7TUFFaEQsSUFDSUgsT0FBTyxLQUNOQSxPQUFPLENBQUNJLFdBQVcsS0FBS0wsTUFBTSxDQUFDTSxjQUFjLElBQUlMLE9BQU8sQ0FB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