matrix-react-sdk
Version:
SDK for matrix.org using React
356 lines (343 loc) • 52.2 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.SlidingSyncSortToFilter = exports.SlidingRoomListStoreClass = exports.LISTS_UPDATE_EVENT = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _logger = require("matrix-js-sdk/src/logger");
var _slidingSync = require("matrix-js-sdk/src/sliding-sync");
var _models = require("./models");
var _models2 = require("./algorithms/models");
var _AsyncStoreWithClient = require("../AsyncStoreWithClient");
var _Interface = require("./Interface");
var _spaces = require("../spaces");
var _RoomListStore = require("./RoomListStore");
var _AsyncStore = require("../AsyncStore");
/*
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.
*/
const SlidingSyncSortToFilter = exports.SlidingSyncSortToFilter = {
[_models2.SortAlgorithm.Alphabetic]: ["by_name", "by_recency"],
[_models2.SortAlgorithm.Recent]: ["by_notification_level", "by_recency"],
[_models2.SortAlgorithm.Manual]: ["by_recency"]
};
const filterConditions = {
[_models.DefaultTagID.Invite]: {
is_invite: true
},
[_models.DefaultTagID.Favourite]: {
tags: ["m.favourite"]
},
[_models.DefaultTagID.DM]: {
is_dm: true,
is_invite: false,
// If a DM has a Favourite & Low Prio tag then it'll be shown in those lists instead
not_tags: ["m.favourite", "m.lowpriority"]
},
[_models.DefaultTagID.Untagged]: {
is_dm: false,
is_invite: false,
not_room_types: ["m.space"],
not_tags: ["m.favourite", "m.lowpriority"]
// spaces filter added dynamically
},
[_models.DefaultTagID.LowPriority]: {
tags: ["m.lowpriority"],
// If a room has both Favourite & Low Prio tags then it'll be shown under Favourites
not_tags: ["m.favourite"]
}
// TODO https://github.com/vector-im/element-web/issues/23207
// DefaultTagID.ServerNotice,
// DefaultTagID.Suggested,
// DefaultTagID.Archived,
};
const LISTS_UPDATE_EVENT = exports.LISTS_UPDATE_EVENT = _Interface.RoomListStoreEvent.ListsUpdate;
class SlidingRoomListStoreClass extends _AsyncStoreWithClient.AsyncStoreWithClient {
constructor(dis, context) {
super(dis);
(0, _defineProperty2.default)(this, "tagIdToSortAlgo", {});
(0, _defineProperty2.default)(this, "tagMap", {});
(0, _defineProperty2.default)(this, "counts", {});
(0, _defineProperty2.default)(this, "stickyRoomId", void 0);
(0, _defineProperty2.default)(this, "onSelectedSpaceUpdated", (activeSpace, allRoomsInHome) => {
_logger.logger.info("SlidingRoomListStore.onSelectedSpaceUpdated", activeSpace);
// update the untagged filter
const tagId = _models.DefaultTagID.Untagged;
const filters = filterConditions[tagId];
const oldSpace = filters.spaces?.[0];
filters.spaces = activeSpace && activeSpace != _spaces.MetaSpace.Home ? [activeSpace] : undefined;
if (oldSpace !== activeSpace) {
// include subspaces in this list
this.context.spaceStore.traverseSpace(activeSpace, roomId => {
if (roomId === activeSpace) {
return;
}
if (!filters.spaces) {
filters.spaces = [];
}
filters.spaces.push(roomId); // add subspace
}, false);
this.emit(_RoomListStore.LISTS_LOADING_EVENT, tagId, true);
this.context.slidingSyncManager.ensureListRegistered(tagId, {
filters: filters
}).then(() => {
this.emit(_RoomListStore.LISTS_LOADING_EVENT, tagId, false);
});
}
});
this.context = context;
this.setMaxListeners(20); // RoomList + LeftPanel + 8xRoomSubList + spares
}
async setTagSorting(tagId, sort) {
_logger.logger.info("SlidingRoomListStore.setTagSorting ", tagId, sort);
this.tagIdToSortAlgo[tagId] = sort;
switch (sort) {
case _models2.SortAlgorithm.Alphabetic:
await this.context.slidingSyncManager.ensureListRegistered(tagId, {
sort: SlidingSyncSortToFilter[_models2.SortAlgorithm.Alphabetic]
});
break;
case _models2.SortAlgorithm.Recent:
await this.context.slidingSyncManager.ensureListRegistered(tagId, {
sort: SlidingSyncSortToFilter[_models2.SortAlgorithm.Recent]
});
break;
case _models2.SortAlgorithm.Manual:
_logger.logger.error("cannot enable manual sort in sliding sync mode");
break;
default:
_logger.logger.error("unknown sort mode: ", sort);
}
}
getTagSorting(tagId) {
let algo = this.tagIdToSortAlgo[tagId];
if (!algo) {
_logger.logger.warn("SlidingRoomListStore.getTagSorting: no sort algorithm for tag ", tagId);
algo = _models2.SortAlgorithm.Recent; // why not, we have to do something..
}
return algo;
}
getCount(tagId) {
return this.counts[tagId] || 0;
}
setListOrder(tagId, order) {
// TODO: https://github.com/vector-im/element-web/issues/23207
}
getListOrder(tagId) {
// TODO: handle unread msgs first? https://github.com/vector-im/element-web/issues/23207
return _models2.ListAlgorithm.Natural;
}
/**
* Adds a filter condition to the room list store. Filters may be applied async,
* and thus might not cause an update to the store immediately.
* @param {IFilterCondition} filter The filter condition to add.
*/
async addFilter(filter) {
// Do nothing, the filters are only used by SpaceWatcher to see if a room should appear
// in the room list. We do not support arbitrary code for filters in sliding sync.
}
/**
* Removes a filter condition from the room list store. If the filter was
* not previously added to the room list store, this will no-op. The effects
* of removing a filter may be applied async and therefore might not cause
* an update right away.
* @param {IFilterCondition} filter The filter condition to remove.
*/
removeFilter(filter) {
// Do nothing, the filters are only used by SpaceWatcher to see if a room should appear
// in the room list. We do not support arbitrary code for filters in sliding sync.
}
/**
* Gets the tags for a room identified by the store. The returned set
* should never be empty, and will contain DefaultTagID.Untagged if
* the store is not aware of any tags.
* @param room The room to get the tags for.
* @returns The tags for the room.
*/
getTagsForRoom(room) {
// check all lists for each tag we know about and see if the room is there
const tags = [];
for (const tagId in this.tagIdToSortAlgo) {
const listData = this.context.slidingSyncManager.slidingSync?.getListData(tagId);
if (!listData) {
continue;
}
for (const roomIndex in listData.roomIndexToRoomId) {
const roomId = listData.roomIndexToRoomId[roomIndex];
if (roomId === room.roomId) {
tags.push(tagId);
break;
}
}
}
return tags;
}
/**
* Manually update a room with a given cause. This should only be used if the
* room list store would otherwise be incapable of doing the update itself. Note
* that this may race with the room list's regular operation.
* @param {Room} room The room to update.
* @param {RoomUpdateCause} cause The cause to update for.
*/
async manualRoomUpdate(room, cause) {
// TODO: this is only used when you forget a room, not that important for now.
}
get orderedLists() {
return this.tagMap;
}
refreshOrderedLists(tagId, roomIndexToRoomId) {
const tagMap = this.tagMap;
// this room will not move due to it being viewed: it is sticky. This can be null to indicate
// no sticky room if you aren't viewing a room.
this.stickyRoomId = this.context.roomViewStore.getRoomId();
let stickyRoomNewIndex = -1;
const stickyRoomOldIndex = (tagMap[tagId] || []).findIndex(room => {
return room.roomId === this.stickyRoomId;
});
// order from low to high
const orderedRoomIndexes = Object.keys(roomIndexToRoomId).map(numStr => {
return Number(numStr);
}).sort((a, b) => {
return a - b;
});
const seenRoomIds = new Set();
const orderedRoomIds = orderedRoomIndexes.map(i => {
const rid = roomIndexToRoomId[i];
if (seenRoomIds.has(rid)) {
_logger.logger.error("room " + rid + " already has an index position: duplicate room!");
}
seenRoomIds.add(rid);
if (!rid) {
throw new Error("index " + i + " has no room ID: Map => " + JSON.stringify(roomIndexToRoomId));
}
if (rid === this.stickyRoomId) {
stickyRoomNewIndex = i;
}
return rid;
});
_logger.logger.debug(`SlidingRoomListStore.refreshOrderedLists ${tagId} sticky: ${this.stickyRoomId}`, `${stickyRoomOldIndex} -> ${stickyRoomNewIndex}`, "rooms:", orderedRoomIds.length < 30 ? orderedRoomIds : orderedRoomIds.length);
if (this.stickyRoomId && stickyRoomOldIndex >= 0 && stickyRoomNewIndex >= 0) {
// this update will move this sticky room from old to new, which we do not want.
// Instead, keep the sticky room ID index position as it is, swap it with
// whatever was in its place.
// Some scenarios with sticky room S and bump room B (other letters unimportant):
// A, S, C, B S, A, B
// B, A, S, C <---- without sticky rooms ---> B, S, A
// B, S, A, C <- with sticky rooms applied -> S, B, A
// In other words, we need to swap positions to keep it locked in place.
const inWayRoomId = orderedRoomIds[stickyRoomOldIndex];
orderedRoomIds[stickyRoomOldIndex] = this.stickyRoomId;
orderedRoomIds[stickyRoomNewIndex] = inWayRoomId;
}
// now set the rooms
const rooms = [];
orderedRoomIds.forEach(roomId => {
const room = this.matrixClient?.getRoom(roomId);
if (!room) {
return;
}
rooms.push(room);
});
tagMap[tagId] = rooms;
this.tagMap = tagMap;
}
onSlidingSyncListUpdate(tagId, joinCount, roomIndexToRoomId) {
this.counts[tagId] = joinCount;
this.refreshOrderedLists(tagId, roomIndexToRoomId);
// let the UI update
this.emit(LISTS_UPDATE_EVENT);
}
onRoomViewStoreUpdated() {
// we only care about this to know when the user has clicked on a room to set the stickiness value
if (this.context.roomViewStore.getRoomId() === this.stickyRoomId) {
return;
}
let hasUpdatedAnyList = false;
// every list with the OLD sticky room ID needs to be resorted because it now needs to take
// its proper place as it is no longer sticky. The newly sticky room can remain the same though,
// as we only actually care about its sticky status when we get list updates.
const oldStickyRoom = this.stickyRoomId;
// it's not safe to check the data in slidingSync as it is tracking the server's view of the
// room list. There's an edge case whereby the sticky room has gone outside the window and so
// would not be present in the roomIndexToRoomId map anymore, and hence clicking away from it
// will make it disappear eventually. We need to check orderedLists as that is the actual
// sorted renderable list of rooms which sticky rooms apply to.
for (const tagId in this.orderedLists) {
const list = this.orderedLists[tagId];
const room = list.find(room => {
return room.roomId === oldStickyRoom;
});
if (room) {
// resort it based on the slidingSync view of the list. This may cause this old sticky
// room to cease to exist.
const listData = this.context.slidingSyncManager.slidingSync?.getListData(tagId);
if (!listData) {
continue;
}
this.refreshOrderedLists(tagId, listData.roomIndexToRoomId);
hasUpdatedAnyList = true;
}
}
// in the event we didn't call refreshOrderedLists, it helps to still remember the sticky room ID.
this.stickyRoomId = this.context.roomViewStore.getRoomId();
if (hasUpdatedAnyList) {
this.emit(LISTS_UPDATE_EVENT);
}
}
async onReady() {
_logger.logger.info("SlidingRoomListStore.onReady");
// permanent listeners: never get destroyed. Could be an issue if we want to test this in isolation.
this.context.slidingSyncManager.slidingSync.on(_slidingSync.SlidingSyncEvent.List, this.onSlidingSyncListUpdate.bind(this));
this.context.roomViewStore.addListener(_AsyncStore.UPDATE_EVENT, this.onRoomViewStoreUpdated.bind(this));
this.context.spaceStore.on(_spaces.UPDATE_SELECTED_SPACE, this.onSelectedSpaceUpdated.bind(this));
if (this.context.spaceStore.activeSpace) {
this.onSelectedSpaceUpdated(this.context.spaceStore.activeSpace, false);
}
// sliding sync has an initial response for spaces. Now request all the lists.
// We do the spaces list _first_ to avoid potential flickering on DefaultTagID.Untagged list
// which would be caused by initially having no `spaces` filter set, and then suddenly setting one.
_models.OrderedDefaultTagIDs.forEach(tagId => {
const filter = filterConditions[tagId];
if (!filter) {
_logger.logger.info("SlidingRoomListStore.onReady unsupported list ", tagId);
return; // we do not support this list yet.
}
const sort = _models2.SortAlgorithm.Recent; // default to recency sort, TODO: read from config
this.tagIdToSortAlgo[tagId] = sort;
this.emit(_RoomListStore.LISTS_LOADING_EVENT, tagId, true);
this.context.slidingSyncManager.ensureListRegistered(tagId, {
filters: filter,
sort: SlidingSyncSortToFilter[sort]
}).then(() => {
this.emit(_RoomListStore.LISTS_LOADING_EVENT, tagId, false);
});
});
}
// Intended for test usage
async resetStore() {
// Test function
}
/**
* Regenerates the room whole room list, discarding any previous results.
*
* Note: This is only exposed externally for the tests. Do not call this from within
* the app.
* @param trigger Set to false to prevent a list update from being sent. Should only
* be used if the calling code will manually trigger the update.
*/
regenerateAllLists({
trigger = true
}) {
// Test function
}
async onNotReady() {
await this.resetStore();
}
async onAction(payload) {}
}
exports.SlidingRoomListStoreClass = SlidingRoomListStoreClass;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbG9nZ2VyIiwicmVxdWlyZSIsIl9zbGlkaW5nU3luYyIsIl9tb2RlbHMiLCJfbW9kZWxzMiIsIl9Bc3luY1N0b3JlV2l0aENsaWVudCIsIl9JbnRlcmZhY2UiLCJfc3BhY2VzIiwiX1Jvb21MaXN0U3RvcmUiLCJfQXN5bmNTdG9yZSIsIlNsaWRpbmdTeW5jU29ydFRvRmlsdGVyIiwiZXhwb3J0cyIsIlNvcnRBbGdvcml0aG0iLCJBbHBoYWJldGljIiwiUmVjZW50IiwiTWFudWFsIiwiZmlsdGVyQ29uZGl0aW9ucyIsIkRlZmF1bHRUYWdJRCIsIkludml0ZSIsImlzX2ludml0ZSIsIkZhdm91cml0ZSIsInRhZ3MiLCJETSIsImlzX2RtIiwibm90X3RhZ3MiLCJVbnRhZ2dlZCIsIm5vdF9yb29tX3R5cGVzIiwiTG93UHJpb3JpdHkiLCJMSVNUU19VUERBVEVfRVZFTlQiLCJSb29tTGlzdFN0b3JlRXZlbnQiLCJMaXN0c1VwZGF0ZSIsIlNsaWRpbmdSb29tTGlzdFN0b3JlQ2xhc3MiLCJBc3luY1N0b3JlV2l0aENsaWVudCIsImNvbnN0cnVjdG9yIiwiZGlzIiwiY29udGV4dCIsIl9kZWZpbmVQcm9wZXJ0eTIiLCJkZWZhdWx0IiwiYWN0aXZlU3BhY2UiLCJhbGxSb29tc0luSG9tZSIsImxvZ2dlciIsImluZm8iLCJ0YWdJZCIsImZpbHRlcnMiLCJvbGRTcGFjZSIsInNwYWNlcyIsIk1ldGFTcGFjZSIsIkhvbWUiLCJ1bmRlZmluZWQiLCJzcGFjZVN0b3JlIiwidHJhdmVyc2VTcGFjZSIsInJvb21JZCIsInB1c2giLCJlbWl0IiwiTElTVFNfTE9BRElOR19FVkVOVCIsInNsaWRpbmdTeW5jTWFuYWdlciIsImVuc3VyZUxpc3RSZWdpc3RlcmVkIiwidGhlbiIsInNldE1heExpc3RlbmVycyIsInNldFRhZ1NvcnRpbmciLCJzb3J0IiwidGFnSWRUb1NvcnRBbGdvIiwiZXJyb3IiLCJnZXRUYWdTb3J0aW5nIiwiYWxnbyIsIndhcm4iLCJnZXRDb3VudCIsImNvdW50cyIsInNldExpc3RPcmRlciIsIm9yZGVyIiwiZ2V0TGlzdE9yZGVyIiwiTGlzdEFsZ29yaXRobSIsIk5hdHVyYWwiLCJhZGRGaWx0ZXIiLCJmaWx0ZXIiLCJyZW1vdmVGaWx0ZXIiLCJnZXRUYWdzRm9yUm9vbSIsInJvb20iLCJsaXN0RGF0YSIsInNsaWRpbmdTeW5jIiwiZ2V0TGlzdERhdGEiLCJyb29tSW5kZXgiLCJyb29tSW5kZXhUb1Jvb21JZCIsIm1hbnVhbFJvb21VcGRhdGUiLCJjYXVzZSIsIm9yZGVyZWRMaXN0cyIsInRhZ01hcCIsInJlZnJlc2hPcmRlcmVkTGlzdHMiLCJzdGlja3lSb29tSWQiLCJyb29tVmlld1N0b3JlIiwiZ2V0Um9vbUlkIiwic3RpY2t5Um9vbU5ld0luZGV4Iiwic3RpY2t5Um9vbU9sZEluZGV4IiwiZmluZEluZGV4Iiwib3JkZXJlZFJvb21JbmRleGVzIiwiT2JqZWN0Iiwia2V5cyIsIm1hcCIsIm51bVN0ciIsIk51bWJlciIsImEiLCJiIiwic2VlblJvb21JZHMiLCJTZXQiLCJvcmRlcmVkUm9vbUlkcyIsImkiLCJyaWQiLCJoYXMiLCJhZGQiLCJFcnJvciIsIkpTT04iLCJzdHJpbmdpZnkiLCJkZWJ1ZyIsImxlbmd0aCIsImluV2F5Um9vbUlkIiwicm9vbXMiLCJmb3JFYWNoIiwibWF0cml4Q2xpZW50IiwiZ2V0Um9vbSIsIm9uU2xpZGluZ1N5bmNMaXN0VXBkYXRlIiwiam9pbkNvdW50Iiwib25Sb29tVmlld1N0b3JlVXBkYXRlZCIsImhhc1VwZGF0ZWRBbnlMaXN0Iiwib2xkU3RpY2t5Um9vbSIsImxpc3QiLCJmaW5kIiwib25SZWFkeSIsIm9uIiwiU2xpZGluZ1N5bmNFdmVudCIsIkxpc3QiLCJiaW5kIiwiYWRkTGlzdGVuZXIiLCJVUERBVEVfRVZFTlQiLCJVUERBVEVfU0VMRUNURURfU1BBQ0UiLCJvblNlbGVjdGVkU3BhY2VVcGRhdGVkIiwiT3JkZXJlZERlZmF1bHRUYWdJRHMiLCJyZXNldFN0b3JlIiwicmVnZW5lcmF0ZUFsbExpc3RzIiwidHJpZ2dlciIsIm9uTm90UmVhZHkiLCJvbkFjdGlvbiIsInBheWxvYWQiXSwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc3RvcmVzL3Jvb20tbGlzdC9TbGlkaW5nUm9vbUxpc3RTdG9yZS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuQ29weXJpZ2h0IDIwMjQgTmV3IFZlY3RvciBMdGQuXG5Db3B5cmlnaHQgMjAyMiBUaGUgTWF0cml4Lm9yZyBGb3VuZGF0aW9uIEMuSS5DLlxuXG5TUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQUdQTC0zLjAtb25seSBPUiBHUEwtMy4wLW9ubHlcblBsZWFzZSBzZWUgTElDRU5TRSBmaWxlcyBpbiB0aGUgcmVwb3NpdG9yeSByb290IGZvciBmdWxsIGRldGFpbHMuXG4qL1xuXG5pbXBvcnQgeyBSb29tIH0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL21hdHJpeFwiO1xuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL2xvZ2dlclwiO1xuaW1wb3J0IHsgTVNDMzU3NUZpbHRlciwgU2xpZGluZ1N5bmNFdmVudCB9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9zbGlkaW5nLXN5bmNcIjtcbmltcG9ydCB7IE9wdGlvbmFsIH0gZnJvbSBcIm1hdHJpeC1ldmVudHMtc2RrXCI7XG5cbmltcG9ydCB7IFJvb21VcGRhdGVDYXVzZSwgVGFnSUQsIE9yZGVyZWREZWZhdWx0VGFnSURzLCBEZWZhdWx0VGFnSUQgfSBmcm9tIFwiLi9tb2RlbHNcIjtcbmltcG9ydCB7IElUYWdNYXAsIExpc3RBbGdvcml0aG0sIFNvcnRBbGdvcml0aG0gfSBmcm9tIFwiLi9hbGdvcml0aG1zL21vZGVsc1wiO1xuaW1wb3J0IHsgQWN0aW9uUGF5bG9hZCB9IGZyb20gXCIuLi8uLi9kaXNwYXRjaGVyL3BheWxvYWRzXCI7XG5pbXBvcnQgeyBNYXRyaXhEaXNwYXRjaGVyIH0gZnJvbSBcIi4uLy4uL2Rpc3BhdGNoZXIvZGlzcGF0Y2hlclwiO1xuaW1wb3J0IHsgSUZpbHRlckNvbmRpdGlvbiB9IGZyb20gXCIuL2ZpbHRlcnMvSUZpbHRlckNvbmRpdGlvblwiO1xuaW1wb3J0IHsgQXN5bmNTdG9yZVdpdGhDbGllbnQgfSBmcm9tIFwiLi4vQXN5bmNTdG9yZVdpdGhDbGllbnRcIjtcbmltcG9ydCB7IFJvb21MaXN0U3RvcmUgYXMgSW50ZXJmYWNlLCBSb29tTGlzdFN0b3JlRXZlbnQgfSBmcm9tIFwiLi9JbnRlcmZhY2VcIjtcbmltcG9ydCB7IE1ldGFTcGFjZSwgU3BhY2VLZXksIFVQREFURV9TRUxFQ1RFRF9TUEFDRSB9IGZyb20gXCIuLi9zcGFjZXNcIjtcbmltcG9ydCB7IExJU1RTX0xPQURJTkdfRVZFTlQgfSBmcm9tIFwiLi9Sb29tTGlzdFN0b3JlXCI7XG5pbXBvcnQgeyBVUERBVEVfRVZFTlQgfSBmcm9tIFwiLi4vQXN5bmNTdG9yZVwiO1xuaW1wb3J0IHsgU2RrQ29udGV4dENsYXNzIH0gZnJvbSBcIi4uLy4uL2NvbnRleHRzL1NES0NvbnRleHRcIjtcblxuaW50ZXJmYWNlIElTdGF0ZSB7XG4gICAgLy8gc3RhdGUgaXMgdHJhY2tlZCBpbiB1bmRlcmx5aW5nIGNsYXNzZXNcbn1cblxuZXhwb3J0IGNvbnN0IFNsaWRpbmdTeW5jU29ydFRvRmlsdGVyOiBSZWNvcmQ8U29ydEFsZ29yaXRobSwgc3RyaW5nW10+ID0ge1xuICAgIFtTb3J0QWxnb3JpdGhtLkFscGhhYmV0aWNdOiBbXCJieV9uYW1lXCIsIFwiYnlfcmVjZW5jeVwiXSxcbiAgICBbU29ydEFsZ29yaXRobS5SZWNlbnRdOiBbXCJieV9ub3RpZmljYXRpb25fbGV2ZWxcIiwgXCJieV9yZWNlbmN5XCJdLFxuICAgIFtTb3J0QWxnb3JpdGhtLk1hbnVhbF06IFtcImJ5X3JlY2VuY3lcIl0sXG59O1xuXG5jb25zdCBmaWx0ZXJDb25kaXRpb25zOiBSZWNvcmQ8VGFnSUQsIE1TQzM1NzVGaWx0ZXI+ID0ge1xuICAgIFtEZWZhdWx0VGFnSUQuSW52aXRlXToge1xuICAgICAgICBpc19pbnZpdGU6IHRydWUsXG4gICAgfSxcbiAgICBbRGVmYXVsdFRhZ0lELkZhdm91cml0ZV06IHtcbiAgICAgICAgdGFnczogW1wibS5mYXZvdXJpdGVcIl0sXG4gICAgfSxcbiAgICBbRGVmYXVsdFRhZ0lELkRNXToge1xuICAgICAgICBpc19kbTogdHJ1ZSxcbiAgICAgICAgaXNfaW52aXRlOiBmYWxzZSxcbiAgICAgICAgLy8gSWYgYSBETSBoYXMgYSBGYXZvdXJpdGUgJiBMb3cgUHJpbyB0YWcgdGhlbiBpdCdsbCBiZSBzaG93biBpbiB0aG9zZSBsaXN0cyBpbnN0ZWFkXG4gICAgICAgIG5vdF90YWdzOiBbXCJtLmZhdm91cml0ZVwiLCBcIm0ubG93cHJpb3JpdHlcIl0sXG4gICAgfSxcbiAgICBbRGVmYXVsdFRhZ0lELlVudGFnZ2VkXToge1xuICAgICAgICBpc19kbTogZmFsc2UsXG4gICAgICAgIGlzX2ludml0ZTogZmFsc2UsXG4gICAgICAgIG5vdF9yb29tX3R5cGVzOiBbXCJtLnNwYWNlXCJdLFxuICAgICAgICBub3RfdGFnczogW1wibS5mYXZvdXJpdGVcIiwgXCJtLmxvd3ByaW9yaXR5XCJdLFxuICAgICAgICAvLyBzcGFjZXMgZmlsdGVyIGFkZGVkIGR5bmFtaWNhbGx5XG4gICAgfSxcbiAgICBbRGVmYXVsdFRhZ0lELkxvd1ByaW9yaXR5XToge1xuICAgICAgICB0YWdzOiBbXCJtLmxvd3ByaW9yaXR5XCJdLFxuICAgICAgICAvLyBJZiBhIHJvb20gaGFzIGJvdGggRmF2b3VyaXRlICYgTG93IFByaW8gdGFncyB0aGVuIGl0J2xsIGJlIHNob3duIHVuZGVyIEZhdm91cml0ZXNcbiAgICAgICAgbm90X3RhZ3M6IFtcIm0uZmF2b3VyaXRlXCJdLFxuICAgIH0sXG4gICAgLy8gVE9ETyBodHRwczovL2dpdGh1Yi5jb20vdmVjdG9yLWltL2VsZW1lbnQtd2ViL2lzc3Vlcy8yMzIwN1xuICAgIC8vIERlZmF1bHRUYWdJRC5TZXJ2ZXJOb3RpY2UsXG4gICAgLy8gRGVmYXVsdFRhZ0lELlN1Z2dlc3RlZCxcbiAgICAvLyBEZWZhdWx0VGFnSUQuQXJjaGl2ZWQsXG59O1xuXG5leHBvcnQgY29uc3QgTElTVFNfVVBEQVRFX0VWRU5UID0gUm9vbUxpc3RTdG9yZUV2ZW50Lkxpc3RzVXBkYXRlO1xuXG5leHBvcnQgY2xhc3MgU2xpZGluZ1Jvb21MaXN0U3RvcmVDbGFzcyBleHRlbmRzIEFzeW5jU3RvcmVXaXRoQ2xpZW50PElTdGF0ZT4gaW1wbGVtZW50cyBJbnRlcmZhY2Uge1xuICAgIHByaXZhdGUgdGFnSWRUb1NvcnRBbGdvOiBSZWNvcmQ8VGFnSUQsIFNvcnRBbGdvcml0aG0+ID0ge307XG4gICAgcHJpdmF0ZSB0YWdNYXA6IElUYWdNYXAgPSB7fTtcbiAgICBwcml2YXRlIGNvdW50czogUmVjb3JkPFRhZ0lELCBudW1iZXI+ID0ge307XG4gICAgcHJpdmF0ZSBzdGlja3lSb29tSWQ6IE9wdGlvbmFsPHN0cmluZz47XG5cbiAgICBwdWJsaWMgY29uc3RydWN0b3IoXG4gICAgICAgIGRpczogTWF0cml4RGlzcGF0Y2hlcixcbiAgICAgICAgcHJpdmF0ZSByZWFkb25seSBjb250ZXh0OiBTZGtDb250ZXh0Q2xhc3MsXG4gICAgKSB7XG4gICAgICAgIHN1cGVyKGRpcyk7XG4gICAgICAgIHRoaXMuc2V0TWF4TGlzdGVuZXJzKDIwKTsgLy8gUm9vbUxpc3QgKyBMZWZ0UGFuZWwgKyA4eFJvb21TdWJMaXN0ICsgc3BhcmVzXG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHNldFRhZ1NvcnRpbmcodGFnSWQ6IFRhZ0lELCBzb3J0OiBTb3J0QWxnb3JpdGhtKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGxvZ2dlci5pbmZvKFwiU2xpZGluZ1Jvb21MaXN0U3RvcmUuc2V0VGFnU29ydGluZyBcIiwgdGFnSWQsIHNvcnQpO1xuICAgICAgICB0aGlzLnRhZ0lkVG9Tb3J0QWxnb1t0YWdJZF0gPSBzb3J0O1xuICAgICAgICBzd2l0Y2ggKHNvcnQpIHtcbiAgICAgICAgICAgIGNhc2UgU29ydEFsZ29yaXRobS5BbHBoYWJldGljOlxuICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMuY29udGV4dC5zbGlkaW5nU3luY01hbmFnZXIuZW5zdXJlTGlzdFJlZ2lzdGVyZWQodGFnSWQsIHtcbiAgICAgICAgICAgICAgICAgICAgc29ydDogU2xpZGluZ1N5bmNTb3J0VG9GaWx0ZXJbU29ydEFsZ29yaXRobS5BbHBoYWJldGljXSxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgU29ydEFsZ29yaXRobS5SZWNlbnQ6XG4gICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5jb250ZXh0LnNsaWRpbmdTeW5jTWFuYWdlci5lbnN1cmVMaXN0UmVnaXN0ZXJlZCh0YWdJZCwge1xuICAgICAgICAgICAgICAgICAgICBzb3J0OiBTbGlkaW5nU3luY1NvcnRUb0ZpbHRlcltTb3J0QWxnb3JpdGhtLlJlY2VudF0sXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIFNvcnRBbGdvcml0aG0uTWFudWFsOlxuICAgICAgICAgICAgICAgIGxvZ2dlci5lcnJvcihcImNhbm5vdCBlbmFibGUgbWFudWFsIHNvcnQgaW4gc2xpZGluZyBzeW5jIG1vZGVcIik7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgIGxvZ2dlci5lcnJvcihcInVua25vd24gc29ydCBtb2RlOiBcIiwgc29ydCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0VGFnU29ydGluZyh0YWdJZDogVGFnSUQpOiBTb3J0QWxnb3JpdGhtIHtcbiAgICAgICAgbGV0IGFsZ28gPSB0aGlzLnRhZ0lkVG9Tb3J0QWxnb1t0YWdJZF07XG4gICAgICAgIGlmICghYWxnbykge1xuICAgICAgICAgICAgbG9nZ2VyLndhcm4oXCJTbGlkaW5nUm9vbUxpc3RTdG9yZS5nZXRUYWdTb3J0aW5nOiBubyBzb3J0IGFsZ29yaXRobSBmb3IgdGFnIFwiLCB0YWdJZCk7XG4gICAgICAgICAgICBhbGdvID0gU29ydEFsZ29yaXRobS5SZWNlbnQ7IC8vIHdoeSBub3QsIHdlIGhhdmUgdG8gZG8gc29tZXRoaW5nLi5cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gYWxnbztcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0Q291bnQodGFnSWQ6IFRhZ0lEKTogbnVtYmVyIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuY291bnRzW3RhZ0lkXSB8fCAwO1xuICAgIH1cblxuICAgIHB1YmxpYyBzZXRMaXN0T3JkZXIodGFnSWQ6IFRhZ0lELCBvcmRlcjogTGlzdEFsZ29yaXRobSk6IHZvaWQge1xuICAgICAgICAvLyBUT0RPOiBodHRwczovL2dpdGh1Yi5jb20vdmVjdG9yLWltL2VsZW1lbnQtd2ViL2lzc3Vlcy8yMzIwN1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXRMaXN0T3JkZXIodGFnSWQ6IFRhZ0lEKTogTGlzdEFsZ29yaXRobSB7XG4gICAgICAgIC8vIFRPRE86IGhhbmRsZSB1bnJlYWQgbXNncyBmaXJzdD8gaHR0cHM6Ly9naXRodWIuY29tL3ZlY3Rvci1pbS9lbGVtZW50LXdlYi9pc3N1ZXMvMjMyMDdcbiAgICAgICAgcmV0dXJuIExpc3RBbGdvcml0aG0uTmF0dXJhbDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBBZGRzIGEgZmlsdGVyIGNvbmRpdGlvbiB0byB0aGUgcm9vbSBsaXN0IHN0b3JlLiBGaWx0ZXJzIG1heSBiZSBhcHBsaWVkIGFzeW5jLFxuICAgICAqIGFuZCB0aHVzIG1pZ2h0IG5vdCBjYXVzZSBhbiB1cGRhdGUgdG8gdGhlIHN0b3JlIGltbWVkaWF0ZWx5LlxuICAgICAqIEBwYXJhbSB7SUZpbHRlckNvbmRpdGlvbn0gZmlsdGVyIFRoZSBmaWx0ZXIgY29uZGl0aW9uIHRvIGFkZC5cbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgYWRkRmlsdGVyKGZpbHRlcjogSUZpbHRlckNvbmRpdGlvbik6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICAvLyBEbyBub3RoaW5nLCB0aGUgZmlsdGVycyBhcmUgb25seSB1c2VkIGJ5IFNwYWNlV2F0Y2hlciB0byBzZWUgaWYgYSByb29tIHNob3VsZCBhcHBlYXJcbiAgICAgICAgLy8gaW4gdGhlIHJvb20gbGlzdC4gV2UgZG8gbm90IHN1cHBvcnQgYXJiaXRyYXJ5IGNvZGUgZm9yIGZpbHRlcnMgaW4gc2xpZGluZyBzeW5jLlxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJlbW92ZXMgYSBmaWx0ZXIgY29uZGl0aW9uIGZyb20gdGhlIHJvb20gbGlzdCBzdG9yZS4gSWYgdGhlIGZpbHRlciB3YXNcbiAgICAgKiBub3QgcHJldmlvdXNseSBhZGRlZCB0byB0aGUgcm9vbSBsaXN0IHN0b3JlLCB0aGlzIHdpbGwgbm8tb3AuIFRoZSBlZmZlY3RzXG4gICAgICogb2YgcmVtb3ZpbmcgYSBmaWx0ZXIgbWF5IGJlIGFwcGxpZWQgYXN5bmMgYW5kIHRoZXJlZm9yZSBtaWdodCBub3QgY2F1c2VcbiAgICAgKiBhbiB1cGRhdGUgcmlnaHQgYXdheS5cbiAgICAgKiBAcGFyYW0ge0lGaWx0ZXJDb25kaXRpb259IGZpbHRlciBUaGUgZmlsdGVyIGNvbmRpdGlvbiB0byByZW1vdmUuXG4gICAgICovXG4gICAgcHVibGljIHJlbW92ZUZpbHRlcihmaWx0ZXI6IElGaWx0ZXJDb25kaXRpb24pOiB2b2lkIHtcbiAgICAgICAgLy8gRG8gbm90aGluZywgdGhlIGZpbHRlcnMgYXJlIG9ubHkgdXNlZCBieSBTcGFjZVdhdGNoZXIgdG8gc2VlIGlmIGEgcm9vbSBzaG91bGQgYXBwZWFyXG4gICAgICAgIC8vIGluIHRoZSByb29tIGxpc3QuIFdlIGRvIG5vdCBzdXBwb3J0IGFyYml0cmFyeSBjb2RlIGZvciBmaWx0ZXJzIGluIHNsaWRpbmcgc3luYy5cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXRzIHRoZSB0YWdzIGZvciBhIHJvb20gaWRlbnRpZmllZCBieSB0aGUgc3RvcmUuIFRoZSByZXR1cm5lZCBzZXRcbiAgICAgKiBzaG91bGQgbmV2ZXIgYmUgZW1wdHksIGFuZCB3aWxsIGNvbnRhaW4gRGVmYXVsdFRhZ0lELlVudGFnZ2VkIGlmXG4gICAgICogdGhlIHN0b3JlIGlzIG5vdCBhd2FyZSBvZiBhbnkgdGFncy5cbiAgICAgKiBAcGFyYW0gcm9vbSBUaGUgcm9vbSB0byBnZXQgdGhlIHRhZ3MgZm9yLlxuICAgICAqIEByZXR1cm5zIFRoZSB0YWdzIGZvciB0aGUgcm9vbS5cbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0VGFnc0ZvclJvb20ocm9vbTogUm9vbSk6IFRhZ0lEW10ge1xuICAgICAgICAvLyBjaGVjayBhbGwgbGlzdHMgZm9yIGVhY2ggdGFnIHdlIGtub3cgYWJvdXQgYW5kIHNlZSBpZiB0aGUgcm9vbSBpcyB0aGVyZVxuICAgICAgICBjb25zdCB0YWdzOiBUYWdJRFtdID0gW107XG4gICAgICAgIGZvciAoY29uc3QgdGFnSWQgaW4gdGhpcy50YWdJZFRvU29ydEFsZ28pIHtcbiAgICAgICAgICAgIGNvbnN0IGxpc3REYXRhID0gdGhpcy5jb250ZXh0LnNsaWRpbmdTeW5jTWFuYWdlci5zbGlkaW5nU3luYz8uZ2V0TGlzdERhdGEodGFnSWQpO1xuICAgICAgICAgICAgaWYgKCFsaXN0RGF0YSkge1xuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZm9yIChjb25zdCByb29tSW5kZXggaW4gbGlzdERhdGEucm9vbUluZGV4VG9Sb29tSWQpIHtcbiAgICAgICAgICAgICAgICBjb25zdCByb29tSWQgPSBsaXN0RGF0YS5yb29tSW5kZXhUb1Jvb21JZFtyb29tSW5kZXhdO1xuICAgICAgICAgICAgICAgIGlmIChyb29tSWQgPT09IHJvb20ucm9vbUlkKSB7XG4gICAgICAgICAgICAgICAgICAgIHRhZ3MucHVzaCh0YWdJZCk7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGFncztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBNYW51YWxseSB1cGRhdGUgYSByb29tIHdpdGggYSBnaXZlbiBjYXVzZS4gVGhpcyBzaG91bGQgb25seSBiZSB1c2VkIGlmIHRoZVxuICAgICAqIHJvb20gbGlzdCBzdG9yZSB3b3VsZCBvdGhlcndpc2UgYmUgaW5jYXBhYmxlIG9mIGRvaW5nIHRoZSB1cGRhdGUgaXRzZWxmLiBOb3RlXG4gICAgICogdGhhdCB0aGlzIG1heSByYWNlIHdpdGggdGhlIHJvb20gbGlzdCdzIHJlZ3VsYXIgb3BlcmF0aW9uLlxuICAgICAqIEBwYXJhbSB7Um9vbX0gcm9vbSBUaGUgcm9vbSB0byB1cGRhdGUuXG4gICAgICogQHBhcmFtIHtSb29tVXBkYXRlQ2F1c2V9IGNhdXNlIFRoZSBjYXVzZSB0byB1cGRhdGUgZm9yLlxuICAgICAqL1xuICAgIHB1YmxpYyBhc3luYyBtYW51YWxSb29tVXBkYXRlKHJvb206IFJvb20sIGNhdXNlOiBSb29tVXBkYXRlQ2F1c2UpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgLy8gVE9ETzogdGhpcyBpcyBvbmx5IHVzZWQgd2hlbiB5b3UgZm9yZ2V0IGEgcm9vbSwgbm90IHRoYXQgaW1wb3J0YW50IGZvciBub3cuXG4gICAgfVxuXG4gICAgcHVibGljIGdldCBvcmRlcmVkTGlzdHMoKTogSVRhZ01hcCB7XG4gICAgICAgIHJldHVybiB0aGlzLnRhZ01hcDtcbiAgICB9XG5cbiAgICBwcml2YXRlIHJlZnJlc2hPcmRlcmVkTGlzdHModGFnSWQ6IHN0cmluZywgcm9vbUluZGV4VG9Sb29tSWQ6IFJlY29yZDxudW1iZXIsIHN0cmluZz4pOiB2b2lkIHtcbiAgICAgICAgY29uc3QgdGFnTWFwID0gdGhpcy50YWdNYXA7XG5cbiAgICAgICAgLy8gdGhpcyByb29tIHdpbGwgbm90IG1vdmUgZHVlIHRvIGl0IGJlaW5nIHZpZXdlZDogaXQgaXMgc3RpY2t5LiBUaGlzIGNhbiBiZSBudWxsIHRvIGluZGljYXRlXG4gICAgICAgIC8vIG5vIHN0aWNreSByb29tIGlmIHlvdSBhcmVuJ3Qgdmlld2luZyBhIHJvb20uXG4gICAgICAgIHRoaXMuc3RpY2t5Um9vbUlkID0gdGhpcy5jb250ZXh0LnJvb21WaWV3U3RvcmUuZ2V0Um9vbUlkKCk7XG4gICAgICAgIGxldCBzdGlja3lSb29tTmV3SW5kZXggPSAtMTtcbiAgICAgICAgY29uc3Qgc3RpY2t5Um9vbU9sZEluZGV4ID0gKHRhZ01hcFt0YWdJZF0gfHwgW10pLmZpbmRJbmRleCgocm9vbSk6IGJvb2xlYW4gPT4ge1xuICAgICAgICAgICAgcmV0dXJuIHJvb20ucm9vbUlkID09PSB0aGlzLnN0aWNreVJvb21JZDtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gb3JkZXIgZnJvbSBsb3cgdG8gaGlnaFxuICAgICAgICBjb25zdCBvcmRlcmVkUm9vbUluZGV4ZXMgPSBPYmplY3Qua2V5cyhyb29tSW5kZXhUb1Jvb21JZClcbiAgICAgICAgICAgIC5tYXAoKG51bVN0cikgPT4ge1xuICAgICAgICAgICAgICAgIHJldHVybiBOdW1iZXIobnVtU3RyKTtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAuc29ydCgoYSwgYikgPT4ge1xuICAgICAgICAgICAgICAgIHJldHVybiBhIC0gYjtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICBjb25zdCBzZWVuUm9vbUlkcyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICAgICAgICBjb25zdCBvcmRlcmVkUm9vbUlkcyA9IG9yZGVyZWRSb29tSW5kZXhlcy5tYXAoKGkpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHJpZCA9IHJvb21JbmRleFRvUm9vbUlkW2ldO1xuICAgICAgICAgICAgaWYgKHNlZW5Sb29tSWRzLmhhcyhyaWQpKSB7XG4gICAgICAgICAgICAgICAgbG9nZ2VyLmVycm9yKFwicm9vbSBcIiArIHJpZCArIFwiIGFscmVhZHkgaGFzIGFuIGluZGV4IHBvc2l0aW9uOiBkdXBsaWNhdGUgcm9vbSFcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBzZWVuUm9vbUlkcy5hZGQocmlkKTtcbiAgICAgICAgICAgIGlmICghcmlkKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiaW5kZXggXCIgKyBpICsgXCIgaGFzIG5vIHJvb20gSUQ6IE1hcCA9PiBcIiArIEpTT04uc3RyaW5naWZ5KHJvb21JbmRleFRvUm9vbUlkKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAocmlkID09PSB0aGlzLnN0aWNreVJvb21JZCkge1xuICAgICAgICAgICAgICAgIHN0aWNreVJvb21OZXdJbmRleCA9IGk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gcmlkO1xuICAgICAgICB9KTtcbiAgICAgICAgbG9nZ2VyLmRlYnVnKFxuICAgICAgICAgICAgYFNsaWRpbmdSb29tTGlzdFN0b3JlLnJlZnJlc2hPcmRlcmVkTGlzdHMgJHt0YWdJZH0gc3RpY2t5OiAke3RoaXMuc3RpY2t5Um9vbUlkfWAsXG4gICAgICAgICAgICBgJHtzdGlja3lSb29tT2xkSW5kZXh9IC0+ICR7c3RpY2t5Um9vbU5ld0luZGV4fWAsXG4gICAgICAgICAgICBcInJvb21zOlwiLFxuICAgICAgICAgICAgb3JkZXJlZFJvb21JZHMubGVuZ3RoIDwgMzAgPyBvcmRlcmVkUm9vbUlkcyA6IG9yZGVyZWRSb29tSWRzLmxlbmd0aCxcbiAgICAgICAgKTtcblxuICAgICAgICBpZiAodGhpcy5zdGlja3lSb29tSWQgJiYgc3RpY2t5Um9vbU9sZEluZGV4ID49IDAgJiYgc3RpY2t5Um9vbU5ld0luZGV4ID49IDApIHtcbiAgICAgICAgICAgIC8vIHRoaXMgdXBkYXRlIHdpbGwgbW92ZSB0aGlzIHN0aWNreSByb29tIGZyb20gb2xkIHRvIG5ldywgd2hpY2ggd2UgZG8gbm90IHdhbnQuXG4gICAgICAgICAgICAvLyBJbnN0ZWFkLCBrZWVwIHRoZSBzdGlja3kgcm9vbSBJRCBpbmRleCBwb3NpdGlvbiBhcyBpdCBpcywgc3dhcCBpdCB3aXRoXG4gICAgICAgICAgICAvLyB3aGF0ZXZlciB3YXMgaW4gaXRzIHBsYWNlLlxuICAgICAgICAgICAgLy8gU29tZSBzY2VuYXJpb3Mgd2l0aCBzdGlja3kgcm9vbSBTIGFuZCBidW1wIHJvb20gQiAob3RoZXIgbGV0dGVycyB1bmltcG9ydGFudCk6XG4gICAgICAgICAgICAvLyBBLCBTLCBDLCBCICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFMsIEEsIEJcbiAgICAgICAgICAgIC8vIEIsIEEsIFMsIEMgIDwtLS0tIHdpdGhvdXQgc3RpY2t5IHJvb21zIC0tLT4gQiwgUywgQVxuICAgICAgICAgICAgLy8gQiwgUywgQSwgQyAgPC0gd2l0aCBzdGlja3kgcm9vbXMgYXBwbGllZCAtPiBTLCBCLCBBXG4gICAgICAgICAgICAvLyBJbiBvdGhlciB3b3Jkcywgd2UgbmVlZCB0byBzd2FwIHBvc2l0aW9ucyB0byBrZWVwIGl0IGxvY2tlZCBpbiBwbGFjZS5cbiAgICAgICAgICAgIGNvbnN0IGluV2F5Um9vbUlkID0gb3JkZXJlZFJvb21JZHNbc3RpY2t5Um9vbU9sZEluZGV4XTtcbiAgICAgICAgICAgIG9yZGVyZWRSb29tSWRzW3N0aWNreVJvb21PbGRJbmRleF0gPSB0aGlzLnN0aWNreVJvb21JZDtcbiAgICAgICAgICAgIG9yZGVyZWRSb29tSWRzW3N0aWNreVJvb21OZXdJbmRleF0gPSBpbldheVJvb21JZDtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIG5vdyBzZXQgdGhlIHJvb21zXG4gICAgICAgIGNvbnN0IHJvb21zOiBSb29tW10gPSBbXTtcbiAgICAgICAgb3JkZXJlZFJvb21JZHMuZm9yRWFjaCgocm9vbUlkKSA9PiB7XG4gICAgICAgICAgICBjb25zdCByb29tID0gdGhpcy5tYXRyaXhDbGllbnQ/LmdldFJvb20ocm9vbUlkKTtcbiAgICAgICAgICAgIGlmICghcm9vbSkge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJvb21zLnB1c2gocm9vbSk7XG4gICAgICAgIH0pO1xuICAgICAgICB0YWdNYXBbdGFnSWRdID0gcm9vbXM7XG4gICAgICAgIHRoaXMudGFnTWFwID0gdGFnTWFwO1xuICAgIH1cblxuICAgIHByaXZhdGUgb25TbGlkaW5nU3luY0xpc3RVcGRhdGUodGFnSWQ6IHN0cmluZywgam9pbkNvdW50OiBudW1iZXIsIHJvb21JbmRleFRvUm9vbUlkOiBSZWNvcmQ8bnVtYmVyLCBzdHJpbmc+KTogdm9pZCB7XG4gICAgICAgIHRoaXMuY291bnRzW3RhZ0lkXSA9IGpvaW5Db3VudDtcbiAgICAgICAgdGhpcy5yZWZyZXNoT3JkZXJlZExpc3RzKHRhZ0lkLCByb29tSW5kZXhUb1Jvb21JZCk7XG4gICAgICAgIC8vIGxldCB0aGUgVUkgdXBkYXRlXG4gICAgICAgIHRoaXMuZW1pdChMSVNUU19VUERBVEVfRVZFTlQpO1xuICAgIH1cblxuICAgIHByaXZhdGUgb25Sb29tVmlld1N0b3JlVXBkYXRlZCgpOiB2b2lkIHtcbiAgICAgICAgLy8gd2Ugb25seSBjYXJlIGFib3V0IHRoaXMgdG8ga25vdyB3aGVuIHRoZSB1c2VyIGhhcyBjbGlja2VkIG9uIGEgcm9vbSB0byBzZXQgdGhlIHN0aWNraW5lc3MgdmFsdWVcbiAgICAgICAgaWYgKHRoaXMuY29udGV4dC5yb29tVmlld1N0b3JlLmdldFJvb21JZCgpID09PSB0aGlzLnN0aWNreVJvb21JZCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IGhhc1VwZGF0ZWRBbnlMaXN0ID0gZmFsc2U7XG5cbiAgICAgICAgLy8gZXZlcnkgbGlzdCB3aXRoIHRoZSBPTEQgc3RpY2t5IHJvb20gSUQgbmVlZHMgdG8gYmUgcmVzb3J0ZWQgYmVjYXVzZSBpdCBub3cgbmVlZHMgdG8gdGFrZVxuICAgICAgICAvLyBpdHMgcHJvcGVyIHBsYWNlIGFzIGl0IGlzIG5vIGxvbmdlciBzdGlja3kuIFRoZSBuZXdseSBzdGlja3kgcm9vbSBjYW4gcmVtYWluIHRoZSBzYW1lIHRob3VnaCxcbiAgICAgICAgLy8gYXMgd2Ugb25seSBhY3R1YWxseSBjYXJlIGFib3V0IGl0cyBzdGlja3kgc3RhdHVzIHdoZW4gd2UgZ2V0IGxpc3QgdXBkYXRlcy5cbiAgICAgICAgY29uc3Qgb2xkU3RpY2t5Um9vbSA9IHRoaXMuc3RpY2t5Um9vbUlkO1xuICAgICAgICAvLyBpdCdzIG5vdCBzYWZlIHRvIGNoZWNrIHRoZSBkYXRhIGluIHNsaWRpbmdTeW5jIGFzIGl0IGlzIHRyYWNraW5nIHRoZSBzZXJ2ZXIncyB2aWV3IG9mIHRoZVxuICAgICAgICAvLyByb29tIGxpc3QuIFRoZXJlJ3MgYW4gZWRnZSBjYXNlIHdoZXJlYnkgdGhlIHN0aWNreSByb29tIGhhcyBnb25lIG91dHNpZGUgdGhlIHdpbmRvdyBhbmQgc29cbiAgICAgICAgLy8gd291bGQgbm90IGJlIHByZXNlbnQgaW4gdGhlIHJvb21JbmRleFRvUm9vbUlkIG1hcCBhbnltb3JlLCBhbmQgaGVuY2UgY2xpY2tpbmcgYXdheSBmcm9tIGl0XG4gICAgICAgIC8vIHdpbGwgbWFrZSBpdCBkaXNhcHBlYXIgZXZlbnR1YWxseS4gV2UgbmVlZCB0byBjaGVjayBvcmRlcmVkTGlzdHMgYXMgdGhhdCBpcyB0aGUgYWN0dWFsXG4gICAgICAgIC8vIHNvcnRlZCByZW5kZXJhYmxlIGxpc3Qgb2Ygcm9vbXMgd2hpY2ggc3RpY2t5IHJvb21zIGFwcGx5IHRvLlxuICAgICAgICBmb3IgKGNvbnN0IHRhZ0lkIGluIHRoaXMub3JkZXJlZExpc3RzKSB7XG4gICAgICAgICAgICBjb25zdCBsaXN0ID0gdGhpcy5vcmRlcmVkTGlzdHNbdGFnSWRdO1xuICAgICAgICAgICAgY29uc3Qgcm9vbSA9IGxpc3QuZmluZCgocm9vbSkgPT4ge1xuICAgICAgICAgICAgICAgIHJldHVybiByb29tLnJvb21JZCA9PT0gb2xkU3RpY2t5Um9vbTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgaWYgKHJvb20pIHtcbiAgICAgICAgICAgICAgICAvLyByZXNvcnQgaXQgYmFzZWQgb24gdGhlIHNsaWRpbmdTeW5jIHZpZXcgb2YgdGhlIGxpc3QuIFRoaXMgbWF5IGNhdXNlIHRoaXMgb2xkIHN0aWNreVxuICAgICAgICAgICAgICAgIC8vIHJvb20gdG8gY2Vhc2UgdG8gZXhpc3QuXG4gICAgICAgICAgICAgICAgY29uc3QgbGlzdERhdGEgPSB0aGlzLmNvbnRleHQuc2xpZGluZ1N5bmNNYW5hZ2VyLnNsaWRpbmdTeW5jPy5nZXRMaXN0RGF0YSh0YWdJZCk7XG4gICAgICAgICAgICAgICAgaWYgKCFsaXN0RGF0YSkge1xuICAgICAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdGhpcy5yZWZyZXNoT3JkZXJlZExpc3RzKHRhZ0lkLCBsaXN0RGF0YS5yb29tSW5kZXhUb1Jvb21JZCk7XG4gICAgICAgICAgICAgICAgaGFzVXBkYXRlZEFueUxpc3QgPSB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIC8vIGluIHRoZSBldmVudCB3ZSBkaWRuJ3QgY2FsbCByZWZyZXNoT3JkZXJlZExpc3RzLCBpdCBoZWxwcyB0byBzdGlsbCByZW1lbWJlciB0aGUgc3RpY2t5IHJvb20gSUQuXG4gICAgICAgIHRoaXMuc3RpY2t5Um9vbUlkID0gdGhpcy5jb250ZXh0LnJvb21WaWV3U3RvcmUuZ2V0Um9vbUlkKCk7XG5cbiAgICAgICAgaWYgKGhhc1VwZGF0ZWRBbnlMaXN0KSB7XG4gICAgICAgICAgICB0aGlzLmVtaXQoTElTVFNfVVBEQVRFX0VWRU5UKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByb3RlY3RlZCBhc3luYyBvblJlYWR5KCk6IFByb21pc2U8YW55PiB7XG4gICAgICAgIGxvZ2dlci5pbmZvKFwiU2xpZGluZ1Jvb21MaXN0U3RvcmUub25SZWFkeVwiKTtcbiAgICAgICAgLy8gcGVybWFuZW50IGxpc3RlbmVyczogbmV2ZXIgZ2V0IGRlc3Ryb3llZC4gQ291bGQgYmUgYW4gaXNzdWUgaWYgd2Ugd2FudCB0byB0ZXN0IHRoaXMgaW4gaXNvbGF0aW9uLlxuICAgICAgICB0aGlzLmNvbnRleHQuc2xpZGluZ1N5bmNNYW5hZ2VyLnNsaWRpbmdTeW5jIS5vbihTbGlkaW5nU3luY0V2ZW50Lkxpc3QsIHRoaXMub25TbGlkaW5nU3luY0xpc3RVcGRhdGUuYmluZCh0aGlzKSk7XG4gICAgICAgIHRoaXMuY29udGV4dC5yb29tVmlld1N0b3JlLmFkZExpc3RlbmVyKFVQREFURV9FVkVOVCwgdGhpcy5vblJvb21WaWV3U3RvcmVVcGRhdGVkLmJpbmQodGhpcykpO1xuICAgICAgICB0aGlzLmNvbnRleHQuc3BhY2VTdG9yZS5vbihVUERBVEVfU0VMRUNURURfU1BBQ0UsIHRoaXMub25TZWxlY3RlZFNwYWNlVXBkYXRlZC5iaW5kKHRoaXMpKTtcbiAgICAgICAgaWYgKHRoaXMuY29udGV4dC5zcGFjZVN0b3JlLmFjdGl2ZVNwYWNlKSB7XG4gICAgICAgICAgICB0aGlzLm9uU2VsZWN0ZWRTcGFjZVVwZGF0ZWQodGhpcy5jb250ZXh0LnNwYWNlU3RvcmUuYWN0aXZlU3BhY2UsIGZhbHNlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIHNsaWRpbmcgc3luYyBoYXMgYW4gaW5pdGlhbCByZXNwb25zZSBmb3Igc3BhY2VzLiBOb3cgcmVxdWVzdCBhbGwgdGhlIGxpc3RzLlxuICAgICAgICAvLyBXZSBkbyB0aGUgc3BhY2VzIGxpc3QgX2ZpcnN0XyB0byBhdm9pZCBwb3RlbnRpYWwgZmxpY2tlcmluZyBvbiBEZWZhdWx0VGFnSUQuVW50YWdnZWQgbGlzdFxuICAgICAgICAvLyB3aGljaCB3b3VsZCBiZSBjYXVzZWQgYnkgaW5pdGlhbGx5IGhhdmluZyBubyBgc3BhY2VzYCBmaWx0ZXIgc2V0LCBhbmQgdGhlbiBzdWRkZW5seSBzZXR0aW5nIG9uZS5cbiAgICAgICAgT3JkZXJlZERlZmF1bHRUYWdJRHMuZm9yRWFjaCgodGFnSWQpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGZpbHRlciA9IGZpbHRlckNvbmRpdGlvbnNbdGFnSWRdO1xuICAgICAgICAgICAgaWYgKCFmaWx0ZXIpIHtcbiAgICAgICAgICAgICAgICBsb2dnZXIuaW5mbyhcIlNsaWRpbmdSb29tTGlzdFN0b3JlLm9uUmVhZHkgdW5zdXBwb3J0ZWQgbGlzdCBcIiwgdGFnSWQpO1xuICAgICAgICAgICAgICAgIHJldHVybjsgLy8gd2UgZG8gbm90IHN1cHBvcnQgdGhpcyBsaXN0IHlldC5cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IHNvcnQgPSBTb3J0QWxnb3JpdGhtLlJlY2VudDsgLy8gZGVmYXVsdCB0byByZWNlbmN5IHNvcnQsIFRPRE86IHJlYWQgZnJvbSBjb25maWdcbiAgICAgICAgICAgIHRoaXMudGFnSWRUb1NvcnRBbGdvW3RhZ0lkXSA9IHNvcnQ7XG4gICAgICAgICAgICB0aGlzLmVtaXQoTElTVFNfTE9BRElOR19FVkVOVCwgdGFnSWQsIHRydWUpO1xuICAgICAgICAgICAgdGhpcy5jb250ZXh0LnNsaWRpbmdTeW5jTWFuYWdlclxuICAgICAgICAgICAgICAgIC5lbnN1cmVMaXN0UmVnaXN0ZXJlZCh0YWdJZCwge1xuICAgICAgICAgICAgICAgICAgICBmaWx0ZXJzOiBmaWx0ZXIsXG4gICAgICAgICAgICAgICAgICAgIHNvcnQ6IFNsaWRpbmdTeW5jU29ydFRvRmlsdGVyW3NvcnRdLFxuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLnRoZW4oKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmVtaXQoTElTVFNfTE9BRElOR19FVkVOVCwgdGFnSWQsIGZhbHNlKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBvblNlbGVjdGVkU3BhY2VVcGRhdGVkID0gKGFjdGl2ZVNwYWNlOiBTcGFjZUtleSwgYWxsUm9vbXNJbkhvbWU6IGJvb2xlYW4pOiB2b2lkID0+IHtcbiAgICAgICAgbG9nZ2VyLmluZm8oXCJTbGlkaW5nUm9vbUxpc3RTdG9yZS5vblNlbGVjdGVkU3BhY2VVcGRhdGVkXCIsIGFjdGl2ZVNwYWNlKTtcbiAgICAgICAgLy8gdXBkYXRlIHRoZSB1bnRhZ2dlZCBmaWx0ZXJcbiAgICAgICAgY29uc3QgdGFnSWQgPSBEZWZhdWx0VGFnSUQuVW50YWdnZWQ7XG4gICAgICAgIGNvbnN0IGZpbHRlcnMgPSBmaWx0ZXJDb25kaXRpb25zW3RhZ0lkXTtcbiAgICAgICAgY29uc3Qgb2xkU3BhY2UgPSBmaWx0ZXJzLnNwYWNlcz8uWzBdO1xuICAgICAgICBmaWx0ZXJzLnNwYWNlcyA9IGFjdGl2ZVNwYWNlICYmIGFjdGl2ZVNwYWNlICE9IE1ldGFTcGFjZS5Ib21lID8gW2FjdGl2ZVNwYWNlXSA6IHVuZGVmaW5lZDtcbiAgICAgICAgaWYgKG9sZFNwYWNlICE9PSBhY3RpdmVTcGFjZSkge1xuICAgICAgICAgICAgLy8gaW5jbHVkZSBzdWJzcGFjZXMgaW4gdGhpcyBsaXN0XG4gICAgICAgICAgICB0aGlzLmNvbnRleHQuc3BhY2VTdG9yZS50cmF2ZXJzZVNwYWNlKFxuICAgICAgICAgICAgICAgIGFjdGl2ZVNwYWNlLFxuICAgICAgICAgICAgICAgIChyb29tSWQ6IHN0cmluZykgPT4ge1xuICAgICAgICAgICAgICAgICAgICBpZiAocm9vbUlkID09PSBhY3RpdmVTcGFjZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGlmICghZmlsdGVycy5zcGFjZXMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcnMuc3BhY2VzID0gW107XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgZmlsdGVycy5zcGFjZXMucHVzaChyb29tSWQpOyAvLyBhZGQgc3Vic3BhY2VcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIGZhbHNlLFxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgdGhpcy5lbWl0KExJU1RTX0xPQURJTkdfRVZFTlQsIHRhZ0lkLCB0cnVlKTtcbiAgICAgICAgICAgIHRoaXMuY29udGV4dC5zbGlkaW5nU3luY01hbmFnZXJcbiAgICAgICAgICAgICAgICAuZW5zdXJlTGlzdFJlZ2lzdGVyZWQodGFnSWQsIHtcbiAgICAgICAgICAgICAgICAgICAgZmlsdGVyczogZmlsdGVycyxcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIC50aGVuKCgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5lbWl0KExJU1RTX0xPQURJTkdfRVZFTlQsIHRhZ0lkLCBmYWxzZSk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgLy8gSW50ZW5kZWQgZm9yIHRlc3QgdXNhZ2VcbiAgICBwdWJsaWMgYXN5bmMgcmVzZXRTdG9yZSgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgLy8gVGVzdCBmdW5jdGlvblxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJlZ2VuZXJhdGVzIHRoZSByb29tIHdob2xlIHJvb20gbGlzdCwgZGlzY2FyZGluZyBhbnkgcHJldmlvdXMgcmVzdWx0cy5cbiAgICAgKlxuICAgICAqIE5vdGU6IFRoaXMgaXMgb25seSBleHBvc2VkIGV4dGVybmFsbHkgZm9yIHRoZSB0ZXN0cy4gRG8gbm90IGNhbGwgdGhpcyBmcm9tIHdpdGhpblxuICAgICAqIHRoZSBhcHAuXG4gICAgICogQHBhcmFtIHRyaWdnZXIgU2V0IHRvIGZhbHNlIHRvIHByZXZlbnQgYSBsaXN0IHVwZGF0ZSBmcm9tIGJlaW5nIHNlbnQuIFNob3VsZCBvbmx5XG4gICAgICogYmUgdXNlZCBpZiB0aGUgY2FsbGluZyBjb2RlIHdpbGwgbWFudWFsbHkgdHJpZ2dlciB0aGUgdXBkYXRlLlxuICAgICAqL1xuICAgIHB1YmxpYyByZWdlbmVyYXRlQWxsTGlzdHMoeyB0cmlnZ2VyID0gdHJ1ZSB9KTogdm9pZCB7XG4gICAgICAgIC8vIFRlc3QgZnVuY3Rpb25cbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgYXN5bmMgb25Ob3RSZWFkeSgpOiBQcm9taXNlPGFueT4ge1xuICAgICAgICBhd2FpdCB0aGlzLnJlc2V0U3RvcmUoKTtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgYXN5bmMgb25BY3Rpb24ocGF5bG9hZDogQWN0aW9uUGF5bG9hZCk6IFByb21pc2U8dm9pZD4ge31cbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7QUFTQSxJQUFBQSxPQUFBLEdBQUFDLE9BQUE7QUFDQSxJQUFBQyxZQUFBLEdBQUFELE9BQUE7QUFHQSxJQUFBRSxPQUFBLEdBQUFGLE9BQUE7QUFDQSxJQUFBRyxRQUFBLEdBQUFILE9BQUE7QUFJQSxJQUFBSSxxQkFBQSxHQUFBSixPQUFBO0FBQ0EsSUFBQUssVUFBQSxHQUFBTCxPQUFBO0FBQ0EsSUFBQU0sT0FBQSxHQUFBTixPQUFBO0FBQ0EsSUFBQU8sY0FBQSxHQUFBUCxPQUFBO0FBQ0EsSUFBQVEsV0FBQSxHQUFBUixPQUFBO0FBdEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQXVCTyxNQUFNUyx1QkFBd0QsR0FBQUMsT0FBQSxDQUFBRCx1QkFBQSxHQUFHO0VBQ3BFLENBQUNFLHNCQUFhLENBQUNDLFVBQVUsR0FBRyxDQUFDLFNBQVMsRUFBRSxZQUFZLENBQUM7RUFDckQsQ0FBQ0Qsc0JBQWEsQ0FBQ0UsTUFBTSxHQUFHLENBQUMsdUJBQXVCLEVBQUUsWUFBWSxDQUFDO0VBQy9ELENBQUNGLHNCQUFhLENBQUNHLE1BQU0sR0FBRyxDQUFDLFlBQVk7QUFDekMsQ0FBQztBQUVELE1BQU1DLGdCQUE4QyxHQUFHO0VBQ25ELENBQUNDLG9CQUFZLENBQUNDLE1BQU0sR0FBRztJQUNuQkMsU0FBUyxFQUFFO0VBQ2YsQ0FBQztFQUNELENBQUNGLG9CQUFZLENBQUNHLFNBQVMsR0FBRztJQUN0QkMsSUFBSSxFQUFFLENBQUMsYUFBYTtFQUN4QixD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