UNPKG

matrix-react-sdk

Version:
516 lines (502 loc) 73.5 kB
"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 _matrix = require("matrix-js-sdk/src/matrix"); var _types = require("matrix-js-sdk/src/types"); var _languageHandler = require("../../../languageHandler"); var _FormattingUtils = require("../../../utils/FormattingUtils"); var _RoomInvite = require("../../../RoomInvite"); var _GenericEventListSummary = _interopRequireDefault(require("./GenericEventListSummary")); var _RightPanelStorePhases = require("../../../stores/right-panel/RightPanelStorePhases"); var _ReactUtils = require("../../../utils/ReactUtils"); var _Layout = require("../../../settings/enums/Layout"); var _RightPanelStore = _interopRequireDefault(require("../../../stores/right-panel/RightPanelStore")); var _AccessibleButton = _interopRequireDefault(require("./AccessibleButton")); var _RoomContext = _interopRequireDefault(require("../../../contexts/RoomContext")); /* Copyright 2024 New Vector Ltd. Copyright 2019, 2020 The Matrix.org Foundation C.I.C. Copyright 2019 Michael Telatynski <7t3chguy@gmail.com> Copyright 2016 OpenMarket Ltd SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only Please see LICENSE files in the repository root for full details. */ const onPinnedMessagesClick = () => { _RightPanelStore.default.instance.setCard({ phase: _RightPanelStorePhases.RightPanelPhases.PinnedMessages }, false); }; const TARGET_AS_DISPLAY_NAME_EVENTS = [_matrix.EventType.RoomMember]; var TransitionType = /*#__PURE__*/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["ServerAcl"] = "server_acl"; TransitionType["ChangedPins"] = "pinned_messages"; TransitionType["MessageRemoved"] = "message_removed"; TransitionType["HiddenEvent"] = "hidden_event"; return TransitionType; }(TransitionType || {}); const SEP = ","; class EventListSummary extends _react.default.Component { 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 || nextProps.layout !== this.props.layout; } /** * 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, orderedTransitionSequences) { 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 = EventListSummary.getCanonicalTransitions(splitTransitions); // Transform into consecutive repetitions of the same transition (like 5 // consecutive 'joined_and_left's) const coalescedTransitions = EventListSummary.coalesceRepeatedTransitions(canonicalTransitions); const descs = coalescedTransitions.map(t => { return EventListSummary.getDescriptionForTransition(t.transitionType, userNames.length, t.repeats); }); const desc = (0, _FormattingUtils.formatList)(descs); return (0, _languageHandler._t)("timeline|summary|format", { nameList, transitionList: desc }); }); if (!summaries) { return null; } return (0, _ReactUtils.jsxJoin)(summaries, ", "); } /** * @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) { return (0, _FormattingUtils.formatList)(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) { const modMap = { [TransitionType.Joined]: { after: TransitionType.Left, newTransition: TransitionType.JoinedAndLeft }, [TransitionType.Left]: { after: TransitionType.Joined, newTransition: TransitionType.LeftAndJoined } }; const res = []; 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) { const res = []; for (const transition of transitions) { if (res.length > 0 && res[res.length - 1].transitionType === transition) { res[res.length - 1].repeats += 1; } else { res.push({ transitionType: transition, 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, userCount, count) { // 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; switch (t) { case TransitionType.Joined: res = userCount > 1 ? (0, _languageHandler._t)("timeline|summary|joined_multiple", { severalUsers: "", count }) : (0, _languageHandler._t)("timeline|summary|joined", { oneUser: "", count }); break; case TransitionType.Left: res = userCount > 1 ? (0, _languageHandler._t)("timeline|summary|left_multiple", { severalUsers: "", count }) : (0, _languageHandler._t)("timeline|summary|left", { oneUser: "", count }); break; case TransitionType.JoinedAndLeft: res = userCount > 1 ? (0, _languageHandler._t)("timeline|summary|joined_and_left_multiple", { severalUsers: "", count }) : (0, _languageHandler._t)("timeline|summary|joined_and_left", { oneUser: "", count }); break; case TransitionType.LeftAndJoined: res = userCount > 1 ? (0, _languageHandler._t)("timeline|summary|rejoined_multiple", { severalUsers: "", count }) : (0, _languageHandler._t)("timeline|summary|rejoined", { oneUser: "", count }); break; case TransitionType.InviteReject: res = userCount > 1 ? (0, _languageHandler._t)("timeline|summary|rejected_invite_multiple", { severalUsers: "", count }) : (0, _languageHandler._t)("timeline|summary|rejected_invite", { oneUser: "", count }); break; case TransitionType.InviteWithdrawal: res = userCount > 1 ? (0, _languageHandler._t)("timeline|summary|invite_withdrawn_multiple", { severalUsers: "", count }) : (0, _languageHandler._t)("timeline|summary|invite_withdrawn", { oneUser: "", count }); break; case TransitionType.Invited: res = userCount > 1 ? (0, _languageHandler._t)("timeline|summary|invited_multiple", { count }) : (0, _languageHandler._t)("timeline|summary|invited", { count }); break; case TransitionType.Banned: res = userCount > 1 ? (0, _languageHandler._t)("timeline|summary|banned_multiple", { count }) : (0, _languageHandler._t)("timeline|summary|banned", { count }); break; case TransitionType.Unbanned: res = userCount > 1 ? (0, _languageHandler._t)("timeline|summary|unbanned_multiple", { count }) : (0, _languageHandler._t)("timeline|summary|unbanned", { count }); break; case TransitionType.Kicked: res = userCount > 1 ? (0, _languageHandler._t)("timeline|summary|kicked_multiple", { count }) : (0, _languageHandler._t)("timeline|summary|kicked", { count }); break; case TransitionType.ChangedName: res = userCount > 1 ? (0, _languageHandler._t)("timeline|summary|changed_name_multiple", { severalUsers: "", count }) : (0, _languageHandler._t)("timeline|summary|changed_name", { oneUser: "", count }); break; case TransitionType.ChangedAvatar: res = userCount > 1 ? (0, _languageHandler._t)("timeline|summary|changed_avatar_multiple", { severalUsers: "", count }) : (0, _languageHandler._t)("timeline|summary|changed_avatar", { oneUser: "", count }); break; case TransitionType.NoChange: res = userCount > 1 ? (0, _languageHandler._t)("timeline|summary|no_change_multiple", { severalUsers: "", count }) : (0, _languageHandler._t)("timeline|summary|no_change", { oneUser: "", count }); break; case TransitionType.ServerAcl: res = userCount > 1 ? (0, _languageHandler._t)("timeline|summary|server_acls_multiple", { severalUsers: "", count }) : (0, _languageHandler._t)("timeline|summary|server_acls", { oneUser: "", count }); break; case TransitionType.ChangedPins: res = userCount > 1 ? (0, _languageHandler._t)("timeline|summary|pinned_events_multiple", { severalUsers: "", count }, { a: sub => /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, { kind: "link_inline", onClick: onPinnedMessagesClick }, sub) }) : (0, _languageHandler._t)("timeline|summary|pinned_events", { oneUser: "", count }, { a: sub => /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, { kind: "link_inline", onClick: onPinnedMessagesClick }, sub) }); break; case TransitionType.MessageRemoved: res = userCount > 1 ? (0, _languageHandler._t)("timeline|summary|redacted_multiple", { severalUsers: "", count }) : (0, _languageHandler._t)("timeline|summary|redacted", { oneUser: "", count }); break; case TransitionType.HiddenEvent: res = userCount > 1 ? (0, _languageHandler._t)("timeline|summary|hidden_event_multiple", { severalUsers: "", count }) : (0, _languageHandler._t)("timeline|summary|hidden_event", { oneUser: "", count }); break; } return res ?? null; } static getTransitionSequence(events) { return events.map(EventListSummary.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) { if (e.mxEvent.isRedacted()) { return TransitionType.MessageRemoved; } switch (e.mxEvent.getType()) { case _matrix.EventType.RoomThirdPartyInvite: // Handle 3pid invites the same as invites so they get bundled together if (!(0, _RoomInvite.isValid3pidInvite)(e.mxEvent)) { return TransitionType.InviteWithdrawal; } return TransitionType.Invited; case _matrix.EventType.RoomServerAcl: return TransitionType.ServerAcl; case _matrix.EventType.RoomPinnedEvents: return TransitionType.ChangedPins; case _matrix.EventType.RoomMember: switch (e.mxEvent.getContent().membership) { case _types.KnownMembership.Invite: return TransitionType.Invited; case _types.KnownMembership.Ban: return TransitionType.Banned; case _types.KnownMembership.Join: if (e.mxEvent.getPrevContent().membership === _types.KnownMembership.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; } return TransitionType.NoChange; } else { return TransitionType.Joined; } case _types.KnownMembership.Leave: if (e.mxEvent.getSender() === e.mxEvent.getStateKey()) { if (e.mxEvent.getPrevContent().membership === _types.KnownMembership.Invite) { return TransitionType.InviteReject; } return TransitionType.Left; } switch (e.mxEvent.getPrevContent().membership) { case _types.KnownMembership.Invite: return TransitionType.InviteWithdrawal; case _types.KnownMembership.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; } default: // otherwise, assume this is a hidden event return TransitionType.HiddenEvent; } } getAggregate(userEvents) { // 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 = { // $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 = { // $aggregateType : int }; const users = Object.keys(userEvents); users.forEach(userId => { const firstEvent = userEvents[userId][0]; const displayName = firstEvent.displayName; const seq = EventListSummary.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 = {}; eventsToRender.forEach((e, index) => { const type = e.getType(); let userKey = e.getSender(); if (e.isState() && type === _matrix.EventType.RoomThirdPartyInvite) { userKey = e.getContent().display_name; } else if (e.isState() && type === _matrix.EventType.RoomMember) { userKey = e.getStateKey(); } else if (e.isRedacted() && e.getUnsigned()?.redacted_because) { userKey = e.getUnsigned().redacted_because.sender; } // Initialise a user's events if (!userEvents[userKey]) { userEvents[userKey] = []; } let displayName = userKey; if (e.isRedacted()) { const sender = this.context?.room?.getMember(userKey); if (sender) { displayName = sender.name; latestUserAvatarMember.set(userKey, sender); } } else if (e.target && TARGET_AS_DISPLAY_NAME_EVENTS.includes(type)) { displayName = e.target.name; latestUserAvatarMember.set(userKey, e.target); } else if (e.sender && type !== _matrix.EventType.RoomThirdPartyInvite) { displayName = e.sender.name; latestUserAvatarMember.set(userKey, e.sender); } userEvents[userKey].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(_GenericEventListSummary.default, { "data-testid": this.props["data-testid"], events: this.props.events, threshold: this.props.threshold, onToggle: this.props.onToggle, startExpanded: this.props.startExpanded, children: this.props.children, summaryMembers: [...latestUserAvatarMember.values()], layout: this.props.layout, summaryText: this.generateSummary(aggregate.names, orderedTransitionSequences) }); } } exports.default = EventListSummary; (0, _defineProperty2.default)(EventListSummary, "contextType", _RoomContext.default); (0, _defineProperty2.default)(EventListSummary, "defaultProps", { summaryLength: 1, threshold: 3, avatarsMaxLength: 5, layout: _Layout.Layout.Group }); //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfcmVhY3QiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwicmVxdWlyZSIsIl9tYXRyaXgiLCJfdHlwZXMiLCJfbGFuZ3VhZ2VIYW5kbGVyIiwiX0Zvcm1hdHRpbmdVdGlscyIsIl9Sb29tSW52aXRlIiwiX0dlbmVyaWNFdmVudExpc3RTdW1tYXJ5IiwiX1JpZ2h0UGFuZWxTdG9yZVBoYXNlcyIsIl9SZWFjdFV0aWxzIiwiX0xheW91dCIsIl9SaWdodFBhbmVsU3RvcmUiLCJfQWNjZXNzaWJsZUJ1dHRvbiIsIl9Sb29tQ29udGV4dCIsIm9uUGlubmVkTWVzc2FnZXNDbGljayIsIlJpZ2h0UGFuZWxTdG9yZSIsImluc3RhbmNlIiwic2V0Q2FyZCIsInBoYXNlIiwiUmlnaHRQYW5lbFBoYXNlcyIsIlBpbm5lZE1lc3NhZ2VzIiwiVEFSR0VUX0FTX0RJU1BMQVlfTkFNRV9FVkVOVFMiLCJFdmVudFR5cGUiLCJSb29tTWVtYmVyIiwiVHJhbnNpdGlvblR5cGUiLCJTRVAiLCJFdmVudExpc3RTdW1tYXJ5IiwiUmVhY3QiLCJDb21wb25lbnQiLCJzaG91bGRDb21wb25lbnRVcGRhdGUiLCJuZXh0UHJvcHMiLCJldmVudHMiLCJsZW5ndGgiLCJwcm9wcyIsInRocmVzaG9sZCIsImxheW91dCIsImdlbmVyYXRlU3VtbWFyeSIsImV2ZW50QWdncmVnYXRlcyIsIm9yZGVyZWRUcmFuc2l0aW9uU2VxdWVuY2VzIiwic3VtbWFyaWVzIiwibWFwIiwidHJhbnNpdGlvbnMiLCJ1c2VyTmFtZXMiLCJuYW1lTGlzdCIsInJlbmRlck5hbWVMaXN0Iiwic3BsaXRUcmFuc2l0aW9ucyIsInNwbGl0IiwiY2Fub25pY2FsVHJhbnNpdGlvbnMiLCJnZXRDYW5vbmljYWxUcmFuc2l0aW9ucyIsImNvYWxlc2NlZFRyYW5zaXRpb25zIiwiY29hbGVzY2VSZXBlYXRlZFRyYW5zaXRpb25zIiwiZGVzY3MiLCJ0IiwiZ2V0RGVzY3JpcHRpb25Gb3JUcmFuc2l0aW9uIiwidHJhbnNpdGlvblR5cGUiLCJyZXBlYXRzIiwiZGVzYyIsImZvcm1hdExpc3QiLCJfdCIsInRyYW5zaXRpb25MaXN0IiwianN4Sm9pbiIsInVzZXJzIiwic3VtbWFyeUxlbmd0aCIsIm1vZE1hcCIsIkpvaW5lZCIsImFmdGVyIiwiTGVmdCIsIm5ld1RyYW5zaXRpb24iLCJKb2luZWRBbmRMZWZ0IiwiTGVmdEFuZEpvaW5lZCIsInJlcyIsImkiLCJ0MiIsInRyYW5zaXRpb24iLCJwdXNoIiwidXNlckNvdW50IiwiY291bnQiLCJzZXZlcmFsVXNlcnMiLCJvbmVVc2VyIiwiSW52aXRlUmVqZWN0IiwiSW52aXRlV2l0aGRyYXdhbCIsIkludml0ZWQiLCJCYW5uZWQiLCJVbmJhbm5lZCIsIktpY2tlZCIsIkNoYW5nZWROYW1lIiwiQ2hhbmdlZEF2YXRhciIsIk5vQ2hhbmdlIiwiU2VydmVyQWNsIiwiQ2hhbmdlZFBpbnMiLCJhIiwic3ViIiwiZGVmYXVsdCIsImNyZWF0ZUVsZW1lbnQiLCJraW5kIiwib25DbGljayIsIk1lc3NhZ2VSZW1vdmVkIiwiSGlkZGVuRXZlbnQiLCJnZXRUcmFuc2l0aW9uU2VxdWVuY2UiLCJnZXRUcmFuc2l0aW9uIiwiZSIsIm14RXZlbnQiLCJpc1JlZGFjdGVkIiwiZ2V0VHlwZSIsIlJvb21UaGlyZFBhcnR5SW52aXRlIiwiaXNWYWxpZDNwaWRJbnZpdGUiLCJSb29tU2VydmVyQWNsIiwiUm9vbVBpbm5lZEV2ZW50cyIsImdldENvbnRlbnQiLCJtZW1iZXJzaGlwIiwiS25vd25NZW1iZXJzaGlwIiwiSW52aXRlIiwiQmFuIiwiSm9pbiIsImdldFByZXZDb250ZW50IiwiZGlzcGxheW5hbWUiLCJhdmF0YXJfdXJsIiwiTGVhdmUiLCJnZXRTZW5kZXIiLCJnZXRTdGF0ZUtleSIsImdldEFnZ3JlZ2F0ZSIsInVzZXJFdmVudHMiLCJhZ2dyZWdhdGUiLCJhZ2dyZWdhdGVJbmRpY2VzIiwiT2JqZWN0Iiwia2V5cyIsImZvckVhY2giLCJ1c2VySWQiLCJmaXJzdEV2ZW50IiwiZGlzcGxheU5hbWUiLCJzZXEiLCJqb2luIiwiaW5kZXgiLCJuYW1lcyIsImluZGljZXMiLCJyZW5kZXIiLCJldmVudHNUb1JlbmRlciIsImxhdGVzdFVzZXJBdmF0YXJNZW1iZXIiLCJNYXAiLCJ0eXBlIiwidXNlcktleSIsImlzU3RhdGUiLCJkaXNwbGF5X25hbWUiLCJnZXRVbnNpZ25lZCIsInJlZGFjdGVkX2JlY2F1c2UiLCJzZW5kZXIiLCJjb250ZXh0Iiwicm9vbSIsImdldE1lbWJlciIsIm5hbWUiLCJzZXQiLCJ0YXJnZXQiLCJpbmNsdWRlcyIsInNvcnQiLCJzZXExIiwic2VxMiIsIm9uVG9nZ2xlIiwic3RhcnRFeHBhbmRlZCIsImNoaWxkcmVuIiwic3VtbWFyeU1lbWJlcnMiLCJ2YWx1ZXMiLCJzdW1tYXJ5VGV4dCIsImV4cG9ydHMiLCJfZGVmaW5lUHJvcGVydHkyIiwiUm9vbUNvbnRleHQiLCJhdmF0YXJzTWF4TGVuZ3RoIiwiTGF5b3V0IiwiR3JvdXAiXSwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvY29tcG9uZW50cy92aWV3cy9lbGVtZW50cy9FdmVudExpc3RTdW1tYXJ5LnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuQ29weXJpZ2h0IDIwMjQgTmV3IFZlY3RvciBMdGQuXG5Db3B5cmlnaHQgMjAxOSwgMjAyMCBUaGUgTWF0cml4Lm9yZyBGb3VuZGF0aW9uIEMuSS5DLlxuQ29weXJpZ2h0IDIwMTkgTWljaGFlbCBUZWxhdHluc2tpIDw3dDNjaGd1eUBnbWFpbC5jb20+XG5Db3B5cmlnaHQgMjAxNiBPcGVuTWFya2V0IEx0ZFxuXG5TUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQUdQTC0zLjAtb25seSBPUiBHUEwtMy4wLW9ubHlcblBsZWFzZSBzZWUgTElDRU5TRSBmaWxlcyBpbiB0aGUgcmVwb3NpdG9yeSByb290IGZvciBmdWxsIGRldGFpbHMuXG4qL1xuXG5pbXBvcnQgUmVhY3QsIHsgQ29tcG9uZW50UHJvcHMsIFJlYWN0Tm9kZSB9IGZyb20gXCJyZWFjdFwiO1xuaW1wb3J0IHsgTWF0cml4RXZlbnQsIFJvb21NZW1iZXIsIEV2ZW50VHlwZSB9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9tYXRyaXhcIjtcbmltcG9ydCB7IEtub3duTWVtYmVyc2hpcCB9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy90eXBlc1wiO1xuXG5pbXBvcnQgeyBfdCB9IGZyb20gXCIuLi8uLi8uLi9sYW5ndWFnZUhhbmRsZXJcIjtcbmltcG9ydCB7IGZvcm1hdExpc3QgfSBmcm9tIFwiLi4vLi4vLi4vdXRpbHMvRm9ybWF0dGluZ1V0aWxzXCI7XG5pbXBvcnQgeyBpc1ZhbGlkM3BpZEludml0ZSB9IGZyb20gXCIuLi8uLi8uLi9Sb29tSW52aXRlXCI7XG5pbXBvcnQgR2VuZXJpY0V2ZW50TGlzdFN1bW1hcnkgZnJvbSBcIi4vR2VuZXJpY0V2ZW50TGlzdFN1bW1hcnlcIjtcbmltcG9ydCB7IFJpZ2h0UGFuZWxQaGFzZXMgfSBmcm9tIFwiLi4vLi4vLi4vc3RvcmVzL3JpZ2h0LXBhbmVsL1JpZ2h0UGFuZWxTdG9yZVBoYXNlc1wiO1xuaW1wb3J0IHsganN4Sm9pbiB9IGZyb20gXCIuLi8uLi8uLi91dGlscy9SZWFjdFV0aWxzXCI7XG5pbXBvcnQgeyBMYXlvdXQgfSBmcm9tIFwiLi4vLi4vLi4vc2V0dGluZ3MvZW51bXMvTGF5b3V0XCI7XG5pbXBvcnQgUmlnaHRQYW5lbFN0b3JlIGZyb20gXCIuLi8uLi8uLi9zdG9yZXMvcmlnaHQtcGFuZWwvUmlnaHRQYW5lbFN0b3JlXCI7XG5pbXBvcnQgQWNjZXNzaWJsZUJ1dHRvbiBmcm9tIFwiLi9BY2Nlc3NpYmxlQnV0dG9uXCI7XG5pbXBvcnQgUm9vbUNvbnRleHQgZnJvbSBcIi4uLy4uLy4uL2NvbnRleHRzL1Jvb21Db250ZXh0XCI7XG5cbmNvbnN0IG9uUGlubmVkTWVzc2FnZXNDbGljayA9ICgpOiB2b2lkID0+IHtcbiAgICBSaWdodFBhbmVsU3RvcmUuaW5zdGFuY2Uuc2V0Q2FyZCh7IHBoYXNlOiBSaWdodFBhbmVsUGhhc2VzLlBpbm5lZE1lc3NhZ2VzIH0sIGZhbHNlKTtcbn07XG5cbmNvbnN0IFRBUkdFVF9BU19ESVNQTEFZX05BTUVfRVZFTlRTID0gW0V2ZW50VHlwZS5Sb29tTWVtYmVyXTtcblxuaW50ZXJmYWNlIElQcm9wcyBleHRlbmRzIE9taXQ8Q29tcG9uZW50UHJvcHM8dHlwZW9mIEdlbmVyaWNFdmVudExpc3RTdW1tYXJ5PiwgXCJzdW1tYXJ5VGV4dFwiIHwgXCJzdW1tYXJ5TWVtYmVyc1wiPiB7XG4gICAgLy8gVGhlIG1heGltdW0gbnVtYmVyIG9mIG5hbWVzIHRvIHNob3cgaW4gZWl0aGVyIGVhY2ggc3VtbWFyeSBlLmcuIDIgd291bGQgcmVzdWx0IFwiQSwgQiBhbmQgMjM0IG90aGVycyBsZWZ0XCJcbiAgICBzdW1tYXJ5TGVuZ3RoPzogbnVtYmVyO1xuICAgIC8vIFRoZSBtYXhpbXVtIG51bWJlciBvZiBhdmF0YXJzIHRvIGRpc3BsYXkgaW4gdGhlIHN1bW1hcnlcbiAgICBhdmF0YXJzTWF4TGVuZ3RoPzogbnVtYmVyO1xuICAgIC8vIFRoZSBjdXJyZW50bHkgc2VsZWN0ZWQgbGF5b3V0XG4gICAgbGF5b3V0OiBMYXlvdXQ7XG59XG5cbmludGVyZmFjZSBJVXNlckV2ZW50cyB7XG4gICAgLy8gVGhlIG9yaWdpbmFsIGV2ZW50XG4gICAgbXhFdmVudDogTWF0cml4RXZlbnQ7XG4gICAgLy8gVGhlIGRpc3BsYXkgbmFtZSBvZiB0aGUgdXNlciAoaWYgbm90LCB0aGVuIHVzZXIgSUQpXG4gICAgZGlzcGxheU5hbWU6IHN0cmluZztcbiAgICAvLyBUaGUgb3JpZ2luYWwgaW5kZXggb2YgdGhlIGV2ZW50IGluIHRoaXMucHJvcHMuZXZlbnRzXG4gICAgaW5kZXg6IG51bWJlcjtcbn1cblxuZW51bSBUcmFuc2l0aW9uVHlwZSB7XG4gICAgSm9pbmVkID0gXCJqb2luZWRcIixcbiAgICBMZWZ0ID0gXCJsZWZ0XCIsXG4gICAgSm9pbmVkQW5kTGVmdCA9IFwiam9pbmVkX2FuZF9sZWZ0XCIsXG4gICAgTGVmdEFuZEpvaW5lZCA9IFwibGVmdF9hbmRfam9pbmVkXCIsXG4gICAgSW52aXRlUmVqZWN0ID0gXCJpbnZpdGVfcmVqZWN0XCIsXG4gICAgSW52aXRlV2l0aGRyYXdhbCA9IFwiaW52aXRlX3dpdGhkcmF3YWxcIixcbiAgICBJbnZpdGVkID0gXCJpbnZpdGVkXCIsXG4gICAgQmFubmVkID0gXCJiYW5uZWRcIixcbiAgICBVbmJhbm5lZCA9IFwidW5iYW5uZWRcIixcbiAgICBLaWNrZWQgPSBcImtpY2tlZFwiLFxuICAgIENoYW5nZWROYW1lID0gXCJjaGFuZ2VkX25hbWVcIixcbiAgICBDaGFuZ2VkQXZhdGFyID0gXCJjaGFuZ2VkX2F2YXRhclwiLFxuICAgIE5vQ2hhbmdlID0gXCJub19jaGFuZ2VcIixcbiAgICBTZXJ2ZXJBY2wgPSBcInNlcnZlcl9hY2xcIixcbiAgICBDaGFuZ2VkUGlucyA9IFwicGlubmVkX21lc3NhZ2VzXCIsXG4gICAgTWVzc2FnZVJlbW92ZWQgPSBcIm1lc3NhZ2VfcmVtb3ZlZFwiLFxuICAgIEhpZGRlbkV2ZW50ID0gXCJoaWRkZW5fZXZlbnRcIixcbn1cblxuY29uc3QgU0VQID0gXCIsXCI7XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIEV2ZW50TGlzdFN1bW1hcnkgZXh0ZW5kcyBSZWFjdC5Db21wb25lbnQ8XG4gICAgSVByb3BzICYgUmVxdWlyZWQ8UGljazxJUHJvcHMsIFwic3VtbWFyeUxlbmd0aFwiIHwgXCJ0aHJlc2hvbGRcIiB8IFwiYXZhdGFyc01heExlbmd0aFwiIHwgXCJsYXlvdXRcIj4+XG4+IHtcbiAgICBwdWJsaWMgc3RhdGljIGNvbnRleHRUeXBlID0gUm9vbUNvbnRleHQ7XG4gICAgcHVibGljIGRlY2xhcmUgY29udGV4dDogUmVhY3QuQ29udGV4dFR5cGU8dHlwZW9mIFJvb21Db250ZXh0PjtcblxuICAgIHB1YmxpYyBzdGF0aWMgZGVmYXVsdFByb3BzID0ge1xuICAgICAgICBzdW1tYXJ5TGVuZ3RoOiAxLFxuICAgICAgICB0aHJlc2hvbGQ6IDMsXG4gICAgICAgIGF2YXRhcnNNYXhMZW5ndGg6IDUsXG4gICAgICAgIGxheW91dDogTGF5b3V0Lkdyb3VwLFxuICAgIH07XG5cbiAgICBwdWJsaWMgc2hvdWxkQ29tcG9uZW50VXBkYXRlKG5leHRQcm9wczogSVByb3BzKTogYm9vbGVhbiB7XG4gICAgICAgIC8vIFVwZGF0ZSBpZlxuICAgICAgICAvLyAgLSBUaGUgbnVtYmVyIG9mIHN1bW1hcmlzZWQgZXZlbnRzIGhhcyBjaGFuZ2VkXG4gICAgICAgIC8vICAtIG9yIGlmIHRoZSBzdW1tYXJ5IGlzIGFib3V0IHRvIHRvZ2dsZSB0byBiZWNvbWUgY29sbGFwc2VkXG4gICAgICAgIC8vICAtIG9yIGlmIHRoZXJlIGFyZSBmZXdFdmVudHMsIG1lYW5pbmcgdGhlIGNoaWxkIGV2ZW50VGlsZXMgYXJlIHNob3duIGFzLWlzXG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICBuZXh0UHJvcHMuZXZlbnRzLmxlbmd0aCAhPT0gdGhpcy5wcm9wcy5ldmVudHMubGVuZ3RoIHx8XG4gICAgICAgICAgICBuZXh0UHJvcHMuZXZlbnRzLmxlbmd0aCA8IHRoaXMucHJvcHMudGhyZXNob2xkIHx8XG4gICAgICAgICAgICBuZXh0UHJvcHMubGF5b3V0ICE9PSB0aGlzLnByb3BzLmxheW91dFxuICAgICAgICApO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdlbmVyYXRlIHRoZSB0ZXh0IGZvciB1c2VycyBhZ2dyZWdhdGVkIGJ5IHRoZWlyIHRyYW5zaXRpb24gc2VxdWVuY2VzIChgZXZlbnRBZ2dyZWdhdGVzYCkgd2hlcmVcbiAgICAgKiB0aGUgc2VxdWVuY2VzIGFyZSBvcmRlcmVkIGJ5IGBvcmRlcmVkVHJhbnNpdGlvblNlcXVlbmNlc2AuXG4gICAgICogQHBhcmFtIHtvYmplY3R9IGV2ZW50QWdncmVnYXRlcyBhIG1hcCBvZiB0cmFuc2l0aW9uIHNlcXVlbmNlIHRvIGFycmF5IG9mIHVzZXIgZGlzcGxheSBuYW1lc1xuICAgICAqIG9yIHVzZXIgSURzLlxuICAgICAqIEBwYXJhbSB7c3RyaW5nW119IG9yZGVyZWRUcmFuc2l0aW9uU2VxdWVuY2VzIGFuIGFycmF5IHdoaWNoIGlzIHNvbWUgb3JkZXJpbmcgb2ZcbiAgICAgKiBgT2JqZWN0LmtleXMoZXZlbnRBZ2dyZWdhdGVzKWAuXG4gICAgICogQHJldHVybnMge3N0cmluZ30gdGhlIHRleHR1YWwgc3VtbWFyeSBvZiB0aGUgYWdncmVnYXRlZCBldmVudHMgdGhhdCBvY2N1cnJlZC5cbiAgICAgKi9cbiAgICBwcml2YXRlIGdlbmVyYXRlU3VtbWFyeShcbiAgICAgICAgZXZlbnRBZ2dyZWdhdGVzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmdbXT4sXG4gICAgICAgIG9yZGVyZWRUcmFuc2l0aW9uU2VxdWVuY2VzOiBzdHJpbmdbXSxcbiAgICApOiBSZWFjdE5vZGUge1xuICAgICAgICBjb25zdCBzdW1tYXJpZXMgPSBvcmRlcmVkVHJhbnNpdGlvblNlcXVlbmNlcy5tYXAoKHRyYW5zaXRpb25zKSA9PiB7XG4gICAgICAgICAgICBjb25zdCB1c2VyTmFtZXMgPSBldmVudEFnZ3JlZ2F0ZXNbdHJhbnNpdGlvbnNdO1xuICAgICAgICAgICAgY29uc3QgbmFtZUxpc3QgPSB0aGlzLnJlbmRlck5hbWVMaXN0KHVzZXJOYW1lcyk7XG5cbiAgICAgICAgICAgIGNvbnN0IHNwbGl0VHJhbnNpdGlvbnMgPSB0cmFuc2l0aW9ucy5zcGxpdChTRVApIGFzIFRyYW5zaXRpb25UeXBlW107XG5cbiAgICAgICAgICAgIC8vIFNvbWUgbmVpZ2hib3VyaW5nIHRyYW5zaXRpb25zIGFyZSBjb21tb24sIHNvIGNhbm9uaWNhbGlzZSBzb21lIGludG8gXCJwYWlyXCJcbiAgICAgICAgICAgIC8vIHRyYW5zaXRpb25zXG4gICAgICAgICAgICBjb25zdCBjYW5vbmljYWxUcmFuc2l0aW9ucyA9IEV2ZW50TGlzdFN1bW1hcnkuZ2V0Q2Fub25pY2FsVHJhbnNpdGlvbnMoc3BsaXRUcmFuc2l0aW9ucyk7XG4gICAgICAgICAgICAvLyBUcmFuc2Zvcm0gaW50byBjb25zZWN1dGl2ZSByZXBldGl0aW9ucyBvZiB0aGUgc2FtZSB0cmFuc2l0aW9uIChsaWtlIDVcbiAgICAgICAgICAgIC8vIGNvbnNlY3V0aXZlICdqb2luZWRfYW5kX2xlZnQncylcbiAgICAgICAgICAgIGNvbnN0IGNvYWxlc2NlZFRyYW5zaXRpb25zID0gRXZlbnRMaXN0U3VtbWFyeS5jb2FsZXNjZVJlcGVhdGVkVHJhbnNpdGlvbnMoY2Fub25pY2FsVHJhbnNpdGlvbnMpO1xuXG4gICAgICAgICAgICBjb25zdCBkZXNjcyA9IGNvYWxlc2NlZFRyYW5zaXRpb25zLm1hcCgodCkgPT4ge1xuICAgICAgICAgICAgICAgIHJldHVybiBFdmVudExpc3RTdW1tYXJ5LmdldERlc2NyaXB0aW9uRm9yVHJhbnNpdGlvbih0LnRyYW5zaXRpb25UeXBlLCB1c2VyTmFtZXMubGVuZ3RoLCB0LnJlcGVhdHMpO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIGNvbnN0IGRlc2MgPSBmb3JtYXRMaXN0KGRlc2NzKTtcblxuICAgICAgICAgICAgcmV0dXJuIF90KFwidGltZWxpbmV8c3VtbWFyeXxmb3JtYXRcIiwgeyBuYW1lTGlzdCwgdHJhbnNpdGlvbkxpc3Q6IGRlc2MgfSk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmICghc3VtbWFyaWVzKSB7XG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBqc3hKb2luKHN1bW1hcmllcywgXCIsIFwiKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBAcGFyYW0ge3N0cmluZ1tdfSB1c2VycyBhbiBhcnJheSBvZiB1c2VyIGRpc3BsYXkgbmFtZXMgb3IgdXNlciBJRHMuXG4gICAgICogQHJldHVybnMge3N0cmluZ30gYSBjb21tYS1zZXBhcmF0ZWQgbGlzdCB0aGF0IGVuZHMgd2l0aCBcImFuZCBbbl0gb3RoZXJzXCIgaWYgdGhlcmUgYXJlXG4gICAgICogbW9yZSBpdGVtcyBpbiBgdXNlcnNgIHRoYW4gYHRoaXMucHJvcHMuc3VtbWFyeUxlbmd0aGAsIHdoaWNoIGlzIHRoZSBudW1iZXIgb2YgbmFtZXNcbiAgICAgKiBpbmNsdWRlZCBiZWZvcmUgXCJhbmQgW25dIG90aGVyc1wiLlxuICAgICAqL1xuICAgIHByaXZhdGUgcmVuZGVyTmFtZUxpc3QodXNlcnM6IHN0cmluZ1tdKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIGZvcm1hdExpc3QodXNlcnMsIHRoaXMucHJvcHMuc3VtbWFyeUxlbmd0aCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ2Fub25pY2FsaXNlIGFuIGFycmF5IG9mIHRyYW5zaXRpb25zIHN1Y2ggdGhhdCBzb21lIHBhaXJzIG9mIHRyYW5zaXRpb25zIGJlY29tZVxuICAgICAqIHNpbmdsZSB0cmFuc2l0aW9ucy4gRm9yIGV4YW1wbGUgYW4gaW5wdXQgWydqb2luZWQnLCdsZWZ0J10gd291bGQgcmVzdWx0IGluIGFuIG91dHB1dFxuICAgICAqIFsnam9pbmVkX2FuZF9sZWZ0J10uXG4gICAgICogQHBhcmFtIHtzdHJpbmdbXX0gdHJhbnNpdGlvbnMgYW4gYXJyYXkgb2YgdHJhbnNpdGlvbnMuXG4gICAgICogQHJldHVybnMge3N0cmluZ1tdfSBhbiBhcnJheSBvZiB0cmFuc2l0aW9ucy5cbiAgICAgKi9cbiAgICBwcml2YXRlIHN0YXRpYyBnZXRDYW5vbmljYWxUcmFuc2l0aW9ucyh0cmFuc2l0aW9uczogVHJhbnNpdGlvblR5cGVbXSk6IFRyYW5zaXRpb25UeXBlW10ge1xuICAgICAgICBjb25zdCBtb2RNYXA6IFBhcnRpYWw8XG4gICAgICAgICAgICBSZWNvcmQ8XG4gICAgICAgICAgICAgICAgVHJhbnNpdGlvblR5cGUsXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBhZnRlcjogVHJhbnNpdGlvblR5cGU7XG4gICAgICAgICAgICAgICAgICAgIG5ld1RyYW5zaXRpb246IFRyYW5zaXRpb25UeXBlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgID5cbiAgICAgICAgPiA9IHtcbiAgICAgICAgICAgIFtUcmFuc2l0aW9uVHlwZS5Kb2luZWRdOiB7XG4gICAgICAgICAgICAgICAgYWZ0ZXI6IFRyYW5zaXRpb25UeXBlLkxlZnQsXG4gICAgICAgICAgICAgICAgbmV3VHJhbnNpdGlvbjogVHJhbnNpdGlvblR5cGUuSm9pbmVkQW5kTGVmdCxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBbVHJhbnNpdGlvblR5cGUuTGVmdF06IHtcbiAgICAgICAgICAgICAgICBhZnRlcjogVHJhbnNpdGlvblR5cGUuSm9pbmVkLFxuICAgICAgICAgICAgICAgIG5ld1RyYW5zaXRpb246IFRyYW5zaXRpb25UeXBlLkxlZnRBbmRKb2luZWQsXG4gICAgICAgICAgICB9LFxuICAgICAgICB9O1xuICAgICAgICBjb25zdCByZXM6IFRyYW5zaXRpb25UeXBlW10gPSBbXTtcblxuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRyYW5zaXRpb25zLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBjb25zdCB0ID0gdHJhbnNpdGlvbnNbaV07XG4gICAgICAgICAgICBjb25zdCB0MiA9IHRyYW5zaXRpb25zW2kgKyAxXTtcblxuICAgICAgICAgICAgbGV0IHRyYW5zaXRpb24gPSB0O1xuXG4gICAgICAgICAgICBpZiAoaSA8IHRyYW5zaXRpb25zLmxlbmd0aCAtIDEgJiYgbW9kTWFwW3RdICYmIG1vZE1hcFt0XSEuYWZ0ZXIgPT09IHQyKSB7XG4gICAgICAgICAgICAgICAgdHJhbnNpdGlvbiA9IG1vZE1hcFt0XSEubmV3VHJhbnNpdGlvbjtcbiAgICAgICAgICAgICAgICBpKys7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJlcy5wdXNoKHRyYW5zaXRpb24pO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVHJhbnNmb3JtIGFuIGFycmF5IG9mIHRyYW5zaXRpb25zIGludG8gYW4gYXJyYXkgb2YgdHJhbnNpdGlvbnMgYW5kIGhvdyBtYW55IHRpbWVzXG4gICAgICogdGhleSBhcmUgcmVwZWF0ZWQgY29uc2VjdXRpdmVseS5cbiAgICAgKlxuICAgICAqIEFuIGFycmF5IG9mIDEyMyBcImpvaW5lZF9hbmRfbGVmdFwiIHRyYW5zaXRpb25zLCB3b3VsZCByZXN1bHQgaW46XG4gICAgICogYGBgXG4gICAgICogW3tcbiAgICAgKiAgIHRyYW5zaXRpb25UeXBlOiBcImpvaW5lZF9hbmRfbGVmdFwiXG4gICAgICogICByZXBlYXRzOiAxMjNcbiAgICAgKiB9XVxuICAgICAqIGBgYFxuICAgICAqIEBwYXJhbSB7c3RyaW5nW119IHRyYW5zaXRpb25zIHRoZSBhcnJheSBvZiB0cmFuc2l0aW9ucyB0byB0cmFuc2Zvcm0uXG4gICAgICogQHJldHVybnMge29iamVjdFtdfSBhbiBhcnJheSBvZiBjb2FsZXNjZWQgdHJhbnNpdGlvbnMuXG4gICAgICovXG4gICAgcHJpdmF0ZSBzdGF0aWMgY29hbGVzY2VSZXBlYXRlZFRyYW5zaXRpb25zKHRyYW5zaXRpb25zOiBUcmFuc2l0aW9uVHlwZVtdKToge1xuICAgICAgICB0cmFuc2l0aW9uVHlwZTogVHJhbnNpdGlvblR5cGU7XG4gICAgICAgIHJlcGVhdHM6IG51bWJlcjtcbiAgICB9W10ge1xuICAgICAgICBjb25zdCByZXM6IHtcbiAgICAgICAgICAgIHRyYW5zaXRpb25UeXBlOiBUcmFuc2l0aW9uVHlwZTtcbiAgICAgICAgICAgIHJlcGVhdHM6IG51bWJlcjtcbiAgICAgICAgfVtdID0gW107XG5cbiAgICAgICAgZm9yIChjb25zdCB0cmFuc2l0aW9uIG9mIHRyYW5zaXRpb25zKSB7XG4gICAgICAgICAgICBpZiAocmVzLmxlbmd0aCA+IDAgJiYgcmVzW3Jlcy5sZW5ndGggLSAxXS50cmFuc2l0aW9uVHlwZSA9PT0gdHJhbnNpdGlvbikge1xuICAgICAgICAgICAgICAgIHJlc1tyZXMubGVuZ3RoIC0gMV0ucmVwZWF0cyArPSAxO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXMucHVzaCh7XG4gICAgICAgICAgICAgICAgICAgIHRyYW5zaXRpb25UeXBlOiB0cmFuc2l0aW9uLFxuICAgICAgICAgICAgICAgICAgICByZXBlYXRzOiAxLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRm9yIGEgY2VydGFpbiB0cmFuc2l0aW9uLCB0LCBkZXNjcmliZSB3aGF0IGhhcHBlbmVkIHRvIHRoZSB1c2VycyB0aGF0XG4gICAgICogdW5kZXJ3ZW50IHRoZSB0cmFuc2l0aW9uLlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSB0IHRoZSB0cmFuc2l0aW9uIHR5cGUuXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IHVzZXJDb3VudCBudW1iZXIgb2YgdXNlcm5hbWVzXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IHJlcGVhdHMgdGhlIG51bWJlciBvZiB0aW1lcyB0aGUgdHJhbnNpdGlvbiB3YXMgcmVwZWF0ZWQgaW4gYSByb3cuXG4gICAgICogQHJldHVybnMge3N0cmluZ30gdGhlIHdyaXR0ZW4gSHVtYW4gUmVhZGFibGUgZXF1aXZhbGVudCBvZiB0aGUgdHJhbnNpdGlvbi5cbiAgICAgKi9cbiAgICBwcml2YXRlIHN0YXRpYyBnZXREZXNjcmlwdGlvbkZvclRyYW5zaXRpb24odDogVHJhbnNpdGlvblR5cGUsIHVzZXJDb3VudDogbnVtYmVyLCBjb3VudDogbnVtYmVyKTogUmVhY3ROb2RlIHwgbnVsbCB7XG4gICAgICAgIC8vIFRoZSBlbXB0eSBpbnRlcnBvbGF0aW9ucyAnc2V2ZXJhbFVzZXJzJyBhbmQgJ29uZVVzZXInXG4gICAgICAgIC8vIGFyZSB0aGVyZSBvbmx5IHRvIHNob3cgdHJhbnNsYXRvcnMgdG8gbm9uLUVuZ2xpc2ggbGFuZ3VhZ2VzXG4gICAgICAgIC8vIHRoYXQgdGhlIHZlcmIgaXMgY29uanVnYXRlZCB0byBwbHVyYWwgb3Igc2luZ3VsYXIgU3ViamVjdC5cbiAgICAgICAgbGV0IHJlczogUmVhY3ROb2RlIHwgdW5kZWZpbmVkO1xuICAgICAgICBzd2l0Y2ggKHQpIHtcbiAgICAgICAgICAgIGNhc2UgVHJhbnNpdGlvblR5cGUuSm9pbmVkOlxuICAgICAgICAgICAgICAgIHJlcyA9XG4gICAgICAgICAgICAgICAgICAgIHVzZXJDb3VudCA+IDFcbiAgICAgICAgICAgICAgICAgICAgICAgID8gX3QoXCJ0aW1lbGluZXxzdW1tYXJ5fGpvaW5lZF9tdWx0aXBsZVwiLCB7IHNldmVyYWxVc2VyczogXCJcIiwgY291bnQgfSlcbiAgICAgICAgICAgICAgICAgICAgICAgIDogX3QoXCJ0aW1lbGluZXxzdW1tYXJ5fGpvaW5lZFwiLCB7IG9uZVVzZXI6IFwiXCIsIGNvdW50IH0pO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBUcmFuc2l0aW9uVHlwZS5MZWZ0OlxuICAgICAgICAgICAgICAgIHJlcyA9XG4gICAgICAgICAgICAgICAgICAgIHVzZXJDb3VudCA+IDFcbiAgICAgICAgICAgICAgICAgICAgICAgID8gX3QoXCJ0aW1lbGluZXxzdW1tYXJ5fGxlZnRfbXVsdGlwbGVcIiwgeyBzZXZlcmFsVXNlcnM6IFwiXCIsIGNvdW50IH0pXG4gICAgICAgICAgICAgICAgICAgICAgICA6IF90KFwidGltZWxpbmV8c3VtbWFyeXxsZWZ0XCIsIHsgb25lVXNlcjogXCJcIiwgY291bnQgfSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIFRyYW5zaXRpb25UeXBlLkpvaW5lZEFuZExlZnQ6XG4gICAgICAgICAgICAgICAgcmVzID1cbiAgICAgICAgICAgICAgICAgICAgdXNlckNvdW50ID4gMVxuICAgICAgICAgICAgICAgICAgICAgICAgPyBfdChcInRpbWVsaW5lfHN1bW1hcnl8am9pbmVkX2FuZF9sZWZ0X211bHRpcGxlXCIsIHsgc2V2ZXJhbFVzZXJzOiBcIlwiLCBjb3VudCB9KVxuICAgICAgICAgICAgICAgICAgICAgICAgOiBfdChcInRpbWVsaW5lfHN1bW1hcnl8am9pbmVkX2FuZF9sZWZ0XCIsIHsgb25lVXNlcjogXCJcIiwgY291bnQgfSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIFRyYW5zaXRpb25UeXBlLkxlZnRBbmRKb2luZWQ6XG4gICAgICAgICAgICAgICAgcmVzID1cbiAgICAgICAgICAgICAgICAgICAgdXNlckNvdW50ID4gMVxuICAgICAgICAgICAgICAgICAgICAgICAgPyBfdChcInRpbWVsaW5lfHN1bW1hcnl8cmVqb2luZWRfbXVsdGlwbGVcIiwgeyBzZXZlcmFsVXNlcnM6IFwiXCIsIGNvdW50IH0pXG4gICAgICAgICAgICAgICAgICAgICAgICA6IF90KFwidGltZWxpbmV8c3VtbWFyeXxyZWpvaW5lZFwiLCB7IG9uZVVzZXI6IFwiXCIsIGNvdW50IH0pO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBUcmFuc2l0aW9uVHlwZS5JbnZpdGVSZWplY3Q6XG4gICAgICAgICAgICAgICAgcmVzID1cbiAgICAgICAgICAgICAgICAgICAgdXNlckNvdW50ID4gMVxuICAgICAgICAgICAgICAgICAgICAgICAgPyBfdChcInRpbWVsaW5lfHN1bW1hcnl8cmVqZWN0ZWRfaW52aXRlX211bHRpcGxlXCIsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNldmVyYWxVc2VyczogXCJcIixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvdW50LFxuICAgICAgICAgICAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgICAgICAgICAgOiBfdChcInRpbWVsaW5lfHN1bW1hcnl8cmVqZWN0ZWRfaW52aXRlXCIsIHsgb25lVXNlcjogXCJcIiwgY291bnQgfSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIFRyYW5zaXRpb25UeXBlLkludml0ZVdpdGhkcmF3YWw6XG4gICAgICAgICAgICAgICAgcmVzID1cbiAgICAgICAgICAgICAgICAgICAgdXNlckNvdW50ID4gMVxuICAgICAgICAgICAgICAgICAgICAgICAgPyBfdChcInRpbWVsaW5lfHN1bW1hcnl8aW52aXRlX3dpdGhkcmF3bl9tdWx0aXBsZVwiLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXZlcmFsVXNlcnM6IFwiXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3VudCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAgICAgICAgIDogX3QoXCJ0aW1lbGluZXxzdW1tYXJ5fGludml0ZV93aXRoZHJhd25cIiwgeyBvbmVVc2VyOiBcIlwiLCBjb3VudCB9KTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgVHJhbnNpdGlvblR5cGUuSW52aXRlZDpcbiAgICAgICAgICAgICAgICByZXMgPVxuICAgICAgICAgICAgICAgICAgICB1c2VyQ291bnQgPiAxXG4gICAgICAgICAgICAgICAgICAgICAgICA/IF90KFwidGltZWxpbmV8c3VtbWFyeXxpbnZpdGVkX211bHRpcGxlXCIsIHsgY291bnQgfSlcbiAgICAgICAgICAgICAgICAgICAgICAgIDogX3QoXCJ0aW1lbGluZXxzdW1tYXJ5fGludml0ZWRcIiwgeyBjb3VudCB9KTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgVHJhbnNpdGlvblR5cGUuQmFubmVkOlxuICAgICAgICAgICAgICAgIHJlcyA9XG4gICAgICAgICAgICAgICAgICAgIHVzZXJDb3VudCA+IDFcbiAgICAgICAgICAgICAgICAgICAgICAgID8gX3QoXCJ0aW1lbGluZXxzdW1tYXJ5fGJhbm5lZF9tdWx0aXBsZVwiLCB7IGNvdW50IH0pXG4gICAgICAgICAgICAgICAgICAgICAgICA6IF90KFwidGltZWxpbmV8c3VtbWFyeXxiYW5uZWRcIiwgeyBjb3VudCB9KTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgVHJhbnNpdGlvblR5cGUuVW5iYW5uZWQ6XG4gICAgICAgICAgICAgICAgcmVzID1cbiAgICAgICAgICAgICAgICAgICAgdXNlckNvdW50ID4gMVxuICAgICAgICAgICAgICAgICAgICAgICAgPyBfdChcInRpbWVsaW5lfHN1bW1hcnl8dW5iYW5uZWRfbXVsdGlwbGVcIiwgeyBjb3VudCB9KVxuICAgICAgICAgICAgICAgICAgICAgICAgOiBfdChcInRpbWVsaW5lfHN1bW1hcnl8dW5iYW5uZWRcIiwgeyBjb3VudCB9KTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgVHJhbnNpdGlvblR5cGUuS2lja2VkOlxuICAgICAgICAgICAgICAgIHJlcyA9XG4gICAgICAgICAgICAgICAgICAgIHVzZXJDb3VudCA+IDFcbiAgICAgICAgICAgICAgICAgICAgICAgID8gX3QoXCJ0aW1lbGluZXxzdW1tYXJ5fGtpY2tlZF9tdWx0aXBsZVwiLCB7IGNvdW50IH0pXG4gICAgICAgICAgICAgICAgICAgICAgICA6IF90KFwidGltZWxpbmV8c3VtbWFyeXxraWNrZWRcIiwgeyBjb3VudCB9KTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgVHJhbnNpdGlvblR5cGUuQ2hhbmdlZE5hbWU6XG4gICAgICAgICAgICAgICAgcmVzID1cbiAgICAgICAgICAgICAgICAgICAgdXNlckNvdW50ID4gMVxuICAgICAgICAgICAgICAgICAgICAgICAgPyBfdChcInRpbWVsaW5lfHN1bW1hcnl8Y2hhbmdlZF9uYW1lX211bHRpcGxlXCIsIHsgc2V2ZXJhbFVzZXJzOiBcIlwiLCBjb3VudCB9KVxuICAgICAgICAgICAgICAgICAgICAgICAgOiBfdChcInRpbWVsaW5lfHN1bW1hcnl8Y2hhbmdlZF9uYW1lXCIsIHsgb25lVXNlcjogXCJcIiwgY291bnQgfSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIFRyYW5zaXRpb25UeXBlLkNoYW5nZWRBdmF0YXI6XG4gICAgICAgICAgICAgICAgcmVzID1cbiAgICAgICAgICAgICAgICAgICAgdXNlckNvdW50ID4gMVxuICAgICAgICAgICAgICAgICAgICAgICAgPyBfdChcInRpbWVsaW5lfHN1bW1hcnl8Y2hhbmdlZF9hdmF0YXJfbXVsdGlwbGVcIiwge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2V2ZXJhbFVzZXJzOiBcIlwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY291bnQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgICAgICAgICA6IF90KFwidGltZWxpbmV8c3VtbWFyeXxjaGFuZ2VkX2F2YXRhclwiLCB7IG9uZVVzZXI6IFwiXCIsIGNvdW50IH0pO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBUcmFuc2l0aW9uVHlwZS5Ob0NoYW5nZTpcbiAgICAgICAgICAgICAgICByZXMgPVxuICAgICAgICAgICAgICAgICAgICB1c2VyQ291bnQgPiAxXG4gICAgICAgICAgICAgICAgICAgICAgICA/IF90KFwidGltZWxpbmV8c3VtbWFyeXxub19jaGFuZ2VfbXVsdGlwbGVcIiwgeyBzZXZlcmFsVXNlcnM6IFwiXCIsIGNvdW50IH0pXG4gICAgICAgICAgICAgICAgICAgICAgICA6IF90KFwidGltZWxpbmV8c3VtbWFyeXxub19jaGFuZ2VcIiwgeyBvbmVVc2VyOiBcIlwiLCBjb3VudCB9KTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgVHJhbnNpdGlvblR5cGUuU2VydmVyQWNsOlxuICAgICAgICAgICAgICAgIHJlcyA9XG4gICAgICAgICAgICAgICAgICAgIHVzZXJDb3VudCA+IDFcbiAgICAgICAgICAgICAgICAgICAgICAgID8gX3QoXCJ0aW1lbGluZXxzdW1tYXJ5fHNlcnZlcl9hY2xzX211bHRpcGxlXCIsIHsgc2V2ZXJhbFVzZXJzOiBcIlwiLCBjb3VudCB9KVxuICAgICAgICAgICAgICAgICAgICAgICAgOiBfdChcInRpbWVsaW5lfHN1bW1hcnl8c2VydmVyX2FjbHNcIiwgeyBvbmVVc2VyOiBcIlwiLCBjb3VudCB9KTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgVHJhbnNpdGlvblR5cGUuQ2hhbmdlZFBpbnM6XG4gICAgICAgICAgICAgICAgcmVzID1cbiAgICAgICAgICAgICAgICAgICAgdXNlckNvdW50ID4gMVxuICAgICAgICAgICAgICAgICAgICAgICAgPyBfdChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwidGltZWxpbmV8c3VtbWFyeXxwaW5uZWRfZXZlbnRzX211bHRpcGxlXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7IHNldmVyYWxVc2VyczogXCJcIiwgY291bnQgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhOiAoc3ViKSA9PiAoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxBY2Nlc3NpYmxlQnV0dG9uIGtpbmQ9XCJsaW5rX2lubGluZVwiIG9uQ2xpY2s9e29uUGlubmVkTWVzc2FnZXNDbGlja30+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7c3VifVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L0FjY2Vzc2libGVCdXR0b24+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICAgICAgICAgIDogX3QoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcInRpbWVsaW5lfHN1bW1hcnl8cGlubmVkX2V2ZW50c1wiLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeyBvbmVVc2VyOiBcIlwiLCBjb3VudCB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGE6IChzdWIpID0+IChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPEFjY2Vzc2libGVCdXR0b24ga2luZD1cImxpbmtfaW5saW5lXCIgb25DbGljaz17b25QaW5uZWRNZXNzYWdlc0NsaWNrfT5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHtzdWJ9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvQWNjZXNzaWJsZUJ1dHRvbj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgVHJhbnNpdGlvblR5cGUuTWVzc2FnZVJlbW92ZWQ6XG4gICAgICAgICAgICAgICAgcmVzID1cbiAgICAgICAgICAgICAgICAgICAgdXNlckNvdW50ID4gMVxuICAgICAgICAgICAgICAgICAgICAgICAgPyBfdChcInRpbWVsaW5lfHN1bW1hcnl8cmVkYWN0ZWRfbXVsdGlwbGVcIiwgeyBzZXZlcmFsVXNlcnM6IFwiXCIsIGNvdW50IH0pXG4gICAgICAgICAgICAgICAgICAgICAgICA6IF90KFwidGltZWxpbmV8c3VtbWFyeXxyZWRhY3RlZFwiLCB7IG9uZVVzZXI6IFwiXCIsIGNvdW50IH0pO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBUcmFuc2l0aW9uVHlwZS5IaWRkZW5FdmVudDpcbiAgICAgICAgICAgICAgICByZXMgPVxuICAgICAgICAgICAgICAgICAgICB1c2VyQ291bnQgPiAxXG4gICAgICAgICAgICAgICAgICAgICAgICA/IF90KFwidGltZWxpbmV8c3VtbWFyeXxoaWRkZW5fZXZlbnRfbXVsdGlwbGVcIiwgeyBzZXZlcmFsVXNlcnM6IFwiXCIsIGNvdW50IH0pXG4gICAgICAgICAgICAgICAgICAgICAgICA6IF90KFwidGltZWxpbmV8c3VtbWFyeXxoaWRkZW5fZXZlbnRcIiwgeyBvbmVVc2VyOiBcIlwiLCBjb3VudCB9KTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiByZXMgPz8gbnVsbDtcbiAgICB9XG5cbiAgICBwcml2YXRlIHN0YXRpYyBnZXRUcmFuc2l0aW9uU2VxdWVuY2UoZXZlbnRzOiBJVXNlckV2ZW50c1tdKTogQXJyYXk8VHJhbnNpdGlvblR5cGUgfCBudWxsPiB7XG4gICAgICAgIHJldHVybiBldmVudHMubWFwKEV2ZW50TGlzdFN1bW1hcnkuZ2V0VHJhbnNpdGlvbik7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogTGFiZWwgYSBnaXZlbiBtZW1iZXJzaGlwIGV2ZW50LCBgZWAsIHdoZXJlIGBnZXRDb250ZW50KCkubWVtYmVyc2hpcGAgaGFzXG4gICAgICogY2hhbmdlZCBmb3IgZWFjaCB0cmFuc2l0aW9uIGFsbG93ZWQgYnkgdGhlIE1hdHJpeCBwcm90b2NvbC4gVGhpcyBhdHRlbXB0cyB0b1xuICAgICAqIGxhYmVsIHRoZSBtZW1iZXJzaGlwIGNoYW5nZXMgdGhhdCBvY2N1ciBpbiBgLi4vLi4vLi4vVGV4dEZvckV2ZW50LmpzYC5cbiAgICAgKiBAcGFyYW0ge01hdHJpeEV2ZW50fSBlIHRoZSBtZW1iZXJzaGlwIGNoYW5nZSBldmVudCB0byBsYWJlbC5cbiAgICAgKiBAcmV0dXJucyB7c3RyaW5nP30gdGhlIHRyYW5zaXRpb24gdHlwZSBnaXZlbiB0byB0aGlzIGV2ZW50LiBUaGlzIGRlZmF1bHRzIHRvIGBudWxsYFxuICAgICAqIGlmIGEgdHJhbnNpdGlvbiBpcyBub3QgcmVjb2duaXNlZC5cbiAgICAgKi9cbiAgICBwcml2YXRlIHN0YXRpYyBnZXRUcmFuc2l0aW9uKGU6IElVc2VyRXZlbnRzKTogVHJhbnNpdGlvblR5cGUgfCBudWxsIHtcbiAgICAgICAgaWYgKGUubXhFdmVudC5pc1JlZGFjdGVkKCkpIHtcbiAgICAgICAgICAgIHJldHVybiBUcmFuc2l0aW9uVHlwZS5NZXNzYWdlUmVtb3ZlZDtcbiAgICAgICAgfVxuXG4gICAgICAgIHN3aXRjaCAoZS5teEV2ZW50LmdldFR5cGUoKSkge1xuICAgICAgICAgICAgY2FzZSBFdmVudFR5cGUuUm9vbVRoaXJkUGFydHlJbnZpdGU6XG4gICAgICAgICAgICAgICAgLy8gSGFuZGxlIDNwaWQgaW52aXRlcyB0aGUgc2FtZSBhcyBpbnZpdGVzIHNvIHRoZXkgZ2V0IGJ1bmRsZWQgdG9nZXRoZXJcbiAgICAgICAgICAgICAgICBpZiAoIWlzVmFsaWQzcGlkSW52aXRlKGUubXhFdmVudCkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIFRyYW5zaXRpb25UeXBlLkludml0ZVdpdGhkcmF3YWw7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybiBUcmFuc2l0aW9uVHlwZS5JbnZpdGVkO1xuXG4gICAgICAgICAgICBjYXNlIEV2ZW50VHlwZS5Sb29tU2VydmVyQWNsOlxuICAgICAgICAgICAgICAgIHJldHVybiBUcmFuc2l0aW9uVHlwZS5TZXJ2ZXJBY2w7XG5cbiAgICAgICAgICAgIGNhc2UgRXZlbnRUeXBlLlJvb21QaW5uZWRFdmVudHM6XG4gICAgICAgICAgICAgICAgcmV0dXJuIFRyYW5zaXRpb25UeXBlLkNoYW5nZWRQaW5zO1xuXG4gICAgICAgICAgICBjYXNlIEV2ZW50VHlwZS5Sb29tTWVtYmVyOlxuICAgICAgICAgICAgICAgIHN3aXRjaCAoZS5teEV2ZW50LmdldENvbnRlbnQoKS5tZW1iZXJzaGlwKSB7XG4gICAgICAgICAgICAgICAgICAgIGNhc2UgS25vd25NZW1iZXJzaGlwLkludml0ZTpcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBUcmFuc2l0aW9uVHlwZS5JbnZpdGVkO1xuICAgICAgICAgICAgICAgICAgICBjYXNlIEtub3duTWVtYmVyc2hpcC5CYW46XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gVHJhbnNpdGlvblR5cGUuQmFubmVkO1xuICAgICAgICAgICAgICAgICAgICBjYXNlIEtub3duTWVtYmVyc2hpcC5Kb2luOlxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGUubXhFdmVudC5nZXRQcmV2Q29udGVudCgpLm1lbWJlcnNoaXAgPT09IEtub3duTWVtYmVyc2hpcC5Kb2luKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGUubXhFdmVudC5nZXRDb250ZW50KCkuZGlzcGxheW5hbWUgIT09IGUubXhFdmVudC5nZXRQcmV2Q29udGVudCgpLmRpc3BsYXluYW1lKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBUcmFuc2l0aW9uVHlwZS5DaGFuZ2VkTmFtZTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGUubXhFdmVudC5nZXRDb250ZW50KCkuYXZhdGFyX3VybCAhPT0gZS5teEV2ZW50LmdldFByZXZDb250ZW50KCkuYXZhdGFyX3VybCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gVHJhbnNpdGlvblR5cGUuQ2hhbmdlZEF2YXRhcjtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIFRyYW5zaXRpb25UeXBlLk5vQ2hhbmdlO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gVHJhbnNpdGlvblR5cGUuSm9pbmVkO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBjYXNlIEtub3duTWVtYmVyc2hpcC5MZWF2ZTpcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChlLm14RXZlbnQuZ2V0U2VuZGVyKCkgPT09IGUubXhFdmVudC5nZXRTdGF0ZUtleSgpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGUubXhFdmVudC5nZXRQcmV2Q29udGVudCgpLm1lbWJlcnNoaXAgPT09IEtub3duTWVtYmVyc2hpcC5JbnZpdGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIFRyYW5zaXRpb25UeXBlLkludml0ZVJlamVjdDtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIFRyYW5zaXRpb25UeXBlLkxlZnQ7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICBzd2l0Y2ggKGUubXhFdmVudC5nZXRQcmV2Q29udGVudCgpLm1lbWJlcnNoaXApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXNlIEtub3duTWVtYmVyc2hpcC5JbnZpdGU6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBUcmFuc2l0aW9uVHlwZS5JbnZpdGVXaXRoZHJhd2FsO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgS25vd25NZW1iZXJzaGlwLkJhbjpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIFRyYW5zaXRpb25UeXBlLlVuYmFubmVkO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHNlbmRlciBpcyBub3QgdGFyZ2V0IGFuZCBtYWRlIHRoZSB0YXJnZXQgbGVhdmUsIGlmIG5vdCBmcm9tIGludml0ZS9iYW4gdGhlbiB0aGlzIGlzIGEga2lja1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBUcmFuc2l0aW9uVHlwZS5LaWNrZWQ7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgLy8gb3RoZXJ3aXNlLCBhc3N1bWUgdGhpcyBpcyBhIGhpZGRlbiBldmVudFxuICAgICAgICAgICAgICAgIHJldHVybiBUcmFuc2l0aW9uVHlwZS5IaWRkZW5FdmVudDtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyBnZXRBZ2dyZWdhdGUodXNlckV2ZW50czogUmVjb3JkPHN0cmluZywgSVVzZXJFdmVudHNbXT4pOiB7XG4gICAgICAgIG5hbWVzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmdbXT47XG4gICAgICAgIGluZGljZXM6IFJlY29yZDxzdHJpbmcsIG51bWJlcj47XG4gICAgfSB7XG4gICAgICAgIC8vIEEgbWFwIG9mIGFnZ3JlZ2F0ZSB0eXBlIHRvIGFycmF5cyBvZiBkaXNwbGF5IG5hbWVzLiBFYWNoIGFnZ3JlZ2F0ZSB0eXBlXG4gICAgICAgIC8vIGlzIGEgY29tbWEtZGVsaW1pdGVkIHN0cmluZyBvZiB0cm