matrix-react-sdk
Version:
SDK for matrix.org using React
382 lines (374 loc) • 56.2 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.UserVote = void 0;
exports.allVotes = allVotes;
exports.collectUserVotes = collectUserVotes;
exports.countVotes = countVotes;
exports.createVoteRelations = createVoteRelations;
exports.default = void 0;
exports.findTopAnswer = findTopAnswer;
exports.isPollEnded = isPollEnded;
exports.launchPollEditor = launchPollEditor;
exports.pollAlreadyHasVotes = pollAlreadyHasVotes;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _react = _interopRequireDefault(require("react"));
var _logger = require("matrix-js-sdk/src/logger");
var _matrix = require("matrix-js-sdk/src/matrix");
var _relatedRelations = require("matrix-js-sdk/src/models/related-relations");
var _PollResponseEvent = require("matrix-js-sdk/src/extensible_events_v1/PollResponseEvent");
var _languageHandler = require("../../../languageHandler");
var _Modal = _interopRequireDefault(require("../../../Modal"));
var _FormattingUtils = require("../../../utils/FormattingUtils");
var _MatrixClientContext = _interopRequireDefault(require("../../../contexts/MatrixClientContext"));
var _ErrorDialog = _interopRequireDefault(require("../dialogs/ErrorDialog"));
var _PollCreateDialog = _interopRequireDefault(require("../elements/PollCreateDialog"));
var _MatrixClientPeg = require("../../../MatrixClientPeg");
var _Spinner = _interopRequireDefault(require("../elements/Spinner"));
var _PollOption = require("../polls/PollOption");
/*
Copyright 2024 New Vector Ltd.
Copyright 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.
*/
function createVoteRelations(getRelationsForEvent, eventId) {
const relationsList = [];
const pollResponseRelations = getRelationsForEvent(eventId, "m.reference", _matrix.M_POLL_RESPONSE.name);
if (pollResponseRelations) {
relationsList.push(pollResponseRelations);
}
const pollResposnseAltRelations = getRelationsForEvent(eventId, "m.reference", _matrix.M_POLL_RESPONSE.altName);
if (pollResposnseAltRelations) {
relationsList.push(pollResposnseAltRelations);
}
return new _relatedRelations.RelatedRelations(relationsList);
}
function findTopAnswer(pollEvent, voteRelations) {
const pollEventId = pollEvent.getId();
if (!pollEventId) {
_logger.logger.warn("findTopAnswer: Poll event needs an event ID to fetch relations in order to determine " + "the top answer - assuming no best answer");
return "";
}
const poll = pollEvent.unstableExtensibleEvent;
if (!poll?.isEquivalentTo(_matrix.M_POLL_START)) {
_logger.logger.warn("Failed to parse poll to determine top answer - assuming no best answer");
return "";
}
const findAnswerText = answerId => {
return poll.answers.find(a => a.id === answerId)?.text ?? "";
};
const userVotes = collectUserVotes(allVotes(voteRelations));
const votes = countVotes(userVotes, poll);
const highestScore = Math.max(...votes.values());
const bestAnswerIds = [];
for (const [answerId, score] of votes) {
if (score == highestScore) {
bestAnswerIds.push(answerId);
}
}
const bestAnswerTexts = bestAnswerIds.map(findAnswerText);
return (0, _FormattingUtils.formatList)(bestAnswerTexts, 3);
}
function isPollEnded(pollEvent, matrixClient) {
const room = matrixClient.getRoom(pollEvent.getRoomId());
const poll = room?.polls.get(pollEvent.getId());
if (!poll || poll.isFetchingResponses) {
return false;
}
return poll.isEnded;
}
function pollAlreadyHasVotes(mxEvent, getRelationsForEvent) {
if (!getRelationsForEvent) return false;
const eventId = mxEvent.getId();
if (!eventId) return false;
const voteRelations = createVoteRelations(getRelationsForEvent, eventId);
return voteRelations.getRelations().length > 0;
}
function launchPollEditor(mxEvent, getRelationsForEvent) {
const room = _MatrixClientPeg.MatrixClientPeg.safeGet().getRoom(mxEvent.getRoomId());
if (pollAlreadyHasVotes(mxEvent, getRelationsForEvent)) {
_Modal.default.createDialog(_ErrorDialog.default, {
title: (0, _languageHandler._t)("poll|unable_edit_title"),
description: (0, _languageHandler._t)("poll|unable_edit_description")
});
} else if (room) {
_Modal.default.createDialog(_PollCreateDialog.default, {
room,
threadId: mxEvent.getThread()?.id,
editingMxEvent: mxEvent
}, "mx_CompoundDialog", false,
// isPriorityModal
true // isStaticModal
);
}
}
class MPollBody extends _react.default.Component {
// Events we have already seen
constructor(props, context) {
super(props, context);
(0, _defineProperty2.default)(this, "seenEventIds", []);
(0, _defineProperty2.default)(this, "onResponsesChange", responses => {
this.setState({
voteRelations: responses
});
this.onRelationsChange();
});
(0, _defineProperty2.default)(this, "onRelationsChange", () => {
// We hold Relations in our state, and they changed under us.
// Check whether we should delete our selection, and then
// re-render.
// Note: re-rendering is a side effect of unselectIfNewEventFromMe().
this.unselectIfNewEventFromMe();
});
this.state = {
selected: null,
pollInitialised: false
};
}
componentDidMount() {
const room = this.context?.getRoom(this.props.mxEvent.getRoomId());
const poll = room?.polls.get(this.props.mxEvent.getId());
if (poll) {
this.setPollInstance(poll);
} else {
room?.on(_matrix.PollEvent.New, this.setPollInstance.bind(this));
}
}
componentWillUnmount() {
this.removeListeners();
}
async setPollInstance(poll) {
if (poll.pollId !== this.props.mxEvent.getId()) {
return;
}
this.setState({
poll
}, () => {
this.addListeners();
});
const responses = await poll.getResponses();
const voteRelations = responses;
this.setState({
pollInitialised: true,
voteRelations
});
}
addListeners() {
this.state.poll?.on(_matrix.PollEvent.Responses, this.onResponsesChange);
this.state.poll?.on(_matrix.PollEvent.End, this.onRelationsChange);
this.state.poll?.on(_matrix.PollEvent.UndecryptableRelations, this.render.bind(this));
}
removeListeners() {
if (this.state.poll) {
this.state.poll.off(_matrix.PollEvent.Responses, this.onResponsesChange);
this.state.poll.off(_matrix.PollEvent.End, this.onRelationsChange);
this.state.poll.off(_matrix.PollEvent.UndecryptableRelations, this.render.bind(this));
}
}
selectOption(answerId) {
if (this.state.poll?.isEnded) {
return;
}
const userVotes = this.collectUserVotes();
const userId = this.context.getSafeUserId();
const myVote = userVotes.get(userId)?.answers[0];
if (answerId === myVote) {
return;
}
const response = _PollResponseEvent.PollResponseEvent.from([answerId], this.props.mxEvent.getId()).serialize();
this.context.sendEvent(this.props.mxEvent.getRoomId(), response.type, response.content).catch(e => {
console.error("Failed to submit poll response event:", e);
_Modal.default.createDialog(_ErrorDialog.default, {
title: (0, _languageHandler._t)("poll|error_voting_title"),
description: (0, _languageHandler._t)("poll|error_voting_description")
});
});
this.setState({
selected: answerId
});
}
/**
* @returns userId -> UserVote
*/
collectUserVotes() {
if (!this.state.voteRelations || !this.context) {
return new Map();
}
return collectUserVotes(allVotes(this.state.voteRelations), this.context.getUserId(), this.state.selected);
}
/**
* If we've just received a new event that we hadn't seen
* before, and that event is me voting (e.g. from a different
* device) then forget when the local user selected.
*
* Either way, calls setState to update our list of events we
* have already seen.
*/
unselectIfNewEventFromMe() {
const relations = this.state.voteRelations?.getRelations() || [];
const newEvents = relations.filter(mxEvent => !this.seenEventIds.includes(mxEvent.getId()));
let newSelected = this.state.selected;
if (newEvents.length > 0) {
for (const mxEvent of newEvents) {
if (mxEvent.getSender() === this.context.getUserId()) {
newSelected = null;
}
}
}
const newEventIds = newEvents.map(mxEvent => mxEvent.getId());
this.seenEventIds = this.seenEventIds.concat(newEventIds);
this.setState({
selected: newSelected
});
}
totalVotes(collectedVotes) {
let sum = 0;
for (const v of collectedVotes.values()) {
sum += v;
}
return sum;
}
render() {
const {
poll,
pollInitialised
} = this.state;
if (!poll?.pollEvent) {
return null;
}
const pollEvent = poll.pollEvent;
const pollId = this.props.mxEvent.getId();
const isFetchingResponses = !pollInitialised || poll.isFetchingResponses;
const userVotes = this.collectUserVotes();
const votes = countVotes(userVotes, pollEvent);
const totalVotes = this.totalVotes(votes);
const winCount = Math.max(...votes.values());
const userId = this.context.getSafeUserId();
const myVote = userVotes?.get(userId)?.answers[0];
const disclosed = _matrix.M_POLL_KIND_DISCLOSED.matches(pollEvent.kind.name);
// Disclosed: votes are hidden until I vote or the poll ends
// Undisclosed: votes are hidden until poll ends
const showResults = poll.isEnded || disclosed && myVote !== undefined;
let totalText;
if (showResults && poll.undecryptableRelationsCount) {
totalText = (0, _languageHandler._t)("poll|total_decryption_errors");
} else if (poll.isEnded) {
totalText = (0, _languageHandler._t)("right_panel|poll|final_result", {
count: totalVotes
});
} else if (!disclosed) {
totalText = (0, _languageHandler._t)("poll|total_not_ended");
} else if (myVote === undefined) {
if (totalVotes === 0) {
totalText = (0, _languageHandler._t)("poll|total_no_votes");
} else {
totalText = (0, _languageHandler._t)("poll|total_n_votes", {
count: totalVotes
});
}
} else {
totalText = (0, _languageHandler._t)("poll|total_n_votes_voted", {
count: totalVotes
});
}
const editedSpan = this.props.mxEvent.replacingEvent() ? /*#__PURE__*/_react.default.createElement("span", {
className: "mx_MPollBody_edited"
}, " (", (0, _languageHandler._t)("common|edited"), ")") : null;
return /*#__PURE__*/_react.default.createElement("div", {
className: "mx_MPollBody"
}, /*#__PURE__*/_react.default.createElement("h2", {
"data-testid": "pollQuestion"
}, pollEvent.question.text, editedSpan), /*#__PURE__*/_react.default.createElement("div", {
className: "mx_MPollBody_allOptions"
}, pollEvent.answers.map(answer => {
let answerVotes = 0;
if (showResults) {
answerVotes = votes.get(answer.id) ?? 0;
}
const checked = !poll.isEnded && myVote === answer.id || poll.isEnded && answerVotes === winCount;
return /*#__PURE__*/_react.default.createElement(_PollOption.PollOption, {
key: answer.id,
pollId: pollId,
answer: answer,
isChecked: checked,
isEnded: poll.isEnded,
voteCount: answerVotes,
totalVoteCount: totalVotes,
displayVoteCount: showResults,
onOptionSelected: this.selectOption.bind(this)
});
})), /*#__PURE__*/_react.default.createElement("div", {
"data-testid": "totalVotes",
className: "mx_MPollBody_totalVotes"
}, totalText, isFetchingResponses && /*#__PURE__*/_react.default.createElement(_Spinner.default, {
w: 16,
h: 16
})));
}
}
exports.default = MPollBody;
(0, _defineProperty2.default)(MPollBody, "contextType", _MatrixClientContext.default);
class UserVote {
constructor(ts, sender, answers) {
this.ts = ts;
this.sender = sender;
this.answers = answers;
}
}
exports.UserVote = UserVote;
function userResponseFromPollResponseEvent(event) {
const response = event.unstableExtensibleEvent;
if (!response?.isEquivalentTo(_matrix.M_POLL_RESPONSE)) {
throw new Error("Failed to parse Poll Response Event to determine user response");
}
return new UserVote(event.getTs(), event.getSender(), response.answerIds);
}
function allVotes(voteRelations) {
if (voteRelations) {
return voteRelations.getRelations().map(userResponseFromPollResponseEvent);
} else {
return [];
}
}
/**
* Figure out the correct vote for each user.
* @param userResponses current vote responses in the poll
* @param {string?} userId The userId for which the `selected` option will apply to.
* Should be set to the current user ID.
* @param {string?} selected Local echo selected option for the userId
* @returns a Map of user ID to their vote info
*/
function collectUserVotes(userResponses, userId, selected) {
const userVotes = new Map();
for (const response of userResponses) {
const otherResponse = userVotes.get(response.sender);
if (!otherResponse || otherResponse.ts < response.ts) {
userVotes.set(response.sender, response);
}
}
if (selected && userId) {
userVotes.set(userId, new UserVote(0, userId, [selected]));
}
return userVotes;
}
function countVotes(userVotes, pollStart) {
const collected = new Map();
for (const response of userVotes.values()) {
const tempResponse = _PollResponseEvent.PollResponseEvent.from(response.answers, "$irrelevant");
tempResponse.validateAgainst(pollStart);
if (!tempResponse.spoiled) {
for (const answerId of tempResponse.answerIds) {
if (collected.has(answerId)) {
collected.set(answerId, collected.get(answerId) + 1);
} else {
collected.set(answerId, 1);
}
}
}
}
return collected;
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfcmVhY3QiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwicmVxdWlyZSIsIl9sb2dnZXIiLCJfbWF0cml4IiwiX3JlbGF0ZWRSZWxhdGlvbnMiLCJfUG9sbFJlc3BvbnNlRXZlbnQiLCJfbGFuZ3VhZ2VIYW5kbGVyIiwiX01vZGFsIiwiX0Zvcm1hdHRpbmdVdGlscyIsIl9NYXRyaXhDbGllbnRDb250ZXh0IiwiX0Vycm9yRGlhbG9nIiwiX1BvbGxDcmVhdGVEaWFsb2ciLCJfTWF0cml4Q2xpZW50UGVnIiwiX1NwaW5uZXIiLCJfUG9sbE9wdGlvbiIsImNyZWF0ZVZvdGVSZWxhdGlvbnMiLCJnZXRSZWxhdGlvbnNGb3JFdmVudCIsImV2ZW50SWQiLCJyZWxhdGlvbnNMaXN0IiwicG9sbFJlc3BvbnNlUmVsYXRpb25zIiwiTV9QT0xMX1JFU1BPTlNFIiwibmFtZSIsInB1c2giLCJwb2xsUmVzcG9zbnNlQWx0UmVsYXRpb25zIiwiYWx0TmFtZSIsIlJlbGF0ZWRSZWxhdGlvbnMiLCJmaW5kVG9wQW5zd2VyIiwicG9sbEV2ZW50Iiwidm90ZVJlbGF0aW9ucyIsInBvbGxFdmVudElkIiwiZ2V0SWQiLCJsb2dnZXIiLCJ3YXJuIiwicG9sbCIsInVuc3RhYmxlRXh0ZW5zaWJsZUV2ZW50IiwiaXNFcXVpdmFsZW50VG8iLCJNX1BPTExfU1RBUlQiLCJmaW5kQW5zd2VyVGV4dCIsImFuc3dlcklkIiwiYW5zd2VycyIsImZpbmQiLCJhIiwiaWQiLCJ0ZXh0IiwidXNlclZvdGVzIiwiY29sbGVjdFVzZXJWb3RlcyIsImFsbFZvdGVzIiwidm90ZXMiLCJjb3VudFZvdGVzIiwiaGlnaGVzdFNjb3JlIiwiTWF0aCIsIm1heCIsInZhbHVlcyIsImJlc3RBbnN3ZXJJZHMiLCJzY29yZSIsImJlc3RBbnN3ZXJUZXh0cyIsIm1hcCIsImZvcm1hdExpc3QiLCJpc1BvbGxFbmRlZCIsIm1hdHJpeENsaWVudCIsInJvb20iLCJnZXRSb29tIiwiZ2V0Um9vbUlkIiwicG9sbHMiLCJnZXQiLCJpc0ZldGNoaW5nUmVzcG9uc2VzIiwiaXNFbmRlZCIsInBvbGxBbHJlYWR5SGFzVm90ZXMiLCJteEV2ZW50IiwiZ2V0UmVsYXRpb25zIiwibGVuZ3RoIiwibGF1bmNoUG9sbEVkaXRvciIsIk1hdHJpeENsaWVudFBlZyIsInNhZmVHZXQiLCJNb2RhbCIsImNyZWF0ZURpYWxvZyIsIkVycm9yRGlhbG9nIiwidGl0bGUiLCJfdCIsImRlc2NyaXB0aW9uIiwiUG9sbENyZWF0ZURpYWxvZyIsInRocmVhZElkIiwiZ2V0VGhyZWFkIiwiZWRpdGluZ014RXZlbnQiLCJNUG9sbEJvZHkiLCJSZWFjdCIsIkNvbXBvbmVudCIsImNvbnN0cnVjdG9yIiwicHJvcHMiLCJjb250ZXh0IiwiX2RlZmluZVByb3BlcnR5MiIsImRlZmF1bHQiLCJyZXNwb25zZXMiLCJzZXRTdGF0ZSIsIm9uUmVsYXRpb25zQ2hhbmdlIiwidW5zZWxlY3RJZk5ld0V2ZW50RnJvbU1lIiwic3RhdGUiLCJzZWxlY3RlZCIsInBvbGxJbml0aWFsaXNlZCIsImNvbXBvbmVudERpZE1vdW50Iiwic2V0UG9sbEluc3RhbmNlIiwib24iLCJQb2xsRXZlbnQiLCJOZXciLCJiaW5kIiwiY29tcG9uZW50V2lsbFVubW91bnQiLCJyZW1vdmVMaXN0ZW5lcnMiLCJwb2xsSWQiLCJhZGRMaXN0ZW5lcnMiLCJnZXRSZXNwb25zZXMiLCJSZXNwb25zZXMiLCJvblJlc3BvbnNlc0NoYW5nZSIsIkVuZCIsIlVuZGVjcnlwdGFibGVSZWxhdGlvbnMiLCJyZW5kZXIiLCJvZmYiLCJzZWxlY3RPcHRpb24iLCJ1c2VySWQiLCJnZXRTYWZlVXNlcklkIiwibXlWb3RlIiwicmVzcG9uc2UiLCJQb2xsUmVzcG9uc2VFdmVudCIsImZyb20iLCJzZXJpYWxpemUiLCJzZW5kRXZlbnQiLCJ0eXBlIiwiY29udGVudCIsImNhdGNoIiwiZSIsImNvbnNvbGUiLCJlcnJvciIsIk1hcCIsImdldFVzZXJJZCIsInJlbGF0aW9ucyIsIm5ld0V2ZW50cyIsImZpbHRlciIsInNlZW5FdmVudElkcyIsImluY2x1ZGVzIiwibmV3U2VsZWN0ZWQiLCJnZXRTZW5kZXIiLCJuZXdFdmVudElkcyIsImNvbmNhdCIsInRvdGFsVm90ZXMiLCJjb2xsZWN0ZWRWb3RlcyIsInN1bSIsInYiLCJ3aW5Db3VudCIsImRpc2Nsb3NlZCIsIk1fUE9MTF9LSU5EX0RJU0NMT1NFRCIsIm1hdGNoZXMiLCJraW5kIiwic2hvd1Jlc3VsdHMiLCJ1bmRlZmluZWQiLCJ0b3RhbFRleHQiLCJ1bmRlY3J5cHRhYmxlUmVsYXRpb25zQ291bnQiLCJjb3VudCIsImVkaXRlZFNwYW4iLCJyZXBsYWNpbmdFdmVudCIsImNyZWF0ZUVsZW1lbnQiLCJjbGFzc05hbWUiLCJxdWVzdGlvbiIsImFuc3dlciIsImFuc3dlclZvdGVzIiwiY2hlY2tlZCIsIlBvbGxPcHRpb24iLCJrZXkiLCJpc0NoZWNrZWQiLCJ2b3RlQ291bnQiLCJ0b3RhbFZvdGVDb3VudCIsImRpc3BsYXlWb3RlQ291bnQiLCJvbk9wdGlvblNlbGVjdGVkIiwidyIsImgiLCJleHBvcnRzIiwiTWF0cml4Q2xpZW50Q29udGV4dCIsIlVzZXJWb3RlIiwidHMiLCJzZW5kZXIiLCJ1c2VyUmVzcG9uc2VGcm9tUG9sbFJlc3BvbnNlRXZlbnQiLCJldmVudCIsIkVycm9yIiwiZ2V0VHMiLCJhbnN3ZXJJZHMiLCJ1c2VyUmVzcG9uc2VzIiwib3RoZXJSZXNwb25zZSIsInNldCIsInBvbGxTdGFydCIsImNvbGxlY3RlZCIsInRlbXBSZXNwb25zZSIsInZhbGlkYXRlQWdhaW5zdCIsInNwb2lsZWQiLCJoYXMiXSwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvY29tcG9uZW50cy92aWV3cy9tZXNzYWdlcy9NUG9sbEJvZHkudHN4Il0sInNvdXJjZXNDb250ZW50IjpbIi8qXG5Db3B5cmlnaHQgMjAyNCBOZXcgVmVjdG9yIEx0ZC5cbkNvcHlyaWdodCAyMDIxIFRoZSBNYXRyaXgub3JnIEZvdW5kYXRpb24gQy5JLkMuXG5cblNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBR1BMLTMuMC1vbmx5IE9SIEdQTC0zLjAtb25seVxuUGxlYXNlIHNlZSBMSUNFTlNFIGZpbGVzIGluIHRoZSByZXBvc2l0b3J5IHJvb3QgZm9yIGZ1bGwgZGV0YWlscy5cbiovXG5cbmltcG9ydCBSZWFjdCwgeyBSZWFjdE5vZGUgfSBmcm9tIFwicmVhY3RcIjtcbmltcG9ydCB7IGxvZ2dlciB9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9sb2dnZXJcIjtcbmltcG9ydCB7XG4gICAgTWF0cml4RXZlbnQsXG4gICAgTWF0cml4Q2xpZW50LFxuICAgIFJlbGF0aW9ucyxcbiAgICBQb2xsLFxuICAgIFBvbGxFdmVudCxcbiAgICBNX1BPTExfS0lORF9ESVNDTE9TRUQsXG4gICAgTV9QT0xMX1JFU1BPTlNFLFxuICAgIE1fUE9MTF9TVEFSVCxcbiAgICBUaW1lbGluZUV2ZW50cyxcbn0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL21hdHJpeFwiO1xuaW1wb3J0IHsgUmVsYXRlZFJlbGF0aW9ucyB9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9tb2RlbHMvcmVsYXRlZC1yZWxhdGlvbnNcIjtcbmltcG9ydCB7IFBvbGxTdGFydEV2ZW50LCBQb2xsQW5zd2VyU3ViZXZlbnQgfSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvZXh0ZW5zaWJsZV9ldmVudHNfdjEvUG9sbFN0YXJ0RXZlbnRcIjtcbmltcG9ydCB7IFBvbGxSZXNwb25zZUV2ZW50IH0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL2V4dGVuc2libGVfZXZlbnRzX3YxL1BvbGxSZXNwb25zZUV2ZW50XCI7XG5cbmltcG9ydCB7IF90IH0gZnJvbSBcIi4uLy4uLy4uL2xhbmd1YWdlSGFuZGxlclwiO1xuaW1wb3J0IE1vZGFsIGZyb20gXCIuLi8uLi8uLi9Nb2RhbFwiO1xuaW1wb3J0IHsgSUJvZHlQcm9wcyB9IGZyb20gXCIuL0lCb2R5UHJvcHNcIjtcbmltcG9ydCB7IGZvcm1hdExpc3QgfSBmcm9tIFwiLi4vLi4vLi4vdXRpbHMvRm9ybWF0dGluZ1V0aWxzXCI7XG5pbXBvcnQgTWF0cml4Q2xpZW50Q29udGV4dCBmcm9tIFwiLi4vLi4vLi4vY29udGV4dHMvTWF0cml4Q2xpZW50Q29udGV4dFwiO1xuaW1wb3J0IEVycm9yRGlhbG9nIGZyb20gXCIuLi9kaWFsb2dzL0Vycm9yRGlhbG9nXCI7XG5pbXBvcnQgeyBHZXRSZWxhdGlvbnNGb3JFdmVudCB9IGZyb20gXCIuLi9yb29tcy9FdmVudFRpbGVcIjtcbmltcG9ydCBQb2xsQ3JlYXRlRGlhbG9nIGZyb20gXCIuLi9lbGVtZW50cy9Qb2xsQ3JlYXRlRGlhbG9nXCI7XG5pbXBvcnQgeyBNYXRyaXhDbGllbnRQZWcgfSBmcm9tIFwiLi4vLi4vLi4vTWF0cml4Q2xpZW50UGVnXCI7XG5pbXBvcnQgU3Bpbm5lciBmcm9tIFwiLi4vZWxlbWVudHMvU3Bpbm5lclwiO1xuaW1wb3J0IHsgUG9sbE9wdGlvbiB9IGZyb20gXCIuLi9wb2xscy9Qb2xsT3B0aW9uXCI7XG5cbmludGVyZmFjZSBJU3RhdGUge1xuICAgIHBvbGw/OiBQb2xsO1xuICAgIC8vIHBvbGwgaW5zdGFuY2UgaGFzIGZldGNoZWQgYXQgbGVhc3Qgb25lIHBhZ2Ugb2YgcmVzcG9uc2VzXG4gICAgcG9sbEluaXRpYWxpc2VkOiBib29sZWFuO1xuICAgIHNlbGVjdGVkPzogc3RyaW5nIHwgbnVsbCB8IHVuZGVmaW5lZDsgLy8gV2hpY2ggb3B0aW9uIHdhcyBjbGlja2VkIGJ5IHRoZSBsb2NhbCB1c2VyXG4gICAgdm90ZVJlbGF0aW9ucz86IFJlbGF0aW9uczsgLy8gVm90aW5nIChyZXNwb25zZSkgZXZlbnRzXG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVWb3RlUmVsYXRpb25zKGdldFJlbGF0aW9uc0ZvckV2ZW50OiBHZXRSZWxhdGlvbnNGb3JFdmVudCwgZXZlbnRJZDogc3RyaW5nKTogUmVsYXRlZFJlbGF0aW9ucyB7XG4gICAgY29uc3QgcmVsYXRpb25zTGlzdDogUmVsYXRpb25zW10gPSBbXTtcblxuICAgIGNvbnN0IHBvbGxSZXNwb25zZVJlbGF0aW9ucyA9IGdldFJlbGF0aW9uc0ZvckV2ZW50KGV2ZW50SWQsIFwibS5yZWZlcmVuY2VcIiwgTV9QT0xMX1JFU1BPTlNFLm5hbWUpO1xuICAgIGlmIChwb2xsUmVzcG9uc2VSZWxhdGlvbnMpIHtcbiAgICAgICAgcmVsYXRpb25zTGlzdC5wdXNoKHBvbGxSZXNwb25zZVJlbGF0aW9ucyk7XG4gICAgfVxuXG4gICAgY29uc3QgcG9sbFJlc3Bvc25zZUFsdFJlbGF0aW9ucyA9IGdldFJlbGF0aW9uc0ZvckV2ZW50KGV2ZW50SWQsIFwibS5yZWZlcmVuY2VcIiwgTV9QT0xMX1JFU1BPTlNFLmFsdE5hbWUpO1xuICAgIGlmIChwb2xsUmVzcG9zbnNlQWx0UmVsYXRpb25zKSB7XG4gICAgICAgIHJlbGF0aW9uc0xpc3QucHVzaChwb2xsUmVzcG9zbnNlQWx0UmVsYXRpb25zKTtcbiAgICB9XG5cbiAgICByZXR1cm4gbmV3IFJlbGF0ZWRSZWxhdGlvbnMocmVsYXRpb25zTGlzdCk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBmaW5kVG9wQW5zd2VyKHBvbGxFdmVudDogTWF0cml4RXZlbnQsIHZvdGVSZWxhdGlvbnM6IFJlbGF0aW9ucyk6IHN0cmluZyB7XG4gICAgY29uc3QgcG9sbEV2ZW50SWQgPSBwb2xsRXZlbnQuZ2V0SWQoKTtcbiAgICBpZiAoIXBvbGxFdmVudElkKSB7XG4gICAgICAgIGxvZ2dlci53YXJuKFxuICAgICAgICAgICAgXCJmaW5kVG9wQW5zd2VyOiBQb2xsIGV2ZW50IG5lZWRzIGFuIGV2ZW50IElEIHRvIGZldGNoIHJlbGF0aW9ucyBpbiBvcmRlciB0byBkZXRlcm1pbmUgXCIgK1xuICAgICAgICAgICAgICAgIFwidGhlIHRvcCBhbnN3ZXIgLSBhc3N1bWluZyBubyBiZXN0IGFuc3dlclwiLFxuICAgICAgICApO1xuICAgICAgICByZXR1cm4gXCJcIjtcbiAgICB9XG5cbiAgICBjb25zdCBwb2xsID0gcG9sbEV2ZW50LnVuc3RhYmxlRXh0ZW5zaWJsZUV2ZW50IGFzIFBvbGxTdGFydEV2ZW50O1xuICAgIGlmICghcG9sbD8uaXNFcXVpdmFsZW50VG8oTV9QT0xMX1NUQVJUKSkge1xuICAgICAgICBsb2dnZXIud2FybihcIkZhaWxlZCB0byBwYXJzZSBwb2xsIHRvIGRldGVybWluZSB0b3AgYW5zd2VyIC0gYXNzdW1pbmcgbm8gYmVzdCBhbnN3ZXJcIik7XG4gICAgICAgIHJldHVybiBcIlwiO1xuICAgIH1cblxuICAgIGNvbnN0IGZpbmRBbnN3ZXJUZXh0ID0gKGFuc3dlcklkOiBzdHJpbmcpOiBzdHJpbmcgPT4ge1xuICAgICAgICByZXR1cm4gcG9sbC5hbnN3ZXJzLmZpbmQoKGEpID0+IGEuaWQgPT09IGFuc3dlcklkKT8udGV4dCA/PyBcIlwiO1xuICAgIH07XG5cbiAgICBjb25zdCB1c2VyVm90ZXM6IE1hcDxzdHJpbmcsIFVzZXJWb3RlPiA9IGNvbGxlY3RVc2VyVm90ZXMoYWxsVm90ZXModm90ZVJlbGF0aW9ucykpO1xuXG4gICAgY29uc3Qgdm90ZXM6IE1hcDxzdHJpbmcsIG51bWJlcj4gPSBjb3VudFZvdGVzKHVzZXJWb3RlcywgcG9sbCk7XG4gICAgY29uc3QgaGlnaGVzdFNjb3JlOiBudW1iZXIgPSBNYXRoLm1heCguLi52b3Rlcy52YWx1ZXMoKSk7XG5cbiAgICBjb25zdCBiZXN0QW5zd2VySWRzOiBzdHJpbmdbXSA9IFtdO1xuICAgIGZvciAoY29uc3QgW2Fuc3dlcklkLCBzY29yZV0gb2Ygdm90ZXMpIHtcbiAgICAgICAgaWYgKHNjb3JlID09IGhpZ2hlc3RTY29yZSkge1xuICAgICAgICAgICAgYmVzdEFuc3dlcklkcy5wdXNoKGFuc3dlcklkKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGNvbnN0IGJlc3RBbnN3ZXJUZXh0cyA9IGJlc3RBbnN3ZXJJZHMubWFwKGZpbmRBbnN3ZXJUZXh0KTtcblxuICAgIHJldHVybiBmb3JtYXRMaXN0KGJlc3RBbnN3ZXJUZXh0cywgMyk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBpc1BvbGxFbmRlZChwb2xsRXZlbnQ6IE1hdHJpeEV2ZW50LCBtYXRyaXhDbGllbnQ6IE1hdHJpeENsaWVudCk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IHJvb20gPSBtYXRyaXhDbGllbnQuZ2V0Um9vbShwb2xsRXZlbnQuZ2V0Um9vbUlkKCkpO1xuICAgIGNvbnN0IHBvbGwgPSByb29tPy5wb2xscy5nZXQocG9sbEV2ZW50LmdldElkKCkhKTtcbiAgICBpZiAoIXBvbGwgfHwgcG9sbC5pc0ZldGNoaW5nUmVzcG9uc2VzKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgcmV0dXJuIHBvbGwuaXNFbmRlZDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHBvbGxBbHJlYWR5SGFzVm90ZXMobXhFdmVudDogTWF0cml4RXZlbnQsIGdldFJlbGF0aW9uc0ZvckV2ZW50PzogR2V0UmVsYXRpb25zRm9yRXZlbnQpOiBib29sZWFuIHtcbiAgICBpZiAoIWdldFJlbGF0aW9uc0ZvckV2ZW50KSByZXR1cm4gZmFsc2U7XG5cbiAgICBjb25zdCBldmVudElkID0gbXhFdmVudC5nZXRJZCgpO1xuICAgIGlmICghZXZlbnRJZCkgcmV0dXJuIGZhbHNlO1xuXG4gICAgY29uc3Qgdm90ZVJlbGF0aW9ucyA9IGNyZWF0ZVZvdGVSZWxhdGlvbnMoZ2V0UmVsYXRpb25zRm9yRXZlbnQsIGV2ZW50SWQpO1xuICAgIHJldHVybiB2b3RlUmVsYXRpb25zLmdldFJlbGF0aW9ucygpLmxlbmd0aCA+IDA7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBsYXVuY2hQb2xsRWRpdG9yKG14RXZlbnQ6IE1hdHJpeEV2ZW50LCBnZXRSZWxhdGlvbnNGb3JFdmVudD86IEdldFJlbGF0aW9uc0ZvckV2ZW50KTogdm9pZCB7XG4gICAgY29uc3Qgcm9vbSA9IE1hdHJpeENsaWVudFBlZy5zYWZlR2V0KCkuZ2V0Um9vbShteEV2ZW50LmdldFJvb21JZCgpKTtcbiAgICBpZiAocG9sbEFscmVhZHlIYXNWb3RlcyhteEV2ZW50LCBnZXRSZWxhdGlvbnNGb3JFdmVudCkpIHtcbiAgICAgICAgTW9kYWwuY3JlYXRlRGlhbG9nKEVycm9yRGlhbG9nLCB7XG4gICAgICAgICAgICB0aXRsZTogX3QoXCJwb2xsfHVuYWJsZV9lZGl0X3RpdGxlXCIpLFxuICAgICAgICAgICAgZGVzY3JpcHRpb246IF90KFwicG9sbHx1bmFibGVfZWRpdF9kZXNjcmlwdGlvblwiKSxcbiAgICAgICAgfSk7XG4gICAgfSBlbHNlIGlmIChyb29tKSB7XG4gICAgICAgIE1vZGFsLmNyZWF0ZURpYWxvZyhcbiAgICAgICAgICAgIFBvbGxDcmVhdGVEaWFsb2csXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgcm9vbSxcbiAgICAgICAgICAgICAgICB0aHJlYWRJZDogbXhFdmVudC5nZXRUaHJlYWQoKT8uaWQsXG4gICAgICAgICAgICAgICAgZWRpdGluZ014RXZlbnQ6IG14RXZlbnQsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJteF9Db21wb3VuZERpYWxvZ1wiLFxuICAgICAgICAgICAgZmFsc2UsIC8vIGlzUHJpb3JpdHlNb2RhbFxuICAgICAgICAgICAgdHJ1ZSwgLy8gaXNTdGF0aWNNb2RhbFxuICAgICAgICApO1xuICAgIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgTVBvbGxCb2R5IGV4dGVuZHMgUmVhY3QuQ29tcG9uZW50PElCb2R5UHJvcHMsIElTdGF0ZT4ge1xuICAgIHB1YmxpYyBzdGF0aWMgY29udGV4dFR5cGUgPSBNYXRyaXhDbGllbnRDb250ZXh0O1xuICAgIHB1YmxpYyBkZWNsYXJlIGNvbnRleHQ6IFJlYWN0LkNvbnRleHRUeXBlPHR5cGVvZiBNYXRyaXhDbGllbnRDb250ZXh0PjtcbiAgICBwcml2YXRlIHNlZW5FdmVudElkczogc3RyaW5nW10gPSBbXTsgLy8gRXZlbnRzIHdlIGhhdmUgYWxyZWFkeSBzZWVuXG5cbiAgICBwdWJsaWMgY29uc3RydWN0b3IocHJvcHM6IElCb2R5UHJvcHMsIGNvbnRleHQ6IFJlYWN0LkNvbnRleHRUeXBlPHR5cGVvZiBNYXRyaXhDbGllbnRDb250ZXh0Pikge1xuICAgICAgICBzdXBlcihwcm9wcywgY29udGV4dCk7XG5cbiAgICAgICAgdGhpcy5zdGF0ZSA9IHtcbiAgICAgICAgICAgIHNlbGVjdGVkOiBudWxsLFxuICAgICAgICAgICAgcG9sbEluaXRpYWxpc2VkOiBmYWxzZSxcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICBwdWJsaWMgY29tcG9uZW50RGlkTW91bnQoKTogdm9pZCB7XG4gICAgICAgIGNvbnN0IHJvb20gPSB0aGlzLmNvbnRleHQ/LmdldFJvb20odGhpcy5wcm9wcy5teEV2ZW50LmdldFJvb21JZCgpKTtcbiAgICAgICAgY29uc3QgcG9sbCA9IHJvb20/LnBvbGxzLmdldCh0aGlzLnByb3BzLm14RXZlbnQuZ2V0SWQoKSEpO1xuICAgICAgICBpZiAocG9sbCkge1xuICAgICAgICAgICAgdGhpcy5zZXRQb2xsSW5zdGFuY2UocG9sbCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByb29tPy5vbihQb2xsRXZlbnQuTmV3LCB0aGlzLnNldFBvbGxJbnN0YW5jZS5iaW5kKHRoaXMpKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyBjb21wb25lbnRXaWxsVW5tb3VudCgpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5yZW1vdmVMaXN0ZW5lcnMoKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIHNldFBvbGxJbnN0YW5jZShwb2xsOiBQb2xsKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGlmIChwb2xsLnBvbGxJZCAhPT0gdGhpcy5wcm9wcy5teEV2ZW50LmdldElkKCkpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLnNldFN0YXRlKHsgcG9sbCB9LCAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLmFkZExpc3RlbmVycygpO1xuICAgICAgICB9KTtcbiAgICAgICAgY29uc3QgcmVzcG9uc2VzID0gYXdhaXQgcG9sbC5nZXRSZXNwb25zZXMoKTtcbiAgICAgICAgY29uc3Qgdm90ZVJlbGF0aW9ucyA9IHJlc3BvbnNlcztcblxuICAgICAgICB0aGlzLnNldFN0YXRlKHsgcG9sbEluaXRpYWxpc2VkOiB0cnVlLCB2b3RlUmVsYXRpb25zIH0pO1xuICAgIH1cblxuICAgIHByaXZhdGUgYWRkTGlzdGVuZXJzKCk6IHZvaWQge1xuICAgICAgICB0aGlzLnN0YXRlLnBvbGw/Lm9uKFBvbGxFdmVudC5SZXNwb25zZXMsIHRoaXMub25SZXNwb25zZXNDaGFuZ2UpO1xuICAgICAgICB0aGlzLnN0YXRlLnBvbGw/Lm9uKFBvbGxFdmVudC5FbmQsIHRoaXMub25SZWxhdGlvbnNDaGFuZ2UpO1xuICAgICAgICB0aGlzLnN0YXRlLnBvbGw/Lm9uKFBvbGxFdmVudC5VbmRlY3J5cHRhYmxlUmVsYXRpb25zLCB0aGlzLnJlbmRlci5iaW5kKHRoaXMpKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHJlbW92ZUxpc3RlbmVycygpOiB2b2lkIHtcbiAgICAgICAgaWYgKHRoaXMuc3RhdGUucG9sbCkge1xuICAgICAgICAgICAgdGhpcy5zdGF0ZS5wb2xsLm9mZihQb2xsRXZlbnQuUmVzcG9uc2VzLCB0aGlzLm9uUmVzcG9uc2VzQ2hhbmdlKTtcbiAgICAgICAgICAgIHRoaXMuc3RhdGUucG9sbC5vZmYoUG9sbEV2ZW50LkVuZCwgdGhpcy5vblJlbGF0aW9uc0NoYW5nZSk7XG4gICAgICAgICAgICB0aGlzLnN0YXRlLnBvbGwub2ZmKFBvbGxFdmVudC5VbmRlY3J5cHRhYmxlUmVsYXRpb25zLCB0aGlzLnJlbmRlci5iaW5kKHRoaXMpKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgb25SZXNwb25zZXNDaGFuZ2UgPSAocmVzcG9uc2VzOiBSZWxhdGlvbnMpOiB2b2lkID0+IHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7IHZvdGVSZWxhdGlvbnM6IHJlc3BvbnNlcyB9KTtcbiAgICAgICAgdGhpcy5vblJlbGF0aW9uc0NoYW5nZSgpO1xuICAgIH07XG5cbiAgICBwcml2YXRlIG9uUmVsYXRpb25zQ2hhbmdlID0gKCk6IHZvaWQgPT4ge1xuICAgICAgICAvLyBXZSBob2xkIFJlbGF0aW9ucyBpbiBvdXIgc3RhdGUsIGFuZCB0aGV5IGNoYW5nZWQgdW5kZXIgdXMuXG4gICAgICAgIC8vIENoZWNrIHdoZXRoZXIgd2Ugc2hvdWxkIGRlbGV0ZSBvdXIgc2VsZWN0aW9uLCBhbmQgdGhlblxuICAgICAgICAvLyByZS1yZW5kZXIuXG4gICAgICAgIC8vIE5vdGU6IHJlLXJlbmRlcmluZyBpcyBhIHNpZGUgZWZmZWN0IG9mIHVuc2VsZWN0SWZOZXdFdmVudEZyb21NZSgpLlxuICAgICAgICB0aGlzLnVuc2VsZWN0SWZOZXdFdmVudEZyb21NZSgpO1xuICAgIH07XG5cbiAgICBwcml2YXRlIHNlbGVjdE9wdGlvbihhbnN3ZXJJZDogc3RyaW5nKTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLnN0YXRlLnBvbGw/LmlzRW5kZWQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCB1c2VyVm90ZXMgPSB0aGlzLmNvbGxlY3RVc2VyVm90ZXMoKTtcbiAgICAgICAgY29uc3QgdXNlcklkID0gdGhpcy5jb250ZXh0LmdldFNhZmVVc2VySWQoKTtcbiAgICAgICAgY29uc3QgbXlWb3RlID0gdXNlclZvdGVzLmdldCh1c2VySWQpPy5hbnN3ZXJzWzBdO1xuICAgICAgICBpZiAoYW5zd2VySWQgPT09IG15Vm90ZSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgcmVzcG9uc2UgPSBQb2xsUmVzcG9uc2VFdmVudC5mcm9tKFthbnN3ZXJJZF0sIHRoaXMucHJvcHMubXhFdmVudC5nZXRJZCgpISkuc2VyaWFsaXplKCk7XG5cbiAgICAgICAgdGhpcy5jb250ZXh0XG4gICAgICAgICAgICAuc2VuZEV2ZW50KFxuICAgICAgICAgICAgICAgIHRoaXMucHJvcHMubXhFdmVudC5nZXRSb29tSWQoKSEsXG4gICAgICAgICAgICAgICAgcmVzcG9uc2UudHlwZSBhcyBrZXlvZiBUaW1lbGluZUV2ZW50cyxcbiAgICAgICAgICAgICAgICByZXNwb25zZS5jb250ZW50IGFzIFRpbWVsaW5lRXZlbnRzW2tleW9mIFRpbWVsaW5lRXZlbnRzXSxcbiAgICAgICAgICAgIClcbiAgICAgICAgICAgIC5jYXRjaCgoZTogYW55KSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIkZhaWxlZCB0byBzdWJtaXQgcG9sbCByZXNwb25zZSBldmVudDpcIiwgZSk7XG5cbiAgICAgICAgICAgICAgICBNb2RhbC5jcmVhdGVEaWFsb2coRXJyb3JEaWFsb2csIHtcbiAgICAgICAgICAgICAgICAgICAgdGl0bGU6IF90KFwicG9sbHxlcnJvcl92b3RpbmdfdGl0bGVcIiksXG4gICAgICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBfdChcInBvbGx8ZXJyb3Jfdm90aW5nX2Rlc2NyaXB0aW9uXCIpLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7IHNlbGVjdGVkOiBhbnN3ZXJJZCB9KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBAcmV0dXJucyB1c2VySWQgLT4gVXNlclZvdGVcbiAgICAgKi9cbiAgICBwcml2YXRlIGNvbGxlY3RVc2VyVm90ZXMoKTogTWFwPHN0cmluZywgVXNlclZvdGU+IHtcbiAgICAgICAgaWYgKCF0aGlzLnN0YXRlLnZvdGVSZWxhdGlvbnMgfHwgIXRoaXMuY29udGV4dCkge1xuICAgICAgICAgICAgcmV0dXJuIG5ldyBNYXA8c3RyaW5nLCBVc2VyVm90ZT4oKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gY29sbGVjdFVzZXJWb3RlcyhhbGxWb3Rlcyh0aGlzLnN0YXRlLnZvdGVSZWxhdGlvbnMpLCB0aGlzLmNvbnRleHQuZ2V0VXNlcklkKCksIHRoaXMuc3RhdGUuc2VsZWN0ZWQpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIElmIHdlJ3ZlIGp1c3QgcmVjZWl2ZWQgYSBuZXcgZXZlbnQgdGhhdCB3ZSBoYWRuJ3Qgc2VlblxuICAgICAqIGJlZm9yZSwgYW5kIHRoYXQgZXZlbnQgaXMgbWUgdm90aW5nIChlLmcuIGZyb20gYSBkaWZmZXJlbnRcbiAgICAgKiBkZXZpY2UpIHRoZW4gZm9yZ2V0IHdoZW4gdGhlIGxvY2FsIHVzZXIgc2VsZWN0ZWQuXG4gICAgICpcbiAgICAgKiBFaXRoZXIgd2F5LCBjYWxscyBzZXRTdGF0ZSB0byB1cGRhdGUgb3VyIGxpc3Qgb2YgZXZlbnRzIHdlXG4gICAgICogaGF2ZSBhbHJlYWR5IHNlZW4uXG4gICAgICovXG4gICAgcHJpdmF0ZSB1bnNlbGVjdElmTmV3RXZlbnRGcm9tTWUoKTogdm9pZCB7XG4gICAgICAgIGNvbnN0IHJlbGF0aW9ucyA9IHRoaXMuc3RhdGUudm90ZVJlbGF0aW9ucz8uZ2V0UmVsYXRpb25zKCkgfHwgW107XG4gICAgICAgIGNvbnN0IG5ld0V2ZW50czogTWF0cml4RXZlbnRbXSA9IHJlbGF0aW9ucy5maWx0ZXIoXG4gICAgICAgICAgICAobXhFdmVudDogTWF0cml4RXZlbnQpID0+ICF0aGlzLnNlZW5FdmVudElkcy5pbmNsdWRlcyhteEV2ZW50LmdldElkKCkhKSxcbiAgICAgICAgKTtcbiAgICAgICAgbGV0IG5ld1NlbGVjdGVkID0gdGhpcy5zdGF0ZS5zZWxlY3RlZDtcblxuICAgICAgICBpZiAobmV3RXZlbnRzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIGZvciAoY29uc3QgbXhFdmVudCBvZiBuZXdFdmVudHMpIHtcbiAgICAgICAgICAgICAgICBpZiAobXhFdmVudC5nZXRTZW5kZXIoKSA9PT0gdGhpcy5jb250ZXh0LmdldFVzZXJJZCgpKSB7XG4gICAgICAgICAgICAgICAgICAgIG5ld1NlbGVjdGVkID0gbnVsbDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgbmV3RXZlbnRJZHMgPSBuZXdFdmVudHMubWFwKChteEV2ZW50OiBNYXRyaXhFdmVudCkgPT4gbXhFdmVudC5nZXRJZCgpISk7XG4gICAgICAgIHRoaXMuc2VlbkV2ZW50SWRzID0gdGhpcy5zZWVuRXZlbnRJZHMuY29uY2F0KG5ld0V2ZW50SWRzKTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7IHNlbGVjdGVkOiBuZXdTZWxlY3RlZCB9KTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHRvdGFsVm90ZXMoY29sbGVjdGVkVm90ZXM6IE1hcDxzdHJpbmcsIG51bWJlcj4pOiBudW1iZXIge1xuICAgICAgICBsZXQgc3VtID0gMDtcbiAgICAgICAgZm9yIChjb25zdCB2IG9mIGNvbGxlY3RlZFZvdGVzLnZhbHVlcygpKSB7XG4gICAgICAgICAgICBzdW0gKz0gdjtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gc3VtO1xuICAgIH1cblxuICAgIHB1YmxpYyByZW5kZXIoKTogUmVhY3ROb2RlIHtcbiAgICAgICAgY29uc3QgeyBwb2xsLCBwb2xsSW5pdGlhbGlzZWQgfSA9IHRoaXMuc3RhdGU7XG4gICAgICAgIGlmICghcG9sbD8ucG9sbEV2ZW50KSB7XG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHBvbGxFdmVudCA9IHBvbGwucG9sbEV2ZW50O1xuXG4gICAgICAgIGNvbnN0IHBvbGxJZCA9IHRoaXMucHJvcHMubXhFdmVudC5nZXRJZCgpITtcbiAgICAgICAgY29uc3QgaXNGZXRjaGluZ1Jlc3BvbnNlcyA9ICFwb2xsSW5pdGlhbGlzZWQgfHwgcG9sbC5pc0ZldGNoaW5nUmVzcG9uc2VzO1xuICAgICAgICBjb25zdCB1c2VyVm90ZXMgPSB0aGlzLmNvbGxlY3RVc2VyVm90ZXMoKTtcbiAgICAgICAgY29uc3Qgdm90ZXMgPSBjb3VudFZvdGVzKHVzZXJWb3RlcywgcG9sbEV2ZW50KTtcbiAgICAgICAgY29uc3QgdG90YWxWb3RlcyA9IHRoaXMudG90YWxWb3Rlcyh2b3Rlcyk7XG4gICAgICAgIGNvbnN0IHdpbkNvdW50ID0gTWF0aC5tYXgoLi4udm90ZXMudmFsdWVzKCkpO1xuICAgICAgICBjb25zdCB1c2VySWQgPSB0aGlzLmNvbnRleHQuZ2V0U2FmZVVzZXJJZCgpO1xuICAgICAgICBjb25zdCBteVZvdGUgPSB1c2VyVm90ZXM/LmdldCh1c2VySWQpPy5hbnN3ZXJzWzBdO1xuICAgICAgICBjb25zdCBkaXNjbG9zZWQgPSBNX1BPTExfS0lORF9ESVNDTE9TRUQubWF0Y2hlcyhwb2xsRXZlbnQua2luZC5uYW1lKTtcblxuICAgICAgICAvLyBEaXNjbG9zZWQ6IHZvdGVzIGFyZSBoaWRkZW4gdW50aWwgSSB2b3RlIG9yIHRoZSBwb2xsIGVuZHNcbiAgICAgICAgLy8gVW5kaXNjbG9zZWQ6IHZvdGVzIGFyZSBoaWRkZW4gdW50aWwgcG9sbCBlbmRzXG4gICAgICAgIGNvbnN0IHNob3dSZXN1bHRzID0gcG9sbC5pc0VuZGVkIHx8IChkaXNjbG9zZWQgJiYgbXlWb3RlICE9PSB1bmRlZmluZWQpO1xuXG4gICAgICAgIGxldCB0b3RhbFRleHQ6IHN0cmluZztcbiAgICAgICAgaWYgKHNob3dSZXN1bHRzICYmIHBvbGwudW5kZWNyeXB0YWJsZVJlbGF0aW9uc0NvdW50KSB7XG4gICAgICAgICAgICB0b3RhbFRleHQgPSBfdChcInBvbGx8dG90YWxfZGVjcnlwdGlvbl9lcnJvcnNcIik7XG4gICAgICAgIH0gZWxzZSBpZiAocG9sbC5pc0VuZGVkKSB7XG4gICAgICAgICAgICB0b3RhbFRleHQgPSBfdChcInJpZ2h0X3BhbmVsfHBvbGx8ZmluYWxfcmVzdWx0XCIsIHsgY291bnQ6IHRvdGFsVm90ZXMgfSk7XG4gICAgICAgIH0gZWxzZSBpZiAoIWRpc2Nsb3NlZCkge1xuICAgICAgICAgICAgdG90YWxUZXh0ID0gX3QoXCJwb2xsfHRvdGFsX25vdF9lbmRlZFwiKTtcbiAgICAgICAgfSBlbHNlIGlmIChteVZvdGUgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgaWYgKHRvdGFsVm90ZXMgPT09IDApIHtcbiAgICAgICAgICAgICAgICB0b3RhbFRleHQgPSBfdChcInBvbGx8dG90YWxfbm9fdm90ZXNcIik7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRvdGFsVGV4dCA9IF90KFwicG9sbHx0b3RhbF9uX3ZvdGVzXCIsIHsgY291bnQ6IHRvdGFsVm90ZXMgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0b3RhbFRleHQgPSBfdChcInBvbGx8dG90YWxfbl92b3Rlc192b3RlZFwiLCB7IGNvdW50OiB0b3RhbFZvdGVzIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgZWRpdGVkU3BhbiA9IHRoaXMucHJvcHMubXhFdmVudC5yZXBsYWNpbmdFdmVudCgpID8gKFxuICAgICAgICAgICAgPHNwYW4gY2xhc3NOYW1lPVwibXhfTVBvbGxCb2R5X2VkaXRlZFwiPiAoe190KFwiY29tbW9ufGVkaXRlZFwiKX0pPC9zcGFuPlxuICAgICAgICApIDogbnVsbDtcblxuICAgICAgICByZXR1cm4gKFxuICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9XCJteF9NUG9sbEJvZHlcIj5cbiAgICAgICAgICAgICAgICA8aDIgZGF0YS10ZXN0aWQ9XCJwb2xsUXVlc3Rpb25cIj5cbiAgICAgICAgICAgICAgICAgICAge3BvbGxFdmVudC5xdWVzdGlvbi50ZXh0fVxuICAgICAgICAgICAgICAgICAgICB7ZWRpdGVkU3Bhbn1cbiAgICAgICAgICAgICAgICA8L2gyPlxuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPVwibXhfTVBvbGxCb2R5X2FsbE9wdGlvbnNcIj5cbiAgICAgICAgICAgICAgICAgICAge3BvbGxFdmVudC5hbnN3ZXJzLm1hcCgoYW5zd2VyOiBQb2xsQW5zd2VyU3ViZXZlbnQpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGxldCBhbnN3ZXJWb3RlcyA9IDA7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChzaG93UmVzdWx0cykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFuc3dlclZvdGVzID0gdm90ZXMuZ2V0KGFuc3dlci5pZCkgPz8gMDtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgY2hlY2tlZCA9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKCFwb2xsLmlzRW5kZWQgJiYgbXlWb3RlID09PSBhbnN3ZXIuaWQpIHx8IChwb2xsLmlzRW5kZWQgJiYgYW5zd2VyVm90ZXMgPT09IHdpbkNvdW50KTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8UG9sbE9wdGlvblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrZXk9e2Fuc3dlci5pZH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9sbElkPXtwb2xsSWR9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFuc3dlcj17YW5zd2VyfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpc0NoZWNrZWQ9e2NoZWNrZWR9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlzRW5kZWQ9e3BvbGwuaXNFbmRlZH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdm90ZUNvdW50PXthbnN3ZXJWb3Rlc31cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG90YWxWb3RlQ291bnQ9e3RvdGFsVm90ZXN9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpc3BsYXlWb3RlQ291bnQ9e3Nob3dSZXN1bHRzfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbk9wdGlvblNlbGVjdGVkPXt0aGlzLnNlbGVjdE9wdGlvbi5iaW5kKHRoaXMpfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8+XG4gICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICB9KX1cbiAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICA8ZGl2IGRhdGEtdGVzdGlkPVwidG90YWxWb3Rlc1wiIGNsYXNzTmFtZT1cIm14X01Qb2xsQm9keV90b3RhbFZvdGVzXCI+XG4gICAgICAgICAgICAgICAgICAgIHt0b3RhbFRleHR9XG4gICAgICAgICAgICAgICAgICAgIHtpc0ZldGNoaW5nUmVzcG9uc2VzICYmIDxTcGlubmVyIHc9ezE2fSBoPXsxNn0gLz59XG4gICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgKTtcbiAgICB9XG59XG5leHBvcnQgY2xhc3MgVXNlclZvdGUge1xuICAgIHB1YmxpYyBjb25zdHJ1Y3RvcihcbiAgICAgICAgcHVibGljIHJlYWRvbmx5IHRzOiBudW1iZXIsXG4gICAgICAgIHB1YmxpYyByZWFkb25seSBzZW5kZXI6IHN0cmluZyxcbiAgICAgICAgcHVibGljIHJlYWRvbmx5IGFuc3dlcnM6IHN0cmluZ1tdLFxuICAgICkge31cbn1cblxuZnVuY3Rpb24gdXNlclJlc3BvbnNlRnJvbVBvbGxSZXNwb25zZUV2ZW50KGV2ZW50OiBNYXRyaXhFdmVudCk6IFVzZXJWb3RlIHtcbiAgICBjb25zdCByZXNwb25zZSA9IGV2ZW50LnVuc3RhYmxlRXh0ZW5zaWJsZUV2ZW50IGFzIFBvbGxSZXNwb25zZUV2ZW50O1xuICAgIGlmICghcmVzcG9uc2U/LmlzRXF1aXZhbGVudFRvKE1fUE9MTF9SRVNQT05TRSkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiRmFpbGVkIHRvIHBhcnNlIFBvbGwgUmVzcG9uc2UgRXZlbnQgdG8gZGV0ZXJtaW5lIHVzZXIgcmVzcG9uc2VcIik7XG4gICAgfVxuXG4gICAgcmV0dXJuIG5ldyBVc2VyVm90ZShldmVudC5nZXRUcygpLCBldmVudC5nZXRTZW5kZXIoKSEsIHJlc3BvbnNlLmFuc3dlcklkcyk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBhbGxWb3Rlcyh2b3RlUmVsYXRpb25zOiBSZWxhdGlvbnMpOiBBcnJheTxVc2VyVm90ZT4ge1xuICAgIGlmICh2b3RlUmVsYXRpb25zKSB7XG4gICAgICAgIHJldHVybiB2b3RlUmVsYXRpb25zLmdldFJlbGF0aW9ucygpLm1hcCh1c2VyUmVzcG9uc2VGcm9tUG9sbFJlc3BvbnNlRXZlbnQpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiBbXTtcbiAgICB9XG59XG5cbi8qKlxuICogRmlndXJlIG91dCB0aGUgY29ycmVjdCB2b3RlIGZvciBlYWNoIHVzZXIuXG4gKiBAcGFyYW0gdXNlclJlc3BvbnNlcyBjdXJyZW50IHZvdGUgcmVzcG9uc2VzIGluIHRoZSBwb2xsXG4gKiBAcGFyYW0ge3N0cmluZz99IHVzZXJJZCBUaGUgdXNlcklkIGZvciB3aGljaCB0aGUgYHNlbGVjdGVkYCBvcHRpb24gd2lsbCBhcHBseSB0by5cbiAqICAgICAgICAgICAgICAgICAgU2hvdWxkIGJlIHNldCB0byB0aGUgY3VycmVudCB1c2VyIElELlxuICogQHBhcmFtIHtzdHJpbmc/fSBzZWxlY3RlZCBMb2NhbCBlY2hvIHNlbGVjdGVkIG9wdGlvbiBmb3IgdGhlIHVzZXJJZFxuICogQHJldHVybnMgYSBNYXAgb2YgdXNlciBJRCB0byB0aGVpciB2b3RlIGluZm9cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvbGxlY3RVc2VyVm90ZXMoXG4gICAgdXNlclJlc3BvbnNlczogQXJyYXk8VXNlclZvdGU+LFxuICAgIHVzZXJJZD86IHN0cmluZyB8IG51bGwgfCB1bmRlZmluZWQsXG4gICAgc2VsZWN0ZWQ/OiBzdHJpbmcgfCBudWxsIHwgdW5kZWZpbmVkLFxuKTogTWFwPHN0cmluZywgVXNlclZvdGU+IHtcbiAgICBjb25zdCB1c2VyVm90ZXM6IE1hcDxzdHJpbmcsIFVzZXJWb3RlPiA9IG5ldyBNYXAoKTtcblxuICAgIGZvciAoY29uc3QgcmVzcG9uc2Ugb2YgdXNlclJlc3BvbnNlcykge1xuICAgICAgICBjb25zdCBvdGhlclJlc3BvbnNlID0gdXNlclZvdGVzLmdldChyZXNwb25zZS5zZW5kZXIpO1xuICAgICAgICBpZiAoIW90aGVyUmVzcG9uc2UgfHwgb3RoZXJSZXNwb25zZS50cyA8IHJlc3BvbnNlLnRzKSB7XG4gICAgICAgICAgICB1c2VyVm90ZXMuc2V0KHJlc3BvbnNlLnNlbmRlciwgcmVzcG9uc2UpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHNlbGVjdGVkICYmIHVzZXJJZCkge1xuICAgICAgICB1c2VyVm90ZXMuc2V0KHVzZXJJZCwgbmV3IFVzZXJWb3RlKDAsIHVzZXJJZCwgW3NlbGVjdGVkXSkpO1xuICAgIH1cblxuICAgIHJldHVybiB1c2VyVm90ZXM7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjb3VudFZvdGVzKHVzZXJWb3RlczogTWFwPHN0cmluZywgVXNlclZvdGU+LCBwb2xsU3RhcnQ6IFBvbGxTdGFydEV2ZW50KTogTWFwPHN0cmluZywgbnVtYmVyPiB7XG4gICAgY29uc3QgY29sbGVjdGVkID0gbmV3IE1hcDxzdHJpbmcsIG51bWJlcj4oKTtcblxuICAgIGZvciAoY29uc3QgcmVzcG9uc2Ugb2YgdXNlclZvdGVzLnZhbHVlcygpKSB7XG4gICAgICAgIGNvbnN0IHRlbXBSZXNwb25zZSA9IFBvbGxSZXNwb25zZUV2ZW50LmZyb20ocmVzcG9uc2UuYW5zd2VycywgXCIkaXJyZWxldmFudFwiKTtcbiAgICAgICAgdGVtcFJlc3BvbnNlLnZhbGlkYXRlQWdhaW5zdChwb2xsU3RhcnQpO1xuICAgICAgICBpZiAoIXRlbXBSZXNwb25zZS5zcG9pbGVkKSB7XG4gICAgICAgICAgICBmb3IgKGNvbnN0IGFuc3dlcklkIG9mIHRlbXBSZXNwb25zZS5hbnN3ZXJJZHMpIHtcbiAgICAgICAgICAgICAgICBpZiAoY29sbGVjdGVkLmhhcyhhbnN3ZXJJZCkpIHtcbiAgICAgICAgICAgICAgICAgICAgY29sbGVjdGVkLnNldChhbnN3ZXJJZCwgY29sbGVjdGVkLmdldChhbnN3ZXJJZCkhICsgMSk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgY29sbGVjdGVkLnNldChhbnN3ZXJJZCwgMSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGNvbGxlY3RlZDtcbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFRQSxJQUFBQSxNQUFBLEdBQUFDLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBQyxPQUFBLEdBQUFELE9BQUE7QUFDQSxJQUFBRSxPQUFBLEdBQUFGLE9BQUE7QUFXQSxJQUFBRyxpQkFBQSxHQUFBSCxPQUFBO0FBRUEsSUFBQUksa0JBQUEsR0FBQUosT0FBQTtBQUVBLElBQUFLLGdCQUFBLEdBQUFMLE9BQUE7QUFDQSxJQUFBTSxNQUFBLEdBQUFQLHNCQUFBLENBQUFDLE9BQUE7QUFFQSxJQUFBTyxnQkFBQSxHQUFBUCxPQUFBO0FBQ0EsSUFBQVEsb0JBQUEsR0FBQVQsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFTLFlBQUEsR0FBQVYsc0JBQUEsQ0FBQUMsT0FBQTtBQUVBLElBQUFVLGlCQUFBLEdBQUFYLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBVyxnQkFBQSxHQUFBWCxPQUFBO0FBQ0EsSUFBQVksUUFBQSxHQUFBYixzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQWEsV0FBQSxHQUFBYixPQUFBO0FBbkNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQXVDTyxTQUFTYyxtQkFBbUJBLENBQUNDLG9CQUEwQyxFQUFFQyxPQUFlLEVBQW9CO0VBQy9HLE1BQU1DLGFBQTBCLEdBQUcsRUFBRTtFQUVyQyxNQUFNQyxxQkFBcUIsR0FBR0gsb0JBQW9CLENBQUNDLE9BQU8sRUFBRSxhQUFhLEVBQUVHLHVCQUFlLENBQUNDLElBQUksQ0FBQztF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