matrix-react-sdk
Version:
SDK for matrix.org using React
329 lines (261 loc) • 46.2 kB
JavaScript
"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 _events = _interopRequireDefault(require("events"));
var _groups = require("../groups");
var _FlairStore = _interopRequireDefault(require("./FlairStore"));
var _MatrixClientPeg = require("../MatrixClientPeg");
var _dispatcher = _interopRequireDefault(require("../dispatcher/dispatcher"));
/*
Copyright 2017 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
function parseMembersResponse(response) {
return response.chunk.map(apiMember => (0, _groups.groupMemberFromApiObject)(apiMember));
}
function parseRoomsResponse(response) {
return response.chunk.map(apiRoom => (0, _groups.groupRoomFromApiObject)(apiRoom));
} // The number of ongoing group requests
let ongoingRequestCount = 0; // This has arbitrarily been set to a small number to lower the priority
// of doing group-related requests because we care about other important
// requests like hitting /sync.
const LIMIT = 3; // Maximum number of ongoing group requests
// FIFO queue of functions to call in the backlog
const backlogQueue = [// () => {...}
]; // Pull from the FIFO queue
function checkBacklog() {
const item = backlogQueue.shift();
if (typeof item === 'function') item();
} // Limit the maximum number of ongoing promises returned by fn to LIMIT and
// use a FIFO queue to handle the backlog.
async function limitConcurrency(fn) {
if (ongoingRequestCount >= LIMIT) {
// Enqueue this request for later execution
await new Promise((resolve, reject) => {
backlogQueue.push(resolve);
});
}
ongoingRequestCount++;
try {
return await fn();
} catch (err) {
// We explicitly do not handle the error here, but let it propogate.
throw err;
} finally {
ongoingRequestCount--;
checkBacklog();
}
}
/**
* Global store for tracking group summary, members, invited members and rooms.
*/
class GroupStore extends _events.default {
constructor() {
super();
(0, _defineProperty2.default)(this, "STATE_KEY", {
GroupMembers: 'GroupMembers',
GroupInvitedMembers: 'GroupInvitedMembers',
Summary: 'Summary',
GroupRooms: 'GroupRooms'
});
this._state = {};
this._state[this.STATE_KEY.Summary] = {};
this._state[this.STATE_KEY.GroupRooms] = {};
this._state[this.STATE_KEY.GroupMembers] = {};
this._state[this.STATE_KEY.GroupInvitedMembers] = {};
this._ready = {};
this._ready[this.STATE_KEY.Summary] = {};
this._ready[this.STATE_KEY.GroupRooms] = {};
this._ready[this.STATE_KEY.GroupMembers] = {};
this._ready[this.STATE_KEY.GroupInvitedMembers] = {};
this._fetchResourcePromise = {
[this.STATE_KEY.Summary]: {},
[this.STATE_KEY.GroupRooms]: {},
[this.STATE_KEY.GroupMembers]: {},
[this.STATE_KEY.GroupInvitedMembers]: {}
};
this._resourceFetcher = {
[this.STATE_KEY.Summary]: groupId => {
return limitConcurrency(() => _MatrixClientPeg.MatrixClientPeg.get().getGroupSummary(groupId));
},
[this.STATE_KEY.GroupRooms]: groupId => {
return limitConcurrency(() => _MatrixClientPeg.MatrixClientPeg.get().getGroupRooms(groupId).then(parseRoomsResponse));
},
[this.STATE_KEY.GroupMembers]: groupId => {
return limitConcurrency(() => _MatrixClientPeg.MatrixClientPeg.get().getGroupUsers(groupId).then(parseMembersResponse));
},
[this.STATE_KEY.GroupInvitedMembers]: groupId => {
return limitConcurrency(() => _MatrixClientPeg.MatrixClientPeg.get().getGroupInvitedUsers(groupId).then(parseMembersResponse));
}
};
}
_fetchResource(stateKey, groupId) {
// Ongoing request, ignore
if (this._fetchResourcePromise[stateKey][groupId]) return;
const clientPromise = this._resourceFetcher[stateKey](groupId); // Indicate ongoing request
this._fetchResourcePromise[stateKey][groupId] = clientPromise;
clientPromise.then(result => {
this._state[stateKey][groupId] = result;
this._ready[stateKey][groupId] = true;
this._notifyListeners();
}).catch(err => {
// Invited users not visible to non-members
if (stateKey === this.STATE_KEY.GroupInvitedMembers && err.httpStatus === 403) {
return;
}
console.error(`Failed to get resource ${stateKey} for ${groupId}`, err);
this.emit('error', err, groupId, stateKey);
}).finally(() => {
// Indicate finished request, allow for future fetches
delete this._fetchResourcePromise[stateKey][groupId];
});
return clientPromise;
}
_notifyListeners() {
this.emit('update');
}
/**
* Register a listener to recieve updates from the store. This also
* immediately triggers an update to send the current state of the
* store (which could be the initial state).
*
* If a group ID is specified, this also causes a fetch of all data
* of the specified group, which might cause 4 separate HTTP
* requests, but only if said requests aren't already ongoing.
*
* @param {string?} groupId the ID of the group to fetch data for.
* Optional.
* @param {function} fn the function to call when the store updates.
* @return {Object} tok a registration "token" with a single
* property `unregister`, a function that can
* be called to unregister the listener such
* that it won't be called any more.
*/
registerListener(groupId, fn) {
this.on('update', fn); // Call to set initial state (before fetching starts)
this.emit('update');
if (groupId) {
this._fetchResource(this.STATE_KEY.Summary, groupId);
this._fetchResource(this.STATE_KEY.GroupRooms, groupId);
this._fetchResource(this.STATE_KEY.GroupMembers, groupId);
this._fetchResource(this.STATE_KEY.GroupInvitedMembers, groupId);
} // Similar to the Store of flux/utils, we return a "token" that
// can be used to unregister the listener.
return {
unregister: () => {
this.unregisterListener(fn);
}
};
}
unregisterListener(fn) {
this.removeListener('update', fn);
}
isStateReady(groupId, id) {
return this._ready[id][groupId];
}
getGroupIdsForRoomId(roomId) {
const groupIds = Object.keys(this._state[this.STATE_KEY.GroupRooms]);
return groupIds.filter(groupId => {
const rooms = this._state[this.STATE_KEY.GroupRooms][groupId] || [];
return rooms.some(room => room.roomId === roomId);
});
}
getSummary(groupId) {
return this._state[this.STATE_KEY.Summary][groupId] || {};
}
getGroupRooms(groupId) {
return this._state[this.STATE_KEY.GroupRooms][groupId] || [];
}
getGroupMembers(groupId) {
return this._state[this.STATE_KEY.GroupMembers][groupId] || [];
}
getGroupInvitedMembers(groupId) {
return this._state[this.STATE_KEY.GroupInvitedMembers][groupId] || [];
}
getGroupPublicity(groupId) {
return (this._state[this.STATE_KEY.Summary][groupId] || {}).user ? (this._state[this.STATE_KEY.Summary][groupId] || {}).user.is_publicised : null;
}
isUserPrivileged(groupId) {
return (this._state[this.STATE_KEY.Summary][groupId] || {}).user ? (this._state[this.STATE_KEY.Summary][groupId] || {}).user.is_privileged : null;
}
refreshGroupRooms(groupId) {
return this._fetchResource(this.STATE_KEY.GroupRooms, groupId);
}
refreshGroupMembers(groupId) {
return this._fetchResource(this.STATE_KEY.GroupMembers, groupId);
}
addRoomToGroup(groupId, roomId, isPublic) {
return _MatrixClientPeg.MatrixClientPeg.get().addRoomToGroup(groupId, roomId, isPublic).then(this._fetchResource.bind(this, this.STATE_KEY.GroupRooms, groupId));
}
updateGroupRoomVisibility(groupId, roomId, isPublic) {
return _MatrixClientPeg.MatrixClientPeg.get().updateGroupRoomVisibility(groupId, roomId, isPublic).then(this._fetchResource.bind(this, this.STATE_KEY.GroupRooms, groupId));
}
removeRoomFromGroup(groupId, roomId) {
return _MatrixClientPeg.MatrixClientPeg.get().removeRoomFromGroup(groupId, roomId) // Room might be in the summary, refresh just in case
.then(this._fetchResource.bind(this, this.STATE_KEY.Summary, groupId)).then(this._fetchResource.bind(this, this.STATE_KEY.GroupRooms, groupId));
}
inviteUserToGroup(groupId, userId) {
return _MatrixClientPeg.MatrixClientPeg.get().inviteUserToGroup(groupId, userId).then(this._fetchResource.bind(this, this.STATE_KEY.GroupInvitedMembers, groupId));
}
acceptGroupInvite(groupId) {
return _MatrixClientPeg.MatrixClientPeg.get().acceptGroupInvite(groupId) // The user should now be able to access (personal) group settings
.then(this._fetchResource.bind(this, this.STATE_KEY.Summary, groupId)) // The user might be able to see more rooms now
.then(this._fetchResource.bind(this, this.STATE_KEY.GroupRooms, groupId)) // The user should now appear as a member
.then(this._fetchResource.bind(this, this.STATE_KEY.GroupMembers, groupId)) // The user should now not appear as an invited member
.then(this._fetchResource.bind(this, this.STATE_KEY.GroupInvitedMembers, groupId));
}
joinGroup(groupId) {
return _MatrixClientPeg.MatrixClientPeg.get().joinGroup(groupId) // The user should now be able to access (personal) group settings
.then(this._fetchResource.bind(this, this.STATE_KEY.Summary, groupId)) // The user might be able to see more rooms now
.then(this._fetchResource.bind(this, this.STATE_KEY.GroupRooms, groupId)) // The user should now appear as a member
.then(this._fetchResource.bind(this, this.STATE_KEY.GroupMembers, groupId)) // The user should now not appear as an invited member
.then(this._fetchResource.bind(this, this.STATE_KEY.GroupInvitedMembers, groupId));
}
leaveGroup(groupId) {
// ensure the tag panel filter is cleared if the group was selected
_dispatcher.default.dispatch({
action: "deselect_tags",
tag: groupId
});
return _MatrixClientPeg.MatrixClientPeg.get().leaveGroup(groupId) // The user should now not be able to access group settings
.then(this._fetchResource.bind(this, this.STATE_KEY.Summary, groupId)) // The user might only be able to see a subset of rooms now
.then(this._fetchResource.bind(this, this.STATE_KEY.GroupRooms, groupId)) // The user should now not appear as a member
.then(this._fetchResource.bind(this, this.STATE_KEY.GroupMembers, groupId));
}
addRoomToGroupSummary(groupId, roomId, categoryId) {
return _MatrixClientPeg.MatrixClientPeg.get().addRoomToGroupSummary(groupId, roomId, categoryId).then(this._fetchResource.bind(this, this.STATE_KEY.Summary, groupId));
}
addUserToGroupSummary(groupId, userId, roleId) {
return _MatrixClientPeg.MatrixClientPeg.get().addUserToGroupSummary(groupId, userId, roleId).then(this._fetchResource.bind(this, this.STATE_KEY.Summary, groupId));
}
removeRoomFromGroupSummary(groupId, roomId) {
return _MatrixClientPeg.MatrixClientPeg.get().removeRoomFromGroupSummary(groupId, roomId).then(this._fetchResource.bind(this, this.STATE_KEY.Summary, groupId));
}
removeUserFromGroupSummary(groupId, userId) {
return _MatrixClientPeg.MatrixClientPeg.get().removeUserFromGroupSummary(groupId, userId).then(this._fetchResource.bind(this, this.STATE_KEY.Summary, groupId));
}
setGroupPublicity(groupId, isPublished) {
return _MatrixClientPeg.MatrixClientPeg.get().setGroupPublicity(groupId, isPublished).then(() => {
_FlairStore.default.invalidatePublicisedGroups(_MatrixClientPeg.MatrixClientPeg.get().credentials.userId);
}).then(this._fetchResource.bind(this, this.STATE_KEY.Summary, groupId));
}
}
let singletonGroupStore = null;
if (!singletonGroupStore) {
singletonGroupStore = new GroupStore();
}
var _default = singletonGroupStore;
exports.default = _default;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zdG9yZXMvR3JvdXBTdG9yZS5qcyJdLCJuYW1lcyI6WyJwYXJzZU1lbWJlcnNSZXNwb25zZSIsInJlc3BvbnNlIiwiY2h1bmsiLCJtYXAiLCJhcGlNZW1iZXIiLCJwYXJzZVJvb21zUmVzcG9uc2UiLCJhcGlSb29tIiwib25nb2luZ1JlcXVlc3RDb3VudCIsIkxJTUlUIiwiYmFja2xvZ1F1ZXVlIiwiY2hlY2tCYWNrbG9nIiwiaXRlbSIsInNoaWZ0IiwibGltaXRDb25jdXJyZW5jeSIsImZuIiwiUHJvbWlzZSIsInJlc29sdmUiLCJyZWplY3QiLCJwdXNoIiwiZXJyIiwiR3JvdXBTdG9yZSIsIkV2ZW50RW1pdHRlciIsImNvbnN0cnVjdG9yIiwiR3JvdXBNZW1iZXJzIiwiR3JvdXBJbnZpdGVkTWVtYmVycyIsIlN1bW1hcnkiLCJHcm91cFJvb21zIiwiX3N0YXRlIiwiU1RBVEVfS0VZIiwiX3JlYWR5IiwiX2ZldGNoUmVzb3VyY2VQcm9taXNlIiwiX3Jlc291cmNlRmV0Y2hlciIsImdyb3VwSWQiLCJNYXRyaXhDbGllbnRQZWciLCJnZXQiLCJnZXRHcm91cFN1bW1hcnkiLCJnZXRHcm91cFJvb21zIiwidGhlbiIsImdldEdyb3VwVXNlcnMiLCJnZXRHcm91cEludml0ZWRVc2VycyIsIl9mZXRjaFJlc291cmNlIiwic3RhdGVLZXkiLCJjbGllbnRQcm9taXNlIiwicmVzdWx0IiwiX25vdGlmeUxpc3RlbmVycyIsImNhdGNoIiwiaHR0cFN0YXR1cyIsImNvbnNvbGUiLCJlcnJvciIsImVtaXQiLCJmaW5hbGx5IiwicmVnaXN0ZXJMaXN0ZW5lciIsIm9uIiwidW5yZWdpc3RlciIsInVucmVnaXN0ZXJMaXN0ZW5lciIsInJlbW92ZUxpc3RlbmVyIiwiaXNTdGF0ZVJlYWR5IiwiaWQiLCJnZXRHcm91cElkc0ZvclJvb21JZCIsInJvb21JZCIsImdyb3VwSWRzIiwiT2JqZWN0Iiwia2V5cyIsImZpbHRlciIsInJvb21zIiwic29tZSIsInJvb20iLCJnZXRTdW1tYXJ5IiwiZ2V0R3JvdXBNZW1iZXJzIiwiZ2V0R3JvdXBJbnZpdGVkTWVtYmVycyIsImdldEdyb3VwUHVibGljaXR5IiwidXNlciIsImlzX3B1YmxpY2lzZWQiLCJpc1VzZXJQcml2aWxlZ2VkIiwiaXNfcHJpdmlsZWdlZCIsInJlZnJlc2hHcm91cFJvb21zIiwicmVmcmVzaEdyb3VwTWVtYmVycyIsImFkZFJvb21Ub0dyb3VwIiwiaXNQdWJsaWMiLCJiaW5kIiwidXBkYXRlR3JvdXBSb29tVmlzaWJpbGl0eSIsInJlbW92ZVJvb21Gcm9tR3JvdXAiLCJpbnZpdGVVc2VyVG9Hcm91cCIsInVzZXJJZCIsImFjY2VwdEdyb3VwSW52aXRlIiwiam9pbkdyb3VwIiwibGVhdmVHcm91cCIsImRpcyIsImRpc3BhdGNoIiwiYWN0aW9uIiwidGFnIiwiYWRkUm9vbVRvR3JvdXBTdW1tYXJ5IiwiY2F0ZWdvcnlJZCIsImFkZFVzZXJUb0dyb3VwU3VtbWFyeSIsInJvbGVJZCIsInJlbW92ZVJvb21Gcm9tR3JvdXBTdW1tYXJ5IiwicmVtb3ZlVXNlckZyb21Hcm91cFN1bW1hcnkiLCJzZXRHcm91cFB1YmxpY2l0eSIsImlzUHVibGlzaGVkIiwiRmxhaXJTdG9yZSIsImludmFsaWRhdGVQdWJsaWNpc2VkR3JvdXBzIiwiY3JlZGVudGlhbHMiLCJzaW5nbGV0b25Hcm91cFN0b3JlIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7OztBQWdCQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFwQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBUUEsU0FBU0Esb0JBQVQsQ0FBOEJDLFFBQTlCLEVBQXdDO0FBQ3BDLFNBQU9BLFFBQVEsQ0FBQ0MsS0FBVCxDQUFlQyxHQUFmLENBQW9CQyxTQUFELElBQWUsc0NBQXlCQSxTQUF6QixDQUFsQyxDQUFQO0FBQ0g7O0FBRUQsU0FBU0Msa0JBQVQsQ0FBNEJKLFFBQTVCLEVBQXNDO0FB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dURPLE9BQXZELENBRkgsQ0FBUDtBQUdIOztBQUVEZ0UsRUFBQUEsMEJBQTBCLENBQUNoRSxPQUFELEVBQVVtRCxNQUFWLEVBQWtCO0FBQ3hDLFdBQU9sRCxpQ0FBZ0JDLEdBQWhCLEdBQ0Y4RCwwQkFERSxDQUN5QmhFLE9BRHpCLEVBQ2tDbUQsTUFEbEMsRUFFRjlDLElBRkUsQ0FFRyxLQUFLRyxjQUFMLENBQW9CdUMsSUFBcEIsQ0FBeUIsSUFBekIsRUFBK0IsS0FBS25ELFNBQUwsQ0FBZUgsT0FBOUMsRUFBdURPLE9BQXZELENBRkgsQ0FBUDtBQUdIOztBQUVEaUUsRUFBQUEsaUJBQWlCLENBQUNqRSxPQUFELEVBQVVrRSxXQUFWLEVBQXVCO0FBQ3BDLFdBQU9qRSxpQ0FBZ0JDLEdBQWhCLEdBQ0YrRCxpQkFERSxDQUNnQmpFLE9BRGhCLEVBQ3lCa0UsV0FEekIsRUFFRjdELElBRkUsQ0FFRyxNQUFNO0FBQUU4RCwwQkFBV0MsMEJBQVgsQ0FBc0NuRSxpQ0FBZ0JDLEdBQWhCLEdBQXNCbUUsV0FBdEIsQ0FBa0NsQixNQUF4RTtBQUFrRixLQUY3RixFQUdGOUMsSUFIRSxDQUdHLEtBQUtHLGNBQUwsQ0FBb0J1QyxJQUFwQixDQUF5QixJQUF6QixFQUErQixLQUFLbkQsU0FBTCxDQUFlSCxPQUE5QyxFQUF1RE8sT0FBdkQsQ0FISCxDQUFQO0FBSUg7O0FBM1FpQzs7QUE4UXRDLElBQUlzRSxtQkFBbUIsR0FBRyxJQUExQjs7QUFDQSxJQUFJLENBQUNBLG1CQUFMLEVBQTBCO0FBQ3RCQSxFQUFBQSxtQkFBbUIsR0FBRyxJQUFJbEYsVUFBSixFQUF0QjtBQUNIOztlQUNja0YsbUIiLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuQ29weXJpZ2h0IDIwMTcgTmV3IFZlY3RvciBMdGRcblxuTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbnlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbllvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuXG4gICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG5cblVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbmRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbldJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxubGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4qL1xuXG5pbXBvcnQgRXZlbnRFbWl0dGVyIGZyb20gJ2V2ZW50cyc7XG5pbXBvcnQgeyBncm91cE1lbWJlckZyb21BcGlPYmplY3QsIGdyb3VwUm9vbUZyb21BcGlPYmplY3QgfSBmcm9tICcuLi9ncm91cHMnO1xuaW1wb3J0IEZsYWlyU3RvcmUgZnJvbSAnLi9GbGFpclN0b3JlJztcbmltcG9ydCB7TWF0cml4Q2xpZW50UGVnfSBmcm9tICcuLi9NYXRyaXhDbGllbnRQZWcnO1xuaW1wb3J0IGRpcyBmcm9tICcuLi9kaXNwYXRjaGVyL2Rpc3BhdGNoZXInO1xuXG5mdW5jdGlvbiBwYXJzZU1lbWJlcnNSZXNwb25zZShyZXNwb25zZSkge1xuICAgIHJldHVybiByZXNwb25zZS5jaHVuay5tYXAoKGFwaU1lbWJlcikgPT4gZ3JvdXBNZW1iZXJGcm9tQXBpT2JqZWN0KGFwaU1lbWJlcikpO1xufVxuXG5mdW5jdGlvbiBwYXJzZVJvb21zUmVzcG9uc2UocmVzcG9uc2UpIHtcbiAgICByZXR1cm4gcmVzcG9uc2UuY2h1bmsubWFwKChhcGlSb29tKSA9PiBncm91cFJvb21Gcm9tQXBpT2JqZWN0KGFwaVJvb20pKTtcbn1cblxuLy8gVGhlIG51bWJlciBvZiBvbmdvaW5nIGdyb3VwIHJlcXVlc3RzXG5sZXQgb25nb2luZ1JlcXVlc3RDb3VudCA9IDA7XG5cbi8vIFRoaXMgaGFzIGFyYml0cmFyaWx5IGJlZW4gc2V0IHRvIGEgc21hbGwgbnVtYmVyIHRvIGxvd2VyIHRoZSBwcmlvcml0eVxuLy8gb2YgZG9pbmcgZ3JvdXAtcmVsYXRlZCByZXF1ZXN0cyBiZWNhdXNlIHdlIGNhcmUgYWJvdXQgb3RoZXIgaW1wb3J0YW50XG4vLyByZXF1ZXN0cyBsaWtlIGhpdHRpbmcgL3N5bmMuXG5jb25zdCBMSU1JVCA9IDM7IC8vIE1heGltdW0gbnVtYmVyIG9mIG9uZ29pbmcgZ3JvdXAgcmVxdWVzdHNcblxuLy8gRklGTyBxdWV1ZSBvZiBmdW5jdGlvbnMgdG8gY2FsbCBpbiB0aGUgYmFja2xvZ1xuY29uc3QgYmFja2xvZ1F1ZXVlID0gW1xuICAgIC8vICgpID0+IHsuLi59XG5dO1xuXG4vLyBQdWxsIGZyb20gdGhlIEZJRk8gcXVldWVcbmZ1bmN0aW9uIGNoZWNrQmFja2xvZygpIHtcbiAgICBjb25zdCBpdGVtID0gYmFja2xvZ1F1ZXVlLnNoaWZ0KCk7XG4gICAgaWYgKHR5cGVvZiBpdGVtID09PSAnZnVuY3Rpb24nKSBpdGVtKCk7XG59XG5cbi8vIExpbWl0IHRoZSBtYXhpbXVtIG51bWJlciBvZiBvbmdvaW5nIHByb21pc2VzIHJldHVybmVkIGJ5IGZuIHRvIExJTUlUIGFuZFxuLy8gdXNlIGEgRklGTyBxdWV1ZSB0byBoYW5kbGUgdGhlIGJhY2tsb2cuXG5hc3luYyBmdW5jdGlvbiBsaW1pdENvbmN1cnJlbmN5KGZuKSB7XG4gICAgaWYgKG9uZ29pbmdSZXF1ZXN0Q291bnQgPj0gTElNSVQpIHtcbiAgICAgICAgLy8gRW5xdWV1ZSB0aGlzIHJlcXVlc3QgZm9yIGxhdGVyIGV4ZWN1dGlvblxuICAgICAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgICAgICBiYWNrbG9nUXVldWUucHVzaChyZXNvbHZlKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgb25nb2luZ1JlcXVlc3RDb3VudCsrO1xuICAgIHRyeSB7XG4gICAgICAgIHJldHVybiBhd2FpdCBmbigpO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAvLyBXZSBleHBsaWNpdGx5IGRvIG5vdCBoYW5kbGUgdGhlIGVycm9yIGhlcmUsIGJ1dCBsZXQgaXQgcHJvcG9nYXRlLlxuICAgICAgICB0aHJvdyBlcnI7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgICAgb25nb2luZ1JlcXVlc3RDb3VudC0tO1xuICAgICAgICBjaGVja0JhY2tsb2coKTtcbiAgICB9XG59XG5cbi8qKlxuICogR2xvYmFsIHN0b3JlIGZvciB0cmFja2luZyBncm91cCBzdW1tYXJ5LCBtZW1iZXJzLCBpbnZpdGVkIG1lbWJlcnMgYW5kIHJvb21zLlxuICovXG5jbGFzcyBHcm91cFN0b3JlIGV4dGVuZHMgRXZlbnRFbWl0dGVyIHtcbiAgICBTVEFURV9LRVkgPSB7XG4gICAgICAgIEdyb3VwTWVtYmVyczogJ0dyb3VwTWVtYmVycycsXG4gICAgICAgIEdyb3VwSW52aXRlZE1lbWJlcnM6ICdHcm91cEludml0ZWRNZW1iZXJzJyxcbiAgICAgICAgU3VtbWFyeTogJ1N1bW1hcnknLFxuICAgICAgICBHcm91cFJvb21zOiAnR3JvdXBSb29tcycsXG4gICAgfTtcblxuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICBzdXBlcigpO1xuICAgICAgICB0aGlzLl9zdGF0ZSA9IHt9O1xuICAgICAgICB0aGlzLl9zdGF0ZVt0aGlzLlNUQVRFX0tFWS5TdW1tYXJ5XSA9IHt9O1xuICAgICAgICB0aGlzLl9zdGF0ZVt0aGlzLlNUQVRFX0tFWS5Hcm91cFJvb21zXSA9IHt9O1xuICAgICAgICB0aGlzLl9zdGF0ZVt0aGlzLlNUQVRFX0tFWS5Hcm91cE1lbWJlcnNdID0ge307XG4gICAgICAgIHRoaXMuX3N0YXRlW3RoaXMuU1RBVEVfS0VZLkdyb3VwSW52aXRlZE1lbWJlcnNdID0ge307XG5cbiAgICAgICAgdGhpcy5fcmVhZHkgPSB7fTtcbiAgICAgICAgdGhpcy5fcmVhZHlbdGhpcy5TVEFURV9LRVkuU3VtbWFyeV0gPSB7fTtcbiAgICAgICAgdGhpcy5fcmVhZHlbdGhpcy5TVEFURV9LRVkuR3JvdXBSb29tc10gPSB7fTtcbiAgICAgICAgdGhpcy5fcmVhZHlbdGhpcy5TVEFURV9LRVkuR3JvdXBNZW1iZXJzXSA9IHt9O1xuICAgICAgICB0aGlzLl9yZWFkeVt0aGlzLlNUQVRFX0tFWS5Hcm91cEludml0ZWRNZW1iZXJzXSA9IHt9O1xuXG4gICAgICAgIHRoaXMuX2ZldGNoUmVzb3VyY2VQcm9taXNlID0ge1xuICAgICAgICAgICAgW3RoaXMuU1RBVEVfS0VZLlN1bW1hcnldOiB7fSxcbiAgICAgICAgICAgIFt0aGlzLlNUQVRFX0tFWS5Hcm91cFJvb21zXToge30sXG4gICAgICAgICAgICBbdGhpcy5TVEFURV9LRVkuR3JvdXBNZW1iZXJzXToge30sXG4gICAgICAgICAgICBbdGhpcy5TVEFURV9LRVkuR3JvdXBJbnZpdGVkTWVtYmVyc106IHt9LFxuICAgICAgICB9O1xuXG4gICAgICAgIHRoaXMuX3Jlc291cmNlRmV0Y2hlciA9IHtcbiAgICAgICAgICAgIFt0aGlzLlNUQVRFX0tFWS5TdW1tYXJ5XTogKGdyb3VwSWQpID0+IHtcbiAgICAgICAgICAgICAgICByZXR1cm4gbGltaXRDb25jdXJyZW5jeShcbiAgICAgICAgICAgICAgICAgICAgKCkgPT4gTWF0cml4Q2xpZW50UGVnLmdldCgpLmdldEdyb3VwU3VtbWFyeShncm91cElkKSxcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFt0aGlzLlNUQVRFX0tFWS5Hcm91cFJvb21zXTogKGdyb3VwSWQpID0+IHtcbiAgICAgICAgICAgICAgICByZXR1cm4gbGltaXRDb25jdXJyZW5jeShcbiAgICAgICAgICAgICAgICAgICAgKCkgPT4gTWF0cml4Q2xpZW50UGVnLmdldCgpLmdldEdyb3VwUm9vbXMoZ3JvdXBJZCkudGhlbihwYXJzZVJvb21zUmVzcG9uc2UpLFxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgW3RoaXMuU1RBVEVfS0VZLkdyb3VwTWVtYmVyc106IChncm91cElkKSA9PiB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGxpbWl0Q29uY3VycmVuY3koXG4gICAgICAgICAgICAgICAgICAgICgpID0+IE1hdHJpeENsaWVudFBlZy5nZXQoKS5nZXRHcm91cFVzZXJzKGdyb3VwSWQpLnRoZW4ocGFyc2VNZW1iZXJzUmVzcG9uc2UpLFxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgW3RoaXMuU1RBVEVfS0VZLkdyb3VwSW52aXRlZE1lbWJlcnNdOiAoZ3JvdXBJZCkgPT4ge1xuICAgICAgICAgICAgICAgIHJldHVybiBsaW1pdENvbmN1cnJlbmN5KFxuICAgICAgICAgICAgICAgICAgICAoKSA9PiBNYXRyaXhDbGllbnRQZWcuZ2V0KCkuZ2V0R3JvdXBJbnZpdGVkVXNlcnMoZ3JvdXBJZCkudGhlbihwYXJzZU1lbWJlcnNSZXNwb25zZSksXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgX2ZldGNoUmVzb3VyY2Uoc3RhdGVLZXksIGdyb3VwSWQpIHtcbiAgICAgICAgLy8gT25nb2luZyByZXF1ZXN0LCBpZ25vcmVcbiAgICAgICAgaWYgKHRoaXMuX2ZldGNoUmVzb3VyY2VQcm9taXNlW3N0YXRlS2V5XVtncm91cElkXSkgcmV0dXJuO1xuXG4gICAgICAgIGNvbnN0IGNsaWVudFByb21pc2UgPSB0aGlzLl9yZXNvdXJjZUZldGNoZXJbc3RhdGVLZXldKGdyb3VwSWQpO1xuXG4gICAgICAgIC8vIEluZGljYXRlIG9uZ29pbmcgcmVxdWVzdFxuICAgICAgICB0aGlzLl9mZXRjaFJlc291cmNlUHJvbWlzZVtzdGF0ZUtleV1bZ3JvdXBJZF0gPSBjbGllbnRQcm9taXNlO1xuXG4gICAgICAgIGNsaWVudFByb21pc2UudGhlbigocmVzdWx0KSA9PiB7XG4gICAgICAgICAgICB0aGlzLl9zdGF0ZVtzdGF0ZUtleV1bZ3JvdXBJZF0gPSByZXN1bHQ7XG4gICAgICAgICAgICB0aGlzLl9yZWFkeVtzdGF0ZUtleV1bZ3JvdXBJZF0gPSB0cnVlO1xuICAgICAgICAgICAgdGhpcy5fbm90aWZ5TGlzdGVuZXJzKCk7XG4gICAgICAgIH0pLmNhdGNoKChlcnIpID0+IHtcbiAgICAgICAgICAgIC8vIEludml0ZWQgdXNlcnMgbm90IHZpc2libGUgdG8gbm9uLW1lbWJlcnNcbiAgICAgICAgICAgIGlmIChzdGF0ZUtleSA9PT0gdGhpcy5TVEFURV9LRVkuR3JvdXBJbnZpdGVkTWVtYmVycyAmJiBlcnIuaHR0cFN0YXR1cyA9PT0gNDAzKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKGBGYWlsZWQgdG8gZ2V0IHJlc291cmNlICR7c3RhdGVLZXl9IGZvciAke2dyb3VwSWR9YCwgZXJyKTtcbiAgICAgICAgICAgIHRoaXMuZW1pdCgnZXJyb3InLCBlcnIsIGdyb3VwSWQsIHN0YXRlS2V5KTtcbiAgICAgICAgfSkuZmluYWxseSgoKSA9PiB7XG4gICAgICAgICAgICAvLyBJbmRpY2F0ZSBmaW5pc2hlZCByZXF1ZXN0LCBhbGxvdyBmb3IgZnV0dXJlIGZldGNoZXNcbiAgICAgICAgICAgIGRlbGV0ZSB0aGlzLl9mZXRjaFJlc291cmNlUHJvbWlzZVtzdGF0ZUtleV1bZ3JvdXBJZF07XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiBjbGllbnRQcm9taXNlO1xuICAgIH1cblxuICAgIF9ub3RpZnlMaXN0ZW5lcnMoKSB7XG4gICAgICAgIHRoaXMuZW1pdCgndXBkYXRlJyk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmVnaXN0ZXIgYSBsaXN0ZW5lciB0byByZWNpZXZlIHVwZGF0ZXMgZnJvbSB0aGUgc3RvcmUuIFRoaXMgYWxzb1xuICAgICAqIGltbWVkaWF0ZWx5IHRyaWdnZXJzIGFuIHVwZGF0ZSB0byBzZW5kIHRoZSBjdXJyZW50IHN0YXRlIG9mIHRoZVxuICAgICAqIHN0b3JlICh3aGljaCBjb3VsZCBiZSB0aGUgaW5pdGlhbCBzdGF0ZSkuXG4gICAgICpcbiAgICAgKiBJZiBhIGdyb3VwIElEIGlzIHNwZWNpZmllZCwgdGhpcyBhbHNvIGNhdXNlcyBhIGZldGNoIG9mIGFsbCBkYXRhXG4gICAgICogb2YgdGhlIHNwZWNpZmllZCBncm91cCwgd2hpY2ggbWlnaHQgY2F1c2UgNCBzZXBhcmF0ZSBIVFRQXG4gICAgICogcmVxdWVzdHMsIGJ1dCBvbmx5IGlmIHNhaWQgcmVxdWVzdHMgYXJlbid0IGFscmVhZHkgb25nb2luZy5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nP30gZ3JvdXBJZCB0aGUgSUQgb2YgdGhlIGdyb3VwIHRvIGZldGNoIGRhdGEgZm9yLlxuICAgICAqICAgICAgICAgICAgICAgICAgICAgICAgICBPcHRpb25hbC5cbiAgICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBmbiB0aGUgZnVuY3Rpb24gdG8gY2FsbCB3aGVuIHRoZSBzdG9yZSB1cGRhdGVzLlxuICAgICAqIEByZXR1cm4ge09iamVjdH0gdG9rIGEgcmVnaXN0cmF0aW9uIFwidG9rZW5cIiB3aXRoIGEgc2luZ2xlXG4gICAgICogICAgICAgICAgICAgICAgICAgICAgcHJvcGVydHkgYHVucmVnaXN0ZXJgLCBhIGZ1bmN0aW9uIHRoYXQgY2FuXG4gICAgICogICAgICAgICAgICAgICAgICAgICAgYmUgY2FsbGVkIHRvIHVucmVnaXN0ZXIgdGhlIGxpc3RlbmVyIHN1Y2hcbiAgICAgKiAgICAgICAgICAgICAgICAgICAgICB0aGF0IGl0IHdvbid0IGJlIGNhbGxlZCBhbnkgbW9yZS5cbiAgICAgKi9cbiAgICByZWdpc3Rlckxpc3RlbmVyKGdyb3VwSWQsIGZuKSB7XG4gICAgICAgIHRoaXMub24oJ3VwZGF0ZScsIGZuKTtcbiAgICAgICAgLy8gQ2FsbCB0byBzZXQgaW5pdGlhbCBzdGF0ZSAoYmVmb3JlIGZldGNoaW5nIHN0YXJ0cylcbiAgICAgICAgdGhpcy5lbWl0KCd1cGRhdGUnKTtcblxuICAgICAgICBpZiAoZ3JvdXBJZCkge1xuICAgICAgICAgICAgdGhpcy5fZmV0Y2hSZXNvdXJjZSh0aGlzLlNUQVRFX0tFWS5TdW1tYXJ5LCBncm91cElkKTtcbiAgICAgICAgICAgIHRoaXMuX2ZldGNoUmVzb3VyY2UodGhpcy5TVEFURV9LRVkuR3JvdXBSb29tcywgZ3JvdXBJZCk7XG4gICAgICAgICAgICB0aGlzLl9mZXRjaFJlc291cmNlKHRoaXMuU1RBVEVfS0VZLkdyb3VwTWVtYmVycywgZ3JvdXBJZCk7XG4gICAgICAgICAgICB0aGlzLl9mZXRjaFJlc291cmNlKHRoaXMuU1RBVEVfS0VZLkdyb3VwSW52aXRlZE1lbWJlcnMsIGdyb3VwSWQpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gU2ltaWxhciB0byB0aGUgU3RvcmUgb2YgZmx1eC91dGlscywgd2UgcmV0dXJuIGEgXCJ0b2tlblwiIHRoYXRcbiAgICAgICAgLy8gY2FuIGJlIHVzZWQgdG8gdW5yZWdpc3RlciB0aGUgbGlzdGVuZXIuXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICB1bnJlZ2lzdGVyOiAoKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy51bnJlZ2lzdGVyTGlzdGVuZXIoZm4pO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICB1bnJlZ2lzdGVyTGlzdGVuZXIoZm4pIHtcbiAgICAgICAgdGhpcy5yZW1vdmVMaXN0ZW5lcigndXBkYXRlJywgZm4pO1xuICAgIH1cblxuICAgIGlzU3RhdGVSZWFkeShncm91cElkLCBpZCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fcmVhZHlbaWRdW2dyb3VwSWRdO1xuICAgIH1cblxuICAgIGdldEdyb3VwSWRzRm9yUm9vbUlkKHJvb21JZCkge1xuICAgICAgICBjb25zdCBncm91cElkcyA9IE9iamVjdC5rZXlzKHRoaXMuX3N0YXRlW3RoaXMuU1RBVEVfS0VZLkdyb3VwUm9vbXNdKTtcbiAgICAgICAgcmV0dXJuIGdyb3VwSWRzLmZpbHRlcihncm91cElkID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHJvb21zID0gdGhpcy5fc3RhdGVbdGhpcy5TVEFURV9LRVkuR3JvdXBSb29tc11bZ3JvdXBJZF0gfHwgW107XG4gICAgICAgICAgICByZXR1cm4gcm9vbXMuc29tZShyb29tID0+IHJvb20ucm9vbUlkID09PSByb29tSWQpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBnZXRTdW1tYXJ5KGdyb3VwSWQpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3N0YXRlW3RoaXMuU1RBVEVfS0VZLlN1bW1hcnldW2dyb3VwSWRdIHx8IHt9O1xuICAgIH1cblxuICAgIGdldEdyb3VwUm9vbXMoZ3JvdXBJZCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fc3RhdGVbdGhpcy5TVEFURV9LRVkuR3JvdXBSb29tc11bZ3JvdXBJZF0gfHwgW107XG4gICAgfVxuXG4gICAgZ2V0R3JvdXBNZW1iZXJzKGdyb3VwSWQpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3N0YXRlW3RoaXMuU1RBVEVfS0VZLkdyb3VwTWVtYmVyc11bZ3JvdXBJZF0gfHwgW107XG4gICAgfVxuXG4gICAgZ2V0R3JvdXBJbnZpdGVkTWVtYmVycyhncm91cElkKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9zdGF0ZVt0aGlzLlNUQVRFX0tFWS5Hcm91cEludml0ZWRNZW1iZXJzXVtncm91cElkXSB8fCBbXTtcbiAgICB9XG5cbiAgICBnZXRHcm91cFB1YmxpY2l0eShncm91cElkKSB7XG4gICAgICAgIHJldHVybiAodGhpcy5fc3RhdGVbdGhpcy5TVEFURV9LRVkuU3VtbWFyeV1bZ3JvdXBJZF0gfHwge30pLnVzZXIgP1xuICAgICAgICAgICAgKHRoaXMuX3N0YXRlW3RoaXMuU1RBVEVfS0VZLlN1bW1hcnldW2dyb3VwSWRdIHx8IHt9KS51c2VyLmlzX3B1YmxpY2lzZWQgOiBudWxsO1xuICAgIH1cblxuICAgIGlzVXNlclByaXZpbGVnZWQoZ3JvdXBJZCkge1xuICAgICAgICByZXR1cm4gKHRoaXMuX3N0YXRlW3RoaXMuU1RBVEVfS0VZLlN1bW1hcnldW2dyb3VwSWRdIHx8IHt9KS51c2VyID9cbiAgICAgICAgICAgICh0aGlzLl9zdGF0ZVt0aGlzLlNUQVRFX0tFWS5TdW1tYXJ5XVtncm91cElkXSB8fCB7fSkudXNlci5pc19wcml2aWxlZ2VkIDogbnVsbDtcbiAgICB9XG5cbiAgICByZWZyZXNoR3JvdXBSb29tcyhncm91cElkKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9mZXRjaFJlc291cmNlKHRoaXMuU1RBVEVfS0VZLkdyb3VwUm9vbXMsIGdyb3VwSWQpO1xuICAgIH1cblxuICAgIHJlZnJlc2hHcm91cE1lbWJlcnMoZ3JvdXBJZCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fZmV0Y2hSZXNvdXJjZSh0aGlzLlNUQVRFX0tFWS5Hcm91cE1lbWJlcnMsIGdyb3VwSWQpO1xuICAgIH1cblxuICAgIGFkZFJvb21Ub0dyb3VwKGdyb3VwSWQsIHJvb21JZCwgaXNQdWJsaWMpIHtcbiAgICAgICAgcmV0dXJuIE1hdHJpeENsaWVudFBlZy5nZXQoKVxuICAgICAgICAgICAgLmFkZFJvb21Ub0dyb3VwKGdyb3VwSWQsIHJvb21JZCwgaXNQdWJsaWMpXG4gICAgICAgICAgICAudGhlbih0aGlzLl9mZXRjaFJlc291cmNlLmJpbmQodGhpcywgdGhpcy5TVEFURV9LRVkuR3JvdXBSb29tcywgZ3JvdXBJZCkpO1xuICAgIH1cblxuICAgIHVwZGF0ZUdyb3VwUm9vbVZpc2liaWxpdHkoZ3JvdXBJZCwgcm9vbUlkLCBpc1B1YmxpYykge1xuICAgICAgICByZXR1cm4gTWF0cml4Q2xpZW50UGVnLmdldCgpXG4gICAgICAgICAgICAudXBkYXRlR3JvdXBSb29tVmlzaWJpbGl0eShncm91cElkLCByb29tSWQsIGlzUHVibGljKVxuICAgICAgICAgICAgLnRoZW4odGhpcy5fZmV0Y2hSZXNvdXJjZS5iaW5kKHRoaXMsIHRoaXMuU1RBVEVfS0VZLkdyb3VwUm9vbXMsIGdyb3VwSWQpKTtcbiAgICB9XG5cbiAgICByZW1vdmVSb29tRnJvbUdyb3VwKGdyb3VwSWQsIHJvb21JZCkge1xuICAgICAgICByZXR1cm4gTWF0cml4Q2xpZW50UGVnLmdldCgpXG4gICAgICAgICAgICAucmVtb3ZlUm9vbUZyb21Hcm91cChncm91cElkLCByb29tSWQpXG4gICAgICAgICAgICAvLyBSb29tIG1pZ2h0IGJlIGluIHRoZSBzdW1tYXJ5LCByZWZyZXNoIGp1c3QgaW4gY2FzZVxuICAgICAgICAgICAgLnRoZW4odGhpcy5fZmV0Y2hSZXNvdXJjZS5iaW5kKHRoaXMsIHRoaXMuU1RBVEVfS0VZLlN1bW1hcnksIGdyb3VwSWQpKVxuICAgICAgICAgICAgLnRoZW4odGhpcy5fZmV0Y2hSZXNvdXJjZS5iaW5kKHRoaXMsIHRoaXMuU1RBVEVfS0VZLkdyb3VwUm9vbXMsIGdyb3VwSWQpKTtcbiAgICB9XG5cbiAgICBpbnZpdGVVc2VyVG9Hcm91cChncm91cElkLCB1c2VySWQpIHtcbiAgICAgICAgcmV0dXJuIE1hdHJpeENsaWVudFBlZy5nZXQoKS5pbnZpdGVVc2VyVG9Hcm91cChncm91cElkLCB1c2VySWQpXG4gICAgICAgICAgICAudGhlbih0aGlzLl9mZXRjaFJlc291cmNlLmJpbmQodGhpcywgdGhpcy5TVEFURV9LRVkuR3JvdXBJbnZpdGVkTWVtYmVycywgZ3JvdXBJZCkpO1xuICAgIH1cblxuICAgIGFjY2VwdEdyb3VwSW52aXRlKGdyb3VwSWQpIHtcbiAgICAgICAgcmV0dXJuIE1hdHJpeENsaWVudFBlZy5nZXQoKS5hY2NlcHRHcm91cEludml0ZShncm91cElkKVxuICAgICAgICAgICAgLy8gVGhlIHVzZXIgc2hvdWxkIG5vdyBiZSBhYmxlIHRvIGFjY2VzcyAocGVyc29uYWwpIGdyb3VwIHNldHRpbmdzXG4gICAgICAgICAgICAudGhlbih0aGlzLl9mZXRjaFJlc291cmNlLmJpbmQodGhpcywgdGhpcy5TVEFURV9LRVkuU3VtbWFyeSwgZ3JvdXBJZCkpXG4gICAgICAgICAgICAvLyBUaGUgdXNlciBtaWdodCBiZSBhYmxlIHRvIHNlZSBtb3JlIHJvb21zIG5vd1xuICAgICAgICAgICAgLnRoZW4odGhpcy5fZmV0Y2hSZXNvdXJjZS5iaW5kKHRoaXMsIHRoaXMuU1RBVEVfS0VZLkdyb3VwUm9vbXMsIGdyb3VwSWQpKVxuICAgICAgICAgICAgLy8gVGhlIHVzZXIgc2hvdWxkIG5vdyBhcHBlYXIgYXMgYSBtZW1iZXJcbiAgICAgICAgICAgIC50aGVuKHRoaXMuX2ZldGNoUmVzb3VyY2UuYmluZCh0aGlzLCB0aGlzLlNUQVRFX0tFWS5Hcm91cE1lbWJlcnMsIGdyb3VwSWQpKVxuICAgICAgICAgICAgLy8gVGhlIHVzZXIgc2hvdWxkIG5vdyBub3QgYXBwZWFyIGFzIGFuIGludml0ZWQgbWVtYmVyXG4gICAgICAgICAgICAudGhlbih0aGlzLl9mZXRjaFJlc291cmNlLmJpbmQodGhpcywgdGhpcy5TVEFURV9LRVkuR3JvdXBJbnZpdGVkTWVtYmVycywgZ3JvdXBJZCkpO1xuICAgIH1cblxuICAgIGpvaW5Hcm91cChncm91cElkKSB7XG4gICAgICAgIHJldHVybiBNYXRyaXhDbGllbnRQZWcuZ2V0KCkuam9pbkdyb3VwKGdyb3VwSWQpXG4gICAgICAgICAgICAvLyBUaGUgdXNlciBzaG91bGQgbm93IGJlIGFibGUgdG8gYWNjZXNzIChwZXJzb25hbCkgZ3JvdXAgc2V0dGluZ3NcbiAgICAgICAgICAgIC50aGVuKHRoaXMuX2ZldGNoUmVzb3VyY2UuYmluZCh0aGlzLCB0aGlzLlNUQVRFX0tFWS5TdW1tYXJ5LCBncm91cElkKSlcbiAgICAgICAgICAgIC8vIFRoZSB1c2VyIG1pZ2h0IGJlIGFibGUgdG8gc2VlIG1vcmUgcm9vbXMgbm93XG4gICAgICAgICAgICAudGhlbih0aGlzLl9mZXRjaFJlc291cmNlLmJpbmQodGhpcywgdGhpcy5TVEFURV9LRVkuR3JvdXBSb29tcywgZ3JvdXBJZCkpXG4gICAgICAgICAgICAvLyBUaGUgdXNlciBzaG91bGQgbm93IGFwcGVhciBhcyBhIG1lbWJlclxuICAgICAgICAgICAgLnRoZW4odGhpcy5fZmV0Y2hSZXNvdXJjZS5iaW5kKHRoaXMsIHRoaXMuU1RBVEVfS0VZLkdyb3VwTWVtYmVycywgZ3JvdXBJZCkpXG4gICAgICAgICAgICAvLyBUaGUgdXNlciBzaG91bGQgbm93IG5vdCBhcHBlYXIgYXMgYW4gaW52aXRlZCBtZW1iZXJcbiAgICAgICAgICAgIC50aGVuKHRoaXMuX2ZldGNoUmVzb3VyY2UuYmluZCh0aGlzLCB0aGlzLlNUQVRFX0tFWS5Hcm91cEludml0ZWRNZW1iZXJzLCBncm91cElkKSk7XG4gICAgfVxuXG4gICAgbGVhdmVHcm91cChncm91cElkKSB7XG4gICAgICAgIC8vIGVuc3VyZSB0aGUgdGFnIHBhbmVsIGZpbHRlciBpcyBjbGVhcmVkIGlmIHRoZSBncm91cCB3YXMgc2VsZWN0ZWRcbiAgICAgICAgZGlzLmRpc3BhdGNoKHtcbiAgICAgICAgICAgIGFjdGlvbjogXCJkZXNlbGVjdF90YWdzXCIsXG4gICAgICAgICAgICB0YWc6IGdyb3VwSWQsXG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gTWF0cml4Q2xpZW50UGVnLmdldCgpLmxlYXZlR3JvdXAoZ3JvdXBJZClcbiAgICAgICAgICAgIC8vIFRoZSB1c2VyIHNob3VsZCBub3cgbm90IGJlIGFibGUgdG8gYWNjZXNzIGdyb3VwIHNldHRpbmdzXG4gICAgICAgICAgICAudGhlbih0aGlzLl9mZXRjaFJlc291cmNlLmJpbmQodGhpcywgdGhpcy5TVEFURV9LRVkuU3VtbWFyeSwgZ3JvdXBJZCkpXG4gICAgICAgICAgICAvLyBUaGUgdXNlciBtaWdodCBvbmx5IGJlIGFibGUgdG8gc2VlIGEgc3Vic2V0IG9mIHJvb21zIG5vd1xuICAgICAgICAgICAgLnRoZW4odGhpcy5fZmV0Y2hSZXNvdXJjZS5iaW5kKHRoaXMsIHRoaXMuU1RBVEVfS0VZLkdyb3VwUm9vbXMsIGdyb3VwSWQpKVxuICAgICAgICAgICAgLy8gVGhlIHVzZXIgc2hvdWxkIG5vdyBub3QgYXBwZWFyIGFzIGEgbWVtYmVyXG4gICAgICAgICAgICAudGhlbih0aGlzLl9mZXRjaFJlc291cmNlLmJpbmQodGhpcywgdGhpcy5TVEFURV9LRVkuR3JvdXBNZW1iZXJzLCBncm91cElkKSk7XG4gICAgfVxuXG4gICAgYWRkUm9vbVRvR3JvdXBTdW1tYXJ5KGdyb3VwSWQsIHJvb21JZCwgY2F0ZWdvcnlJZCkge1xuICAgICAgICByZXR1cm4gTWF0cml4Q2xpZW50UGVnLmdldCgpXG4gICAgICAgICAgICAuYWRkUm9vbVRvR3JvdXBTdW1tYXJ5KGdyb3VwSWQsIHJvb21JZCwgY2F0ZWdvcnlJZClcbiAgICAgICAgICAgIC50aGVuKHRoaXMuX2ZldGNoUmVzb3VyY2UuYmluZCh0aGlzLCB0aGlzLlNUQVRFX0tFWS5TdW1tYXJ5LCBncm91cElkKSk7XG4gICAgfVxuXG4gICAgYWRkVXNlclRvR3JvdXBTdW1tYXJ5KGdyb3VwSWQsIHVzZXJJZCwgcm9sZUlkKSB7XG4gICAgICAgIHJldHVybiBNYXRyaXhDbGllbnRQZWcuZ2V0KClcbiAgICAgICAgICAgIC5hZGRVc2VyVG9Hcm91cFN1bW1hcnkoZ3JvdXBJZCwgdXNlcklkLCByb2xlSWQpXG4gICAgICAgICAgICAudGhlbih0aGlzLl9mZXRjaFJlc291cmNlLmJpbmQodGhpcywgdGhpcy5TVEFURV9LRVkuU3VtbWFyeSwgZ3JvdXBJZCkpO1xuICAgIH1cblxuICAgIHJlbW92ZVJvb21Gcm9tR3JvdXBTdW1tYXJ5KGdyb3VwSWQsIHJvb21JZCkge1xuICAgICAgICByZXR1cm4gTWF0cml4Q2xpZW50UGVnLmdldCgpXG4gICAgICAgICAgICAucmVtb3ZlUm9vbUZyb21Hcm91cFN1bW1hcnkoZ3JvdXBJZCwgcm9vbUlkKVxuICAgICAgICAgICAgLnRoZW4odGhpcy5fZmV0Y2hSZXNvdXJjZS5iaW5kKHRoaXMsIHRoaXMuU1RBVEVfS0VZLlN1bW1hcnksIGdyb3VwSWQpKTtcbiAgICB9XG5cbiAgICByZW1vdmVVc2VyRnJvbUdyb3VwU3VtbWFyeShncm91cElkLCB1c2VySWQpIHtcbiAgICAgICAgcmV0dXJuIE1hdHJpeENsaWVudFBlZy5nZXQoKVxuICAgICAgICAgICAgLnJlbW92ZVVzZXJGcm9tR3JvdXBTdW1tYXJ5KGdyb3VwSWQsIHVzZXJJZClcbiAgICAgICAgICAgIC50aGVuKHRoaXMuX2ZldGNoUmVzb3VyY2UuYmluZCh0aGlzLCB0aGlzLlNUQVRFX0tFWS5TdW1tYXJ5LCBncm91cElkKSk7XG4gICAgfVxuXG4gICAgc2V0R3JvdXBQdWJsaWNpdHkoZ3JvdXBJZCwgaXNQdWJsaXNoZWQpIHtcbiAgICAgICAgcmV0dXJuIE1hdHJpeENsaWVudFBlZy5nZXQoKVxuICAgICAgICAgICAgLnNldEdyb3VwUHVibGljaXR5KGdyb3VwSWQsIGlzUHVibGlzaGVkKVxuICAgICAgICAgICAgLnRoZW4oKCkgPT4geyBGbGFpclN0b3JlLmludmFsaWRhdGVQdWJsaWNpc2VkR3JvdXBzKE1hdHJpeENsaWVudFBlZy5nZXQoKS5jcmVkZW50aWFscy51c2VySWQpOyB9KVxuICAgICAgICAgICAgLnRoZW4odGhpcy5fZmV0Y2hSZXNvdXJjZS5iaW5kKHRoaXMsIHRoaXMuU1RBVEVfS0VZLlN1bW1hcnksIGdyb3VwSWQpKTtcbiAgICB9XG59XG5cbmxldCBzaW5nbGV0b25Hcm91cFN0b3JlID0gbnVsbDtcbmlmICghc2luZ2xldG9uR3JvdXBTdG9yZSkge1xuICAgIHNpbmdsZXRvbkdyb3VwU3RvcmUgPSBuZXcgR3JvdXBTdG9yZSgpO1xufVxuZXhwb3J0IGRlZmF1bHQgc2luZ2xldG9uR3JvdXBTdG9yZTtcbiJdfQ==