matrix-react-sdk
Version:
SDK for matrix.org using React
336 lines (329 loc) • 50 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = exports.UNKNOWN_PROFILE_ERRORS = exports.InviteState = 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 _logger = require("matrix-js-sdk/src/logger");
var _UserAddress = require("../UserAddress");
var _languageHandler = require("../languageHandler");
var _Modal = _interopRequireDefault(require("../Modal"));
var _SettingsStore = _interopRequireDefault(require("../settings/SettingsStore"));
var _AskInviteAnywayDialog = _interopRequireDefault(require("../components/views/dialogs/AskInviteAnywayDialog"));
var _ConfirmUserActionDialog = _interopRequireDefault(require("../components/views/dialogs/ConfirmUserActionDialog"));
/*
Copyright 2024 New Vector Ltd.
Copyright 2016-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.
*/
let InviteState = exports.InviteState = /*#__PURE__*/function (InviteState) {
InviteState["Invited"] = "invited";
InviteState["Error"] = "error";
return InviteState;
}({});
const UNKNOWN_PROFILE_ERRORS = exports.UNKNOWN_PROFILE_ERRORS = ["M_NOT_FOUND", "M_USER_NOT_FOUND", "M_PROFILE_UNDISCLOSED", "M_PROFILE_NOT_FOUND"];
const USER_ALREADY_JOINED = "IO.ELEMENT.ALREADY_JOINED";
const USER_ALREADY_INVITED = "IO.ELEMENT.ALREADY_INVITED";
const USER_BANNED = "IO.ELEMENT.BANNED";
/**
* Invites multiple addresses to a room, handling rate limiting from the server
*/
class MultiInviter {
/**
* @param matrixClient the client of the logged in user
* @param {string} roomId The ID of the room to invite to
* @param {function} progressCallback optional callback, fired after each invite.
*/
constructor(matrixClient, roomId, progressCallback) {
(0, _defineProperty2.default)(this, "canceled", false);
(0, _defineProperty2.default)(this, "addresses", []);
(0, _defineProperty2.default)(this, "busy", false);
(0, _defineProperty2.default)(this, "_fatal", false);
(0, _defineProperty2.default)(this, "completionStates", {});
// State of each address (invited or error)
(0, _defineProperty2.default)(this, "errors", {});
// { address: {errorText, errcode} }
(0, _defineProperty2.default)(this, "deferred", null);
(0, _defineProperty2.default)(this, "reason", void 0);
this.matrixClient = matrixClient;
this.roomId = roomId;
this.progressCallback = progressCallback;
}
get fatal() {
return this._fatal;
}
/**
* Invite users to this room. This may only be called once per
* instance of the class.
*
* @param {array} addresses Array of addresses to invite
* @param {string} reason Reason for inviting (optional)
* @returns {Promise} Resolved when all invitations in the queue are complete
*/
invite(addresses, reason) {
if (this.addresses.length > 0) {
throw new Error("Already inviting/invited");
}
this.addresses.push(...addresses);
this.reason = reason;
for (const addr of this.addresses) {
if ((0, _UserAddress.getAddressType)(addr) === null) {
this.completionStates[addr] = InviteState.Error;
this.errors[addr] = {
errcode: "M_INVALID",
errorText: (0, _languageHandler._t)("invite|invalid_address")
};
}
}
this.deferred = (0, _utils.defer)();
this.inviteMore(0);
return this.deferred.promise;
}
/**
* Stops inviting. Causes promises returned by invite() to be rejected.
*/
cancel() {
if (!this.busy) return;
this.canceled = true;
this.deferred?.reject(new Error("canceled"));
}
getCompletionState(addr) {
return this.completionStates[addr];
}
getErrorText(addr) {
return this.errors[addr]?.errorText ?? null;
}
async inviteToRoom(roomId, addr, ignoreProfile = false) {
const addrType = (0, _UserAddress.getAddressType)(addr);
if (addrType === _UserAddress.AddressType.Email) {
return this.matrixClient.inviteByEmail(roomId, addr);
} else if (addrType === _UserAddress.AddressType.MatrixUserId) {
const room = this.matrixClient.getRoom(roomId);
if (!room) throw new Error("Room not found");
const member = room.getMember(addr);
if (member?.membership === _types.KnownMembership.Join) {
throw new _matrix.MatrixError({
errcode: USER_ALREADY_JOINED,
error: "Member already joined"
});
} else if (member?.membership === _types.KnownMembership.Invite) {
throw new _matrix.MatrixError({
errcode: USER_ALREADY_INVITED,
error: "Member already invited"
});
} else if (member?.membership === _types.KnownMembership.Ban) {
let proceed = false;
// Check if we can unban the invitee.
// See https://spec.matrix.org/v1.7/rooms/v10/#authorization-rules, particularly 4.5.3 and 4.5.4.
const ourMember = room.getMember(this.matrixClient.getSafeUserId());
if (!!ourMember && member.powerLevel < ourMember.powerLevel && room.currentState.hasSufficientPowerLevelFor("ban", ourMember.powerLevel) && room.currentState.hasSufficientPowerLevelFor("kick", ourMember.powerLevel)) {
const {
finished
} = _Modal.default.createDialog(_ConfirmUserActionDialog.default, {
member,
action: (0, _languageHandler._t)("action|unban"),
title: (0, _languageHandler._t)("invite|unban_first_title")
});
[proceed = false] = await finished;
if (proceed) {
await this.matrixClient.unban(roomId, member.userId);
}
}
if (!proceed) {
throw new _matrix.MatrixError({
errcode: USER_BANNED,
error: "Member is banned"
});
}
}
if (!ignoreProfile && _SettingsStore.default.getValue("promptBeforeInviteUnknownUsers", this.roomId)) {
try {
await this.matrixClient.getProfileInfo(addr);
} catch (err) {
// The error handling during the invitation process covers any API.
// Some errors must to me mapped from profile API errors to more specific ones to avoid collisions.
switch (err instanceof _matrix.MatrixError ? err.errcode : err) {
case "M_FORBIDDEN":
throw new _matrix.MatrixError({
errcode: "M_PROFILE_UNDISCLOSED"
});
case "M_NOT_FOUND":
throw new _matrix.MatrixError({
errcode: "M_USER_NOT_FOUND"
});
default:
throw err;
}
}
}
return this.matrixClient.invite(roomId, addr, this.reason);
} else {
throw new Error("Unsupported address");
}
}
doInvite(address, ignoreProfile = false) {
return new Promise((resolve, reject) => {
_logger.logger.log(`Inviting ${address}`);
const doInvite = this.inviteToRoom(this.roomId, address, ignoreProfile);
doInvite.then(() => {
if (this.canceled) {
return;
}
this.completionStates[address] = InviteState.Invited;
delete this.errors[address];
resolve();
this.progressCallback?.();
}).catch(err => {
if (this.canceled) {
return;
}
_logger.logger.error(err);
const room = this.roomId ? this.matrixClient.getRoom(this.roomId) : null;
const isSpace = room?.isSpaceRoom();
const isFederated = room?.currentState.getStateEvents(_matrix.EventType.RoomCreate, "")?.getContent()["m.federate"];
let errorText;
let fatal = false;
switch (err.errcode) {
case "M_FORBIDDEN":
if (isSpace) {
errorText = isFederated === false ? (0, _languageHandler._t)("invite|error_unfederated_space") : (0, _languageHandler._t)("invite|error_permissions_space");
} else {
errorText = isFederated === false ? (0, _languageHandler._t)("invite|error_unfederated_room") : (0, _languageHandler._t)("invite|error_permissions_room");
}
fatal = true;
break;
case USER_ALREADY_INVITED:
if (isSpace) {
errorText = (0, _languageHandler._t)("invite|error_already_invited_space");
} else {
errorText = (0, _languageHandler._t)("invite|error_already_invited_room");
}
break;
case USER_ALREADY_JOINED:
if (isSpace) {
errorText = (0, _languageHandler._t)("invite|error_already_joined_space");
} else {
errorText = (0, _languageHandler._t)("invite|error_already_joined_room");
}
break;
case "M_LIMIT_EXCEEDED":
// we're being throttled so wait a bit & try again
window.setTimeout(() => {
this.doInvite(address, ignoreProfile).then(resolve, reject);
}, 5000);
return;
case "M_NOT_FOUND":
case "M_USER_NOT_FOUND":
errorText = (0, _languageHandler._t)("invite|error_user_not_found");
break;
case "M_PROFILE_UNDISCLOSED":
errorText = (0, _languageHandler._t)("invite|error_profile_undisclosed");
break;
case "M_PROFILE_NOT_FOUND":
if (!ignoreProfile) {
// Invite without the profile check
_logger.logger.warn(`User ${address} does not have a profile - inviting anyways automatically`);
this.doInvite(address, true).then(resolve, reject);
return;
}
break;
case "M_BAD_STATE":
case USER_BANNED:
errorText = (0, _languageHandler._t)("invite|error_bad_state");
break;
case "M_UNSUPPORTED_ROOM_VERSION":
if (isSpace) {
errorText = (0, _languageHandler._t)("invite|error_version_unsupported_space");
} else {
errorText = (0, _languageHandler._t)("invite|error_version_unsupported_room");
}
break;
case "ORG.MATRIX.JSSDK_MISSING_PARAM":
if ((0, _UserAddress.getAddressType)(address) === _UserAddress.AddressType.Email) {
errorText = (0, _languageHandler._t)("cannot_invite_without_identity_server");
}
}
if (!errorText) {
errorText = (0, _languageHandler._t)("invite|error_unknown");
}
this.completionStates[address] = InviteState.Error;
this.errors[address] = {
errorText,
errcode: err.errcode
};
this.busy = !fatal;
this._fatal = fatal;
if (fatal) {
reject(err);
} else {
resolve();
}
});
});
}
inviteMore(nextIndex, ignoreProfile = false) {
if (this.canceled) {
return;
}
if (nextIndex === this.addresses.length) {
this.busy = false;
if (Object.keys(this.errors).length > 0) {
// There were problems inviting some people - see if we can invite them
// without caring if they exist or not.
const unknownProfileUsers = Object.keys(this.errors).filter(a => UNKNOWN_PROFILE_ERRORS.includes(this.errors[a].errcode));
if (unknownProfileUsers.length > 0) {
const inviteUnknowns = () => {
const promises = unknownProfileUsers.map(u => this.doInvite(u, true));
Promise.all(promises).then(() => this.deferred?.resolve(this.completionStates));
};
if (!_SettingsStore.default.getValue("promptBeforeInviteUnknownUsers", this.roomId)) {
inviteUnknowns();
return;
}
_logger.logger.log("Showing failed to invite dialog...");
_Modal.default.createDialog(_AskInviteAnywayDialog.default, {
unknownProfileUsers: unknownProfileUsers.map(u => ({
userId: u,
errorText: this.errors[u].errorText
})),
onInviteAnyways: () => inviteUnknowns(),
onGiveUp: () => {
// Fake all the completion states because we already warned the user
for (const addr of unknownProfileUsers) {
this.completionStates[addr] = InviteState.Invited;
}
this.deferred?.resolve(this.completionStates);
}
});
return;
}
}
this.deferred?.resolve(this.completionStates);
return;
}
const addr = this.addresses[nextIndex];
// don't try to invite it if it's an invalid address
// (it will already be marked as an error though,
// so no need to do so again)
if ((0, _UserAddress.getAddressType)(addr) === null) {
this.inviteMore(nextIndex + 1);
return;
}
// don't re-invite (there's no way in the UI to do this, but
// for sanity's sake)
if (this.completionStates[addr] === InviteState.Invited) {
this.inviteMore(nextIndex + 1);
return;
}
this.doInvite(addr, ignoreProfile).then(() => {
this.inviteMore(nextIndex + 1, ignoreProfile);
}).catch(() => this.deferred?.resolve(this.completionStates));
}
}
exports.default = MultiInviter;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbWF0cml4IiwicmVxdWlyZSIsIl90eXBlcyIsIl91dGlscyIsIl9sb2dnZXIiLCJfVXNlckFkZHJlc3MiLCJfbGFuZ3VhZ2VIYW5kbGVyIiwiX01vZGFsIiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsIl9TZXR0aW5nc1N0b3JlIiwiX0Fza0ludml0ZUFueXdheURpYWxvZyIsIl9Db25maXJtVXNlckFjdGlvbkRpYWxvZyIsIkludml0ZVN0YXRlIiwiZXhwb3J0cyIsIlVOS05PV05fUFJPRklMRV9FUlJPUlMiLCJVU0VSX0FMUkVBRFlfSk9JTkVEIiwiVVNFUl9BTFJFQURZX0lOVklURUQiLCJVU0VSX0JBTk5FRCIsIk11bHRpSW52aXRlciIsImNvbnN0cnVjdG9yIiwibWF0cml4Q2xpZW50Iiwicm9vbUlkIiwicHJvZ3Jlc3NDYWxsYmFjayIsIl9kZWZpbmVQcm9wZXJ0eTIiLCJkZWZhdWx0IiwiZmF0YWwiLCJfZmF0YWwiLCJpbnZpdGUiLCJhZGRyZXNzZXMiLCJyZWFzb24iLCJsZW5ndGgiLCJFcnJvciIsInB1c2giLCJhZGRyIiwiZ2V0QWRkcmVzc1R5cGUiLCJjb21wbGV0aW9uU3RhdGVzIiwiZXJyb3JzIiwiZXJyY29kZSIsImVycm9yVGV4dCIsIl90IiwiZGVmZXJyZWQiLCJkZWZlciIsImludml0ZU1vcmUiLCJwcm9taXNlIiwiY2FuY2VsIiwiYnVzeSIsImNhbmNlbGVkIiwicmVqZWN0IiwiZ2V0Q29tcGxldGlvblN0YXRlIiwiZ2V0RXJyb3JUZXh0IiwiaW52aXRlVG9Sb29tIiwiaWdub3JlUHJvZmlsZSIsImFkZHJUeXBlIiwiQWRkcmVzc1R5cGUiLCJFbWFpbCIsImludml0ZUJ5RW1haWwiLCJNYXRyaXhVc2VySWQiLCJyb29tIiwiZ2V0Um9vbSIsIm1lbWJlciIsImdldE1lbWJlciIsIm1lbWJlcnNoaXAiLCJLbm93bk1lbWJlcnNoaXAiLCJKb2luIiwiTWF0cml4RXJyb3IiLCJlcnJvciIsIkludml0ZSIsIkJhbiIsInByb2NlZWQiLCJvdXJNZW1iZXIiLCJnZXRTYWZlVXNlcklkIiwicG93ZXJMZXZlbCIsImN1cnJlbnRTdGF0ZSIsImhhc1N1ZmZpY2llbnRQb3dlckxldmVsRm9yIiwiZmluaXNoZWQiLCJNb2RhbCIsImNyZWF0ZURpYWxvZyIsIkNvbmZpcm1Vc2VyQWN0aW9uRGlhbG9nIiwiYWN0aW9uIiwidGl0bGUiLCJ1bmJhbiIsInVzZXJJZCIsIlNldHRpbmdzU3RvcmUiLCJnZXRWYWx1ZSIsImdldFByb2ZpbGVJbmZvIiwiZXJyIiwiZG9JbnZpdGUiLCJhZGRyZXNzIiwiUHJvbWlzZSIsInJlc29sdmUiLCJsb2dnZXIiLCJsb2ciLCJ0aGVuIiwiSW52aXRlZCIsImNhdGNoIiwiaXNTcGFjZSIsImlzU3BhY2VSb29tIiwiaXNGZWRlcmF0ZWQiLCJnZXRTdGF0ZUV2ZW50cyIsIkV2ZW50VHlwZSIsIlJvb21DcmVhdGUiLCJnZXRDb250ZW50Iiwid2luZG93Iiwic2V0VGltZW91dCIsIndhcm4iLCJuZXh0SW5kZXgiLCJPYmplY3QiLCJrZXlzIiwidW5rbm93blByb2ZpbGVVc2VycyIsImZpbHRlciIsImEiLCJpbmNsdWRlcyIsImludml0ZVVua25vd25zIiwicHJvbWlzZXMiLCJtYXAiLCJ1IiwiYWxsIiwiQXNrSW52aXRlQW55d2F5RGlhbG9nIiwib25JbnZpdGVBbnl3YXlzIiwib25HaXZlVXAiXSwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvTXVsdGlJbnZpdGVyLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qXG5Db3B5cmlnaHQgMjAyNCBOZXcgVmVjdG9yIEx0ZC5cbkNvcHlyaWdodCAyMDE2LTIwMjEgVGhlIE1hdHJpeC5vcmcgRm91bmRhdGlvbiBDLkkuQy5cblxuU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFHUEwtMy4wLW9ubHkgT1IgR1BMLTMuMC1vbmx5XG5QbGVhc2Ugc2VlIExJQ0VOU0UgZmlsZXMgaW4gdGhlIHJlcG9zaXRvcnkgcm9vdCBmb3IgZnVsbCBkZXRhaWxzLlxuKi9cblxuaW1wb3J0IHsgTWF0cml4RXJyb3IsIE1hdHJpeENsaWVudCwgRXZlbnRUeXBlIH0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL21hdHJpeFwiO1xuaW1wb3J0IHsgS25vd25NZW1iZXJzaGlwIH0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL3R5cGVzXCI7XG5pbXBvcnQgeyBkZWZlciwgSURlZmVycmVkIH0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL3V0aWxzXCI7XG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvbG9nZ2VyXCI7XG5cbmltcG9ydCB7IEFkZHJlc3NUeXBlLCBnZXRBZGRyZXNzVHlwZSB9IGZyb20gXCIuLi9Vc2VyQWRkcmVzc1wiO1xuaW1wb3J0IHsgX3QgfSBmcm9tIFwiLi4vbGFuZ3VhZ2VIYW5kbGVyXCI7XG5pbXBvcnQgTW9kYWwgZnJvbSBcIi4uL01vZGFsXCI7XG5pbXBvcnQgU2V0dGluZ3NTdG9yZSBmcm9tIFwiLi4vc2V0dGluZ3MvU2V0dGluZ3NTdG9yZVwiO1xuaW1wb3J0IEFza0ludml0ZUFueXdheURpYWxvZyBmcm9tIFwiLi4vY29tcG9uZW50cy92aWV3cy9kaWFsb2dzL0Fza0ludml0ZUFueXdheURpYWxvZ1wiO1xuaW1wb3J0IENvbmZpcm1Vc2VyQWN0aW9uRGlhbG9nIGZyb20gXCIuLi9jb21wb25lbnRzL3ZpZXdzL2RpYWxvZ3MvQ29uZmlybVVzZXJBY3Rpb25EaWFsb2dcIjtcblxuZXhwb3J0IGVudW0gSW52aXRlU3RhdGUge1xuICAgIEludml0ZWQgPSBcImludml0ZWRcIixcbiAgICBFcnJvciA9IFwiZXJyb3JcIixcbn1cblxuaW50ZXJmYWNlIElFcnJvciB7XG4gICAgZXJyb3JUZXh0OiBzdHJpbmc7XG4gICAgZXJyY29kZTogc3RyaW5nO1xufVxuXG5leHBvcnQgY29uc3QgVU5LTk9XTl9QUk9GSUxFX0VSUk9SUyA9IFtcbiAgICBcIk1fTk9UX0ZPVU5EXCIsXG4gICAgXCJNX1VTRVJfTk9UX0ZPVU5EXCIsXG4gICAgXCJNX1BST0ZJTEVfVU5ESVNDTE9TRURcIixcbiAgICBcIk1fUFJPRklMRV9OT1RfRk9VTkRcIixcbl07XG5cbmV4cG9ydCB0eXBlIENvbXBsZXRpb25TdGF0ZXMgPSBSZWNvcmQ8c3RyaW5nLCBJbnZpdGVTdGF0ZT47XG5cbmNvbnN0IFVTRVJfQUxSRUFEWV9KT0lORUQgPSBcIklPLkVMRU1FTlQuQUxSRUFEWV9KT0lORURcIjtcbmNvbnN0IFVTRVJfQUxSRUFEWV9JTlZJVEVEID0gXCJJTy5FTEVNRU5ULkFMUkVBRFlfSU5WSVRFRFwiO1xuY29uc3QgVVNFUl9CQU5ORUQgPSBcIklPLkVMRU1FTlQuQkFOTkVEXCI7XG5cbi8qKlxuICogSW52aXRlcyBtdWx0aXBsZSBhZGRyZXNzZXMgdG8gYSByb29tLCBoYW5kbGluZyByYXRlIGxpbWl0aW5nIGZyb20gdGhlIHNlcnZlclxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBNdWx0aUludml0ZXIge1xuICAgIHByaXZhdGUgY2FuY2VsZWQgPSBmYWxzZTtcbiAgICBwcml2YXRlIGFkZHJlc3Nlczogc3RyaW5nW10gPSBbXTtcbiAgICBwcml2YXRlIGJ1c3kgPSBmYWxzZTtcbiAgICBwcml2YXRlIF9mYXRhbCA9IGZhbHNlO1xuICAgIHByaXZhdGUgY29tcGxldGlvblN0YXRlczogQ29tcGxldGlvblN0YXRlcyA9IHt9OyAvLyBTdGF0ZSBvZiBlYWNoIGFkZHJlc3MgKGludml0ZWQgb3IgZXJyb3IpXG4gICAgcHJpdmF0ZSBlcnJvcnM6IFJlY29yZDxzdHJpbmcsIElFcnJvcj4gPSB7fTsgLy8geyBhZGRyZXNzOiB7ZXJyb3JUZXh0LCBlcnJjb2RlfSB9XG4gICAgcHJpdmF0ZSBkZWZlcnJlZDogSURlZmVycmVkPENvbXBsZXRpb25TdGF0ZXM+IHwgbnVsbCA9IG51bGw7XG4gICAgcHJpdmF0ZSByZWFzb246IHN0cmluZyB8IHVuZGVmaW5lZDtcblxuICAgIC8qKlxuICAgICAqIEBwYXJhbSBtYXRyaXhDbGllbnQgdGhlIGNsaWVudCBvZiB0aGUgbG9nZ2VkIGluIHVzZXJcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gcm9vbUlkIFRoZSBJRCBvZiB0aGUgcm9vbSB0byBpbnZpdGUgdG9cbiAgICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBwcm9ncmVzc0NhbGxiYWNrIG9wdGlvbmFsIGNhbGxiYWNrLCBmaXJlZCBhZnRlciBlYWNoIGludml0ZS5cbiAgICAgKi9cbiAgICBwdWJsaWMgY29uc3RydWN0b3IoXG4gICAgICAgIHByaXZhdGUgcmVhZG9ubHkgbWF0cml4Q2xpZW50OiBNYXRyaXhDbGllbnQsXG4gICAgICAgIHByaXZhdGUgcm9vbUlkOiBzdHJpbmcsXG4gICAgICAgIHByaXZhdGUgcmVhZG9ubHkgcHJvZ3Jlc3NDYWxsYmFjaz86ICgpID0+IHZvaWQsXG4gICAgKSB7fVxuXG4gICAgcHVibGljIGdldCBmYXRhbCgpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2ZhdGFsO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEludml0ZSB1c2VycyB0byB0aGlzIHJvb20uIFRoaXMgbWF5IG9ubHkgYmUgY2FsbGVkIG9uY2UgcGVyXG4gICAgICogaW5zdGFuY2Ugb2YgdGhlIGNsYXNzLlxuICAgICAqXG4gICAgICogQHBhcmFtIHthcnJheX0gYWRkcmVzc2VzIEFycmF5IG9mIGFkZHJlc3NlcyB0byBpbnZpdGVcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gcmVhc29uIFJlYXNvbiBmb3IgaW52aXRpbmcgKG9wdGlvbmFsKVxuICAgICAqIEByZXR1cm5zIHtQcm9taXNlfSBSZXNvbHZlZCB3aGVuIGFsbCBpbnZpdGF0aW9ucyBpbiB0aGUgcXVldWUgYXJlIGNvbXBsZXRlXG4gICAgICovXG4gICAgcHVibGljIGludml0ZShhZGRyZXNzZXM6IHN0cmluZ1tdLCByZWFzb24/OiBzdHJpbmcpOiBQcm9taXNlPENvbXBsZXRpb25TdGF0ZXM+IHtcbiAgICAgICAgaWYgKHRoaXMuYWRkcmVzc2VzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkFscmVhZHkgaW52aXRpbmcvaW52aXRlZFwiKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmFkZHJlc3Nlcy5wdXNoKC4uLmFkZHJlc3Nlcyk7XG4gICAgICAgIHRoaXMucmVhc29uID0gcmVhc29uO1xuXG4gICAgICAgIGZvciAoY29uc3QgYWRkciBvZiB0aGlzLmFkZHJlc3Nlcykge1xuICAgICAgICAgICAgaWYgKGdldEFkZHJlc3NUeXBlKGFkZHIpID09PSBudWxsKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5jb21wbGV0aW9uU3RhdGVzW2FkZHJdID0gSW52aXRlU3RhdGUuRXJyb3I7XG4gICAgICAgICAgICAgICAgdGhpcy5lcnJvcnNbYWRkcl0gPSB7XG4gICAgICAgICAgICAgICAgICAgIGVycmNvZGU6IFwiTV9JTlZBTElEXCIsXG4gICAgICAgICAgICAgICAgICAgIGVycm9yVGV4dDogX3QoXCJpbnZpdGV8aW52YWxpZF9hZGRyZXNzXCIpLFxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5kZWZlcnJlZCA9IGRlZmVyPENvbXBsZXRpb25TdGF0ZXM+KCk7XG4gICAgICAgIHRoaXMuaW52aXRlTW9yZSgwKTtcblxuICAgICAgICByZXR1cm4gdGhpcy5kZWZlcnJlZC5wcm9taXNlO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFN0b3BzIGludml0aW5nLiBDYXVzZXMgcHJvbWlzZXMgcmV0dXJuZWQgYnkgaW52aXRlKCkgdG8gYmUgcmVqZWN0ZWQuXG4gICAgICovXG4gICAgcHVibGljIGNhbmNlbCgpOiB2b2lkIHtcbiAgICAgICAgaWYgKCF0aGlzLmJ1c3kpIHJldHVybjtcblxuICAgICAgICB0aGlzLmNhbmNlbGVkID0gdHJ1ZTtcbiAgICAgICAgdGhpcy5kZWZlcnJlZD8ucmVqZWN0KG5ldyBFcnJvcihcImNhbmNlbGVkXCIpKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0Q29tcGxldGlvblN0YXRlKGFkZHI6IHN0cmluZyk6IEludml0ZVN0YXRlIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuY29tcGxldGlvblN0YXRlc1thZGRyXTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0RXJyb3JUZXh0KGFkZHI6IHN0cmluZyk6IHN0cmluZyB8IG51bGwge1xuICAgICAgICByZXR1cm4gdGhpcy5lcnJvcnNbYWRkcl0/LmVycm9yVGV4dCA/PyBudWxsO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgaW52aXRlVG9Sb29tKHJvb21JZDogc3RyaW5nLCBhZGRyOiBzdHJpbmcsIGlnbm9yZVByb2ZpbGUgPSBmYWxzZSk6IFByb21pc2U8e30+IHtcbiAgICAgICAgY29uc3QgYWRkclR5cGUgPSBnZXRBZGRyZXNzVHlwZShhZGRyKTtcblxuICAgICAgICBpZiAoYWRkclR5cGUgPT09IEFkZHJlc3NUeXBlLkVtYWlsKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5tYXRyaXhDbGllbnQuaW52aXRlQnlFbWFpbChyb29tSWQsIGFkZHIpO1xuICAgICAgICB9IGVsc2UgaWYgKGFkZHJUeXBlID09PSBBZGRyZXNzVHlwZS5NYXRyaXhVc2VySWQpIHtcbiAgICAgICAgICAgIGNvbnN0IHJvb20gPSB0aGlzLm1hdHJpeENsaWVudC5nZXRSb29tKHJvb21JZCk7XG4gICAgICAgICAgICBpZiAoIXJvb20pIHRocm93IG5ldyBFcnJvcihcIlJvb20gbm90IGZvdW5kXCIpO1xuXG4gICAgICAgICAgICBjb25zdCBtZW1iZXIgPSByb29tLmdldE1lbWJlcihhZGRyKTtcbiAgICAgICAgICAgIGlmIChtZW1iZXI/Lm1lbWJlcnNoaXAgPT09IEtub3duTWVtYmVyc2hpcC5Kb2luKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IE1hdHJpeEVycm9yKHtcbiAgICAgICAgICAgICAgICAgICAgZXJyY29kZTogVVNFUl9BTFJFQURZX0pPSU5FRCxcbiAgICAgICAgICAgICAgICAgICAgZXJyb3I6IFwiTWVtYmVyIGFscmVhZHkgam9pbmVkXCIsXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKG1lbWJlcj8ubWVtYmVyc2hpcCA9PT0gS25vd25NZW1iZXJzaGlwLkludml0ZSkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBNYXRyaXhFcnJvcih7XG4gICAgICAgICAgICAgICAgICAgIGVycmNvZGU6IFVTRVJfQUxSRUFEWV9JTlZJVEVELFxuICAgICAgICAgICAgICAgICAgICBlcnJvcjogXCJNZW1iZXIgYWxyZWFkeSBpbnZpdGVkXCIsXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKG1lbWJlcj8ubWVtYmVyc2hpcCA9PT0gS25vd25NZW1iZXJzaGlwLkJhbikge1xuICAgICAgICAgICAgICAgIGxldCBwcm9jZWVkID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgLy8gQ2hlY2sgaWYgd2UgY2FuIHVuYmFuIHRoZSBpbnZpdGVlLlxuICAgICAgICAgICAgICAgIC8vIFNlZSBodHRwczovL3NwZWMubWF0cml4Lm9yZy92MS43L3Jvb21zL3YxMC8jYXV0aG9yaXphdGlvbi1ydWxlcywgcGFydGljdWxhcmx5IDQuNS4zIGFuZCA0LjUuNC5cbiAgICAgICAgICAgICAgICBjb25zdCBvdXJNZW1iZXIgPSByb29tLmdldE1lbWJlcih0aGlzLm1hdHJpeENsaWVudC5nZXRTYWZlVXNlcklkKCkpO1xuICAgICAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICAgICAgISFvdXJNZW1iZXIgJiZcbiAgICAgICAgICAgICAgICAgICAgbWVtYmVyLnBvd2VyTGV2ZWwgPCBvdXJNZW1iZXIucG93ZXJMZXZlbCAmJlxuICAgICAgICAgICAgICAgICAgICByb29tLmN1cnJlbnRTdGF0ZS5oYXNTdWZmaWNpZW50UG93ZXJMZXZlbEZvcihcImJhblwiLCBvdXJNZW1iZXIucG93ZXJMZXZlbCkgJiZcbiAgICAgICAgICAgICAgICAgICAgcm9vbS5jdXJyZW50U3RhdGUuaGFzU3VmZmljaWVudFBvd2VyTGV2ZWxGb3IoXCJraWNrXCIsIG91ck1lbWJlci5wb3dlckxldmVsKVxuICAgICAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCB7IGZpbmlzaGVkIH0gPSBNb2RhbC5jcmVhdGVEaWFsb2coQ29uZmlybVVzZXJBY3Rpb25EaWFsb2csIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG1lbWJlcixcbiAgICAgICAgICAgICAgICAgICAgICAgIGFjdGlvbjogX3QoXCJhY3Rpb258dW5iYW5cIiksXG4gICAgICAgICAgICAgICAgICAgICAgICB0aXRsZTogX3QoXCJpbnZpdGV8dW5iYW5fZmlyc3RfdGl0bGVcIiksXG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICBbcHJvY2VlZCA9IGZhbHNlXSA9IGF3YWl0IGZpbmlzaGVkO1xuICAgICAgICAgICAgICAgICAgICBpZiAocHJvY2VlZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5tYXRyaXhDbGllbnQudW5iYW4ocm9vbUlkLCBtZW1iZXIudXNlcklkKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmICghcHJvY2VlZCkge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgTWF0cml4RXJyb3Ioe1xuICAgICAgICAgICAgICAgICAgICAgICAgZXJyY29kZTogVVNFUl9CQU5ORUQsXG4gICAgICAgICAgICAgICAgICAgICAgICBlcnJvcjogXCJNZW1iZXIgaXMgYmFubmVkXCIsXG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKCFpZ25vcmVQcm9maWxlICYmIFNldHRpbmdzU3RvcmUuZ2V0VmFsdWUoXCJwcm9tcHRCZWZvcmVJbnZpdGVVbmtub3duVXNlcnNcIiwgdGhpcy5yb29tSWQpKSB7XG4gICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5tYXRyaXhDbGllbnQuZ2V0UHJvZmlsZUluZm8oYWRkcik7XG4gICAgICAgICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIFRoZSBlcnJvciBoYW5kbGluZyBkdXJpbmcgdGhlIGludml0YXRpb24gcHJvY2VzcyBjb3ZlcnMgYW55IEFQSS5cbiAgICAgICAgICAgICAgICAgICAgLy8gU29tZSBlcnJvcnMgbXVzdCB0byBtZSBtYXBwZWQgZnJvbSBwcm9maWxlIEFQSSBlcnJvcnMgdG8gbW9yZSBzcGVjaWZpYyBvbmVzIHRvIGF2b2lkIGNvbGxpc2lvbnMuXG4gICAgICAgICAgICAgICAgICAgIHN3aXRjaCAoZXJyIGluc3RhbmNlb2YgTWF0cml4RXJyb3IgPyBlcnIuZXJyY29kZSA6IGVycikge1xuICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSBcIk1fRk9SQklEREVOXCI6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IE1hdHJpeEVycm9yKHsgZXJyY29kZTogXCJNX1BST0ZJTEVfVU5ESVNDTE9TRURcIiB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgXCJNX05PVF9GT1VORFwiOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBNYXRyaXhFcnJvcih7IGVycmNvZGU6IFwiTV9VU0VSX05PVF9GT1VORFwiIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBlcnI7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiB0aGlzLm1hdHJpeENsaWVudC5pbnZpdGUocm9vbUlkLCBhZGRyLCB0aGlzLnJlYXNvbik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJVbnN1cHBvcnRlZCBhZGRyZXNzXCIpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBkb0ludml0ZShhZGRyZXNzOiBzdHJpbmcsIGlnbm9yZVByb2ZpbGUgPSBmYWxzZSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICByZXR1cm4gbmV3IFByb21pc2U8dm9pZD4oKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICAgICAgbG9nZ2VyLmxvZyhgSW52aXRpbmcgJHthZGRyZXNzfWApO1xuXG4gICAgICAgICAgICBjb25zdCBkb0ludml0ZSA9IHRoaXMuaW52aXRlVG9Sb29tKHRoaXMucm9vbUlkLCBhZGRyZXNzLCBpZ25vcmVQcm9maWxlKTtcbiAgICAgICAgICAgIGRvSW52aXRlXG4gICAgICAgICAgICAgICAgLnRoZW4oKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy5jYW5jZWxlZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jb21wbGV0aW9uU3RhdGVzW2FkZHJlc3NdID0gSW52aXRlU3RhdGUuSW52aXRlZDtcbiAgICAgICAgICAgICAgICAgICAgZGVsZXRlIHRoaXMuZXJyb3JzW2FkZHJlc3NdO1xuXG4gICAgICAgICAgICAgICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5wcm9ncmVzc0NhbGxiYWNrPy4oKTtcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIC5jYXRjaCgoZXJyKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLmNhbmNlbGVkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICBsb2dnZXIuZXJyb3IoZXJyKTtcblxuICAgICAgICAgICAgICAgICAgICBjb25zdCByb29tID0gdGhpcy5yb29tSWQgPyB0aGlzLm1hdHJpeENsaWVudC5nZXRSb29tKHRoaXMucm9vbUlkKSA6IG51bGw7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGlzU3BhY2UgPSByb29tPy5pc1NwYWNlUm9vbSgpO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBpc0ZlZGVyYXRlZCA9IHJvb20/LmN1cnJlbnRTdGF0ZS5nZXRTdGF0ZUV2ZW50cyhFdmVudFR5cGUuUm9vbUNyZWF0ZSwgXCJcIik/LmdldENvbnRlbnQoKVtcbiAgICAgICAgICAgICAgICAgICAgICAgIFwibS5mZWRlcmF0ZVwiXG4gICAgICAgICAgICAgICAgICAgIF07XG5cbiAgICAgICAgICAgICAgICAgICAgbGV0IGVycm9yVGV4dDogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgICAgICBsZXQgZmF0YWwgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgc3dpdGNoIChlcnIuZXJyY29kZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSBcIk1fRk9SQklEREVOXCI6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzU3BhY2UpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3JUZXh0ID1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlzRmVkZXJhdGVkID09PSBmYWxzZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID8gX3QoXCJpbnZpdGV8ZXJyb3JfdW5mZWRlcmF0ZWRfc3BhY2VcIilcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA6IF90KFwiaW52aXRlfGVycm9yX3Blcm1pc3Npb25zX3NwYWNlXCIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yVGV4dCA9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpc0ZlZGVyYXRlZCA9PT0gZmFsc2VcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA/IF90KFwiaW52aXRlfGVycm9yX3VuZmVkZXJhdGVkX3Jvb21cIilcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA6IF90KFwiaW52aXRlfGVycm9yX3Blcm1pc3Npb25zX3Jvb21cIik7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhdGFsID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgVVNFUl9BTFJFQURZX0lOVklURUQ6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzU3BhY2UpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3JUZXh0ID0gX3QoXCJpbnZpdGV8ZXJyb3JfYWxyZWFkeV9pbnZpdGVkX3NwYWNlXCIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yVGV4dCA9IF90KFwiaW52aXRlfGVycm9yX2FscmVhZHlfaW52aXRlZF9yb29tXCIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgVVNFUl9BTFJFQURZX0pPSU5FRDpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoaXNTcGFjZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnJvclRleHQgPSBfdChcImludml0ZXxlcnJvcl9hbHJlYWR5X2pvaW5lZF9zcGFjZVwiKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnJvclRleHQgPSBfdChcImludml0ZXxlcnJvcl9hbHJlYWR5X2pvaW5lZF9yb29tXCIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgXCJNX0xJTUlUX0VYQ0VFREVEXCI6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gd2UncmUgYmVpbmcgdGhyb3R0bGVkIHNvIHdhaXQgYSBiaXQgJiB0cnkgYWdhaW5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aW5kb3cuc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZG9JbnZpdGUoYWRkcmVzcywgaWdub3JlUHJvZmlsZSkudGhlbihyZXNvbHZlLCByZWplY3QpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sIDUwMDApO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgXCJNX05PVF9GT1VORFwiOlxuICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSBcIk1fVVNFUl9OT1RfRk9VTkRcIjpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnJvclRleHQgPSBfdChcImludml0ZXxlcnJvcl91c2VyX25vdF9mb3VuZFwiKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgXCJNX1BST0ZJTEVfVU5ESVNDTE9TRURcIjpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnJvclRleHQgPSBfdChcImludml0ZXxlcnJvcl9wcm9maWxlX3VuZGlzY2xvc2VkXCIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSBcIk1fUFJPRklMRV9OT1RfRk9VTkRcIjpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWlnbm9yZVByb2ZpbGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gSW52aXRlIHdpdGhvdXQgdGhlIHByb2ZpbGUgY2hlY2tcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nZ2VyLndhcm4oYFVzZXIgJHthZGRyZXNzfSBkb2VzIG5vdCBoYXZlIGEgcHJvZmlsZSAtIGludml0aW5nIGFueXdheXMgYXV0b21hdGljYWxseWApO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmRvSW52aXRlKGFkZHJlc3MsIHRydWUpLnRoZW4ocmVzb2x2ZSwgcmVqZWN0KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgXCJNX0JBRF9TVEFURVwiOlxuICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSBVU0VSX0JBTk5FRDpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnJvclRleHQgPSBfdChcImludml0ZXxlcnJvcl9iYWRfc3RhdGVcIik7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgICAgICBjYXNlIFwiTV9VTlNVUFBPUlRFRF9ST09NX1ZFUlNJT05cIjpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoaXNTcGFjZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnJvclRleHQgPSBfdChcImludml0ZXxlcnJvcl92ZXJzaW9uX3Vuc3VwcG9ydGVkX3NwYWNlXCIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yVGV4dCA9IF90KFwiaW52aXRlfGVycm9yX3ZlcnNpb25fdW5zdXBwb3J0ZWRfcm9vbVwiKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgICAgICBjYXNlIFwiT1JHLk1BVFJJWC5KU1NES19NSVNTSU5HX1BBUkFNXCI6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGdldEFkZHJlc3NUeXBlKGFkZHJlc3MpID09PSBBZGRyZXNzVHlwZS5FbWFpbCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnJvclRleHQgPSBfdChcImNhbm5vdF9pbnZpdGVfd2l0aG91dF9pZGVudGl0eV9zZXJ2ZXJcIik7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKCFlcnJvclRleHQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yVGV4dCA9IF90KFwiaW52aXRlfGVycm9yX3Vua25vd25cIik7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICB0aGlzLmNvbXBsZXRpb25TdGF0ZXNbYWRkcmVzc10gPSBJbnZpdGVTdGF0ZS5FcnJvcjtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5lcnJvcnNbYWRkcmVzc10gPSB7IGVycm9yVGV4dCwgZXJyY29kZTogZXJyLmVycmNvZGUgfTtcblxuICAgICAgICAgICAgICAgICAgICB0aGlzLmJ1c3kgPSAhZmF0YWw7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX2ZhdGFsID0gZmF0YWw7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKGZhdGFsKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZWplY3QoZXJyKTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGludml0ZU1vcmUobmV4dEluZGV4OiBudW1iZXIsIGlnbm9yZVByb2ZpbGUgPSBmYWxzZSk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy5jYW5jZWxlZCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKG5leHRJbmRleCA9PT0gdGhpcy5hZGRyZXNzZXMubGVuZ3RoKSB7XG4gICAgICAgICAgICB0aGlzLmJ1c3kgPSBmYWxzZTtcbiAgICAgICAgICAgIGlmIChPYmplY3Qua2V5cyh0aGlzLmVycm9ycykubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgIC8vIFRoZXJlIHdlcmUgcHJvYmxlbXMgaW52aXRpbmcgc29tZSBwZW9wbGUgLSBzZWUgaWYgd2UgY2FuIGludml0ZSB0aGVtXG4gICAgICAgICAgICAgICAgLy8gd2l0aG91dCBjYXJpbmcgaWYgdGhleSBleGlzdCBvciBub3QuXG4gICAgICAgICAgICAgICAgY29uc3QgdW5rbm93blByb2ZpbGVVc2VycyA9IE9iamVjdC5rZXlzKHRoaXMuZXJyb3JzKS5maWx0ZXIoKGEpID0+XG4gICAgICAgICAgICAgICAgICAgIFVOS05PV05fUFJPRklMRV9FUlJPUlMuaW5jbHVkZXModGhpcy5lcnJvcnNbYV0uZXJyY29kZSksXG4gICAgICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgICAgIGlmICh1bmtub3duUHJvZmlsZVVzZXJzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgaW52aXRlVW5rbm93bnMgPSAoKTogdm9pZCA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBwcm9taXNlcyA9IHVua25vd25Qcm9maWxlVXNlcnMubWFwKCh1KSA9PiB0aGlzLmRvSW52aXRlKHUsIHRydWUpKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIFByb21pc2UuYWxsKHByb21pc2VzKS50aGVuKCgpID0+IHRoaXMuZGVmZXJyZWQ/LnJlc29sdmUodGhpcy5jb21wbGV0aW9uU3RhdGVzKSk7XG4gICAgICAgICAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKCFTZXR0aW5nc1N0b3JlLmdldFZhbHVlKFwicHJvbXB0QmVmb3JlSW52aXRlVW5rbm93blVzZXJzXCIsIHRoaXMucm9vbUlkKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgaW52aXRlVW5rbm93bnMoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIGxvZ2dlci5sb2coXCJTaG93aW5nIGZhaWxlZCB0byBpbnZpdGUgZGlhbG9nLi4uXCIpO1xuICAgICAgICAgICAgICAgICAgICBNb2RhbC5jcmVhdGVEaWFsb2coQXNrSW52aXRlQW55d2F5RGlhbG9nLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICB1bmtub3duUHJvZmlsZVVzZXJzOiB1bmtub3duUHJvZmlsZVVzZXJzLm1hcCgodSkgPT4gKHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2VySWQ6IHUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3JUZXh0OiB0aGlzLmVycm9yc1t1XS5lcnJvclRleHQsXG4gICAgICAgICAgICAgICAgICAgICAgICB9KSksXG4gICAgICAgICAgICAgICAgICAgICAgICBvbkludml0ZUFueXdheXM6ICgpID0+IGludml0ZVVua25vd25zKCksXG4gICAgICAgICAgICAgICAgICAgICAgICBvbkdpdmVVcDogKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEZha2UgYWxsIHRoZSBjb21wbGV0aW9uIHN0YXRlcyBiZWNhdXNlIHdlIGFscmVhZHkgd2FybmVkIHRoZSB1c2VyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9yIChjb25zdCBhZGRyIG9mIHVua25vd25Qcm9maWxlVXNlcnMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5jb21wbGV0aW9uU3RhdGVzW2FkZHJdID0gSW52aXRlU3RhdGUuSW52aXRlZDtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5kZWZlcnJlZD8ucmVzb2x2ZSh0aGlzLmNvbXBsZXRpb25TdGF0ZXMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLmRlZmVycmVkPy5yZXNvbHZlKHRoaXMuY29tcGxldGlvblN0YXRlcyk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBhZGRyID0gdGhpcy5hZGRyZXNzZXNbbmV4dEluZGV4XTtcblxuICAgICAgICAvLyBkb24ndCB0cnkgdG8gaW52aXRlIGl0IGlmIGl0J3MgYW4gaW52YWxpZCBhZGRyZXNzXG4gICAgICAgIC8vIChpdCB3aWxsIGFscmVhZHkgYmUgbWFya2VkIGFzIGFuIGVycm9yIHRob3VnaCxcbiAgICAgICAgLy8gc28gbm8gbmVlZCB0byBkbyBzbyBhZ2FpbilcbiAgICAgICAgaWYgKGdldEFkZHJlc3NUeXBlKGFkZHIpID09PSBudWxsKSB7XG4gICAgICAgICAgICB0aGlzLmludml0ZU1vcmUobmV4dEluZGV4ICsgMSk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyBkb24ndCByZS1pbnZpdGUgKHRoZXJlJ3Mgbm8gd2F5IGluIHRoZSBVSSB0byBkbyB0aGlzLCBidXRcbiAgICAgICAgLy8gZm9yIHNhbml0eSdzIHNha2UpXG4gICAgICAgIGlmICh0aGlzLmNvbXBsZXRpb25TdGF0ZXNbYWRkcl0gPT09IEludml0ZVN0YXRlLkludml0ZWQpIHtcbiAgICAgICAgICAgIHRoaXMuaW52aXRlTW9yZShuZXh0SW5kZXggKyAxKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuZG9JbnZpdGUoYWRkciwgaWdub3JlUHJvZmlsZSlcbiAgICAgICAgICAgIC50aGVuKCgpID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLmludml0ZU1vcmUobmV4dEluZGV4ICsgMSwgaWdub3JlUHJvZmlsZSk7XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLmNhdGNoKCgpID0+IHRoaXMuZGVmZXJyZWQ/LnJlc29sdmUodGhpcy5jb21wbGV0aW9uU3RhdGVzKSk7XG4gICAgfVxufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7OztBQVFBLElBQUFBLE9BQUEsR0FBQUMsT0FBQTtBQUNBLElBQUFDLE1BQUEsR0FBQUQsT0FBQTtBQUNBLElBQUFFLE1BQUEsR0FBQUYsT0FBQTtBQUNBLElBQUFHLE9BQUEsR0FBQUgsT0FBQTtBQUVBLElBQUFJLFlBQUEsR0FBQUosT0FBQTtBQUNBLElBQUFLLGdCQUFBLEdBQUFMLE9BQUE7QUFDQSxJQUFBTSxNQUFBLEdBQUFDLHNCQUFBLENBQUFQLE9BQUE7QUFDQSxJQUFBUSxjQUFBLEdBQUFELHNCQUFBLENBQUFQLE9BQUE7QUFDQSxJQUFBUyxzQkFBQSxHQUFBRixzQkFBQSxDQUFBUCxPQUFBO0FBQ0EsSUFBQVUsd0JBQUEsR0FBQUgsc0JBQUEsQ0FBQVAsT0FBQTtBQWxCQTtBQUNBO0FBQ0E7QUFD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