matrix-react-sdk
Version:
SDK for matrix.org using React
517 lines (439 loc) • 59 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 _react = _interopRequireDefault(require("react"));
var _languageHandler = require("../../../languageHandler");
var _FormattingUtils = require("../../../utils/FormattingUtils");
var _RoomInvite = require("../../../RoomInvite");
var _EventListSummary = _interopRequireDefault(require("./EventListSummary"));
var _replaceableComponent = require("../../../utils/replaceableComponent");
var _dec, _class, _class2, _temp;
var TransitionType;
(function (TransitionType) {
TransitionType["Joined"] = "joined";
TransitionType["Left"] = "left";
TransitionType["JoinedAndLeft"] = "joined_and_left";
TransitionType["LeftAndJoined"] = "left_and_joined";
TransitionType["InviteReject"] = "invite_reject";
TransitionType["InviteWithdrawal"] = "invite_withdrawal";
TransitionType["Invited"] = "invited";
TransitionType["Banned"] = "banned";
TransitionType["Unbanned"] = "unbanned";
TransitionType["Kicked"] = "kicked";
TransitionType["ChangedName"] = "changed_name";
TransitionType["ChangedAvatar"] = "changed_avatar";
TransitionType["NoChange"] = "no_change";
})(TransitionType || (TransitionType = {}));
const SEP = ",";
let MemberEventListSummary = (_dec = (0, _replaceableComponent.replaceableComponent)("views.elements.MemberEventListSummary"), _dec(_class = (_temp = _class2 = class MemberEventListSummary extends _react.default.Component
/*:: <IProps>*/
{
shouldComponentUpdate(nextProps) {
// Update if
// - The number of summarised events has changed
// - or if the summary is about to toggle to become collapsed
// - or if there are fewEvents, meaning the child eventTiles are shown as-is
return nextProps.events.length !== this.props.events.length || nextProps.events.length < this.props.threshold;
}
/**
* Generate the text for users aggregated by their transition sequences (`eventAggregates`) where
* the sequences are ordered by `orderedTransitionSequences`.
* @param {object} eventAggregates a map of transition sequence to array of user display names
* or user IDs.
* @param {string[]} orderedTransitionSequences an array which is some ordering of
* `Object.keys(eventAggregates)`.
* @returns {string} the textual summary of the aggregated events that occurred.
*/
generateSummary(eventAggregates
/*: Record<string, string[]>*/
, orderedTransitionSequences
/*: string[]*/
) {
const summaries = orderedTransitionSequences.map(transitions => {
const userNames = eventAggregates[transitions];
const nameList = this.renderNameList(userNames);
const splitTransitions = transitions.split(SEP); // Some neighbouring transitions are common, so canonicalise some into "pair"
// transitions
const canonicalTransitions = MemberEventListSummary.getCanonicalTransitions(splitTransitions); // Transform into consecutive repetitions of the same transition (like 5
// consecutive 'joined_and_left's)
const coalescedTransitions = MemberEventListSummary.coalesceRepeatedTransitions(canonicalTransitions);
const descs = coalescedTransitions.map(t => {
return MemberEventListSummary.getDescriptionForTransition(t.transitionType, userNames.length, t.repeats);
});
const desc = (0, _FormattingUtils.formatCommaSeparatedList)(descs);
return (0, _languageHandler._t)('%(nameList)s %(transitionList)s', {
nameList: nameList,
transitionList: desc
});
});
if (!summaries) {
return null;
}
return summaries.join(", ");
}
/**
* @param {string[]} users an array of user display names or user IDs.
* @returns {string} a comma-separated list that ends with "and [n] others" if there are
* more items in `users` than `this.props.summaryLength`, which is the number of names
* included before "and [n] others".
*/
renderNameList(users
/*: string[]*/
) {
return (0, _FormattingUtils.formatCommaSeparatedList)(users, this.props.summaryLength);
}
/**
* Canonicalise an array of transitions such that some pairs of transitions become
* single transitions. For example an input ['joined','left'] would result in an output
* ['joined_and_left'].
* @param {string[]} transitions an array of transitions.
* @returns {string[]} an array of transitions.
*/
static getCanonicalTransitions(transitions
/*: TransitionType[]*/
)
/*: TransitionType[]*/
{
const modMap = {
[TransitionType.Joined]: {
after: TransitionType.Left,
newTransition: TransitionType.JoinedAndLeft
},
[TransitionType.Left]: {
after: TransitionType.Joined,
newTransition: TransitionType.LeftAndJoined
} // $currentTransition : {
// 'after' : $nextTransition,
// 'newTransition' : 'new_transition_type',
// },
};
const res
/*: TransitionType[]*/
= [];
for (let i = 0; i < transitions.length; i++) {
const t = transitions[i];
const t2 = transitions[i + 1];
let transition = t;
if (i < transitions.length - 1 && modMap[t] && modMap[t].after === t2) {
transition = modMap[t].newTransition;
i++;
}
res.push(transition);
}
return res;
}
/**
* Transform an array of transitions into an array of transitions and how many times
* they are repeated consecutively.
*
* An array of 123 "joined_and_left" transitions, would result in:
* ```
* [{
* transitionType: "joined_and_left"
* repeats: 123
* }]
* ```
* @param {string[]} transitions the array of transitions to transform.
* @returns {object[]} an array of coalesced transitions.
*/
static coalesceRepeatedTransitions(transitions
/*: TransitionType[]*/
) {
const res
/*: {
transitionType: TransitionType;
repeats: number;
}[]*/
= [];
for (let i = 0; i < transitions.length; i++) {
if (res.length > 0 && res[res.length - 1].transitionType === transitions[i]) {
res[res.length - 1].repeats += 1;
} else {
res.push({
transitionType: transitions[i],
repeats: 1
});
}
}
return res;
}
/**
* For a certain transition, t, describe what happened to the users that
* underwent the transition.
* @param {string} t the transition type.
* @param {number} userCount number of usernames
* @param {number} repeats the number of times the transition was repeated in a row.
* @returns {string} the written Human Readable equivalent of the transition.
*/
static getDescriptionForTransition(t
/*: TransitionType*/
, userCount
/*: number*/
, repeats
/*: number*/
) {
// The empty interpolations 'severalUsers' and 'oneUser'
// are there only to show translators to non-English languages
// that the verb is conjugated to plural or singular Subject.
let res = null;
switch (t) {
case "joined":
res = userCount > 1 ? (0, _languageHandler._t)("%(severalUsers)sjoined %(count)s times", {
severalUsers: "",
count: repeats
}) : (0, _languageHandler._t)("%(oneUser)sjoined %(count)s times", {
oneUser: "",
count: repeats
});
break;
case "left":
res = userCount > 1 ? (0, _languageHandler._t)("%(severalUsers)sleft %(count)s times", {
severalUsers: "",
count: repeats
}) : (0, _languageHandler._t)("%(oneUser)sleft %(count)s times", {
oneUser: "",
count: repeats
});
break;
case "joined_and_left":
res = userCount > 1 ? (0, _languageHandler._t)("%(severalUsers)sjoined and left %(count)s times", {
severalUsers: "",
count: repeats
}) : (0, _languageHandler._t)("%(oneUser)sjoined and left %(count)s times", {
oneUser: "",
count: repeats
});
break;
case "left_and_joined":
res = userCount > 1 ? (0, _languageHandler._t)("%(severalUsers)sleft and rejoined %(count)s times", {
severalUsers: "",
count: repeats
}) : (0, _languageHandler._t)("%(oneUser)sleft and rejoined %(count)s times", {
oneUser: "",
count: repeats
});
break;
case "invite_reject":
res = userCount > 1 ? (0, _languageHandler._t)("%(severalUsers)srejected their invitations %(count)s times", {
severalUsers: "",
count: repeats
}) : (0, _languageHandler._t)("%(oneUser)srejected their invitation %(count)s times", {
oneUser: "",
count: repeats
});
break;
case "invite_withdrawal":
res = userCount > 1 ? (0, _languageHandler._t)("%(severalUsers)shad their invitations withdrawn %(count)s times", {
severalUsers: "",
count: repeats
}) : (0, _languageHandler._t)("%(oneUser)shad their invitation withdrawn %(count)s times", {
oneUser: "",
count: repeats
});
break;
case "invited":
res = userCount > 1 ? (0, _languageHandler._t)("were invited %(count)s times", {
count: repeats
}) : (0, _languageHandler._t)("was invited %(count)s times", {
count: repeats
});
break;
case "banned":
res = userCount > 1 ? (0, _languageHandler._t)("were banned %(count)s times", {
count: repeats
}) : (0, _languageHandler._t)("was banned %(count)s times", {
count: repeats
});
break;
case "unbanned":
res = userCount > 1 ? (0, _languageHandler._t)("were unbanned %(count)s times", {
count: repeats
}) : (0, _languageHandler._t)("was unbanned %(count)s times", {
count: repeats
});
break;
case "kicked":
res = userCount > 1 ? (0, _languageHandler._t)("were kicked %(count)s times", {
count: repeats
}) : (0, _languageHandler._t)("was kicked %(count)s times", {
count: repeats
});
break;
case "changed_name":
res = userCount > 1 ? (0, _languageHandler._t)("%(severalUsers)schanged their name %(count)s times", {
severalUsers: "",
count: repeats
}) : (0, _languageHandler._t)("%(oneUser)schanged their name %(count)s times", {
oneUser: "",
count: repeats
});
break;
case "changed_avatar":
res = userCount > 1 ? (0, _languageHandler._t)("%(severalUsers)schanged their avatar %(count)s times", {
severalUsers: "",
count: repeats
}) : (0, _languageHandler._t)("%(oneUser)schanged their avatar %(count)s times", {
oneUser: "",
count: repeats
});
break;
case "no_change":
res = userCount > 1 ? (0, _languageHandler._t)("%(severalUsers)smade no changes %(count)s times", {
severalUsers: "",
count: repeats
}) : (0, _languageHandler._t)("%(oneUser)smade no changes %(count)s times", {
oneUser: "",
count: repeats
});
break;
}
return res;
}
static getTransitionSequence(events
/*: MatrixEvent[]*/
) {
return events.map(MemberEventListSummary.getTransition);
}
/**
* Label a given membership event, `e`, where `getContent().membership` has
* changed for each transition allowed by the Matrix protocol. This attempts to
* label the membership changes that occur in `../../../TextForEvent.js`.
* @param {MatrixEvent} e the membership change event to label.
* @returns {string?} the transition type given to this event. This defaults to `null`
* if a transition is not recognised.
*/
static getTransition(e
/*: MatrixEvent*/
)
/*: TransitionType*/
{
if (e.mxEvent.getType() === 'm.room.third_party_invite') {
// Handle 3pid invites the same as invites so they get bundled together
if (!(0, _RoomInvite.isValid3pidInvite)(e.mxEvent)) {
return TransitionType.InviteWithdrawal;
}
return TransitionType.Invited;
}
switch (e.mxEvent.getContent().membership) {
case 'invite':
return TransitionType.Invited;
case 'ban':
return TransitionType.Banned;
case 'join':
if (e.mxEvent.getPrevContent().membership === 'join') {
if (e.mxEvent.getContent().displayname !== e.mxEvent.getPrevContent().displayname) {
return TransitionType.ChangedName;
} else if (e.mxEvent.getContent().avatar_url !== e.mxEvent.getPrevContent().avatar_url) {
return TransitionType.ChangedAvatar;
} // console.log("MELS ignoring duplicate membership join event");
return TransitionType.NoChange;
} else {
return TransitionType.Joined;
}
case 'leave':
if (e.mxEvent.getSender() === e.mxEvent.getStateKey()) {
switch (e.mxEvent.getPrevContent().membership) {
case 'invite':
return TransitionType.InviteReject;
default:
return TransitionType.Left;
}
}
switch (e.mxEvent.getPrevContent().membership) {
case 'invite':
return TransitionType.InviteWithdrawal;
case 'ban':
return TransitionType.Unbanned;
// sender is not target and made the target leave, if not from invite/ban then this is a kick
default:
return TransitionType.Kicked;
}
default:
return null;
}
}
getAggregate(userEvents
/*: Record<string, IUserEvents[]>*/
) {
// A map of aggregate type to arrays of display names. Each aggregate type
// is a comma-delimited string of transitions, e.g. "joined,left,kicked".
// The array of display names is the array of users who went through that
// sequence during eventsToRender.
const aggregate
/*: Record<string, string[]>*/
= {// $aggregateType : []:string
}; // A map of aggregate types to the indices that order them (the index of
// the first event for a given transition sequence)
const aggregateIndices
/*: Record<string, number>*/
= {// $aggregateType : int
};
const users = Object.keys(userEvents);
users.forEach(userId => {
const firstEvent = userEvents[userId][0];
const displayName = firstEvent.displayName;
const seq = MemberEventListSummary.getTransitionSequence(userEvents[userId]).join(SEP);
if (!aggregate[seq]) {
aggregate[seq] = [];
aggregateIndices[seq] = -1;
}
aggregate[seq].push(displayName);
if (aggregateIndices[seq] === -1 || firstEvent.index < aggregateIndices[seq]) {
aggregateIndices[seq] = firstEvent.index;
}
});
return {
names: aggregate,
indices: aggregateIndices
};
}
render() {
const eventsToRender = this.props.events; // Map user IDs to latest Avatar Member. ES6 Maps are ordered by when the key was created,
// so this works perfectly for us to match event order whilst storing the latest Avatar Member
const latestUserAvatarMember = new Map(); // Object mapping user IDs to an array of IUserEvents
const userEvents
/*: Record<string, IUserEvents[]>*/
= {};
eventsToRender.forEach((e, index) => {
const userId = e.getStateKey(); // Initialise a user's events
if (!userEvents[userId]) {
userEvents[userId] = [];
}
if (e.target) {
latestUserAvatarMember.set(userId, e.target);
}
let displayName = userId;
if (e.getType() === 'm.room.third_party_invite') {
displayName = e.getContent().display_name;
} else if (e.target) {
displayName = e.target.name;
}
userEvents[userId].push({
mxEvent: e,
displayName,
index: index
});
});
const aggregate = this.getAggregate(userEvents); // Sort types by order of lowest event index within sequence
const orderedTransitionSequences = Object.keys(aggregate.names).sort((seq1, seq2) => aggregate.indices[seq1] - aggregate.indices[seq2]);
return /*#__PURE__*/_react.default.createElement(_EventListSummary.default, {
events: this.props.events,
threshold: this.props.threshold,
onToggle: this.props.onToggle,
startExpanded: this.props.startExpanded,
children: this.props.children,
summaryMembers: [...latestUserAvatarMember.values()],
summaryText: this.generateSummary(aggregate.names, orderedTransitionSequences)
});
}
}, (0, _defineProperty2.default)(_class2, "defaultProps", {
summaryLength: 1,
threshold: 3,
avatarsMaxLength: 5
}), _temp)) || _class);
exports.default = MemberEventListSummary;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9jb21wb25lbnRzL3ZpZXdzL2VsZW1lbnRzL01lbWJlckV2ZW50TGlzdFN1bW1hcnkudHN4Il0sIm5hbWVzIjpbIlRyYW5zaXRpb25UeXBlIiwiU0VQIiwiTWVtYmVyRXZlbnRMaXN0U3VtbWFyeSIsIlJlYWN0IiwiQ29tcG9uZW50Iiwic2hvdWxkQ29tcG9uZW50VXBkYXRlIiwibmV4dFByb3BzIiwiZXZlbnRzIiwibGVuZ3RoIiwicHJvcHMiLCJ0aHJlc2hvbGQiLCJnZW5lcmF0ZVN1bW1hcnkiLCJldmVudEFnZ3JlZ2F0ZXMiLCJvcmRlcmVkVHJhbnNpdGlvblNlcXVlbmNlcyIsInN1bW1hcmllcyIsIm1hcCIsInRyYW5zaXRpb25zIiwidXNlck5hbWVzIiwibmFtZUxpc3QiLCJyZW5kZXJOYW1lTGlzdCIsInNwbGl0VHJhbnNpdGlvbnMiLCJzcGxpdCIsImNhbm9uaWNhbFRyYW5zaXRpb25zIiwiZ2V0Q2Fub25pY2FsVHJhbnNpdGlvbnMiLCJjb2FsZXNjZWRUcmFuc2l0aW9ucyIsImNvYWxlc2NlUmVwZWF0ZWRUcmFuc2l0aW9ucyIsImRlc2NzIiwidCIsImdldERlc2NyaXB0aW9uRm9yVHJhbnNpdGlvbiIsInRyYW5zaXRpb25UeXBlIiwicmVwZWF0cyIsImRlc2MiLCJ0cmFuc2l0aW9uTGlzdCIsImpvaW4iLCJ1c2VycyIsInN1bW1hcnlMZW5ndGgiLCJtb2RNYXAiLCJKb2luZWQiLCJhZnRlciIsIkxlZnQiLCJuZXdUcmFuc2l0aW9uIiwiSm9pbmVkQW5kTGVmdCIsIkxlZnRBbmRKb2luZWQiLCJyZXMiLCJpIiwidDIiLCJ0cmFuc2l0aW9uIiwicHVzaCIsInVzZXJDb3VudCIsInNldmVyYWxVc2VycyIsImNvdW50Iiwib25lVXNlciIsImdldFRyYW5zaXRpb25TZXF1ZW5jZSIsImdldFRyYW5zaXRpb24iLCJlIiwibXhFdmVudCIsImdldFR5cGUiLCJJbnZpdGVXaXRoZHJhd2FsIiwiSW52aXRlZCIsImdldENvbnRlbnQiLCJtZW1iZXJzaGlwIiwiQmFubmVkIiwiZ2V0UHJldkNvbnRlbnQiLCJkaXNwbGF5bmFtZSIsIkNoYW5nZWROYW1lIiwiYXZhdGFyX3VybCIsIkNoYW5nZWRBdmF0YXIiLCJOb0NoYW5nZSIsImdldFNlbmRlciIsImdldFN0YXRlS2V5IiwiSW52aXRlUmVqZWN0IiwiVW5iYW5uZWQiLCJLaWNrZWQiLCJnZXRBZ2dyZWdhdGUiLCJ1c2VyRXZlbnRzIiwiYWdncmVnYXRlIiwiYWdncmVnYXRlSW5kaWNlcyIsIk9iamVjdCIsImtleXMiLCJmb3JFYWNoIiwidXNlcklkIiwiZmlyc3RFdmVudCIsImRpc3BsYXlOYW1lIiwic2VxIiwiaW5kZXgiLCJuYW1lcyIsImluZGljZXMiLCJyZW5kZXIiLCJldmVudHNUb1JlbmRlciIsImxhdGVzdFVzZXJBdmF0YXJNZW1iZXIiLCJNYXAiLCJ0YXJnZXQiLCJzZXQiLCJkaXNwbGF5X25hbWUiLCJuYW1lIiwic29ydCIsInNlcTEiLCJzZXEyIiwib25Ub2dnbGUiLCJzdGFydEV4cGFuZGVkIiwiY2hpbGRyZW4iLCJ2YWx1ZXMiLCJhdmF0YXJzTWF4TGVuZ3RoIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7OztBQWtCQTs7QUFJQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7OztJQTRCS0EsYzs7V0FBQUEsYztBQUFBQSxFQUFBQSxjO0FBQUFBLEVBQUFBLGM7QUFBQUEsRUFBQUEsYztBQUFBQSxFQUFBQSxjO0FBQUFBLEVBQUFBLGM7QUFBQUEsRUFBQUEsYztBQUFBQSxFQUFBQSxjO0FBQUFBLEVBQUFBLGM7QUFBQUEsRUFBQUEsYztBQUFBQSxFQUFBQSxjO0FBQUFBLEVBQUFBLGM7QUFBQUEsRUFBQUEsYztBQUFBQSxFQUFBQSxjO0dBQUFBLGMsS0FBQUEsYzs7QUFnQkwsTUFBTUMsR0FBRyxHQUFHLEdBQVo7SUFHcUJDLHNCLFdBRHBCLGdEQUFxQix1Q0FBckIsQyxtQ0FBRCxNQUNxQkEsc0JBRHJCLFNBQ29EQyxlQUFNQztBQUQxRDtBQUM0RTtBQU94RUMsRUFB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QixFQUFzQ3hFLDBCQUF0QztBQVBWLE1BQVA7QUFRSDs7QUExWHVFLEMseURBQ2xEO0FBQ2xCc0IsRUFBQUEsYUFBYSxFQUFFLENBREc7QUFFbEJ6QixFQUFBQSxTQUFTLEVBQUUsQ0FGTztBQUdsQjRGLEVBQUFBLGdCQUFnQixFQUFFO0FBSEEsQyIsInNvdXJjZXNDb250ZW50IjpbIi8qXG5Db3B5cmlnaHQgMjAxNiBPcGVuTWFya2V0IEx0ZFxuQ29weXJpZ2h0IDIwMTksIDIwMjAgVGhlIE1hdHJpeC5vcmcgRm91bmRhdGlvbiBDLkkuQy5cbkNvcHlyaWdodCAyMDE5IE1pY2hhZWwgVGVsYXR5bnNraSA8N3QzY2hndXlAZ21haWwuY29tPlxuXG5MaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpO1xueW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLlxuWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0XG5cbiAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcblxuVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG5TZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXG5saW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiovXG5cbmltcG9ydCBSZWFjdCwgeyBSZWFjdENoaWxkcmVuIH0gZnJvbSAncmVhY3QnO1xuaW1wb3J0IHsgTWF0cml4RXZlbnQgfSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvbW9kZWxzL2V2ZW50XCI7XG5pbXBvcnQgeyBSb29tTWVtYmVyIH0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL21vZGVscy9yb29tLW1lbWJlclwiO1xuXG5pbXBvcnQgeyBfdCB9IGZyb20gJy4uLy4uLy4uL2xhbmd1YWdlSGFuZGxlcic7XG5pbXBvcnQgeyBmb3JtYXRDb21tYVNlcGFyYXRlZExpc3QgfSBmcm9tICcuLi8uLi8uLi91dGlscy9Gb3JtYXR0aW5nVXRpbHMnO1xuaW1wb3J0IHsgaXNWYWxpZDNwaWRJbnZpdGUgfSBmcm9tIFwiLi4vLi4vLi4vUm9vbUludml0ZVwiO1xuaW1wb3J0IEV2ZW50TGlzdFN1bW1hcnkgZnJvbSBcIi4vRXZlbnRMaXN0U3VtbWFyeVwiO1xuaW1wb3J0IHtyZXBsYWNlYWJsZUNvbXBvbmVudH0gZnJvbSBcIi4uLy4uLy4uL3V0aWxzL3JlcGxhY2VhYmxlQ29tcG9uZW50XCI7XG5cbmludGVyZmFjZSBJUHJvcHMge1xuICAgIC8vIEFuIGFycmF5IG9mIG1lbWJlciBldmVudHMgdG8gc3VtbWFyaXNlXG4gICAgZXZlbnRzOiBNYXRyaXhFdmVudFtdO1xuICAgIC8vIFRoZSBtYXhpbXVtIG51bWJlciBvZiBuYW1lcyB0byBzaG93IGluIGVpdGhlciBlYWNoIHN1bW1hcnkgZS5nLiAyIHdvdWxkIHJlc3VsdCBcIkEsIEIgYW5kIDIzNCBvdGhlcnMgbGVmdFwiXG4gICAgc3VtbWFyeUxlbmd0aD86IG51bWJlcjtcbiAgICAvLyBUaGUgbWF4aW11bSBudW1iZXIgb2YgYXZhdGFycyB0byBkaXNwbGF5IGluIHRoZSBzdW1tYXJ5XG4gICAgYXZhdGFyc01heExlbmd0aD86IG51bWJlcjtcbiAgICAvLyBUaGUgbWluaW11bSBudW1iZXIgb2YgZXZlbnRzIG5lZWRlZCB0byB0cmlnZ2VyIHN1bW1hcmlzYXRpb25cbiAgICB0aHJlc2hvbGQ/OiBudW1iZXIsXG4gICAgLy8gV2hldGhlciBvciBub3QgdG8gYmVnaW4gd2l0aCBzdGF0ZS5leHBhbmRlZD10cnVlXG4gICAgc3RhcnRFeHBhbmRlZD86IGJvb2xlYW4sXG4gICAgLy8gQW4gYXJyYXkgb2YgRXZlbnRUaWxlcyB0byByZW5kZXIgd2hlbiBleHBhbmRlZFxuICAgIGNoaWxkcmVuOiBSZWFjdENoaWxkcmVuO1xuICAgIC8vIENhbGxlZCB3aGVuIHRoZSBNRUxTIGV4cGFuc2lvbiBpcyB0b2dnbGVkXG4gICAgb25Ub2dnbGU/KCk6IHZvaWQsXG59XG5cbmludGVyZmFjZSBJVXNlckV2ZW50cyB7XG4gICAgLy8gVGhlIG9yaWdpbmFsIGV2ZW50XG4gICAgbXhFdmVudDogTWF0cml4RXZlbnQ7XG4gICAgLy8gVGhlIGRpc3BsYXkgbmFtZSBvZiB0aGUgdXNlciAoaWYgbm90LCB0aGVuIHVzZXIgSUQpXG4gICAgZGlzcGxheU5hbWU6IHN0cmluZztcbiAgICAvLyBUaGUgb3JpZ2luYWwgaW5kZXggb2YgdGhlIGV2ZW50IGluIHRoaXMucHJvcHMuZXZlbnRzXG4gICAgaW5kZXg6IG51bWJlcjtcbn1cblxuZW51bSBUcmFuc2l0aW9uVHlwZSB7XG4gICAgSm9pbmVkID0gXCJqb2luZWRcIixcbiAgICBMZWZ0ID0gXCJsZWZ0XCIsXG4gICAgSm9pbmVkQW5kTGVmdCA9IFwiam9pbmVkX2FuZF9sZWZ0XCIsXG4gICAgTGVmdEFuZEpvaW5lZCA9IFwibGVmdF9hbmRfam9pbmVkXCIsXG4gICAgSW52aXRlUmVqZWN0ID0gXCJpbnZpdGVfcmVqZWN0XCIsXG4gICAgSW52aXRlV2l0aGRyYXdhbCA9IFwiaW52aXRlX3dpdGhkcmF3YWxcIixcbiAgICBJbnZpdGVkID0gXCJpbnZpdGVkXCIsXG4gICAgQmFubmVkID0gXCJiYW5uZWRcIixcbiAgICBVbmJhbm5lZCA9IFwidW5iYW5uZWRcIixcbiAgICBLaWNrZWQgPSBcImtpY2tlZFwiLFxuICAgIENoYW5nZWROYW1lID0gXCJjaGFuZ2VkX25hbWVcIixcbiAgICBDaGFuZ2VkQXZhdGFyID0gXCJjaGFuZ2VkX2F2YXRhclwiLFxuICAgIE5vQ2hhbmdlID0gXCJub19jaGFuZ2VcIixcbn1cblxuY29uc3QgU0VQID0gXCIsXCI7XG5cbkByZXBsYWNlYWJsZUNvbXBvbmVudChcInZpZXdzLmVsZW1lbnRzLk1lbWJlckV2ZW50TGlzdFN1bW1hcnlcIilcbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE1lbWJlckV2ZW50TGlzdFN1bW1hcnkgZXh0ZW5kcyBSZWFjdC5Db21wb25lbnQ8SVByb3BzPiB7XG4gICAgc3RhdGljIGRlZmF1bHRQcm9wcyA9IHtcbiAgICAgICAgc3VtbWFyeUxlbmd0aDogMSxcbiAgICAgICAgdGhyZXNob2xkOiAzLFxuICAgICAgICBhdmF0YXJzTWF4TGVuZ3RoOiA1LFxuICAgIH07XG5cbiAgICBzaG91bGRDb21wb25lbnRVcGRhdGUobmV4dFByb3BzKSB7XG4gICAgICAgIC8vIFVwZGF0ZSBpZlxuICAgICAgICAvLyAgLSBUaGUgbnVtYmVyIG9mIHN1bW1hcmlzZWQgZXZlbnRzIGhhcyBjaGFuZ2VkXG4gICAgICAgIC8vICAtIG9yIGlmIHRoZSBzdW1tYXJ5IGlzIGFib3V0IHRvIHRvZ2dsZSB0byBiZWNvbWUgY29sbGFwc2VkXG4gICAgICAgIC8vICAtIG9yIGlmIHRoZXJlIGFyZSBmZXdFdmVudHMsIG1lYW5pbmcgdGhlIGNoaWxkIGV2ZW50VGlsZXMgYXJlIHNob3duIGFzLWlzXG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICBuZXh0UHJvcHMuZXZlbnRzLmxlbmd0aCAhPT0gdGhpcy5wcm9wcy5ldmVudHMubGVuZ3RoIHx8XG4gICAgICAgICAgICBuZXh0UHJvcHMuZXZlbnRzLmxlbmd0aCA8IHRoaXMucHJvcHMudGhyZXNob2xkXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2VuZXJhdGUgdGhlIHRleHQgZm9yIHVzZXJzIGFnZ3JlZ2F0ZWQgYnkgdGhlaXIgdHJhbnNpdGlvbiBzZXF1ZW5jZXMgKGBldmVudEFnZ3JlZ2F0ZXNgKSB3aGVyZVxuICAgICAqIHRoZSBzZXF1ZW5jZXMgYXJlIG9yZGVyZWQgYnkgYG9yZGVyZWRUcmFuc2l0aW9uU2VxdWVuY2VzYC5cbiAgICAgKiBAcGFyYW0ge29iamVjdH0gZXZlbnRBZ2dyZWdhdGVzIGEgbWFwIG9mIHRyYW5zaXRpb24gc2VxdWVuY2UgdG8gYXJyYXkgb2YgdXNlciBkaXNwbGF5IG5hbWVzXG4gICAgICogb3IgdXNlciBJRHMuXG4gICAgICogQHBhcmFtIHtzdHJpbmdbXX0gb3JkZXJlZFRyYW5zaXRpb25TZXF1ZW5jZXMgYW4gYXJyYXkgd2hpY2ggaXMgc29tZSBvcmRlcmluZyBvZlxuICAgICAqIGBPYmplY3Qua2V5cyhldmVudEFnZ3JlZ2F0ZXMpYC5cbiAgICAgKiBAcmV0dXJucyB7c3RyaW5nfSB0aGUgdGV4dHVhbCBzdW1tYXJ5IG9mIHRoZSBhZ2dyZWdhdGVkIGV2ZW50cyB0aGF0IG9jY3VycmVkLlxuICAgICAqL1xuICAgIHByaXZhdGUgZ2VuZXJhdGVTdW1tYXJ5KGV2ZW50QWdncmVnYXRlczogUmVjb3JkPHN0cmluZywgc3RyaW5nW10+LCBvcmRlcmVkVHJhbnNpdGlvblNlcXVlbmNlczogc3RyaW5nW10pIHtcbiAgICAgICAgY29uc3Qgc3VtbWFyaWVzID0gb3JkZXJlZFRyYW5zaXRpb25TZXF1ZW5jZXMubWFwKCh0cmFuc2l0aW9ucykgPT4ge1xuICAgICAgICAgICAgY29uc3QgdXNlck5hbWVzID0gZXZlbnRBZ2dyZWdhdGVzW3RyYW5zaXRpb25zXTtcbiAgICAgICAgICAgIGNvbnN0IG5hbWVMaXN0ID0gdGhpcy5yZW5kZXJOYW1lTGlzdCh1c2VyTmFtZXMpO1xuXG4gICAgICAgICAgICBjb25zdCBzcGxpdFRyYW5zaXRpb25zID0gdHJhbnNpdGlvbnMuc3BsaXQoU0VQKSBhcyBUcmFuc2l0aW9uVHlwZVtdO1xuXG4gICAgICAgICAgICAvLyBTb21lIG5laWdoYm91cmluZyB0cmFuc2l0aW9ucyBhcmUgY29tbW9uLCBzbyBjYW5vbmljYWxpc2Ugc29tZSBpbnRvIFwicGFpclwiXG4gICAgICAgICAgICAvLyB0cmFuc2l0aW9uc1xuICAgICAgICAgICAgY29uc3QgY2Fub25pY2FsVHJhbnNpdGlvbnMgPSBNZW1iZXJFdmVudExpc3RTdW1tYXJ5LmdldENhbm9uaWNhbFRyYW5zaXRpb25zKHNwbGl0VHJhbnNpdGlvbnMpO1xuICAgICAgICAgICAgLy8gVHJhbnNmb3JtIGludG8gY29uc2VjdXRpdmUgcmVwZXRpdGlvbnMgb2YgdGhlIHNhbWUgdHJhbnNpdGlvbiAobGlrZSA1XG4gICAgICAgICAgICAvLyBjb25zZWN1dGl2ZSAnam9pbmVkX2FuZF9sZWZ0J3MpXG4gICAgICAgICAgICBjb25zdCBjb2FsZXNjZWRUcmFuc2l0aW9ucyA9IE1lbWJlckV2ZW50TGlzdFN1bW1hcnkuY29hbGVzY2VSZXBlYXRlZFRyYW5zaXRpb25zKGNhbm9uaWNhbFRyYW5zaXRpb25zKTtcblxuICAgICAgICAgICAgY29uc3QgZGVzY3MgPSBjb2FsZXNjZWRUcmFuc2l0aW9ucy5tYXAoKHQpID0+IHtcbiAgICAgICAgICAgICAgICByZXR1cm4gTWVtYmVyRXZlbnRMaXN0U3VtbWFyeS5nZXREZXNjcmlwdGlvbkZvclRyYW5zaXRpb24oXG4gICAgICAgICAgICAgICAgICAgIHQudHJhbnNpdGlvblR5cGUsIHVzZXJOYW1lcy5sZW5ndGgsIHQucmVwZWF0cyxcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIGNvbnN0IGRlc2MgPSBmb3JtYXRDb21tYVNlcGFyYXRlZExpc3QoZGVzY3MpO1xuXG4gICAgICAgICAgICByZXR1cm4gX3QoJyUobmFtZUxpc3QpcyAlKHRyYW5zaXRpb25MaXN0KXMnLCB7IG5hbWVMaXN0OiBuYW1lTGlzdCwgdHJhbnNpdGlvbkxpc3Q6IGRlc2MgfSk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmICghc3VtbWFyaWVzKSB7XG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBzdW1tYXJpZXMuam9pbihcIiwgXCIpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nW119IHVzZXJzIGFuIGFycmF5IG9mIHVzZXIgZGlzcGxheSBuYW1lcyBvciB1c2VyIElEcy5cbiAgICAgKiBAcmV0dXJucyB7c3RyaW5nfSBhIGNvbW1hLXNlcGFyYXRlZCBsaXN0IHRoYXQgZW5kcyB3aXRoIFwiYW5kIFtuXSBvdGhlcnNcIiBpZiB0aGVyZSBhcmVcbiAgICAgKiBtb3JlIGl0ZW1zIGluIGB1c2Vyc2AgdGhhbiBgdGhpcy5wcm9wcy5zdW1tYXJ5TGVuZ3RoYCwgd2hpY2ggaXMgdGhlIG51bWJlciBvZiBuYW1lc1xuICAgICAqIGluY2x1ZGVkIGJlZm9yZSBcImFuZCBbbl0gb3RoZXJzXCIuXG4gICAgICovXG4gICAgcHJpdmF0ZSByZW5kZXJOYW1lTGlzdCh1c2Vyczogc3RyaW5nW10pIHtcbiAgICAgICAgcmV0dXJuIGZvcm1hdENvbW1hU2VwYXJhdGVkTGlzdCh1c2VycywgdGhpcy5wcm9wcy5zdW1tYXJ5TGVuZ3RoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDYW5vbmljYWxpc2UgYW4gYXJyYXkgb2YgdHJhbnNpdGlvbnMgc3VjaCB0aGF0IHNvbWUgcGFpcnMgb2YgdHJhbnNpdGlvbnMgYmVjb21lXG4gICAgICogc2luZ2xlIHRyYW5zaXRpb25zLiBGb3IgZXhhbXBsZSBhbiBpbnB1dCBbJ2pvaW5lZCcsJ2xlZnQnXSB3b3VsZCByZXN1bHQgaW4gYW4gb3V0cHV0XG4gICAgICogWydqb2luZWRfYW5kX2xlZnQnXS5cbiAgICAgKiBAcGFyYW0ge3N0cmluZ1tdfSB0cmFuc2l0aW9ucyBhbiBhcnJheSBvZiB0cmFuc2l0aW9ucy5cbiAgICAgKiBAcmV0dXJucyB7c3RyaW5nW119IGFuIGFycmF5IG9mIHRyYW5zaXRpb25zLlxuICAgICAqL1xuICAgIHByaXZhdGUgc3RhdGljIGdldENhbm9uaWNhbFRyYW5zaXRpb25zKHRyYW5zaXRpb25zOiBUcmFuc2l0aW9uVHlwZVtdKTogVHJhbnNpdGlvblR5cGVbXSB7XG4gICAgICAgIGNvbnN0IG1vZE1hcCA9IHtcbiAgICAgICAgICAgIFtUcmFuc2l0aW9uVHlwZS5Kb2luZWRdOiB7XG4gICAgICAgICAgICAgICAgYWZ0ZXI6IFRyYW5zaXRpb25UeXBlLkxlZnQsXG4gICAgICAgICAgICAgICAgbmV3VHJhbnNpdGlvbjogVHJhbnNpdGlvblR5cGUuSm9pbmVkQW5kTGVmdCxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBbVHJhbnNpdGlvblR5cGUuTGVmdF06IHtcbiAgICAgICAgICAgICAgICBhZnRlcjogVHJhbnNpdGlvblR5cGUuSm9pbmVkLFxuICAgICAgICAgICAgICAgIG5ld1RyYW5zaXRpb246IFRyYW5zaXRpb25UeXBlLkxlZnRBbmRKb2luZWQsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgLy8gJGN1cnJlbnRUcmFuc2l0aW9uIDoge1xuICAgICAgICAgICAgLy8gICAgICdhZnRlcicgOiAkbmV4dFRyYW5zaXRpb24sXG4gICAgICAgICAgICAvLyAgICAgJ25ld1RyYW5zaXRpb24nIDogJ25ld190cmFuc2l0aW9uX3R5cGUnLFxuICAgICAgICAgICAgLy8gfSxcbiAgICAgICAgfTtcbiAgICAgICAgY29uc3QgcmVzOiBUcmFuc2l0aW9uVHlwZVtdID0gW107XG5cbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0cmFuc2l0aW9ucy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgY29uc3QgdCA9IHRyYW5zaXRpb25zW2ldO1xuICAgICAgICAgICAgY29uc3QgdDIgPSB0cmFuc2l0aW9uc1tpICsgMV07XG5cbiAgICAgICAgICAgIGxldCB0cmFuc2l0aW9uID0gdDtcblxuICAgICAgICAgICAgaWYgKGkgPCB0cmFuc2l0aW9ucy5sZW5ndGggLSAxICYmIG1vZE1hcFt0XSAmJiBtb2RNYXBbdF0uYWZ0ZXIgPT09IHQyKSB7XG4gICAgICAgICAgICAgICAgdHJhbnNpdGlvbiA9IG1vZE1hcFt0XS5uZXdUcmFuc2l0aW9uO1xuICAgICAgICAgICAgICAgIGkrKztcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmVzLnB1c2godHJhbnNpdGlvbik7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJlcztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBUcmFuc2Zvcm0gYW4gYXJyYXkgb2YgdHJhbnNpdGlvbnMgaW50byBhbiBhcnJheSBvZiB0cmFuc2l0aW9ucyBhbmQgaG93IG1hbnkgdGltZXNcbiAgICAgKiB0aGV5IGFyZSByZXBlYXRlZCBjb25zZWN1dGl2ZWx5LlxuICAgICAqXG4gICAgICogQW4gYXJyYXkgb2YgMTIzIFwiam9pbmVkX2FuZF9sZWZ0XCIgdHJhbnNpdGlvbnMsIHdvdWxkIHJlc3VsdCBpbjpcbiAgICAgKiBgYGBcbiAgICAgKiBbe1xuICAgICAqICAgdHJhbnNpdGlvblR5cGU6IFwiam9pbmVkX2FuZF9sZWZ0XCJcbiAgICAgKiAgIHJlcGVhdHM6IDEyM1xuICAgICAqIH1dXG4gICAgICogYGBgXG4gICAgICogQHBhcmFtIHtzdHJpbmdbXX0gdHJhbnNpdGlvbnMgdGhlIGFycmF5IG9mIHRyYW5zaXRpb25zIHRvIHRyYW5zZm9ybS5cbiAgICAgKiBAcmV0dXJucyB7b2JqZWN0W119IGFuIGFycmF5IG9mIGNvYWxlc2NlZCB0cmFuc2l0aW9ucy5cbiAgICAgKi9cbiAgICBwcml2YXRlIHN0YXRpYyBjb2FsZXNjZVJlcGVhdGVkVHJhbnNpdGlvbnModHJhbnNpdGlvbnM6IFRyYW5zaXRpb25UeXBlW10pIHtcbiAgICAgICAgY29uc3QgcmVzOiB7XG4gICAgICAgICAgICB0cmFuc2l0aW9uVHlwZTogVHJhbnNpdGlvblR5cGU7XG4gICAgICAgICAgICByZXBlYXRzOiBudW1iZXI7XG4gICAgICAgIH1bXSA9IFtdO1xuXG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdHJhbnNpdGlvbnMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGlmIChyZXMubGVuZ3RoID4gMCAmJiByZXNbcmVzLmxlbmd0aCAtIDFdLnRyYW5zaXRpb25UeXBlID09PSB0cmFuc2l0aW9uc1tpXSkge1xuICAgICAgICAgICAgICAgIHJlc1tyZXMubGVuZ3RoIC0gMV0ucmVwZWF0cyArPSAxO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXMucHVzaCh7XG4gICAgICAgICAgICAgICAgICAgIHRyYW5zaXRpb25UeXBlOiB0cmFuc2l0aW9uc1tpXSxcbiAgICAgICAgICAgICAgICAgICAgcmVwZWF0czogMSxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcmVzO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEZvciBhIGNlcnRhaW4gdHJhbnNpdGlvbiwgdCwgZGVzY3JpYmUgd2hhdCBoYXBwZW5lZCB0byB0aGUgdXNlcnMgdGhhdFxuICAgICAqIHVuZGVyd2VudCB0aGUgdHJhbnNpdGlvbi5cbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gdCB0aGUgdHJhbnNpdGlvbiB0eXBlLlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSB1c2VyQ291bnQgbnVtYmVyIG9mIHVzZXJuYW1lc1xuICAgICAqIEBwYXJhbSB7bnVtYmVyfSByZXBlYXRzIHRoZSBudW1iZXIgb2YgdGltZXMgdGhlIHRyYW5zaXRpb24gd2FzIHJlcGVhdGVkIGluIGEgcm93LlxuICAgICAqIEByZXR1cm5zIHtzdHJpbmd9IHRoZSB3cml0dGVuIEh1bWFuIFJlYWRhYmxlIGVxdWl2YWxlbnQgb2YgdGhlIHRyYW5zaXRpb24uXG4gICAgICovXG4gICAgcHJpdmF0ZSBzdGF0aWMgZ2V0RGVzY3JpcHRpb25Gb3JUcmFuc2l0aW9uKHQ6IFRyYW5zaXRpb25UeXBlLCB1c2VyQ291bnQ6IG51bWJlciwgcmVwZWF0czogbnVtYmVyKSB7XG4gICAgICAgIC8vIFRoZSBlbXB0eSBpbnRlcnBvbGF0aW9ucyAnc2V2ZXJhbFVzZXJzJyBhbmQgJ29uZVVzZXInXG4gICAgICAgIC8vIGFyZSB0aGVyZSBvbmx5IHRvIHNob3cgdHJhbnNsYXRvcnMgdG8gbm9uLUVuZ2xpc2ggbGFuZ3VhZ2VzXG4gICAgICAgIC8vIHRoYXQgdGhlIHZlcmIgaXMgY29uanVnYXRlZCB0byBwbHVyYWwgb3Igc2luZ3VsYXIgU3ViamVjdC5cbiAgICAgICAgbGV0IHJlcyA9IG51bGw7XG4gICAgICAgIHN3aXRjaCAodCkge1xuICAgICAgICAgICAgY2FzZSBcImpvaW5lZFwiOlxuICAgICAgICAgICAgICAgIHJlcyA9ICh1c2VyQ291bnQgPiAxKVxuICAgICAgICAgICAgICAgICAgICA/IF90KFwiJShzZXZlcmFsVXNlcnMpc2pvaW5lZCAlKGNvdW50KXMgdGltZXNcIiwgeyBzZXZlcmFsVXNlcnM6IFwiXCIsIGNvdW50OiByZXBlYXRzIH0pXG4gICAgICAgICAgICAgICAgICAgIDogX3QoXCIlKG9uZVVzZXIpc2pvaW5lZCAlKGNvdW50KXMgdGltZXNcIiwgeyBvbmVVc2VyOiBcIlwiLCBjb3VudDogcmVwZWF0cyB9KTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgXCJsZWZ0XCI6XG4gICAgICAgICAgICAgICAgcmVzID0gKHVzZXJDb3VudCA+IDEpXG4gICAgICAgICAgICAgICAgICAgID8gX3QoXCIlKHNldmVyYWxVc2VycylzbGVmdCAlKGNvdW50KXMgdGltZXNcIiwgeyBzZXZlcmFsVXNlcnM6IFwiXCIsIGNvdW50OiByZXBlYXRzIH0pXG4gICAgICAgICAgICAgICAgICAgIDogX3QoXCIlKG9uZVVzZXIpc2xlZnQgJShjb3VudClzIHRpbWVzXCIsIHsgb25lVXNlcjogXCJcIiwgY291bnQ6IHJlcGVhdHMgfSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIFwiam9pbmVkX2FuZF9sZWZ0XCI6XG4gICAgICAgICAgICAgICAgcmVzID0gKHVzZXJDb3VudCA+IDEpXG4gICAgICAgICAgICAgICAgICAgID8gX3QoXCIlKHNldmVyYWxVc2Vycylzam9pbmVkIGFuZCBsZWZ0ICUoY291bnQpcyB0aW1lc1wiLCB7IHNldmVyYWxVc2VyczogXCJcIiwgY291bnQ6IHJlcGVhdHMgfSlcbiAgICAgICAgICAgICAgICAgICAgOiBfdChcIiUob25lVXNlcilzam9pbmVkIGFuZCBsZWZ0ICUoY291bnQpcyB0aW1lc1wiLCB7IG9uZVVzZXI6IFwiXCIsIGNvdW50OiByZXBlYXRzIH0pO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBcImxlZnRfYW5kX2pvaW5lZFwiOlxuICAgICAgICAgICAgICAgIHJlcyA9ICh1c2VyQ291bnQgPiAxKVxuICAgICAgICAgICAgICAgICAgICA/IF90KFwiJShzZXZlcmFsVXNlcnMpc2xlZnQgYW5kIHJlam9pbmVkICUoY291bnQpcyB0aW1lc1wiLCB7IHNldmVyYWxVc2VyczogXCJcIiwgY291bnQ6IHJlcGVhdHMgfSlcbiAgICAgICAgICAgICAgICAgICAgOiBfdChcIiUob25lVXNlcilzbGVmdCBhbmQgcmVqb2luZWQgJShjb3VudClzIHRpbWVzXCIsIHsgb25lVXNlcjogXCJcIiwgY291bnQ6IHJlcGVhdHMgfSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIFwiaW52aXRlX3JlamVjdFwiOlxuICAgICAgICAgICAgICAgIHJlcyA9ICh1c2VyQ291bnQgPiAxKVxuICAgICAgICAgICAgICAgICAgICA/IF90KFwiJShzZXZlcmFsVXNlcnMpc3JlamVjdGVkIHRoZWlyIGludml0YXRpb25zICUoY291bnQpcyB0aW1lc1wiLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZXZlcmFsVXNlcnM6IFwiXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICBjb3VudDogcmVwZWF0cyxcbiAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAgICAgOiBfdChcIiUob25lVXNlcilzcmVqZWN0ZWQgdGhlaXIgaW52aXRhdGlvbiAlKGNvdW50KXMgdGltZXNcIiwgeyBvbmVVc2VyOiBcIlwiLCBjb3VudDogcmVwZWF0cyB9KTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgXCJpbnZpdGVfd2l0aGRyYXdhbFwiOlxuICAgICAgICAgICAgICAgIHJlcyA9ICh1c2VyQ291bnQgPiAxKVxuICAgICAgICAgICAgICAgICAgICA/IF90KFwiJShzZXZlcmFsVXNlcnMpc2hhZCB0aGVpciBpbnZpdGF0aW9ucyB3aXRoZHJhd24gJShjb3VudClzIHRpbWVzXCIsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNldmVyYWxVc2VyczogXCJcIixcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvdW50OiByZXBlYXRzLFxuICAgICAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgICAgICA6IF90KFwiJShvbmVVc2VyKXNoYWQgdGhlaXIgaW52aXRhdGlvbiB3aXRoZHJhd24gJShjb3VudClzIHRpbWVzXCIsIHsgb25lVXNlcjogXCJcIiwgY291bnQ6IHJlcGVhdHMgfSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIFwiaW52aXRlZFwiOlxuICAgICAgICAgICAgICAgIHJlcyA9ICh1c2VyQ291bnQgPiAxKVxuICAgICAgICAgICAgICAgICAgICA/IF90KFwid2VyZSBpbnZpdGVkICUoY291bnQpcyB0aW1lc1wiLCB7IGNvdW50OiByZXBlYXRzIH0pXG4gICAgICAgICAgICAgICAgICAgIDogX3QoXCJ3YXMgaW52aXRlZCAlKGNvdW50KXMgdGltZXNcIiwgeyBjb3VudDogcmVwZWF0cyB9KTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgXCJiYW5uZWRcIjpcbiAgICAgICAgICAgICAgICByZXMgPSAodXNlckNvdW50ID4gMSlcbiAgICAgICAgICAgICAgICAgICAgPyBfdChcIndlcmUgYmFubmVkICUoY291bnQpcyB0aW1lc1wiLCB7IGNvdW50OiByZXBlYXRzIH0pXG4gICAgICAgICAgICAgICAgICAgIDogX3QoXCJ3YXMgYmFubmVkICUoY291bnQpcyB0aW1lc1wiLCB7IGNvdW50OiByZXBlYXRzIH0pO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBcInVuYmFubmVkXCI6XG4gICAgICAgICAgICAgICAgcmVzID0gKHVzZXJDb3VudCA+IDEpXG4gICAgICAgICAgICAgICAgICAgID8gX3QoXCJ3ZXJlIHVuYmFubmVkICUoY291bnQpcyB0aW1lc1wiLCB7IGNvdW50OiByZXBlYXRzIH0pXG4gICAgICAgICAgICAgICAgICAgIDogX3QoXCJ3YXMgdW5iYW5uZWQgJShjb3VudClzIHRpbWVzXCIsIHsgY291bnQ6IHJlcGVhdHMgfSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIFwia2lja2VkXCI6XG4gICAgICAgICAgICAgICAgcmVzID0gKHVzZXJDb3VudCA+IDEpXG4gICAgICAgICAgICAgICAgICAgID8gX3QoXCJ3ZXJlIGtpY2tlZCAlKGNvdW50KXMgdGltZXNcIiwgeyBjb3VudDogcmVwZWF0cyB9KVxuICAgICAgICAgICAgICAgICAgICA6IF90KFwid2FzIGtpY2tlZCAlKGNvdW50KXMgdGltZXNcIiwgeyBjb3VudDogcmVwZWF0cyB9KTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgXCJjaGFuZ2VkX25hbWVcIjpcbiAgICAgICAgICAgICAgICByZXMgPSAodXNlckNvdW50ID4gMSlcbiAgICAgICAgICAgICAgICAgICAgPyBfdChcIiUoc2V2ZXJhbFVzZXJzKXNjaGFuZ2VkIHRoZWlyIG5hbWUgJShjb3VudClzIHRpbWVzXCIsIHsgc2V2ZXJhbFVzZXJzOiBcIlwiLCBjb3VudDogcmVwZWF0cyB9KVxuICAgICAgICAgICAgICAgICAgICA6IF90KFwiJShvbmVVc2VyKXNjaGFuZ2VkIHRoZWlyIG5hbWUgJShjb3VudClzIHRpbWVzXCIsIHsgb25lVXNlcjogXCJcIiwgY291bnQ6IHJlcGVhdHMgfSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIFwiY2hhbmdlZF9hdmF0YXJcIjpcbiAgICAgICAgICAgICAgICByZXMgPSAodXNlckNvdW50ID4gMSlcbiAgICAgICAgICAgICAgICAgICAgPyBfdChcIiUoc2V2ZXJhbFVzZXJzKXNjaGFuZ2VkIHRoZWlyIGF2YXRhciAlKGNvdW50KXMgdGltZXNcIiwgeyBzZXZlcmFsVXNlcnM6IFwiXCIsIGNvdW50OiByZXBlYXRzIH0pXG4gICAgICAgICAgICAgICAgICAgIDogX3QoXCIlKG9uZVVzZXIpc2NoYW5nZWQgdGhlaXIgYXZhdGFyICUo