matrix-react-sdk
Version:
SDK for matrix.org using React
184 lines (175 loc) • 28.2 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.BreadcrumbsStore = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _matrix = require("matrix-js-sdk/src/matrix");
var _types = require("matrix-js-sdk/src/types");
var _utils = require("matrix-js-sdk/src/utils");
var _SettingsStore = _interopRequireDefault(require("../settings/SettingsStore"));
var _AsyncStoreWithClient = require("./AsyncStoreWithClient");
var _dispatcher = _interopRequireDefault(require("../dispatcher/dispatcher"));
var _arrays = require("../utils/arrays");
var _SettingLevel = require("../settings/SettingLevel");
var _actions = require("../dispatcher/actions");
var _BreadcrumbsStore;
/*
Copyright 2024 New Vector Ltd.
Copyright 2020, 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.
*/
const MAX_ROOMS = 20; // arbitrary
const AUTOJOIN_WAIT_THRESHOLD_MS = 90000; // 90s, the time we wait for an autojoined room to show up
class BreadcrumbsStore extends _AsyncStoreWithClient.AsyncStoreWithClient {
constructor() {
super(_dispatcher.default);
(0, _defineProperty2.default)(this, "waitingRooms", []);
(0, _defineProperty2.default)(this, "onMyMembership", async room => {
// Only turn on breadcrumbs is the user hasn't explicitly turned it off again.
const settingValueRaw = _SettingsStore.default.getValue("breadcrumbs", null, /*excludeDefault=*/true);
if (this.meetsRoomRequirement && (0, _utils.isNullOrUndefined)(settingValueRaw)) {
await _SettingsStore.default.setValue("breadcrumbs", null, _SettingLevel.SettingLevel.ACCOUNT, true);
}
});
(0, _defineProperty2.default)(this, "onRoom", async room => {
const waitingRoom = this.waitingRooms.find(r => r.roomId === room.roomId);
if (!waitingRoom) return;
this.waitingRooms.splice(this.waitingRooms.indexOf(waitingRoom), 1);
if (Date.now() - waitingRoom.addedTs > AUTOJOIN_WAIT_THRESHOLD_MS) return; // Too long ago.
await this.appendRoom(room);
});
_SettingsStore.default.monitorSetting("breadcrumb_rooms", null);
_SettingsStore.default.monitorSetting("breadcrumbs", null);
}
static get instance() {
return BreadcrumbsStore.internalInstance;
}
get rooms() {
return this.state.rooms || [];
}
get visible() {
return !!this.state.enabled && this.meetsRoomRequirement;
}
/**
* Do we have enough rooms to justify showing the breadcrumbs?
* (Or is the labs feature enabled?)
*
* @returns true if there are at least 20 visible rooms.
*/
get meetsRoomRequirement() {
const msc3946ProcessDynamicPredecessor = _SettingsStore.default.getValue("feature_dynamic_room_predecessors");
return !!this.matrixClient && this.matrixClient.getVisibleRooms(msc3946ProcessDynamicPredecessor).length >= 20;
}
async onAction(payload) {
if (!this.matrixClient) return;
if (payload.action === _actions.Action.SettingUpdated) {
if (payload.settingName === "breadcrumb_rooms") {
await this.updateRooms();
} else if (payload.settingName === "breadcrumbs") {
await this.updateState({
enabled: _SettingsStore.default.getValue("breadcrumbs", null)
});
}
} else if (payload.action === _actions.Action.ViewRoom) {
if (payload.auto_join && payload.room_id && !this.matrixClient.getRoom(payload.room_id)) {
// Queue the room instead of pushing it immediately. We're probably just
// waiting for a room join to complete.
this.waitingRooms.push({
roomId: payload.room_id,
addedTs: Date.now()
});
} else {
// The tests might not result in a valid room object.
const room = this.matrixClient.getRoom(payload.room_id);
const membership = room?.getMyMembership();
if (room && membership === _types.KnownMembership.Join) await this.appendRoom(room);
}
} else if (payload.action === _actions.Action.JoinRoom) {
const room = this.matrixClient.getRoom(payload.roomId);
if (room) await this.appendRoom(room);
}
}
async onReady() {
await this.updateRooms();
await this.updateState({
enabled: _SettingsStore.default.getValue("breadcrumbs", null)
});
if (this.matrixClient) {
this.matrixClient.on(_matrix.RoomEvent.MyMembership, this.onMyMembership);
this.matrixClient.on(_matrix.ClientEvent.Room, this.onRoom);
}
}
async onNotReady() {
if (this.matrixClient) {
this.matrixClient.removeListener(_matrix.RoomEvent.MyMembership, this.onMyMembership);
this.matrixClient.removeListener(_matrix.ClientEvent.Room, this.onRoom);
}
}
async updateRooms() {
let roomIds = _SettingsStore.default.getValue("breadcrumb_rooms");
if (!roomIds || roomIds.length === 0) roomIds = [];
const rooms = (0, _arrays.filterBoolean)(roomIds.map(r => this.matrixClient?.getRoom(r)));
const currentRooms = this.state.rooms || [];
if (!(0, _arrays.arrayHasDiff)(rooms, currentRooms)) return; // no change (probably echo)
await this.updateState({
rooms
});
}
async appendRoom(room) {
let updated = false;
const rooms = (this.state.rooms || []).slice(); // cheap clone
const msc3946ProcessDynamicPredecessor = _SettingsStore.default.getValue("feature_dynamic_room_predecessors");
// If the room is upgraded, use that room instead. We'll also splice out
// any children of the room.
const history = this.matrixClient?.getRoomUpgradeHistory(room.roomId, false, msc3946ProcessDynamicPredecessor);
if (history && history.length > 1) {
room = history[history.length - 1]; // Last room is most recent in history
// Take out any room that isn't the most recent room
for (let i = 0; i < history.length - 1; i++) {
const idx = rooms.findIndex(r => r.roomId === history[i].roomId);
if (idx !== -1) {
rooms.splice(idx, 1);
updated = true;
}
}
}
// Remove the existing room, if it is present
const existingIdx = rooms.findIndex(r => r.roomId === room.roomId);
// If we're focusing on the first room no-op
if (existingIdx !== 0) {
if (existingIdx !== -1) {
rooms.splice(existingIdx, 1);
}
// Splice the room to the start of the list
rooms.splice(0, 0, room);
updated = true;
}
if (rooms.length > MAX_ROOMS) {
// This looks weird, but it's saying to start at the MAX_ROOMS point in the
// list and delete everything after it.
rooms.splice(MAX_ROOMS, rooms.length - MAX_ROOMS);
updated = true;
}
if (updated) {
// Update the breadcrumbs
await this.updateState({
rooms
});
const roomIds = rooms.map(r => r.roomId);
if (roomIds.length > 0) {
await _SettingsStore.default.setValue("breadcrumb_rooms", null, _SettingLevel.SettingLevel.ACCOUNT, roomIds);
}
}
}
}
exports.BreadcrumbsStore = BreadcrumbsStore;
_BreadcrumbsStore = BreadcrumbsStore;
(0, _defineProperty2.default)(BreadcrumbsStore, "internalInstance", (() => {
const instance = new _BreadcrumbsStore();
instance.start();
return instance;
})());
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbWF0cml4IiwicmVxdWlyZSIsIl90eXBlcyIsIl91dGlscyIsIl9TZXR0aW5nc1N0b3JlIiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsIl9Bc3luY1N0b3JlV2l0aENsaWVudCIsIl9kaXNwYXRjaGVyIiwiX2FycmF5cyIsIl9TZXR0aW5nTGV2ZWwiLCJfYWN0aW9ucyIsIl9CcmVhZGNydW1ic1N0b3JlIiwiTUFYX1JPT01TIiwiQVVUT0pPSU5fV0FJVF9USFJFU0hPTERfTVMiLCJCcmVhZGNydW1ic1N0b3JlIiwiQXN5bmNTdG9yZVdpdGhDbGllbnQiLCJjb25zdHJ1Y3RvciIsImRlZmF1bHREaXNwYXRjaGVyIiwiX2RlZmluZVByb3BlcnR5MiIsImRlZmF1bHQiLCJyb29tIiwic2V0dGluZ1ZhbHVlUmF3IiwiU2V0dGluZ3NTdG9yZSIsImdldFZhbHVlIiwibWVldHNSb29tUmVxdWlyZW1lbnQiLCJpc051bGxPclVuZGVmaW5lZCIsInNldFZhbHVlIiwiU2V0dGluZ0xldmVsIiwiQUNDT1VOVCIsIndhaXRpbmdSb29tIiwid2FpdGluZ1Jvb21zIiwiZmluZCIsInIiLCJyb29tSWQiLCJzcGxpY2UiLCJpbmRleE9mIiwiRGF0ZSIsIm5vdyIsImFkZGVkVHMiLCJhcHBlbmRSb29tIiwibW9uaXRvclNldHRpbmciLCJpbnN0YW5jZSIsImludGVybmFsSW5zdGFuY2UiLCJyb29tcyIsInN0YXRlIiwidmlzaWJsZSIsImVuYWJsZWQiLCJtc2MzOTQ2UHJvY2Vzc0R5bmFtaWNQcmVkZWNlc3NvciIsIm1hdHJpeENsaWVudCIsImdldFZpc2libGVSb29tcyIsImxlbmd0aCIsIm9uQWN0aW9uIiwicGF5bG9hZCIsImFjdGlvbiIsIkFjdGlvbiIsIlNldHRpbmdVcGRhdGVkIiwic2V0dGluZ05hbWUiLCJ1cGRhdGVSb29tcyIsInVwZGF0ZVN0YXRlIiwiVmlld1Jvb20iLCJhdXRvX2pvaW4iLCJyb29tX2lkIiwiZ2V0Um9vbSIsInB1c2giLCJtZW1iZXJzaGlwIiwiZ2V0TXlNZW1iZXJzaGlwIiwiS25vd25NZW1iZXJzaGlwIiwiSm9pbiIsIkpvaW5Sb29tIiwib25SZWFkeSIsIm9uIiwiUm9vbUV2ZW50IiwiTXlNZW1iZXJzaGlwIiwib25NeU1lbWJlcnNoaXAiLCJDbGllbnRFdmVudCIsIlJvb20iLCJvblJvb20iLCJvbk5vdFJlYWR5IiwicmVtb3ZlTGlzdGVuZXIiLCJyb29tSWRzIiwiZmlsdGVyQm9vbGVhbiIsIm1hcCIsImN1cnJlbnRSb29tcyIsImFycmF5SGFzRGlmZiIsInVwZGF0ZWQiLCJzbGljZSIsImhpc3RvcnkiLCJnZXRSb29tVXBncmFkZUhpc3RvcnkiLCJpIiwiaWR4IiwiZmluZEluZGV4IiwiZXhpc3RpbmdJZHgiLCJleHBvcnRzIiwic3RhcnQiXSwic291cmNlcyI6WyIuLi8uLi9zcmMvc3RvcmVzL0JyZWFkY3J1bWJzU3RvcmUudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLypcbkNvcHlyaWdodCAyMDI0IE5ldyBWZWN0b3IgTHRkLlxuQ29weXJpZ2h0IDIwMjAsIDIwMjEgVGhlIE1hdHJpeC5vcmcgRm91bmRhdGlvbiBDLkkuQy5cblxuU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFHUEwtMy4wLW9ubHkgT1IgR1BMLTMuMC1vbmx5XG5QbGVhc2Ugc2VlIExJQ0VOU0UgZmlsZXMgaW4gdGhlIHJlcG9zaXRvcnkgcm9vdCBmb3IgZnVsbCBkZXRhaWxzLlxuKi9cblxuaW1wb3J0IHsgUm9vbSwgUm9vbUV2ZW50LCBDbGllbnRFdmVudCB9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9tYXRyaXhcIjtcbmltcG9ydCB7IEtub3duTWVtYmVyc2hpcCB9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy90eXBlc1wiO1xuaW1wb3J0IHsgaXNOdWxsT3JVbmRlZmluZWQgfSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvdXRpbHNcIjtcblxuaW1wb3J0IFNldHRpbmdzU3RvcmUgZnJvbSBcIi4uL3NldHRpbmdzL1NldHRpbmdzU3RvcmVcIjtcbmltcG9ydCB7IEFzeW5jU3RvcmVXaXRoQ2xpZW50IH0gZnJvbSBcIi4vQXN5bmNTdG9yZVdpdGhDbGllbnRcIjtcbmltcG9ydCBkZWZhdWx0RGlzcGF0Y2hlciBmcm9tIFwiLi4vZGlzcGF0Y2hlci9kaXNwYXRjaGVyXCI7XG5pbXBvcnQgeyBhcnJheUhhc0RpZmYsIGZpbHRlckJvb2xlYW4gfSBmcm9tIFwiLi4vdXRpbHMvYXJyYXlzXCI7XG5pbXBvcnQgeyBTZXR0aW5nTGV2ZWwgfSBmcm9tIFwiLi4vc2V0dGluZ3MvU2V0dGluZ0xldmVsXCI7XG5pbXBvcnQgeyBBY3Rpb24gfSBmcm9tIFwiLi4vZGlzcGF0Y2hlci9hY3Rpb25zXCI7XG5pbXBvcnQgeyBTZXR0aW5nVXBkYXRlZFBheWxvYWQgfSBmcm9tIFwiLi4vZGlzcGF0Y2hlci9wYXlsb2Fkcy9TZXR0aW5nVXBkYXRlZFBheWxvYWRcIjtcbmltcG9ydCB7IFZpZXdSb29tUGF5bG9hZCB9IGZyb20gXCIuLi9kaXNwYXRjaGVyL3BheWxvYWRzL1ZpZXdSb29tUGF5bG9hZFwiO1xuaW1wb3J0IHsgSm9pblJvb21QYXlsb2FkIH0gZnJvbSBcIi4uL2Rpc3BhdGNoZXIvcGF5bG9hZHMvSm9pblJvb21QYXlsb2FkXCI7XG5cbmNvbnN0IE1BWF9ST09NUyA9IDIwOyAvLyBhcmJpdHJhcnlcbmNvbnN0IEFVVE9KT0lOX1dBSVRfVEhSRVNIT0xEX01TID0gOTAwMDA7IC8vIDkwcywgdGhlIHRpbWUgd2Ugd2FpdCBmb3IgYW4gYXV0b2pvaW5lZCByb29tIHRvIHNob3cgdXBcblxuaW50ZXJmYWNlIElTdGF0ZSB7XG4gICAgZW5hYmxlZD86IGJvb2xlYW47XG4gICAgcm9vbXM/OiBSb29tW107XG59XG5cbmV4cG9ydCBjbGFzcyBCcmVhZGNydW1ic1N0b3JlIGV4dGVuZHMgQXN5bmNTdG9yZVdpdGhDbGllbnQ8SVN0YXRlPiB7XG4gICAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgaW50ZXJuYWxJbnN0YW5jZSA9ICgoKSA9PiB7XG4gICAgICAgIGNvbnN0IGluc3RhbmNlID0gbmV3IEJyZWFkY3J1bWJzU3RvcmUoKTtcbiAgICAgICAgaW5zdGFuY2Uuc3RhcnQoKTtcbiAgICAgICAgcmV0dXJuIGluc3RhbmNlO1xuICAgIH0pKCk7XG5cbiAgICBwcml2YXRlIHdhaXRpbmdSb29tczogeyByb29tSWQ6IHN0cmluZzsgYWRkZWRUczogbnVtYmVyIH1bXSA9IFtdO1xuXG4gICAgcHJpdmF0ZSBjb25zdHJ1Y3RvcigpIHtcbiAgICAgICAgc3VwZXIoZGVmYXVsdERpc3BhdGNoZXIpO1xuXG4gICAgICAgIFNldHRpbmdzU3RvcmUubW9uaXRvclNldHRpbmcoXCJicmVhZGNydW1iX3Jvb21zXCIsIG51bGwpO1xuICAgICAgICBTZXR0aW5nc1N0b3JlLm1vbml0b3JTZXR0aW5nKFwiYnJlYWRjcnVtYnNcIiwgbnVsbCk7XG4gICAgfVxuXG4gICAgcHVibGljIHN0YXRpYyBnZXQgaW5zdGFuY2UoKTogQnJlYWRjcnVtYnNTdG9yZSB7XG4gICAgICAgIHJldHVybiBCcmVhZGNydW1ic1N0b3JlLmludGVybmFsSW5zdGFuY2U7XG4gICAgfVxuXG4gICAgcHVibGljIGdldCByb29tcygpOiBSb29tW10ge1xuICAgICAgICByZXR1cm4gdGhpcy5zdGF0ZS5yb29tcyB8fCBbXTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0IHZpc2libGUoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiAhIXRoaXMuc3RhdGUuZW5hYmxlZCAmJiB0aGlzLm1lZXRzUm9vbVJlcXVpcmVtZW50O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIERvIHdlIGhhdmUgZW5vdWdoIHJvb21zIHRvIGp1c3RpZnkgc2hvd2luZyB0aGUgYnJlYWRjcnVtYnM/XG4gICAgICogKE9yIGlzIHRoZSBsYWJzIGZlYXR1cmUgZW5hYmxlZD8pXG4gICAgICpcbiAgICAgKiBAcmV0dXJucyB0cnVlIGlmIHRoZXJlIGFyZSBhdCBsZWFzdCAyMCB2aXNpYmxlIHJvb21zLlxuICAgICAqL1xuICAgIHB1YmxpYyBnZXQgbWVldHNSb29tUmVxdWlyZW1lbnQoKTogYm9vbGVhbiB7XG4gICAgICAgIGNvbnN0IG1zYzM5NDZQcm9jZXNzRHluYW1pY1ByZWRlY2Vzc29yID0gU2V0dGluZ3NTdG9yZS5nZXRWYWx1ZShcImZlYXR1cmVfZHluYW1pY19yb29tX3ByZWRlY2Vzc29yc1wiKTtcbiAgICAgICAgcmV0dXJuICEhdGhpcy5tYXRyaXhDbGllbnQgJiYgdGhpcy5tYXRyaXhDbGllbnQuZ2V0VmlzaWJsZVJvb21zKG1zYzM5NDZQcm9jZXNzRHluYW1pY1ByZWRlY2Vzc29yKS5sZW5ndGggPj0gMjA7XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIGFzeW5jIG9uQWN0aW9uKHBheWxvYWQ6IFNldHRpbmdVcGRhdGVkUGF5bG9hZCB8IFZpZXdSb29tUGF5bG9hZCB8IEpvaW5Sb29tUGF5bG9hZCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBpZiAoIXRoaXMubWF0cml4Q2xpZW50KSByZXR1cm47XG4gICAgICAgIGlmIChwYXlsb2FkLmFjdGlvbiA9PT0gQWN0aW9uLlNldHRpbmdVcGRhdGVkKSB7XG4gICAgICAgICAgICBpZiAocGF5bG9hZC5zZXR0aW5nTmFtZSA9PT0gXCJicmVhZGNydW1iX3Jvb21zXCIpIHtcbiAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnVwZGF0ZVJvb21zKCk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKHBheWxvYWQuc2V0dGluZ05hbWUgPT09IFwiYnJlYWRjcnVtYnNcIikge1xuICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMudXBkYXRlU3RhdGUoeyBlbmFibGVkOiBTZXR0aW5nc1N0b3JlLmdldFZhbHVlKFwiYnJlYWRjcnVtYnNcIiwgbnVsbCkgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAocGF5bG9hZC5hY3Rpb24gPT09IEFjdGlvbi5WaWV3Um9vbSkge1xuICAgICAgICAgICAgaWYgKHBheWxvYWQuYXV0b19qb2luICYmIHBheWxvYWQucm9vbV9pZCAmJiAhdGhpcy5tYXRyaXhDbGllbnQuZ2V0Um9vbShwYXlsb2FkLnJvb21faWQpKSB7XG4gICAgICAgICAgICAgICAgLy8gUXVldWUgdGhlIHJvb20gaW5zdGVhZCBvZiBwdXNoaW5nIGl0IGltbWVkaWF0ZWx5LiBXZSdyZSBwcm9iYWJseSBqdXN0XG4gICAgICAgICAgICAgICAgLy8gd2FpdGluZyBmb3IgYSByb29tIGpvaW4gdG8gY29tcGxldGUuXG4gICAgICAgICAgICAgICAgdGhpcy53YWl0aW5nUm9vbXMucHVzaCh7IHJvb21JZDogcGF5bG9hZC5yb29tX2lkLCBhZGRlZFRzOiBEYXRlLm5vdygpIH0pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAvLyBUaGUgdGVzdHMgbWlnaHQgbm90IHJlc3VsdCBpbiBhIHZhbGlkIHJvb20gb2JqZWN0LlxuICAgICAgICAgICAgICAgIGNvbnN0IHJvb20gPSB0aGlzLm1hdHJpeENsaWVudC5nZXRSb29tKHBheWxvYWQucm9vbV9pZCk7XG4gICAgICAgICAgICAgICAgY29uc3QgbWVtYmVyc2hpcCA9IHJvb20/LmdldE15TWVtYmVyc2hpcCgpO1xuICAgICAgICAgICAgICAgIGlmIChyb29tICYmIG1lbWJlcnNoaXAgPT09IEtub3duTWVtYmVyc2hpcC5Kb2luKSBhd2FpdCB0aGlzLmFwcGVuZFJvb20ocm9vbSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAocGF5bG9hZC5hY3Rpb24gPT09IEFjdGlvbi5Kb2luUm9vbSkge1xuICAgICAgICAgICAgY29uc3Qgcm9vbSA9IHRoaXMubWF0cml4Q2xpZW50LmdldFJvb20ocGF5bG9hZC5yb29tSWQpO1xuICAgICAgICAgICAgaWYgKHJvb20pIGF3YWl0IHRoaXMuYXBwZW5kUm9vbShyb29tKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByb3RlY3RlZCBhc3luYyBvblJlYWR5KCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCB0aGlzLnVwZGF0ZVJvb21zKCk7XG4gICAgICAgIGF3YWl0IHRoaXMudXBkYXRlU3RhdGUoeyBlbmFibGVkOiBTZXR0aW5nc1N0b3JlLmdldFZhbHVlKFwiYnJlYWRjcnVtYnNcIiwgbnVsbCkgfSk7XG5cbiAgICAgICAgaWYgKHRoaXMubWF0cml4Q2xpZW50KSB7XG4gICAgICAgICAgICB0aGlzLm1hdHJpeENsaWVudC5vbihSb29tRXZlbnQuTXlNZW1iZXJzaGlwLCB0aGlzLm9uTXlNZW1iZXJzaGlwKTtcbiAgICAgICAgICAgIHRoaXMubWF0cml4Q2xpZW50Lm9uKENsaWVudEV2ZW50LlJvb20sIHRoaXMub25Sb29tKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByb3RlY3RlZCBhc3luYyBvbk5vdFJlYWR5KCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBpZiAodGhpcy5tYXRyaXhDbGllbnQpIHtcbiAgICAgICAgICAgIHRoaXMubWF0cml4Q2xpZW50LnJlbW92ZUxpc3RlbmVyKFJvb21FdmVudC5NeU1lbWJlcnNoaXAsIHRoaXMub25NeU1lbWJlcnNoaXApO1xuICAgICAgICAgICAgdGhpcy5tYXRyaXhDbGllbnQucmVtb3ZlTGlzdGVuZXIoQ2xpZW50RXZlbnQuUm9vbSwgdGhpcy5vblJvb20pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBvbk15TWVtYmVyc2hpcCA9IGFzeW5jIChyb29tOiBSb29tKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgICAgIC8vIE9ubHkgdHVybiBvbiBicmVhZGNydW1icyBpcyB0aGUgdXNlciBoYXNuJ3QgZXhwbGljaXRseSB0dXJuZWQgaXQgb2ZmIGFnYWluLlxuICAgICAgICBjb25zdCBzZXR0aW5nVmFsdWVSYXcgPSBTZXR0aW5nc1N0b3JlLmdldFZhbHVlKFwiYnJlYWRjcnVtYnNcIiwgbnVsbCwgLypleGNsdWRlRGVmYXVsdD0qLyB0cnVlKTtcbiAgICAgICAgaWYgKHRoaXMubWVldHNSb29tUmVxdWlyZW1lbnQgJiYgaXNOdWxsT3JVbmRlZmluZWQoc2V0dGluZ1ZhbHVlUmF3KSkge1xuICAgICAgICAgICAgYXdhaXQgU2V0dGluZ3NTdG9yZS5zZXRWYWx1ZShcImJyZWFkY3J1bWJzXCIsIG51bGwsIFNldHRpbmdMZXZlbC5BQ0NPVU5ULCB0cnVlKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBwcml2YXRlIG9uUm9vbSA9IGFzeW5jIChyb29tOiBSb29tKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgICAgIGNvbnN0IHdhaXRpbmdSb29tID0gdGhpcy53YWl0aW5nUm9vbXMuZmluZCgocikgPT4gci5yb29tSWQgPT09IHJvb20ucm9vbUlkKTtcbiAgICAgICAgaWYgKCF3YWl0aW5nUm9vbSkgcmV0dXJuO1xuICAgICAgICB0aGlzLndhaXRpbmdSb29tcy5zcGxpY2UodGhpcy53YWl0aW5nUm9vbXMuaW5kZXhPZih3YWl0aW5nUm9vbSksIDEpO1xuXG4gICAgICAgIGlmIChEYXRlLm5vdygpIC0gd2FpdGluZ1Jvb20uYWRkZWRUcyA+IEFVVE9KT0lOX1dBSVRfVEhSRVNIT0xEX01TKSByZXR1cm47IC8vIFRvbyBsb25nIGFnby5cbiAgICAgICAgYXdhaXQgdGhpcy5hcHBlbmRSb29tKHJvb20pO1xuICAgIH07XG5cbiAgICBwcml2YXRlIGFzeW5jIHVwZGF0ZVJvb21zKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBsZXQgcm9vbUlkcyA9IFNldHRpbmdzU3RvcmUuZ2V0VmFsdWU8c3RyaW5nW10+KFwiYnJlYWRjcnVtYl9yb29tc1wiKTtcbiAgICAgICAgaWYgKCFyb29tSWRzIHx8IHJvb21JZHMubGVuZ3RoID09PSAwKSByb29tSWRzID0gW107XG5cbiAgICAgICAgY29uc3Qgcm9vbXMgPSBmaWx0ZXJCb29sZWFuKHJvb21JZHMubWFwKChyKSA9PiB0aGlzLm1hdHJpeENsaWVudD8uZ2V0Um9vbShyKSkpO1xuICAgICAgICBjb25zdCBjdXJyZW50Um9vbXMgPSB0aGlzLnN0YXRlLnJvb21zIHx8IFtdO1xuICAgICAgICBpZiAoIWFycmF5SGFzRGlmZihyb29tcywgY3VycmVudFJvb21zKSkgcmV0dXJuOyAvLyBubyBjaGFuZ2UgKHByb2JhYmx5IGVjaG8pXG4gICAgICAgIGF3YWl0IHRoaXMudXBkYXRlU3RhdGUoeyByb29tcyB9KTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIGFwcGVuZFJvb20ocm9vbTogUm9vbSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBsZXQgdXBkYXRlZCA9IGZhbHNlO1xuICAgICAgICBjb25zdCByb29tcyA9ICh0aGlzLnN0YXRlLnJvb21zIHx8IFtdKS5zbGljZSgpOyAvLyBjaGVhcCBjbG9uZVxuICAgICAgICBjb25zdCBtc2MzOTQ2UHJvY2Vzc0R5bmFtaWNQcmVkZWNlc3NvciA9IFNldHRpbmdzU3RvcmUuZ2V0VmFsdWUoXCJmZWF0dXJlX2R5bmFtaWNfcm9vbV9wcmVkZWNlc3NvcnNcIik7XG5cbiAgICAgICAgLy8gSWYgdGhlIHJvb20gaXMgdXBncmFkZWQsIHVzZSB0aGF0IHJvb20gaW5zdGVhZC4gV2UnbGwgYWxzbyBzcGxpY2Ugb3V0XG4gICAgICAgIC8vIGFueSBjaGlsZHJlbiBvZiB0aGUgcm9vbS5cbiAgICAgICAgY29uc3QgaGlzdG9yeSA9IHRoaXMubWF0cml4Q2xpZW50Py5nZXRSb29tVXBncmFkZUhpc3Rvcnkocm9vbS5yb29tSWQsIGZhbHNlLCBtc2MzOTQ2UHJvY2Vzc0R5bmFtaWNQcmVkZWNlc3Nvcik7XG4gICAgICAgIGlmIChoaXN0b3J5ICYmIGhpc3RvcnkubGVuZ3RoID4gMSkge1xuICAgICAgICAgICAgcm9vbSA9IGhpc3RvcnlbaGlzdG9yeS5sZW5ndGggLSAxXTsgLy8gTGFzdCByb29tIGlzIG1vc3QgcmVjZW50IGluIGhpc3RvcnlcblxuICAgICAgICAgICAgLy8gVGFrZSBvdXQgYW55IHJvb20gdGhhdCBpc24ndCB0aGUgbW9zdCByZWNlbnQgcm9vbVxuICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBoaXN0b3J5Lmxlbmd0aCAtIDE7IGkrKykge1xuICAgICAgICAgICAgICAgIGNvbnN0IGlkeCA9IHJvb21zLmZpbmRJbmRleCgocikgPT4gci5yb29tSWQgPT09IGhpc3RvcnlbaV0ucm9vbUlkKTtcbiAgICAgICAgICAgICAgICBpZiAoaWR4ICE9PSAtMSkge1xuICAgICAgICAgICAgICAgICAgICByb29tcy5zcGxpY2UoaWR4LCAxKTtcbiAgICAgICAgICAgICAgICAgICAgdXBkYXRlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gUmVtb3ZlIHRoZSBleGlzdGluZyByb29tLCBpZiBpdCBpcyBwcmVzZW50XG4gICAgICAgIGNvbnN0IGV4aXN0aW5nSWR4ID0gcm9vbXMuZmluZEluZGV4KChyKSA9PiByLnJvb21JZCA9PT0gcm9vbS5yb29tSWQpO1xuXG4gICAgICAgIC8vIElmIHdlJ3JlIGZvY3VzaW5nIG9uIHRoZSBmaXJzdCByb29tIG5vLW9wXG4gICAgICAgIGlmIChleGlzdGluZ0lkeCAhPT0gMCkge1xuICAgICAgICAgICAgaWYgKGV4aXN0aW5nSWR4ICE9PSAtMSkge1xuICAgICAgICAgICAgICAgIHJvb21zLnNwbGljZShleGlzdGluZ0lkeCwgMSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIFNwbGljZSB0aGUgcm9vbSB0byB0aGUgc3RhcnQgb2YgdGhlIGxpc3RcbiAgICAgICAgICAgIHJvb21zLnNwbGljZSgwLCAwLCByb29tKTtcbiAgICAgICAgICAgIHVwZGF0ZWQgPSB0cnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHJvb21zLmxlbmd0aCA+IE1BWF9ST09NUykge1xuICAgICAgICAgICAgLy8gVGhpcyBsb29rcyB3ZWlyZCwgYnV0IGl0J3Mgc2F5aW5nIHRvIHN0YXJ0IGF0IHRoZSBNQVhfUk9PTVMgcG9pbnQgaW4gdGhlXG4gICAgICAgICAgICAvLyBsaXN0IGFuZCBkZWxldGUgZXZlcnl0aGluZyBhZnRlciBpdC5cbiAgICAgICAgICAgIHJvb21zLnNwbGljZShNQVhfUk9PTVMsIHJvb21zLmxlbmd0aCAtIE1BWF9ST09NUyk7XG4gICAgICAgICAgICB1cGRhdGVkID0gdHJ1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh1cGRhdGVkKSB7XG4gICAgICAgICAgICAvLyBVcGRhdGUgdGhlIGJyZWFkY3J1bWJzXG4gICAgICAgICAgICBhd2FpdCB0aGlzLnVwZGF0ZVN0YXRlKHsgcm9vbXMgfSk7XG4gICAgICAgICAgICBjb25zdCByb29tSWRzID0gcm9vbXMubWFwKChyKSA9PiByLnJvb21JZCk7XG4gICAgICAgICAgICBpZiAocm9vbUlkcy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgU2V0dGluZ3NTdG9yZS5zZXRWYWx1ZShcImJyZWFkY3J1bWJfcm9vbXNcIiwgbnVsbCwgU2V0dGluZ0xldmVsLkFDQ09VTlQsIHJvb21JZHMpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7OztBQVFBLElBQUFBLE9BQUEsR0FBQUMsT0FBQTtBQUNBLElBQUFDLE1BQUEsR0FBQUQsT0FBQTtBQUNBLElBQUFFLE1BQUEsR0FBQUYsT0FBQTtBQUVBLElBQUFHLGNBQUEsR0FBQUMsc0JBQUEsQ0FBQUosT0FBQTtBQUNBLElBQUFLLHFCQUFBLEdBQUFMLE9BQUE7QUFDQSxJQUFBTSxXQUFBLEdBQUFGLHNCQUFBLENBQUFKLE9BQUE7QUFDQSxJQUFBTyxPQUFBLEdBQUFQLE9BQUE7QUFDQSxJQUFBUSxhQUFBLEdBQUFSLE9BQUE7QUFDQSxJQUFBUyxRQUFBLEdBQUFULE9BQUE7QUFBK0MsSUFBQVUsaUJBQUE7QUFqQi9DO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBZ0JBLE1BQU1DLFNBQVMsR0FBRyxFQUFFLENBQUMsQ0FBQztBQUN0QixNQUFNQywwQkFBMEIsR0FBRyxLQUFLLENBQUMsQ0FBQzs7QUFPbkMsTUFBTUMsZ0JBQWdCLFNBQVNDLDBDQUFvQixDQUFT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RyxJQUFJO1FBQ2xCO01BQ0o7SUFDSjs7SUFFQTtJQUNBLE1BQU1PLFdBQVcsR0FBR2hELEtBQUssQ0FBQytDLFNBQVMsQ0FBRTFELENBQUMsSUFBS0EsQ0FBQyxDQUFDQyxNQUFNLEtBQUtiLElBQUksQ0FBQ2EsTUFBTSxDQUFDOztJQUVwRTtJQUNBLElBQUkwRCxXQUFXLEtBQUssQ0FBQyxFQUFFO01BQ25CLElBQUlBLFdBQVcsS0FBSyxDQUFDLENBQUMsRUFBRTtRQUNwQmhELEtBQUssQ0FBQ1QsTUFBTSxDQUFDeUQsV0FBVyxFQUFFLENBQUMsQ0FBQztNQUNoQzs7TUFFQTtNQUNBaEQsS0FBSyxDQUFDVCxNQUFNLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRWQsSUFBSSxDQUFDO01BQ3hCZ0UsT0FBTyxHQUFHLElBQUk7SUFDbEI7SUFFQSxJQUFJekMsS0FBSyxDQUFDTyxNQUFNLEdBQUd0QyxTQUFTLEVBQUU7TUFDMUI7TUFDQTtNQUNBK0IsS0FBSyxDQUFDVCxNQUFNLENBQUN0QixTQUFTLEVBQUUrQixLQUFLLENBQUNPLE1BQU0sR0FBR3RDLFNBQVMsQ0FBQztNQUNqRHdFLE9BQU8sR0FBRyxJQUFJO0lBQ2xCO0lBRUEsSUFBSUEsT0FBTyxFQUFFO01BQ1Q7TUFDQSxNQUFNLElBQUksQ0FBQzFCLFdBQVcsQ0FBQztRQUFFZjtNQUFNLENBQUMsQ0FBQztNQUNqQyxNQUFNb0MsT0FBTyxHQUFHcEMsS0FBSyxDQUFDc0MsR0FBRyxDQUFFakQsQ0FBQyxJQUFLQSxDQUFDLENBQUNDLE1BQU0sQ0FBQztNQUMxQyxJQUFJOEMsT0FBTyxDQUFDN0IsTUFBTSxHQUFHLENBQUMsRUFBRTtRQUNwQixNQUFNNUIsc0JBQWEsQ0FBQ0ksUUFBUSxDQUFDLGtCQUFrQixFQUFFLElBQUksRUFBRUMsMEJBQVksQ0FBQ0MsT0FBTyxFQUFFbUQsT0FBTyxDQUFDO01BQ3pGO0lBQ0o7RUFDSjtBQUNKO0FBQUNhLE9BQUEsQ0FBQTlFLGdCQUFBLEdBQUFBLGdCQUFBO0FBQUFILGlCQUFBLEdBL0pZRyxnQkFBZ0I7QUFBQSxJQUFBSSxnQkFBQSxDQUFBQyxPQUFBLEVBQWhCTCxnQkFBZ0Isc0JBQ2tCLENBQUMsTUFBTTtFQUM5QyxNQUFNMkIsUUFBUSxHQUFHLElBQUkzQixpQkFBZ0IsQ0FBQyxDQUFDO0VBQ3ZDMkIsUUFBUSxDQUFDb0QsS0FBSyxDQUFDLENBQUM7RUFDaEIsT0FBT3BELFFBQVE7QUFDbkIsQ0FBQyxFQUFFLENBQUMiLCJpZ25vcmVMaXN0IjpbXX0=