UNPKG

matrix-react-sdk

Version:
438 lines (430 loc) 75.2 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.createEditContent = createEditContent; exports.default = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _react = _interopRequireWildcard(require("react")); var _classnames = _interopRequireDefault(require("classnames")); var _matrix = require("matrix-js-sdk/src/matrix"); var _logger = require("matrix-js-sdk/src/logger"); var _languageHandler = require("../../../languageHandler"); var _dispatcher = _interopRequireDefault(require("../../../dispatcher/dispatcher")); var _model = _interopRequireDefault(require("../../../editor/model")); var _dom = require("../../../editor/dom"); var _serialize = require("../../../editor/serialize"); var _EventUtils = require("../../../utils/EventUtils"); var _deserialize = require("../../../editor/deserialize"); var _parts = require("../../../editor/parts"); var _BasicMessageComposer = _interopRequireWildcard(require("./BasicMessageComposer")); var _SlashCommands = require("../../../SlashCommands"); var _actions = require("../../../dispatcher/actions"); var _KeyBindingsManager = require("../../../KeyBindingsManager"); var _SendHistoryManager = _interopRequireDefault(require("../../../SendHistoryManager")); var _AccessibleButton = _interopRequireDefault(require("../elements/AccessibleButton")); var _ConfirmRedactDialog = require("../dialogs/ConfirmRedactDialog"); var _SettingsStore = _interopRequireDefault(require("../../../settings/SettingsStore")); var _MatrixClientContext = require("../../../contexts/MatrixClientContext"); var _RoomContext = _interopRequireDefault(require("../../../contexts/RoomContext")); var _ComposerInsertPayload = require("../../../dispatcher/payloads/ComposerInsertPayload"); var _commands = require("../../../editor/commands"); var _KeyboardShortcuts = require("../../../accessibility/KeyboardShortcuts"); var _PosthogAnalytics = require("../../../PosthogAnalytics"); var _Editing = require("../../../Editing"); var _SendMessageComposer = require("./SendMessageComposer"); var _arrays = require("../../../utils/arrays"); var _MatrixClientPeg = require("../../../MatrixClientPeg"); function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } /* Copyright 2024 New Vector Ltd. Copyright 2019-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 getHtmlReplyFallback(mxEvent) { const html = mxEvent.getContent().formatted_body; if (!html) { return ""; } const rootNode = new DOMParser().parseFromString(html, "text/html").body; const mxReply = rootNode.querySelector("mx-reply"); return mxReply && mxReply.outerHTML || ""; } function getTextReplyFallback(mxEvent) { const body = mxEvent.getContent().body; const lines = body.split("\n").map(l => l.trim()); if (lines.length > 2 && lines[0].startsWith("> ") && lines[1].length === 0) { return `${lines[0]}\n\n`; } return ""; } // exported for tests function createEditContent(model, editedEvent, replyToEvent) { const isEmote = (0, _serialize.containsEmote)(model); if (isEmote) { model = (0, _serialize.stripEmoteCommand)(model); } const isReply = !!editedEvent.replyEventId; let plainPrefix = ""; let htmlPrefix = ""; if (isReply) { plainPrefix = getTextReplyFallback(editedEvent); htmlPrefix = getHtmlReplyFallback(editedEvent); } const body = (0, _serialize.textSerialize)(model); const newContent = { msgtype: isEmote ? _matrix.MsgType.Emote : _matrix.MsgType.Text, body: body }; const contentBody = { "msgtype": newContent.msgtype, "body": `${plainPrefix} * ${body}`, "m.new_content": newContent }; const formattedBody = (0, _serialize.htmlSerializeIfNeeded)(model, { forceHTML: isReply, useMarkdown: _SettingsStore.default.getValue("MessageComposerInput.useMarkdown") }); if (formattedBody) { newContent.format = "org.matrix.custom.html"; newContent.formatted_body = formattedBody; contentBody.format = newContent.format; contentBody.formatted_body = `${htmlPrefix} * ${formattedBody}`; } // Build the mentions properties for both the content and new_content. (0, _SendMessageComposer.attachMentions)(editedEvent.sender.userId, contentBody, model, replyToEvent, editedEvent.getContent()); (0, _SendMessageComposer.attachRelation)(contentBody, { rel_type: "m.replace", event_id: editedEvent.getId() }); return contentBody; } class EditMessageComposer extends _react.default.Component { constructor(props, context) { super(props, context); (0, _defineProperty2.default)(this, "editorRef", /*#__PURE__*/(0, _react.createRef)()); (0, _defineProperty2.default)(this, "dispatcherRef", void 0); (0, _defineProperty2.default)(this, "replyToEvent", void 0); (0, _defineProperty2.default)(this, "model", void 0); (0, _defineProperty2.default)(this, "onKeyDown", event => { // ignore any keypress while doing IME compositions if (this.editorRef.current?.isComposing(event)) { return; } const action = (0, _KeyBindingsManager.getKeyBindingsManager)().getMessageComposerAction(event); switch (action) { case _KeyboardShortcuts.KeyBindingAction.SendMessage: this.sendEdit(); event.stopPropagation(); event.preventDefault(); break; case _KeyboardShortcuts.KeyBindingAction.CancelReplyOrEdit: event.stopPropagation(); this.cancelEdit(); break; case _KeyboardShortcuts.KeyBindingAction.EditPrevMessage: { if (this.editorRef.current?.isModified() || !this.editorRef.current?.isCaretAtStart()) { return; } const previousEvent = (0, _EventUtils.findEditableEvent)({ events: this.events, isForward: false, fromEventId: this.props.editState.getEvent().getId(), matrixClient: _MatrixClientPeg.MatrixClientPeg.safeGet() }); if (previousEvent) { _dispatcher.default.dispatch({ action: _actions.Action.EditEvent, event: previousEvent, timelineRenderingType: this.context.timelineRenderingType }); event.preventDefault(); } break; } case _KeyboardShortcuts.KeyBindingAction.EditNextMessage: { if (this.editorRef.current?.isModified() || !this.editorRef.current?.isCaretAtEnd()) { return; } const nextEvent = (0, _EventUtils.findEditableEvent)({ events: this.events, isForward: true, fromEventId: this.props.editState.getEvent().getId(), matrixClient: _MatrixClientPeg.MatrixClientPeg.safeGet() }); if (nextEvent) { _dispatcher.default.dispatch({ action: _actions.Action.EditEvent, event: nextEvent, timelineRenderingType: this.context.timelineRenderingType }); } else { this.cancelEdit(); } event.preventDefault(); break; } } }); (0, _defineProperty2.default)(this, "cancelEdit", () => { this.endEdit(); }); (0, _defineProperty2.default)(this, "saveStoredEditorState", () => { const item = _SendHistoryManager.default.createItem(this.model); this.clearPreviousEdit(); localStorage.setItem(this.editorRoomKey, this.props.editState.getEvent().getId()); localStorage.setItem(this.editorStateKey, JSON.stringify(item)); }); (0, _defineProperty2.default)(this, "sendEdit", async () => { if (this.state.saveDisabled) return; const editedEvent = this.props.editState.getEvent(); _PosthogAnalytics.PosthogAnalytics.instance.trackEvent({ eventName: "Composer", isEditing: true, messageType: "Text", inThread: !!editedEvent?.getThread(), isReply: !!editedEvent.replyEventId }); // Replace emoticon at the end of the message if (_SettingsStore.default.getValue("MessageComposerInput.autoReplaceEmoji") && this.editorRef.current) { const caret = this.editorRef.current.getCaret(); const position = this.model.positionForOffset(caret.offset, caret.atNodeEnd); this.editorRef.current.replaceEmoticon(position, _BasicMessageComposer.REGEX_EMOTICON); } const editContent = createEditContent(this.model, editedEvent, this.replyToEvent); const newContent = editContent["m.new_content"]; let shouldSend = true; if (newContent?.body === "") { this.cancelPreviousPendingEdit(); (0, _ConfirmRedactDialog.createRedactEventDialog)({ mxEvent: editedEvent, onCloseDialog: () => { this.cancelEdit(); } }); return; } // If content is modified then send an updated event into the room if (this.isContentModified(newContent)) { const roomId = editedEvent.getRoomId(); if (!(0, _serialize.containsEmote)(this.model) && (0, _commands.isSlashCommand)(this.model)) { const [cmd, args, commandText] = (0, _commands.getSlashCommand)(this.model); if (cmd) { const threadId = editedEvent?.getThread()?.id || null; const [content, commandSuccessful] = await (0, _commands.runSlashCommand)(_MatrixClientPeg.MatrixClientPeg.safeGet(), cmd, args, roomId, threadId); if (!commandSuccessful) { return; // errored } if (cmd.category === _SlashCommands.CommandCategories.messages || cmd.category === _SlashCommands.CommandCategories.effects) { editContent["m.new_content"] = content; } else { shouldSend = false; } } else { const sendAnyway = await (0, _commands.shouldSendAnyway)(commandText); // re-focus the composer after QuestionDialog is closed _dispatcher.default.dispatch({ action: _actions.Action.FocusAComposer, context: this.context.timelineRenderingType }); // if !sendAnyway bail to let the user edit the composer and try again if (!sendAnyway) return; } } if (shouldSend) { this.cancelPreviousPendingEdit(); const event = this.props.editState.getEvent(); const threadId = event.threadRootId || null; this.props.mxClient.sendMessage(roomId, threadId, editContent); _dispatcher.default.dispatch({ action: "message_sent" }); } } this.endEdit(); }); (0, _defineProperty2.default)(this, "onChange", () => { if (!this.state.saveDisabled || !this.editorRef.current?.isModified()) { return; } this.setState({ saveDisabled: false }); }); (0, _defineProperty2.default)(this, "onAction", payload => { if (!this.editorRef.current) return; if (payload.action === _actions.Action.ComposerInsert) { if (payload.timelineRenderingType !== this.context.timelineRenderingType) return; if (payload.composerType !== _ComposerInsertPayload.ComposerType.Edit) return; if (payload.userId) { this.editorRef.current?.insertMention(payload.userId); } else if (payload.event) { this.editorRef.current?.insertQuotedMessage(payload.event); } else if (payload.text) { this.editorRef.current?.insertPlaintext(payload.text); } } else if (payload.action === _actions.Action.FocusEditMessageComposer) { this.editorRef.current.focus(); } }); const isRestored = this.createEditorModel(); const ev = this.props.editState.getEvent(); this.replyToEvent = ev.replyEventId ? this.context.room?.findEventById(ev.replyEventId) : undefined; const _editContent = createEditContent(this.model, ev, this.replyToEvent); this.state = { saveDisabled: !isRestored || !this.isContentModified(_editContent["m.new_content"]) }; window.addEventListener("beforeunload", this.saveStoredEditorState); this.dispatcherRef = _dispatcher.default.register(this.onAction); } getRoom() { if (!this.context.room) { throw new Error(`Cannot render without room`); } return this.context.room; } endEdit() { localStorage.removeItem(this.editorRoomKey); localStorage.removeItem(this.editorStateKey); // close the event editing and focus composer _dispatcher.default.dispatch({ action: _actions.Action.EditEvent, event: null, timelineRenderingType: this.context.timelineRenderingType }); _dispatcher.default.dispatch({ action: _actions.Action.FocusSendMessageComposer, context: this.context.timelineRenderingType }); } get editorRoomKey() { return (0, _Editing.editorRoomKey)(this.props.editState.getEvent().getRoomId(), this.context.timelineRenderingType); } get editorStateKey() { return (0, _Editing.editorStateKey)(this.props.editState.getEvent().getId()); } get events() { const liveTimelineEvents = this.context.liveTimeline?.getEvents(); const room = this.getRoom(); if (!liveTimelineEvents || !room) return []; const pendingEvents = room.getPendingEvents(); const isInThread = Boolean(this.props.editState.getEvent().getThread()); return liveTimelineEvents.concat(isInThread ? [] : pendingEvents); } get shouldSaveStoredEditorState() { return localStorage.getItem(this.editorRoomKey) !== null; } restoreStoredEditorState(partCreator) { const json = localStorage.getItem(this.editorStateKey); if (json) { try { const { parts: serializedParts } = JSON.parse(json); const parts = serializedParts.map(p => partCreator.deserializePart(p)); return parts; } catch (e) { _logger.logger.error("Error parsing editing state: ", e); } } } clearPreviousEdit() { if (localStorage.getItem(this.editorRoomKey)) { localStorage.removeItem(`mx_edit_state_${localStorage.getItem(this.editorRoomKey)}`); } } isContentModified(newContent) { // if nothing has changed then bail const oldContent = this.props.editState.getEvent().getContent(); if (oldContent["msgtype"] === newContent["msgtype"] && oldContent["body"] === newContent["body"] && oldContent["format"] === newContent["format"] && oldContent["formatted_body"] === newContent["formatted_body"]) { return false; } return true; } cancelPreviousPendingEdit() { const originalEvent = this.props.editState.getEvent(); const previousEdit = originalEvent.replacingEvent(); if (previousEdit && (previousEdit.status === _matrix.EventStatus.QUEUED || previousEdit.status === _matrix.EventStatus.NOT_SENT)) { this.props.mxClient.cancelPendingEvent(previousEdit); } } componentWillUnmount() { // store caret and serialized parts in the // editorstate so it can be restored when the remote echo event tile gets rendered // in case we're currently editing a pending event const sel = document.getSelection(); let caret; if (sel.focusNode && this.editorRef.current?.editorRef.current) { caret = (0, _dom.getCaretOffsetAndText)(this.editorRef.current.editorRef.current, sel).caret; } const parts = this.model.serializeParts(); // if caret is undefined because for some reason there isn't a valid selection, // then when mounting the editor again with the same editor state, // it will set the cursor at the end. this.props.editState.setEditorState(caret ?? null, parts); window.removeEventListener("beforeunload", this.saveStoredEditorState); if (this.shouldSaveStoredEditorState) { this.saveStoredEditorState(); } _dispatcher.default.unregister(this.dispatcherRef); } createEditorModel() { const { editState } = this.props; const room = this.getRoom(); const partCreator = new _parts.CommandPartCreator(room, this.props.mxClient); let parts; let isRestored = false; if (editState.hasEditorState()) { // if restoring state from a previous editor, // restore serialized parts from the state // (editState.hasEditorState() checks getSerializedParts is not null) parts = (0, _arrays.filterBoolean)(editState.getSerializedParts().map(p => partCreator.deserializePart(p))); } else { // otherwise, either restore serialized parts from localStorage or parse the body of the event const restoredParts = this.restoreStoredEditorState(partCreator); parts = restoredParts || (0, _deserialize.parseEvent)(editState.getEvent(), partCreator, { shouldEscape: _SettingsStore.default.getValue("MessageComposerInput.useMarkdown") }); isRestored = !!restoredParts; } this.model = new _model.default(parts, partCreator); this.saveStoredEditorState(); return isRestored; } render() { const room = this.getRoom(); if (!room) return null; return /*#__PURE__*/_react.default.createElement("div", { className: (0, _classnames.default)("mx_EditMessageComposer", this.props.className), onKeyDown: this.onKeyDown }, /*#__PURE__*/_react.default.createElement(_BasicMessageComposer.default, { ref: this.editorRef, model: this.model, room: room, threadId: this.props.editState?.getEvent()?.getThread()?.id, initialCaret: this.props.editState.getCaret() ?? undefined, label: (0, _languageHandler._t)("composer|edit_composer_label"), onChange: this.onChange }), /*#__PURE__*/_react.default.createElement("div", { className: "mx_EditMessageComposer_buttons" }, /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, { kind: "secondary", onClick: this.cancelEdit }, (0, _languageHandler._t)("action|cancel")), /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, { kind: "primary", onClick: this.sendEdit, disabled: this.state.saveDisabled }, (0, _languageHandler._t)("action|save")))); } } (0, _defineProperty2.default)(EditMessageComposer, "contextType", _RoomContext.default); const EditMessageComposerWithMatrixClient = (0, _MatrixClientContext.withMatrixClientHOC)(EditMessageComposer); var _default = exports.default = EditMessageComposerWithMatrixClient; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfcmVhY3QiLCJfaW50ZXJvcFJlcXVpcmVXaWxkY2FyZCIsInJlcXVpcmUiLCJfY2xhc3NuYW1lcyIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJfbWF0cml4IiwiX2xvZ2dlciIsIl9sYW5ndWFnZUhhbmRsZXIiLCJfZGlzcGF0Y2hlciIsIl9tb2RlbCIsIl9kb20iLCJfc2VyaWFsaXplIiwiX0V2ZW50VXRpbHMiLCJfZGVzZXJpYWxpemUiLCJfcGFydHMiLCJfQmFzaWNNZXNzYWdlQ29tcG9zZXIiLCJfU2xhc2hDb21tYW5kcyIsIl9hY3Rpb25zIiwiX0tleUJpbmRpbmdzTWFuYWdlciIsIl9TZW5kSGlzdG9yeU1hbmFnZXIiLCJfQWNjZXNzaWJsZUJ1dHRvbiIsIl9Db25maXJtUmVkYWN0RGlhbG9nIiwiX1NldHRpbmdzU3RvcmUiLCJfTWF0cml4Q2xpZW50Q29udGV4dCIsIl9Sb29tQ29udGV4dCIsIl9Db21wb3Nlckluc2VydFBheWxvYWQiLCJfY29tbWFuZHMiLCJfS2V5Ym9hcmRTaG9ydGN1dHMiLCJfUG9zdGhvZ0FuYWx5dGljcyIsIl9FZGl0aW5nIiwiX1NlbmRNZXNzYWdlQ29tcG9zZXIiLCJfYXJyYXlzIiwiX01hdHJpeENsaWVudFBlZyIsIl9nZXRSZXF1aXJlV2lsZGNhcmRDYWNoZSIsImUiLCJXZWFrTWFwIiwiciIsInQiLCJfX2VzTW9kdWxlIiwiZGVmYXVsdCIsImhhcyIsImdldCIsIm4iLCJfX3Byb3RvX18iLCJhIiwiT2JqZWN0IiwiZGVmaW5lUHJvcGVydHkiLCJnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IiLCJ1IiwiaGFzT3duUHJvcGVydHkiLCJjYWxsIiwiaSIsInNldCIsImdldEh0bWxSZXBseUZhbGxiYWNrIiwibXhFdmVudCIsImh0bWwiLCJnZXRDb250ZW50IiwiZm9ybWF0dGVkX2JvZHkiLCJyb290Tm9kZSIsIkRPTVBhcnNlciIsInBhcnNlRnJvbVN0cmluZyIsImJvZHkiLCJteFJlcGx5IiwicXVlcnlTZWxlY3RvciIsIm91dGVySFRNTCIsImdldFRleHRSZXBseUZhbGxiYWNrIiwibGluZXMiLCJzcGxpdCIsIm1hcCIsImwiLCJ0cmltIiwibGVuZ3RoIiwic3RhcnRzV2l0aCIsImNyZWF0ZUVkaXRDb250ZW50IiwibW9kZWwiLCJlZGl0ZWRFdmVudCIsInJlcGx5VG9FdmVudCIsImlzRW1vdGUiLCJjb250YWluc0Vtb3RlIiwic3RyaXBFbW90ZUNvbW1hbmQiLCJpc1JlcGx5IiwicmVwbHlFdmVudElkIiwicGxhaW5QcmVmaXgiLCJodG1sUHJlZml4IiwidGV4dFNlcmlhbGl6ZSIsIm5ld0NvbnRlbnQiLCJtc2d0eXBlIiwiTXNnVHlwZSIsIkVtb3RlIiwiVGV4dCIsImNvbnRlbnRCb2R5IiwiZm9ybWF0dGVkQm9keSIsImh0bWxTZXJpYWxpemVJZk5lZWRlZCIsImZvcmNlSFRNTCIsInVzZU1hcmtkb3duIiwiU2V0dGluZ3NTdG9yZSIsImdldFZhbHVlIiwiZm9ybWF0IiwiYXR0YWNoTWVudGlvbnMiLCJzZW5kZXIiLCJ1c2VySWQiLCJhdHRhY2hSZWxhdGlvbiIsInJlbF90eXBlIiwiZXZlbnRfaWQiLCJnZXRJZCIsIkVkaXRNZXNzYWdlQ29tcG9zZXIiLCJSZWFjdCIsIkNvbXBvbmVudCIsImNvbnN0cnVjdG9yIiwicHJvcHMiLCJjb250ZXh0IiwiX2RlZmluZVByb3BlcnR5MiIsImNyZWF0ZVJlZiIsImV2ZW50IiwiZWRpdG9yUmVmIiwiY3VycmVudCIsImlzQ29tcG9zaW5nIiwiYWN0aW9uIiwiZ2V0S2V5QmluZGluZ3NNYW5hZ2VyIiwiZ2V0TWVzc2FnZUNvbXBvc2VyQWN0aW9uIiwiS2V5QmluZGluZ0FjdGlvbiIsIlNlbmRNZXNzYWdlIiwic2VuZEVkaXQiLCJzdG9wUHJvcGFnYXRpb24iLCJwcmV2ZW50RGVmYXVsdCIsIkNhbmNlbFJlcGx5T3JFZGl0IiwiY2FuY2VsRWRpdCIsIkVkaXRQcmV2TWVzc2FnZSIsImlzTW9kaWZpZWQiLCJpc0NhcmV0QXRTdGFydCIsInByZXZpb3VzRXZlbnQiLCJmaW5kRWRpdGFibGVFdmVudCIsImV2ZW50cyIsImlzRm9yd2FyZCIsImZyb21FdmVudElkIiwiZWRpdFN0YXRlIiwiZ2V0RXZlbnQiLCJtYXRyaXhDbGllbnQiLCJNYXRyaXhDbGllbnRQZWciLCJzYWZlR2V0IiwiZGlzIiwiZGlzcGF0Y2giLCJBY3Rpb24iLCJFZGl0RXZlbnQiLCJ0aW1lbGluZVJlbmRlcmluZ1R5cGUiLCJFZGl0TmV4dE1lc3NhZ2UiLCJpc0NhcmV0QXRFbmQiLCJuZXh0RXZlbnQiLCJlbmRFZGl0IiwiaXRlbSIsIlNlbmRIaXN0b3J5TWFuYWdlciIsImNyZWF0ZUl0ZW0iLCJjbGVhclByZXZpb3VzRWRpdCIsImxvY2FsU3RvcmFnZSIsInNldEl0ZW0iLCJlZGl0b3JSb29tS2V5IiwiZWRpdG9yU3RhdGVLZXkiLCJKU09OIiwic3RyaW5naWZ5Iiwic3RhdGUiLCJzYXZlRGlzYWJsZWQiLCJQb3N0aG9nQW5hbHl0aWNzIiwiaW5zdGFuY2UiLCJ0cmFja0V2ZW50IiwiZXZlbnROYW1lIiwiaXNFZGl0aW5nIiwibWVzc2FnZVR5cGUiLCJpblRocmVhZCIsImdldFRocmVhZCIsImNhcmV0IiwiZ2V0Q2FyZXQiLCJwb3NpdGlvbiIsInBvc2l0aW9uRm9yT2Zmc2V0Iiwib2Zmc2V0IiwiYXROb2RlRW5kIiwicmVwbGFjZUVtb3RpY29uIiwiUkVHRVhfRU1PVElDT04iLCJlZGl0Q29udGVudCIsInNob3VsZFNlbmQiLCJjYW5jZWxQcmV2aW91c1BlbmRpbmdFZGl0IiwiY3JlYXRlUmVkYWN0RXZlbnREaWFsb2ciLCJvbkNsb3NlRGlhbG9nIiwiaXNDb250ZW50TW9kaWZpZWQiLCJyb29tSWQiLCJnZXRSb29tSWQiLCJpc1NsYXNoQ29tbWFuZCIsImNtZCIsImFyZ3MiLCJjb21tYW5kVGV4dCIsImdldFNsYXNoQ29tbWFuZCIsInRocmVhZElkIiwiaWQiLCJjb250ZW50IiwiY29tbWFuZFN1Y2Nlc3NmdWwiLCJydW5TbGFzaENvbW1hbmQiLCJjYXRlZ29yeSIsIkNvbW1hbmRDYXRlZ29yaWVzIiwibWVzc2FnZXMiLCJlZmZlY3RzIiwic2VuZEFueXdheSIsInNob3VsZFNlbmRBbnl3YXkiLCJGb2N1c0FDb21wb3NlciIsInRocmVhZFJvb3RJZCIsIm14Q2xpZW50Iiwic2VuZE1lc3NhZ2UiLCJzZXRTdGF0ZSIsInBheWxvYWQiLCJDb21wb3Nlckluc2VydCIsImNvbXBvc2VyVHlwZSIsIkNvbXBvc2VyVHlwZSIsIkVkaXQiLCJpbnNlcnRNZW50aW9uIiwiaW5zZXJ0UXVvdGVkTWVzc2FnZSIsInRleHQiLCJpbnNlcnRQbGFpbnRleHQiLCJGb2N1c0VkaXRNZXNzYWdlQ29tcG9zZXIiLCJmb2N1cyIsImlzUmVzdG9yZWQiLCJjcmVhdGVFZGl0b3JNb2RlbCIsImV2Iiwicm9vbSIsImZpbmRFdmVudEJ5SWQiLCJ1bmRlZmluZWQiLCJ3aW5kb3ciLCJhZGRFdmVudExpc3RlbmVyIiwic2F2ZVN0b3JlZEVkaXRvclN0YXRlIiwiZGlzcGF0Y2hlclJlZiIsInJlZ2lzdGVyIiwib25BY3Rpb24iLCJnZXRSb29tIiwiRXJyb3IiLCJyZW1vdmVJdGVtIiwiRm9jdXNTZW5kTWVzc2FnZUNvbXBvc2VyIiwibGl2ZVRpbWVsaW5lRXZlbnRzIiwibGl2ZVRpbWVsaW5lIiwiZ2V0RXZlbnRzIiwicGVuZGluZ0V2ZW50cyIsImdldFBlbmRpbmdFdmVudHMiLCJpc0luVGhyZWFkIiwiQm9vbGVhbiIsImNvbmNhdCIsInNob3VsZFNhdmVTdG9yZWRFZGl0b3JTdGF0ZSIsImdldEl0ZW0iLCJyZXN0b3JlU3RvcmVkRWRpdG9yU3RhdGUiLCJwYXJ0Q3JlYXRvciIsImpzb24iLCJwYXJ0cyIsInNlcmlhbGl6ZWRQYXJ0cyIsInBhcnNlIiwicCIsImRlc2VyaWFsaXplUGFydCIsImxvZ2dlciIsImVycm9yIiwib2xkQ29udGVudCIsIm9yaWdpbmFsRXZlbnQiLCJwcmV2aW91c0VkaXQiLCJyZXBsYWNpbmdFdmVudCIsInN0YXR1cyIsIkV2ZW50U3RhdHVzIiwiUVVFVUVEIiwiTk9UX1NFTlQiLCJjYW5jZWxQZW5kaW5nRXZlbnQiLCJjb21wb25lbnRXaWxsVW5tb3VudCIsInNlbCIsImRvY3VtZW50IiwiZ2V0U2VsZWN0aW9uIiwiZm9jdXNOb2RlIiwiZ2V0Q2FyZXRPZmZzZXRBbmRUZXh0Iiwic2VyaWFsaXplUGFydHMiLCJzZXRFZGl0b3JTdGF0ZSIsInJlbW92ZUV2ZW50TGlzdGVuZXIiLCJ1bnJlZ2lzdGVyIiwiQ29tbWFuZFBhcnRDcmVhdG9yIiwiaGFzRWRpdG9yU3RhdGUiLCJmaWx0ZXJCb29sZWFuIiwiZ2V0U2VyaWFsaXplZFBhcnRzIiwicmVzdG9yZWRQYXJ0cyIsInBhcnNlRXZlbnQiLCJzaG91bGRFc2NhcGUiLCJFZGl0b3JNb2RlbCIsInJlbmRlciIsImNyZWF0ZUVsZW1lbnQiLCJjbGFzc05hbWUiLCJjbGFzc05hbWVzIiwib25LZXlEb3duIiwicmVmIiwiaW5pdGlhbENhcmV0IiwibGFiZWwiLCJfdCIsIm9uQ2hhbmdlIiwia2luZCIsIm9uQ2xpY2siLCJkaXNhYmxlZCIsIlJvb21Db250ZXh0IiwiRWRpdE1lc3NhZ2VDb21wb3NlcldpdGhNYXRyaXhDbGllbnQiLCJ3aXRoTWF0cml4Q2xpZW50SE9DIiwiX2RlZmF1bHQiLCJleHBvcnRzIl0sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2NvbXBvbmVudHMvdmlld3Mvcm9vbXMvRWRpdE1lc3NhZ2VDb21wb3Nlci50c3giXSwic291cmNlc0NvbnRlbnQiOlsiLypcbkNvcHlyaWdodCAyMDI0IE5ldyBWZWN0b3IgTHRkLlxuQ29weXJpZ2h0IDIwMTktMjAyMSBUaGUgTWF0cml4Lm9yZyBGb3VuZGF0aW9uIEMuSS5DLlxuXG5TUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQUdQTC0zLjAtb25seSBPUiBHUEwtMy4wLW9ubHlcblBsZWFzZSBzZWUgTElDRU5TRSBmaWxlcyBpbiB0aGUgcmVwb3NpdG9yeSByb290IGZvciBmdWxsIGRldGFpbHMuXG4qL1xuXG5pbXBvcnQgUmVhY3QsIHsgY3JlYXRlUmVmLCBLZXlib2FyZEV2ZW50IH0gZnJvbSBcInJlYWN0XCI7XG5pbXBvcnQgY2xhc3NOYW1lcyBmcm9tIFwiY2xhc3NuYW1lc1wiO1xuaW1wb3J0IHsgRXZlbnRTdGF0dXMsIE1hdHJpeEV2ZW50LCBSb29tLCBNc2dUeXBlIH0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL21hdHJpeFwiO1xuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL2xvZ2dlclwiO1xuaW1wb3J0IHsgQ29tcG9zZXIgYXMgQ29tcG9zZXJFdmVudCB9IGZyb20gXCJAbWF0cml4LW9yZy9hbmFseXRpY3MtZXZlbnRzL3R5cGVzL3R5cGVzY3JpcHQvQ29tcG9zZXJcIjtcbmltcG9ydCB7IFJlcGxhY2VtZW50RXZlbnQsIFJvb21NZXNzYWdlRXZlbnRDb250ZW50LCBSb29tTWVzc2FnZVRleHRFdmVudENvbnRlbnQgfSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvdHlwZXNcIjtcblxuaW1wb3J0IHsgX3QgfSBmcm9tIFwiLi4vLi4vLi4vbGFuZ3VhZ2VIYW5kbGVyXCI7XG5pbXBvcnQgZGlzIGZyb20gXCIuLi8uLi8uLi9kaXNwYXRjaGVyL2Rpc3BhdGNoZXJcIjtcbmltcG9ydCBFZGl0b3JNb2RlbCBmcm9tIFwiLi4vLi4vLi4vZWRpdG9yL21vZGVsXCI7XG5pbXBvcnQgeyBnZXRDYXJldE9mZnNldEFuZFRleHQgfSBmcm9tIFwiLi4vLi4vLi4vZWRpdG9yL2RvbVwiO1xuaW1wb3J0IHsgaHRtbFNlcmlhbGl6ZUlmTmVlZGVkLCB0ZXh0U2VyaWFsaXplLCBjb250YWluc0Vtb3RlLCBzdHJpcEVtb3RlQ29tbWFuZCB9IGZyb20gXCIuLi8uLi8uLi9lZGl0b3Ivc2VyaWFsaXplXCI7XG5pbXBvcnQgeyBmaW5kRWRpdGFibGVFdmVudCB9IGZyb20gXCIuLi8uLi8uLi91dGlscy9FdmVudFV0aWxzXCI7XG5pbXBvcnQgeyBwYXJzZUV2ZW50IH0gZnJvbSBcIi4uLy4uLy4uL2VkaXRvci9kZXNlcmlhbGl6ZVwiO1xuaW1wb3J0IHsgQ29tbWFuZFBhcnRDcmVhdG9yLCBQYXJ0LCBQYXJ0Q3JlYXRvciwgU2VyaWFsaXplZFBhcnQgfSBmcm9tIFwiLi4vLi4vLi4vZWRpdG9yL3BhcnRzXCI7XG5pbXBvcnQgRWRpdG9yU3RhdGVUcmFuc2ZlciBmcm9tIFwiLi4vLi4vLi4vdXRpbHMvRWRpdG9yU3RhdGVUcmFuc2ZlclwiO1xuaW1wb3J0IEJhc2ljTWVzc2FnZUNvbXBvc2VyLCB7IFJFR0VYX0VNT1RJQ09OIH0gZnJvbSBcIi4vQmFzaWNNZXNzYWdlQ29tcG9zZXJcIjtcbmltcG9ydCB7IENvbW1hbmRDYXRlZ29yaWVzIH0gZnJvbSBcIi4uLy4uLy4uL1NsYXNoQ29tbWFuZHNcIjtcbmltcG9ydCB7IEFjdGlvbiB9IGZyb20gXCIuLi8uLi8uLi9kaXNwYXRjaGVyL2FjdGlvbnNcIjtcbmltcG9ydCB7IGdldEtleUJpbmRpbmdzTWFuYWdlciB9IGZyb20gXCIuLi8uLi8uLi9LZXlCaW5kaW5nc01hbmFnZXJcIjtcbmltcG9ydCBTZW5kSGlzdG9yeU1hbmFnZXIgZnJvbSBcIi4uLy4uLy4uL1NlbmRIaXN0b3J5TWFuYWdlclwiO1xuaW1wb3J0IHsgQWN0aW9uUGF5bG9hZCB9IGZyb20gXCIuLi8uLi8uLi9kaXNwYXRjaGVyL3BheWxvYWRzXCI7XG5pbXBvcnQgQWNjZXNzaWJsZUJ1dHRvbiBmcm9tIFwiLi4vZWxlbWVudHMvQWNjZXNzaWJsZUJ1dHRvblwiO1xuaW1wb3J0IHsgY3JlYXRlUmVkYWN0RXZlbnREaWFsb2cgfSBmcm9tIFwiLi4vZGlhbG9ncy9Db25maXJtUmVkYWN0RGlhbG9nXCI7XG5pbXBvcnQgU2V0dGluZ3NTdG9yZSBmcm9tIFwiLi4vLi4vLi4vc2V0dGluZ3MvU2V0dGluZ3NTdG9yZVwiO1xuaW1wb3J0IHsgd2l0aE1hdHJpeENsaWVudEhPQywgTWF0cml4Q2xpZW50UHJvcHMgfSBmcm9tIFwiLi4vLi4vLi4vY29udGV4dHMvTWF0cml4Q2xpZW50Q29udGV4dFwiO1xuaW1wb3J0IFJvb21Db250ZXh0IGZyb20gXCIuLi8uLi8uLi9jb250ZXh0cy9Sb29tQ29udGV4dFwiO1xuaW1wb3J0IHsgQ29tcG9zZXJUeXBlIH0gZnJvbSBcIi4uLy4uLy4uL2Rpc3BhdGNoZXIvcGF5bG9hZHMvQ29tcG9zZXJJbnNlcnRQYXlsb2FkXCI7XG5pbXBvcnQgeyBnZXRTbGFzaENvbW1hbmQsIGlzU2xhc2hDb21tYW5kLCBydW5TbGFzaENvbW1hbmQsIHNob3VsZFNlbmRBbnl3YXkgfSBmcm9tIFwiLi4vLi4vLi4vZWRpdG9yL2NvbW1hbmRzXCI7XG5pbXBvcnQgeyBLZXlCaW5kaW5nQWN0aW9uIH0gZnJvbSBcIi4uLy4uLy4uL2FjY2Vzc2liaWxpdHkvS2V5Ym9hcmRTaG9ydGN1dHNcIjtcbmltcG9ydCB7IFBvc3Rob2dBbmFseXRpY3MgfSBmcm9tIFwiLi4vLi4vLi4vUG9zdGhvZ0FuYWx5dGljc1wiO1xuaW1wb3J0IHsgZWRpdG9yUm9vbUtleSwgZWRpdG9yU3RhdGVLZXkgfSBmcm9tIFwiLi4vLi4vLi4vRWRpdGluZ1wiO1xuaW1wb3J0IERvY3VtZW50T2Zmc2V0IGZyb20gXCIuLi8uLi8uLi9lZGl0b3Ivb2Zmc2V0XCI7XG5pbXBvcnQgeyBhdHRhY2hNZW50aW9ucywgYXR0YWNoUmVsYXRpb24gfSBmcm9tIFwiLi9TZW5kTWVzc2FnZUNvbXBvc2VyXCI7XG5pbXBvcnQgeyBmaWx0ZXJCb29sZWFuIH0gZnJvbSBcIi4uLy4uLy4uL3V0aWxzL2FycmF5c1wiO1xuaW1wb3J0IHsgTWF0cml4Q2xpZW50UGVnIH0gZnJvbSBcIi4uLy4uLy4uL01hdHJpeENsaWVudFBlZ1wiO1xuXG5mdW5jdGlvbiBnZXRIdG1sUmVwbHlGYWxsYmFjayhteEV2ZW50OiBNYXRyaXhFdmVudCk6IHN0cmluZyB7XG4gICAgY29uc3QgaHRtbCA9IG14RXZlbnQuZ2V0Q29udGVudCgpLmZvcm1hdHRlZF9ib2R5O1xuICAgIGlmICghaHRtbCkge1xuICAgICAgICByZXR1cm4gXCJcIjtcbiAgICB9XG4gICAgY29uc3Qgcm9vdE5vZGUgPSBuZXcgRE9NUGFyc2VyKCkucGFyc2VGcm9tU3RyaW5nKGh0bWwsIFwidGV4dC9odG1sXCIpLmJvZHk7XG4gICAgY29uc3QgbXhSZXBseSA9IHJvb3ROb2RlLnF1ZXJ5U2VsZWN0b3IoXCJteC1yZXBseVwiKTtcbiAgICByZXR1cm4gKG14UmVwbHkgJiYgbXhSZXBseS5vdXRlckhUTUwpIHx8IFwiXCI7XG59XG5cbmZ1bmN0aW9uIGdldFRleHRSZXBseUZhbGxiYWNrKG14RXZlbnQ6IE1hdHJpeEV2ZW50KTogc3RyaW5nIHtcbiAgICBjb25zdCBib2R5OiBzdHJpbmcgPSBteEV2ZW50LmdldENvbnRlbnQoKS5ib2R5O1xuICAgIGNvbnN0IGxpbmVzID0gYm9keS5zcGxpdChcIlxcblwiKS5tYXAoKGwpID0+IGwudHJpbSgpKTtcbiAgICBpZiAobGluZXMubGVuZ3RoID4gMiAmJiBsaW5lc1swXS5zdGFydHNXaXRoKFwiPiBcIikgJiYgbGluZXNbMV0ubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIHJldHVybiBgJHtsaW5lc1swXX1cXG5cXG5gO1xuICAgIH1cbiAgICByZXR1cm4gXCJcIjtcbn1cblxuLy8gZXhwb3J0ZWQgZm9yIHRlc3RzXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlRWRpdENvbnRlbnQoXG4gICAgbW9kZWw6IEVkaXRvck1vZGVsLFxuICAgIGVkaXRlZEV2ZW50OiBNYXRyaXhFdmVudCxcbiAgICByZXBseVRvRXZlbnQ/OiBNYXRyaXhFdmVudCxcbik6IFJvb21NZXNzYWdlRXZlbnRDb250ZW50IHtcbiAgICBjb25zdCBpc0Vtb3RlID0gY29udGFpbnNFbW90ZShtb2RlbCk7XG4gICAgaWYgKGlzRW1vdGUpIHtcbiAgICAgICAgbW9kZWwgPSBzdHJpcEVtb3RlQ29tbWFuZChtb2RlbCk7XG4gICAgfVxuICAgIGNvbnN0IGlzUmVwbHkgPSAhIWVkaXRlZEV2ZW50LnJlcGx5RXZlbnRJZDtcbiAgICBsZXQgcGxhaW5QcmVmaXggPSBcIlwiO1xuICAgIGxldCBodG1sUHJlZml4ID0gXCJcIjtcblxuICAgIGlmIChpc1JlcGx5KSB7XG4gICAgICAgIHBsYWluUHJlZml4ID0gZ2V0VGV4dFJlcGx5RmFsbGJhY2soZWRpdGVkRXZlbnQpO1xuICAgICAgICBodG1sUHJlZml4ID0gZ2V0SHRtbFJlcGx5RmFsbGJhY2soZWRpdGVkRXZlbnQpO1xuICAgIH1cblxuICAgIGNvbnN0IGJvZHkgPSB0ZXh0U2VyaWFsaXplKG1vZGVsKTtcblxuICAgIGNvbnN0IG5ld0NvbnRlbnQ6IFJvb21NZXNzYWdlRXZlbnRDb250ZW50ID0ge1xuICAgICAgICBtc2d0eXBlOiBpc0Vtb3RlID8gTXNnVHlwZS5FbW90ZSA6IE1zZ1R5cGUuVGV4dCxcbiAgICAgICAgYm9keTogYm9keSxcbiAgICB9O1xuICAgIGNvbnN0IGNvbnRlbnRCb2R5OiBSb29tTWVzc2FnZVRleHRFdmVudENvbnRlbnQgJiBPbWl0PFJlcGxhY2VtZW50RXZlbnQ8Um9vbU1lc3NhZ2VFdmVudENvbnRlbnQ+LCBcIm0ucmVsYXRlc190b1wiPiA9IHtcbiAgICAgICAgXCJtc2d0eXBlXCI6IG5ld0NvbnRlbnQubXNndHlwZSxcbiAgICAgICAgXCJib2R5XCI6IGAke3BsYWluUHJlZml4fSAqICR7Ym9keX1gLFxuICAgICAgICBcIm0ubmV3X2NvbnRlbnRcIjogbmV3Q29udGVudCxcbiAgICB9O1xuXG4gICAgY29uc3QgZm9ybWF0dGVkQm9keSA9IGh0bWxTZXJpYWxpemVJZk5lZWRlZChtb2RlbCwge1xuICAgICAgICBmb3JjZUhUTUw6IGlzUmVwbHksXG4gICAgICAgIHVzZU1hcmtkb3duOiBTZXR0aW5nc1N0b3JlLmdldFZhbHVlKFwiTWVzc2FnZUNvbXBvc2VySW5wdXQudXNlTWFya2Rvd25cIiksXG4gICAgfSk7XG4gICAgaWYgKGZvcm1hdHRlZEJvZHkpIHtcbiAgICAgICAgbmV3Q29udGVudC5mb3JtYXQgPSBcIm9yZy5tYXRyaXguY3VzdG9tLmh0bWxcIjtcbiAgICAgICAgbmV3Q29udGVudC5mb3JtYXR0ZWRfYm9keSA9IGZvcm1hdHRlZEJvZHk7XG4gICAgICAgIGNvbnRlbnRCb2R5LmZvcm1hdCA9IG5ld0NvbnRlbnQuZm9ybWF0O1xuICAgICAgICBjb250ZW50Qm9keS5mb3JtYXR0ZWRfYm9keSA9IGAke2h0bWxQcmVmaXh9ICogJHtmb3JtYXR0ZWRCb2R5fWA7XG4gICAgfVxuXG4gICAgLy8gQnVpbGQgdGhlIG1lbnRpb25zIHByb3BlcnRpZXMgZm9yIGJvdGggdGhlIGNvbnRlbnQgYW5kIG5ld19jb250ZW50LlxuICAgIGF0dGFjaE1lbnRpb25zKGVkaXRlZEV2ZW50LnNlbmRlciEudXNlcklkLCBjb250ZW50Qm9keSwgbW9kZWwsIHJlcGx5VG9FdmVudCwgZWRpdGVkRXZlbnQuZ2V0Q29udGVudCgpKTtcbiAgICBhdHRhY2hSZWxhdGlvbihjb250ZW50Qm9keSwgeyByZWxfdHlwZTogXCJtLnJlcGxhY2VcIiwgZXZlbnRfaWQ6IGVkaXRlZEV2ZW50LmdldElkKCkgfSk7XG5cbiAgICByZXR1cm4gY29udGVudEJvZHkgYXMgUm9vbU1lc3NhZ2VFdmVudENvbnRlbnQ7XG59XG5cbmludGVyZmFjZSBJRWRpdE1lc3NhZ2VDb21wb3NlclByb3BzIGV4dGVuZHMgTWF0cml4Q2xpZW50UHJvcHMge1xuICAgIGVkaXRTdGF0ZTogRWRpdG9yU3RhdGVUcmFuc2ZlcjtcbiAgICBjbGFzc05hbWU/OiBzdHJpbmc7XG59XG5pbnRlcmZhY2UgSVN0YXRlIHtcbiAgICBzYXZlRGlzYWJsZWQ6IGJvb2xlYW47XG59XG5cbmNsYXNzIEVkaXRNZXNzYWdlQ29tcG9zZXIgZXh0ZW5kcyBSZWFjdC5Db21wb25lbnQ8SUVkaXRNZXNzYWdlQ29tcG9zZXJQcm9wcywgSVN0YXRlPiB7XG4gICAgcHVibGljIHN0YXRpYyBjb250ZXh0VHlwZSA9IFJvb21Db250ZXh0O1xuICAgIHB1YmxpYyBkZWNsYXJlIGNvbnRleHQ6IFJlYWN0LkNvbnRleHRUeXBlPHR5cGVvZiBSb29tQ29udGV4dD47XG5cbiAgICBwcml2YXRlIHJlYWRvbmx5IGVkaXRvclJlZiA9IGNyZWF0ZVJlZjxCYXNpY01lc3NhZ2VDb21wb3Nlcj4oKTtcbiAgICBwcml2YXRlIHJlYWRvbmx5IGRpc3BhdGNoZXJSZWY6IHN0cmluZztcbiAgICBwcml2YXRlIHJlYWRvbmx5IHJlcGx5VG9FdmVudD86IE1hdHJpeEV2ZW50O1xuICAgIHByaXZhdGUgbW9kZWwhOiBFZGl0b3JNb2RlbDtcblxuICAgIHB1YmxpYyBjb25zdHJ1Y3Rvcihwcm9wczogSUVkaXRNZXNzYWdlQ29tcG9zZXJQcm9wcywgY29udGV4dDogUmVhY3QuQ29udGV4dFR5cGU8dHlwZW9mIFJvb21Db250ZXh0Pikge1xuICAgICAgICBzdXBlcihwcm9wcywgY29udGV4dCk7XG5cbiAgICAgICAgY29uc3QgaXNSZXN0b3JlZCA9IHRoaXMuY3JlYXRlRWRpdG9yTW9kZWwoKTtcbiAgICAgICAgY29uc3QgZXYgPSB0aGlzLnByb3BzLmVkaXRTdGF0ZS5nZXRFdmVudCgpO1xuXG4gICAgICAgIHRoaXMucmVwbHlUb0V2ZW50ID0gZXYucmVwbHlFdmVudElkID8gdGhpcy5jb250ZXh0LnJvb20/LmZpbmRFdmVudEJ5SWQoZXYucmVwbHlFdmVudElkKSA6IHVuZGVmaW5lZDtcblxuICAgICAgICBjb25zdCBlZGl0Q29udGVudCA9IGNyZWF0ZUVkaXRDb250ZW50KHRoaXMubW9kZWwsIGV2LCB0aGlzLnJlcGx5VG9FdmVudCk7XG4gICAgICAgIHRoaXMuc3RhdGUgPSB7XG4gICAgICAgICAgICBzYXZlRGlzYWJsZWQ6ICFpc1Jlc3RvcmVkIHx8ICF0aGlzLmlzQ29udGVudE1vZGlmaWVkKGVkaXRDb250ZW50W1wibS5uZXdfY29udGVudFwiXSEpLFxuICAgICAgICB9O1xuXG4gICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKFwiYmVmb3JldW5sb2FkXCIsIHRoaXMuc2F2ZVN0b3JlZEVkaXRvclN0YXRlKTtcbiAgICAgICAgdGhpcy5kaXNwYXRjaGVyUmVmID0gZGlzLnJlZ2lzdGVyKHRoaXMub25BY3Rpb24pO1xuICAgIH1cblxuICAgIHByaXZhdGUgZ2V0Um9vbSgpOiBSb29tIHtcbiAgICAgICAgaWYgKCF0aGlzLmNvbnRleHQucm9vbSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBDYW5ub3QgcmVuZGVyIHdpdGhvdXQgcm9vbWApO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzLmNvbnRleHQucm9vbTtcbiAgICB9XG5cbiAgICBwcml2YXRlIG9uS2V5RG93biA9IChldmVudDogS2V5Ym9hcmRFdmVudCk6IHZvaWQgPT4ge1xuICAgICAgICAvLyBpZ25vcmUgYW55IGtleXByZXNzIHdoaWxlIGRvaW5nIElNRSBjb21wb3NpdGlvbnNcbiAgICAgICAgaWYgKHRoaXMuZWRpdG9yUmVmLmN1cnJlbnQ/LmlzQ29tcG9zaW5nKGV2ZW50KSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGFjdGlvbiA9IGdldEtleUJpbmRpbmdzTWFuYWdlcigpLmdldE1lc3NhZ2VDb21wb3NlckFjdGlvbihldmVudCk7XG4gICAgICAgIHN3aXRjaCAoYWN0aW9uKSB7XG4gICAgICAgICAgICBjYXNlIEtleUJpbmRpbmdBY3Rpb24uU2VuZE1lc3NhZ2U6XG4gICAgICAgICAgICAgICAgdGhpcy5zZW5kRWRpdCgpO1xuICAgICAgICAgICAgICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgICAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIEtleUJpbmRpbmdBY3Rpb24uQ2FuY2VsUmVwbHlPckVkaXQ6XG4gICAgICAgICAgICAgICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgICAgICAgICAgICAgdGhpcy5jYW5jZWxFZGl0KCk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIEtleUJpbmRpbmdBY3Rpb24uRWRpdFByZXZNZXNzYWdlOiB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuZWRpdG9yUmVmLmN1cnJlbnQ/LmlzTW9kaWZpZWQoKSB8fCAhdGhpcy5lZGl0b3JSZWYuY3VycmVudD8uaXNDYXJldEF0U3RhcnQoKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNvbnN0IHByZXZpb3VzRXZlbnQgPSBmaW5kRWRpdGFibGVFdmVudCh7XG4gICAgICAgICAgICAgICAgICAgIGV2ZW50czogdGhpcy5ldmVudHMsXG4gICAgICAgICAgICAgICAgICAgIGlzRm9yd2FyZDogZmFsc2UsXG4gICAgICAgICAgICAgICAgICAgIGZyb21FdmVudElkOiB0aGlzLnByb3BzLmVkaXRTdGF0ZS5nZXRFdmVudCgpLmdldElkKCksXG4gICAgICAgICAgICAgICAgICAgIG1hdHJpeENsaWVudDogTWF0cml4Q2xpZW50UGVnLnNhZmVHZXQoKSxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICBpZiAocHJldmlvdXNFdmVudCkge1xuICAgICAgICAgICAgICAgICAgICBkaXMuZGlzcGF0Y2goe1xuICAgICAgICAgICAgICAgICAgICAgICAgYWN0aW9uOiBBY3Rpb24uRWRpdEV2ZW50LFxuICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnQ6IHByZXZpb3VzRXZlbnQsXG4gICAgICAgICAgICAgICAgICAgICAgICB0aW1lbGluZVJlbmRlcmluZ1R5cGU6IHRoaXMuY29udGV4dC50aW1lbGluZVJlbmRlcmluZ1R5cGUsXG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhc2UgS2V5QmluZGluZ0FjdGlvbi5FZGl0TmV4dE1lc3NhZ2U6IHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5lZGl0b3JSZWYuY3VycmVudD8uaXNNb2RpZmllZCgpIHx8ICF0aGlzLmVkaXRvclJlZi5jdXJyZW50Py5pc0NhcmV0QXRFbmQoKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNvbnN0IG5leHRFdmVudCA9IGZpbmRFZGl0YWJsZUV2ZW50KHtcbiAgICAgICAgICAgICAgICAgICAgZXZlbnRzOiB0aGlzLmV2ZW50cyxcbiAgICAgICAgICAgICAgICAgICAgaXNGb3J3YXJkOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICBmcm9tRXZlbnRJZDogdGhpcy5wcm9wcy5lZGl0U3RhdGUuZ2V0RXZlbnQoKS5nZXRJZCgpLFxuICAgICAgICAgICAgICAgICAgICBtYXRyaXhDbGllbnQ6IE1hdHJpeENsaWVudFBlZy5zYWZlR2V0KCksXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgaWYgKG5leHRFdmVudCkge1xuICAgICAgICAgICAgICAgICAgICBkaXMuZGlzcGF0Y2goe1xuICAgICAgICAgICAgICAgICAgICAgICAgYWN0aW9uOiBBY3Rpb24uRWRpdEV2ZW50LFxuICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnQ6IG5leHRFdmVudCxcbiAgICAgICAgICAgICAgICAgICAgICAgIHRpbWVsaW5lUmVuZGVyaW5nVHlwZTogdGhpcy5jb250ZXh0LnRpbWVsaW5lUmVuZGVyaW5nVHlwZSxcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jYW5jZWxFZGl0KCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgcHJpdmF0ZSBlbmRFZGl0KCk6IHZvaWQge1xuICAgICAgICBsb2NhbFN0b3JhZ2UucmVtb3ZlSXRlbSh0aGlzLmVkaXRvclJvb21LZXkpO1xuICAgICAgICBsb2NhbFN0b3JhZ2UucmVtb3ZlSXRlbSh0aGlzLmVkaXRvclN0YXRlS2V5KTtcblxuICAgICAgICAvLyBjbG9zZSB0aGUgZXZlbnQgZWRpdGluZyBhbmQgZm9jdXMgY29tcG9zZXJcbiAgICAgICAgZGlzLmRpc3BhdGNoKHtcbiAgICAgICAgICAgIGFjdGlvbjogQWN0aW9uLkVkaXRFdmVudCxcbiAgICAgICAgICAgIGV2ZW50OiBudWxsLFxuICAgICAgICAgICAgdGltZWxpbmVSZW5kZXJpbmdUeXBlOiB0aGlzLmNvbnRleHQudGltZWxpbmVSZW5kZXJpbmdUeXBlLFxuICAgICAgICB9KTtcbiAgICAgICAgZGlzLmRpc3BhdGNoKHtcbiAgICAgICAgICAgIGFjdGlvbjogQWN0aW9uLkZvY3VzU2VuZE1lc3NhZ2VDb21wb3NlcixcbiAgICAgICAgICAgIGNvbnRleHQ6IHRoaXMuY29udGV4dC50aW1lbGluZVJlbmRlcmluZ1R5cGUsXG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHByaXZhdGUgZ2V0IGVkaXRvclJvb21LZXkoKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIGVkaXRvclJvb21LZXkodGhpcy5wcm9wcy5lZGl0U3RhdGUuZ2V0RXZlbnQoKS5nZXRSb29tSWQoKSEsIHRoaXMuY29udGV4dC50aW1lbGluZVJlbmRlcmluZ1R5cGUpO1xuICAgIH1cblxuICAgIHByaXZhdGUgZ2V0IGVkaXRvclN0YXRlS2V5KCk6IHN0cmluZyB7XG4gICAgICAgIHJldHVybiBlZGl0b3JTdGF0ZUtleSh0aGlzLnByb3BzLmVkaXRTdGF0ZS5nZXRFdmVudCgpLmdldElkKCkhKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGdldCBldmVudHMoKTogTWF0cml4RXZlbnRbXSB7XG4gICAgICAgIGNvbnN0IGxpdmVUaW1lbGluZUV2ZW50cyA9IHRoaXMuY29udGV4dC5saXZlVGltZWxpbmU/LmdldEV2ZW50cygpO1xuICAgICAgICBjb25zdCByb29tID0gdGhpcy5nZXRSb29tKCk7XG4gICAgICAgIGlmICghbGl2ZVRpbWVsaW5lRXZlbnRzIHx8ICFyb29tKSByZXR1cm4gW107XG4gICAgICAgIGNvbnN0IHBlbmRpbmdFdmVudHMgPSByb29tLmdldFBlbmRpbmdFdmVudHMoKTtcbiAgICAgICAgY29uc3QgaXNJblRocmVhZCA9IEJvb2xlYW4odGhpcy5wcm9wcy5lZGl0U3RhdGUuZ2V0RXZlbnQoKS5nZXRUaHJlYWQoKSk7XG4gICAgICAgIHJldHVybiBsaXZlVGltZWxpbmVFdmVudHMuY29uY2F0KGlzSW5UaHJlYWQgPyBbXSA6IHBlbmRpbmdFdmVudHMpO1xuICAgIH1cblxuICAgIHByaXZhdGUgY2FuY2VsRWRpdCA9ICgpOiB2b2lkID0+IHtcbiAgICAgICAgdGhpcy5lbmRFZGl0KCk7XG4gICAgfTtcblxuICAgIHByaXZhdGUgZ2V0IHNob3VsZFNhdmVTdG9yZWRFZGl0b3JTdGF0ZSgpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIGxvY2FsU3RvcmFnZS5nZXRJdGVtKHRoaXMuZWRpdG9yUm9vbUtleSkgIT09IG51bGw7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSByZXN0b3JlU3RvcmVkRWRpdG9yU3RhdGUocGFydENyZWF0b3I6IFBhcnRDcmVhdG9yKTogUGFydFtdIHwgdW5kZWZpbmVkIHtcbiAgICAgICAgY29uc3QganNvbiA9IGxvY2FsU3RvcmFnZS5nZXRJdGVtKHRoaXMuZWRpdG9yU3RhdGVLZXkpO1xuICAgICAgICBpZiAoanNvbikge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICBjb25zdCB7IHBhcnRzOiBzZXJpYWxpemVkUGFydHMgfSA9IEpTT04ucGFyc2UoanNvbik7XG4gICAgICAgICAgICAgICAgY29uc3QgcGFydHM6IFBhcnRbXSA9IHNlcmlhbGl6ZWRQYXJ0cy5tYXAoKHA6IFNlcmlhbGl6ZWRQYXJ0KSA9PiBwYXJ0Q3JlYXRvci5kZXNlcmlhbGl6ZVBhcnQocCkpO1xuICAgICAgICAgICAgICAgIHJldHVybiBwYXJ0cztcbiAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICBsb2dnZXIuZXJyb3IoXCJFcnJvciBwYXJzaW5nIGVkaXRpbmcgc3RhdGU6IFwiLCBlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgY2xlYXJQcmV2aW91c0VkaXQoKTogdm9pZCB7XG4gICAgICAgIGlmIChsb2NhbFN0b3JhZ2UuZ2V0SXRlbSh0aGlzLmVkaXRvclJvb21LZXkpKSB7XG4gICAgICAgICAgICBsb2NhbFN0b3JhZ2UucmVtb3ZlSXRlbShgbXhfZWRpdF9zdGF0ZV8ke2xvY2FsU3RvcmFnZS5nZXRJdGVtKHRoaXMuZWRpdG9yUm9vbUtleSl9YCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIHNhdmVTdG9yZWRFZGl0b3JTdGF0ZSA9ICgpOiB2b2lkID0+IHtcbiAgICAgICAgY29uc3QgaXRlbSA9IFNlbmRIaXN0b3J5TWFuYWdlci5jcmVhdGVJdGVtKHRoaXMubW9kZWwpO1xuICAgICAgICB0aGlzLmNsZWFyUHJldmlvdXNFZGl0KCk7XG4gICAgICAgIGxvY2FsU3RvcmFnZS5zZXRJdGVtKHRoaXMuZWRpdG9yUm9vbUtleSwgdGhpcy5wcm9wcy5lZGl0U3RhdGUuZ2V0RXZlbnQoKS5nZXRJZCgpISk7XG4gICAgICAgIGxvY2FsU3RvcmFnZS5zZXRJdGVtKHRoaXMuZWRpdG9yU3RhdGVLZXksIEpTT04uc3RyaW5naWZ5KGl0ZW0pKTtcbiAgICB9O1xuXG4gICAgcHJpdmF0ZSBpc0NvbnRlbnRNb2RpZmllZChuZXdDb250ZW50OiBSb29tTWVzc2FnZUV2ZW50Q29udGVudCk6IGJvb2xlYW4ge1xuICAgICAgICAvLyBpZiBub3RoaW5nIGhhcyBjaGFuZ2VkIHRoZW4gYmFpbFxuICAgICAgICBjb25zdCBvbGRDb250ZW50ID0gdGhpcy5wcm9wcy5lZGl0U3RhdGUuZ2V0RXZlbnQoKS5nZXRDb250ZW50PFJvb21NZXNzYWdlRXZlbnRDb250ZW50PigpO1xuICAgICAgICBpZiAoXG4gICAgICAgICAgICBvbGRDb250ZW50W1wibXNndHlwZVwiXSA9PT0gbmV3Q29udGVudFtcIm1zZ3R5cGVcIl0gJiZcbiAgICAgICAgICAgIG9sZENvbnRlbnRbXCJib2R5XCJdID09PSBuZXdDb250ZW50W1wiYm9keVwiXSAmJlxuICAgICAgICAgICAgKG9sZENvbnRlbnQgYXMgUm9vbU1lc3NhZ2VUZXh0RXZlbnRDb250ZW50KVtcImZvcm1hdFwiXSA9PT1cbiAgICAgICAgICAgICAgICAobmV3Q29udGVudCBhcyBSb29tTWVzc2FnZVRleHRFdmVudENvbnRlbnQpW1wiZm9ybWF0XCJdICYmXG4gICAgICAgICAgICAob2xkQ29udGVudCBhcyBSb29tTWVzc2FnZVRleHRFdmVudENvbnRlbnQpW1wiZm9ybWF0dGVkX2JvZHlcIl0gPT09XG4gICAgICAgICAgICAgICAgKG5ld0NvbnRlbnQgYXMgUm9vbU1lc3NhZ2VUZXh0RXZlbnRDb250ZW50KVtcImZvcm1hdHRlZF9ib2R5XCJdXG4gICAgICAgICkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIHByaXZhdGUgc2VuZEVkaXQgPSBhc3luYyAoKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgICAgIGlmICh0aGlzLnN0YXRlLnNhdmVEaXNhYmxlZCkgcmV0dXJuO1xuXG4gICAgICAgIGNvbnN0IGVkaXRlZEV2ZW50ID0gdGhpcy5wcm9wcy5lZGl0U3RhdGUuZ2V0RXZlbnQoKTtcblxuICAgICAgICBQb3N0aG9nQW5hbHl0aWNzLmluc3RhbmNlLnRyYWNrRXZlbnQ8Q29tcG9zZXJFdmVudD4oe1xuICAgICAgICAgICAgZXZlbnROYW1lOiBcIkNvbXBvc2VyXCIsXG4gICAgICAgICAgICBpc0VkaXRpbmc6IHRydWUsXG4gICAgICAgICAgICBtZXNzYWdlVHlwZTogXCJUZXh0XCIsXG4gICAgICAgICAgICBpblRocmVhZDogISFlZGl0ZWRFdmVudD8uZ2V0VGhyZWFkKCksXG4gICAgICAgICAgICBpc1JlcGx5OiAhIWVkaXRlZEV2ZW50LnJlcGx5RXZlbnRJZCxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gUmVwbGFjZSBlbW90aWNvbiBhdCB0aGUgZW5kIG9mIHRoZSBtZXNzYWdlXG4gICAgICAgIGlmIChTZXR0aW5nc1N0b3JlLmdldFZhbHVlKFwiTWVzc2FnZUNvbXBvc2VySW5wdXQuYXV0b1JlcGxhY2VFbW9qaVwiKSAmJiB0aGlzLmVkaXRvclJlZi5jdXJyZW50KSB7XG4gICAgICAgICAgICBjb25zdCBjYXJldCA9IHRoaXMuZWRpdG9yUmVmLmN1cnJlbnQuZ2V0Q2FyZXQoKTtcbiAgICAgICAgICAgIGNvbnN0IHBvc2l0aW9uID0gdGhpcy5tb2RlbC5wb3NpdGlvbkZvck9mZnNldChjYXJldC5vZmZzZXQsIGNhcmV0LmF0Tm9kZUVuZCk7XG4gICAgICAgICAgICB0aGlzLmVkaXRvclJlZi5jdXJyZW50LnJlcGxhY2VFbW90aWNvbihwb3NpdGlvbiwgUkVHRVhfRU1PVElDT04pO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGVkaXRDb250ZW50ID0gY3JlYXRlRWRpdENvbnRlbnQodGhpcy5tb2RlbCwgZWRpdGVkRXZlbnQsIHRoaXMucmVwbHlUb0V2ZW50KTtcbiAgICAgICAgY29uc3QgbmV3Q29udGVudCA9IGVkaXRDb250ZW50W1wibS5uZXdfY29udGVudFwiXSE7XG5cbiAgICAgICAgbGV0IHNob3VsZFNlbmQgPSB0cnVlO1xuXG4gICAgICAgIGlmIChuZXdDb250ZW50Py5ib2R5ID09PSBcIlwiKSB7XG4gICAgICAgICAgICB0aGlzLmNhbmNlbFByZXZpb3VzUGVuZGluZ0VkaXQoKTtcbiAgICAgICAgICAgIGNyZWF0ZVJlZGFjdEV2ZW50RGlhbG9nKHtcbiAgICAgICAgICAgICAgICBteEV2ZW50OiBlZGl0ZWRFdmVudCxcbiAgICAgICAgICAgICAgICBvbkNsb3NlRGlhbG9nOiAoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY2FuY2VsRWRpdCgpO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIElmIGNvbnRlbnQgaXMgbW9kaWZpZWQgdGhlbiBzZW5kIGFuIHVwZGF0ZWQgZXZlbnQgaW50byB0aGUgcm9vbVxuICAgICAgICBpZiAodGhpcy5pc0NvbnRlbnRNb2RpZmllZChuZXdDb250ZW50KSkge1xuICAgICAgICAgICAgY29uc3Qgcm9vbUlkID0gZWRpdGVkRXZlbnQuZ2V0Um9vbUlkKCkhO1xuICAgICAgICAgICAgaWYgKCFjb250YWluc0Vtb3RlKHRoaXMubW9kZWwpICYmIGlzU2xhc2hDb21tYW5kKHRoaXMubW9kZWwpKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgW2NtZCwgYXJncywgY29tbWFuZFRleHRdID0gZ2V0U2xhc2hDb21tYW5kKHRoaXMubW9kZWwpO1xuICAgICAgICAgICAgICAgIGlmIChjbWQpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgdGhyZWFkSWQgPSBlZGl0ZWRFdmVudD8uZ2V0VGhyZWFkKCk/LmlkIHx8IG51bGw7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IFtjb250ZW50LCBjb21tYW5kU3VjY2Vzc2Z1bF0gPSBhd2FpdCBydW5TbGFzaENvbW1hbmQoXG4gICAgICAgICAgICAgICAgICAgICAgICBNYXRyaXhDbGllbnRQZWcuc2FmZUdldCgpLFxuICAgICAgICAgICAgICAgICAgICAgICAgY21kLFxuICAgICAgICAgICAgICAgICAgICAgICAgYXJncyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHJvb21JZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIHRocmVhZElkLFxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICBpZiAoIWNvbW1hbmRTdWNjZXNzZnVsKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47IC8vIGVycm9yZWRcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIGlmIChjbWQuY2F0ZWdvcnkgPT09IENvbW1hbmRDYXRlZ29yaWVzLm1lc3NhZ2VzIHx8IGNtZC5jYXRlZ29yeSA9PT0gQ29tbWFuZENhdGVnb3JpZXMuZWZmZWN0cykge1xuICAgICAgICAgICAgICAgICAgICAgICAgZWRpdENvbnRlbnRbXCJtLm5ld19jb250ZW50XCJdID0gY29udGVudCE7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzaG91bGRTZW5kID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBzZW5kQW55d2F5ID0gYXdhaXQgc2hvdWxkU2VuZEFueXdheShjb21tYW5kVGV4dCk7XG4gICAgICAgICAgICAgICAgICAgIC8vIHJlLWZvY3VzIHRoZSBjb21wb3NlciBhZnRlciBRdWVzdGlvbkRpYWxvZyBpcyBjbG9zZWRcbiAgICAgICAgICAgICAgICAgICAgZGlzLmRpc3BhdGNoKHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGFjdGlvbjogQWN0aW9uLkZvY3VzQUNvbXBvc2VyLFxuICAgICAgICAgICAgICAgICAgICAgICAgY29udGV4dDogdGhpcy5jb250ZXh0LnRpbWVsaW5lUmVuZGVyaW5nVHlwZSxcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIC8vIGlmICFzZW5kQW55d2F5IGJhaWwgdG8gbGV0IHRoZSB1c2VyIGVkaXQgdGhlIGNvbXBvc2VyIGFuZCB0cnkgYWdhaW5cbiAgICAgICAgICAgICAgICAgICAgaWYgKCFzZW5kQW55d2F5KSByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHNob3VsZFNlbmQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmNhbmNlbFByZXZpb3VzUGVuZGluZ0VkaXQoKTtcblxuICAgICAgICAgICAgICAgIGNvbnN0IGV2ZW50ID0gdGhpcy5wcm9wcy5lZGl0U3RhdGUuZ2V0RXZlbnQoKTtcbiAgICAgICAgICAgICAgICBjb25zdCB0aHJlYWRJZCA9IGV2ZW50LnRocmVhZFJvb3RJZCB8fCBudWxsO1xuXG4gICAgICAgICAgICAgICAgdGhpcy5wcm9wcy5teENsaWVudC5zZW5kTWVzc2FnZShyb29tSWQsIHRocmVhZElkLCBlZGl0Q29udGVudCk7XG4gICAgICAgICAgICAgICAgZGlzLmRpc3BhdGNoKHsgYWN0aW9uOiBcIm1lc3NhZ2Vfc2VudFwiIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5lbmRFZGl0KCk7XG4gICAgfTtcblxuICAgIHByaXZhdGUgY2FuY2VsUHJldmlvdXNQZW5kaW5nRWRpdCgpOiB2b2lkIHtcbiAgICAgICAgY29uc3Qgb3JpZ2luYWxFdmVudCA9IHRoaXMucHJvcHMuZWRpdFN0YXRlLmdldEV2ZW50KCk7XG4gICAgICAgIGNvbnN0IHByZXZpb3VzRWRpdCA9IG9yaWdpbmFsRXZlbnQucmVwbGFjaW5nRXZlbnQoKTtcbiAgICAgICAgaWYgKFxuICAgICAgICAgICAgcHJldmlvdXNFZGl0ICYmXG4gICAgICAgICAgICAocHJldmlvdXNFZGl0LnN0YXR1cyA9PT0gRXZlbnRTdGF0dXMuUVVFVUVEIHx8IHByZXZpb3VzRWRpdC5zdGF0dXMgPT09IEV2ZW50U3RhdHVzLk5PVF9TRU5UKVxuICAgICAgICApIHtcbiAgICAgICAgICAgIHRoaXMucHJvcHMubXhDbGllbnQuY2FuY2VsUGVuZGluZ0V2ZW50KHByZXZpb3VzRWRpdCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwdWJsaWMgY29tcG9uZW50V2lsbFVubW91bnQoKTogdm9pZCB7XG4gICAgICAgIC8vIHN0b3JlIGNhcmV0IGFuZCBzZXJpYWxpemVkIHBhcnRzIGluIHRoZVxuICAgICAgICAvLyBlZGl0b3JzdGF0ZSBzbyBpdCBjYW4gYmUgcmVzdG9yZWQgd2hlbiB0aGUgcmVtb3RlIGVjaG8gZXZlbnQgdGlsZSBnZXRzIHJlbmRlcmVkXG4gICAgICAgIC8vIGluIGNhc2Ugd2UncmUgY3VycmVudGx5IGVkaXRpbmcgYSBwZW5kaW5nIGV2ZW50XG4gICAgICAgIGNvbnN0IHNlbCA9IGRvY3VtZW50LmdldFNlbGVjdGlvbigpITtcbiAgICAgICAgbGV0IGNhcmV0OiBEb2N1bWVudE9mZnNldCB8IHVuZGVmaW5lZDtcbiAgICAgICAgaWYgKHNlbC5mb2N1c05vZGUgJiYgdGhpcy5lZGl0b3JSZWYuY3VycmVudD8uZWRpdG9yUmVmLmN1cnJlbnQpIHtcbiAgICAgICAgICAgIGNhcmV0ID0gZ2V0Q2FyZXRPZmZzZXRBbmRUZXh0KHRoaXMuZWRpdG9yUmVmLmN1cnJlbnQuZWRpdG9yUmVmLmN1cnJlbnQsIHNlbCkuY2FyZXQ7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgcGFydHMgPSB0aGlzLm1vZGVsLnNlcmlhbGl6ZVBhcnRzKCk7XG4gICAgICAgIC8vIGlmIGNhcmV0IGlzIHVuZGVmaW5lZCBiZWNhdXNlIGZvciBzb21lIHJlYXNvbiB0aGVyZSBpc24ndCBhIHZhbGlkIHNlbGVjdGlvbixcbiAgICAgICAgLy8gdGhlbiB3aGVuIG1vdW50aW5nIHRoZSBlZGl0b3IgYWdhaW4gd2l0aCB0aGUgc2FtZSBlZGl0b3Igc3RhdGUsXG4gICAgICAgIC8vIGl0IHdpbGwgc2V0IHRoZSBjdXJzb3IgYXQgdGhlIGVuZC5cbiAgICAgICAgdGhpcy5wcm9wcy5lZGl0U3RhdGUuc2V0RWRpdG9yU3RhdGUoY2FyZXQgPz8gbnVsbCwgcGFydHMpO1xuICAgICAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihcImJlZm9yZXVubG9hZFwiLCB0aGlzLnNhdmVTdG9yZWRFZGl0b3JTdGF0ZSk7XG4gICAgICAgIGlmICh0aGlzLnNob3VsZFNhdmVTdG9yZWRFZGl0b3JTdGF0ZSkge1xuICAgICAgICAgICAgdGhpcy5zYXZlU3RvcmVkRWRpdG9yU3RhdGUoKTtcbiAgICAgICAgfVxuICAgICAgICBkaXMudW5yZWdpc3Rlcih0aGlzLmRpc3BhdGNoZXJSZWYpO1xuICAgIH1cblxuICAgIHByaXZhdGUgY3JlYXRlRWRpdG9yTW9kZWwoKTogYm9vbGVhbiB7XG4gICAgICAgIGNvbnN0IHsgZWRpdFN0YXRlIH0gPSB0aGlzLnByb3BzO1xuICAgICAgICBjb25zdCByb29tID0gdGhpcy5nZXRSb29tKCk7XG4gICAgICAgIGNvbnN0IHBhcnRDcmVhdG9yID0gbmV3IENvbW1hbmRQYXJ0Q3JlYXRvcihyb29tLCB0aGlzLnByb3BzLm14Q2xpZW50KTtcblxuICAgICAgICBsZXQgcGFydHM6IFBhcnRbXTtcbiAgICAgICAgbGV0IGlzUmVzdG9yZWQgPSBmYWxzZTtcbiAgICAgICAgaWYgKGVkaXRTdGF0ZS5oYXNFZGl0b3JTdGF0ZSgpKSB7XG4gICAgICAgICAgICAvLyBpZiByZXN0b3Jpbmcgc3RhdGUgZnJvbSBhIHByZXZpb3VzIGVkaXRvcixcbiAgICAgICAgICAgIC8vIHJlc3RvcmUgc2VyaWFsaXplZCBwYXJ0cyBmcm9tIHRoZSBzdGF0ZVxuICAgICAgICAgICAgLy8gKGVkaXRTdGF0ZS5oYXNFZGl0b3JTdGF0ZSgpIGNoZWNrcyBnZXRTZXJpYWxpemVkUGFydHMgaXMgbm90IG51bGwpXG4gICAgICAgICAgICBwYXJ0cyA9IGZpbHRlckJvb2xlYW48UGFydD4oZWRpdFN0YXRlLmdldFNlcmlhbGl6ZWRQYXJ0cygpIS5tYXAoKHApID0+IHBhcnRDcmVhdG9yLmRlc2VyaWFsaXplUGFydChwKSkpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gb3RoZXJ3aXNlLCBlaXRoZXIgcmVzdG9yZSBzZXJpYWxpemVkIHBhcnRzIGZyb20gbG9jYWxTdG9yYWdlIG9yIHBhcnNlIHRoZSBib2R5IG9mIHRoZSBldmVudFxuICAgICAgICAgICAgY29uc3QgcmVzdG9yZWRQYXJ0cyA9IHRoaXMucmVzdG9yZVN0b3JlZEVkaXRvclN0YXRlKHBhcnRDcmVhdG9yKTtcbiAgICAgICAgICAgIHBhcnRzID1cbiAgICAgICAgICAgICAgICByZXN0b3JlZFBhcnRzIHx8XG4gICAgICAgICAgICAgICAgcGFyc2VFdmVudChlZGl0U3RhdGUuZ2V0RXZlbnQoKSwgcGFydENyZWF0b3IsIHtcbiAgICAgICAgICAgICAgICAgICAgc2hvdWxkRXNjYXBlOiBTZXR0aW5nc1N0b3JlLmdldFZhbHVlKFwiTWVzc2FnZUNvbXBvc2VySW5wdXQudXNlTWFya2Rvd25cIiksXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAg