UNPKG

matrix-react-sdk

Version:
653 lines (632 loc) 113 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.SendMessageComposer = exports.EDITOR_STATE_STORAGE_PREFIX = void 0; exports.attachMentions = attachMentions; exports.attachRelation = attachRelation; exports.createMessageContent = createMessageContent; exports.default = void 0; exports.isQuickReaction = isQuickReaction; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _react = _interopRequireWildcard(require("react")); var _matrix = require("matrix-js-sdk/src/matrix"); var _lodash = require("lodash"); var _logger = require("matrix-js-sdk/src/logger"); var _dispatcher = _interopRequireDefault(require("../../../dispatcher/dispatcher")); var _model = _interopRequireDefault(require("../../../editor/model")); var _serialize = require("../../../editor/serialize"); var _BasicMessageComposer = _interopRequireWildcard(require("./BasicMessageComposer")); var _parts2 = require("../../../editor/parts"); var _EventUtils = require("../../../utils/EventUtils"); var _SendHistoryManager = _interopRequireDefault(require("../../../SendHistoryManager")); var _SlashCommands = require("../../../SlashCommands"); var _ContentMessages = _interopRequireDefault(require("../../../ContentMessages")); var _MatrixClientContext = require("../../../contexts/MatrixClientContext"); var _actions = require("../../../dispatcher/actions"); var _utils = require("../../../effects/utils"); var _effects = require("../../../effects"); var _MatrixClientPeg = require("../../../MatrixClientPeg"); var _KeyBindingsManager = require("../../../KeyBindingsManager"); var _SettingsStore = _interopRequireDefault(require("../../../settings/SettingsStore")); var _sendTimePerformanceMetrics = require("../../../sendTimePerformanceMetrics"); var _RoomContext = _interopRequireWildcard(require("../../../contexts/RoomContext")); var _position = _interopRequireDefault(require("../../../editor/position")); var _ComposerInsertPayload = require("../../../dispatcher/payloads/ComposerInsertPayload"); var _commands = require("../../../editor/commands"); var _KeyboardShortcuts = require("../../../accessibility/KeyboardShortcuts"); var _PosthogAnalytics = require("../../../PosthogAnalytics"); var _Reply = require("../../../utils/Reply"); var _localRoom = require("../../../utils/local-room"); var _blobs = require("../../../utils/blobs"); var _HtmlUtils = require("../../../HtmlUtils"); 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; } function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } /* Copyright 2024 New Vector Ltd. Copyright 2019-2023 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. */ // The prefix used when persisting editor drafts to localstorage. const EDITOR_STATE_STORAGE_PREFIX = exports.EDITOR_STATE_STORAGE_PREFIX = "mx_cider_state_"; /** * Build the mentions information based on the editor model (and any related events): * * 1. Search the model parts for room or user pills and fill in the mentions object. * 2. If this is a reply to another event, include any user mentions from that * (but do not include a room mention). * * @param sender - The Matrix ID of the user sending the event. * @param content - The event content. * @param model - The editor model to search for mentions, null if there is no editor. * @param replyToEvent - The event being replied to or undefined if it is not a reply. * @param editedContent - The content of the parent event being edited. */ function attachMentions(sender, content, model, replyToEvent, editedContent = null) { // We always attach the mentions even if the home server doesn't yet support // intentional mentions. This is safe because m.mentions is an additive change // that should simply be ignored by incapable home servers. // The mentions property *always* gets included to disable legacy push rules. const mentions = content["m.mentions"] = {}; const userMentions = new Set(); let roomMention = false; // If there's a reply, initialize the mentioned users as the sender of that // event + any mentioned users in that event. if (replyToEvent) { userMentions.add(replyToEvent.sender.userId); // TODO What do we do if the reply event *doeesn't* have this property? // Try to fish out replies from the contents? const userIds = replyToEvent.getContent()["m.mentions"]?.user_ids; if (Array.isArray(userIds)) { userIds.forEach(userId => userMentions.add(userId)); } } // If user provided content is available, check to see if any users are mentioned. if (model) { // Add any mentioned users in the current content. for (const part of model.parts) { if (part.type === _parts2.Type.UserPill) { userMentions.add(part.resourceId); } else if (part.type === _parts2.Type.AtRoomPill) { roomMention = true; } } } // Ensure the *current* user isn't listed in the mentioned users. userMentions.delete(sender); // Finally, if this event is editing a previous event, only include users who // were not previously mentioned and a room mention if the previous event was // not a room mention. if (editedContent) { // First, the new event content gets the *full* set of users. const newContent = content["m.new_content"]; const newMentions = newContent["m.mentions"] = {}; // Only include the users/room if there is any content. if (userMentions.size) { newMentions.user_ids = [...userMentions]; } if (roomMention) { newMentions.room = true; } // Fetch the mentions from the original event and remove any previously // mentioned users. const prevMentions = editedContent["m.mentions"]; if (Array.isArray(prevMentions?.user_ids)) { prevMentions.user_ids.forEach(userId => userMentions.delete(userId)); } // If the original event mentioned the room, nothing to do here. if (prevMentions?.room) { roomMention = false; } } // Only include the users/room if there is any content. if (userMentions.size) { mentions.user_ids = [...userMentions]; } if (roomMention) { mentions.room = true; } } // Merges favouring the given relation function attachRelation(content, relation) { if (relation) { content["m.relates_to"] = _objectSpread(_objectSpread({}, content["m.relates_to"] || {}), relation); } } // exported for tests function createMessageContent(sender, model, replyToEvent, relation, permalinkCreator, includeReplyLegacyFallback = true) { const isEmote = (0, _serialize.containsEmote)(model); if (isEmote) { model = (0, _serialize.stripEmoteCommand)(model); } if ((0, _serialize.startsWith)(model, "//")) { model = (0, _serialize.stripPrefix)(model, "/"); } model = (0, _serialize.unescapeMessage)(model); const body = (0, _serialize.textSerialize)(model); const content = { msgtype: isEmote ? _matrix.MsgType.Emote : _matrix.MsgType.Text, body: body }; const formattedBody = (0, _serialize.htmlSerializeIfNeeded)(model, { forceHTML: !!replyToEvent, useMarkdown: _SettingsStore.default.getValue("MessageComposerInput.useMarkdown") }); if (formattedBody) { content.format = "org.matrix.custom.html"; content.formatted_body = formattedBody; } // Build the mentions property and add it to the event content. attachMentions(sender, content, model, replyToEvent); attachRelation(content, relation); if (replyToEvent) { (0, _Reply.addReplyToMessageContent)(content, replyToEvent, { permalinkCreator, includeLegacyFallback: includeReplyLegacyFallback }); } return content; } // exported for tests function isQuickReaction(model) { const parts = model.parts; if (parts.length == 0) return false; const text = (0, _serialize.textSerialize)(model); // shortcut takes the form "+:emoji:" or "+ :emoji:"" // can be in 1 or 2 parts if (parts.length <= 2) { const hasShortcut = text.startsWith("+") || text.startsWith("+ "); const emojiMatch = text.match(_HtmlUtils.EMOJI_REGEX); if (hasShortcut && emojiMatch && emojiMatch.length == 1) { return emojiMatch[0] === text.substring(1) || emojiMatch[0] === text.substring(2); } } return false; } class SendMessageComposer extends _react.default.Component { constructor(props, context) { super(props, context); (0, _defineProperty2.default)(this, "prepareToEncrypt", void 0); (0, _defineProperty2.default)(this, "editorRef", /*#__PURE__*/(0, _react.createRef)()); (0, _defineProperty2.default)(this, "model", void 0); (0, _defineProperty2.default)(this, "currentlyComposedEditorState", null); (0, _defineProperty2.default)(this, "dispatcherRef", void 0); (0, _defineProperty2.default)(this, "sendHistoryManager", void 0); (0, _defineProperty2.default)(this, "onKeyDown", event => { // ignore any keypress while doing IME compositions if (this.editorRef.current?.isComposing(event)) { return; } const replyingToThread = this.props.relation?.key === _matrix.THREAD_RELATION_TYPE.name; const action = (0, _KeyBindingsManager.getKeyBindingsManager)().getMessageComposerAction(event); switch (action) { case _KeyboardShortcuts.KeyBindingAction.SendMessage: this.sendMessage(); event.preventDefault(); break; case _KeyboardShortcuts.KeyBindingAction.SelectPrevSendHistory: case _KeyboardShortcuts.KeyBindingAction.SelectNextSendHistory: { // Try select composer history const selected = this.selectSendHistory(action === _KeyboardShortcuts.KeyBindingAction.SelectPrevSendHistory); if (selected) { // We're selecting history, so prevent the key event from doing anything else event.preventDefault(); } break; } case _KeyboardShortcuts.KeyBindingAction.ShowStickerPicker: { if (!_SettingsStore.default.getValue("MessageComposerInput.showStickersButton")) { return; // Do nothing if there is no Stickers button } this.props.toggleStickerPickerOpen(); event.preventDefault(); break; } case _KeyboardShortcuts.KeyBindingAction.EditPrevMessage: // selection must be collapsed and caret at start if (this.editorRef.current?.isSelectionCollapsed() && this.editorRef.current?.isCaretAtStart()) { const events = this.context.liveTimeline?.getEvents().concat(replyingToThread ? [] : this.props.room.getPendingEvents()); const editEvent = events ? (0, _EventUtils.findEditableEvent)({ events, isForward: false, matrixClient: _MatrixClientPeg.MatrixClientPeg.safeGet() }) : undefined; if (editEvent) { // We're selecting history, so prevent the key event from doing anything else event.preventDefault(); _dispatcher.default.dispatch({ action: _actions.Action.EditEvent, event: editEvent, timelineRenderingType: this.context.timelineRenderingType }); } } break; case _KeyboardShortcuts.KeyBindingAction.CancelReplyOrEdit: if (!!this.context.replyToEvent) { _dispatcher.default.dispatch({ action: "reply_to_event", event: null, context: this.context.timelineRenderingType }); event.preventDefault(); event.stopPropagation(); } break; } }); // should save state when editor has contents or reply is open (0, _defineProperty2.default)(this, "shouldSaveStoredEditorState", () => { return !this.model.isEmpty || !!this.props.replyToEvent; }); (0, _defineProperty2.default)(this, "saveStoredEditorState", () => { if (this.shouldSaveStoredEditorState()) { const item = _SendHistoryManager.default.createItem(this.model, this.props.replyToEvent); localStorage.setItem(this.editorStateKey, JSON.stringify(item)); } else { this.clearStoredEditorState(); } }); (0, _defineProperty2.default)(this, "onAction", payload => { // don't let the user into the composer if it is disabled - all of these branches lead // to the cursor being in the composer if (this.props.disabled) return; switch (payload.action) { case "reply_to_event": case _actions.Action.FocusSendMessageComposer: if ((payload.context ?? _RoomContext.TimelineRenderingType.Room) === this.context.timelineRenderingType) { this.editorRef.current?.focus(); } break; case _actions.Action.ComposerInsert: if (payload.timelineRenderingType !== this.context.timelineRenderingType) break; if (payload.composerType !== _ComposerInsertPayload.ComposerType.Send) break; 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); } break; } }); (0, _defineProperty2.default)(this, "onPaste", (event, data) => { // Prioritize text on the clipboard over files if RTF is present as Office on macOS puts a bitmap // in the clipboard as well as the content being copied. Modern versions of Office seem to not do this anymore. // We check text/rtf instead of text/plain as when copy+pasting a file from Finder or Gnome Image Viewer // it puts the filename in as text/plain which we want to ignore. if (data.files.length && !data.types.includes("text/rtf")) { _ContentMessages.default.sharedInstance().sendContentListToRoom(Array.from(data.files), this.props.room.roomId, this.props.relation, this.props.mxClient, this.context.timelineRenderingType); return true; // to skip internal onPaste handler } // Safari `Insert from iPhone or iPad` // data.getData("text/html") returns a string like: <img src="blob:https://..."> if (data.types.includes("text/html")) { const imgElementStr = data.getData("text/html"); const parser = new DOMParser(); const imgDoc = parser.parseFromString(imgElementStr, "text/html"); if (imgDoc.getElementsByTagName("img").length !== 1 || !imgDoc.querySelector("img")?.src.startsWith("blob:") || imgDoc.childNodes.length !== 1) { console.log("Failed to handle pasted content as Safari inserted content"); // Fallback to internal onPaste handler return false; } const imgSrc = imgDoc.querySelector("img").src; fetch(imgSrc).then(response => { response.blob().then(imgBlob => { const type = imgBlob.type; const safetype = (0, _blobs.getBlobSafeMimeType)(type); const ext = type.split("/")[1]; const parts = response.url.split("/"); const filename = parts[parts.length - 1]; const file = new File([imgBlob], filename + "." + ext, { type: safetype }); _ContentMessages.default.sharedInstance().sendContentToRoom(file, this.props.room.roomId, this.props.relation, this.props.mxClient, this.context.replyToEvent); }, error => { console.log(error); }); }, error => { console.log(error); }); // Skip internal onPaste handler return true; } return false; }); (0, _defineProperty2.default)(this, "onChange", (selection, inputType, diff) => { // We call this in here rather than onKeyDown as that would trip it on global shortcuts e.g. Ctrl-k also if (!!diff) { this.prepareToEncrypt?.(); } this.props.onChange?.(this.model); }); (0, _defineProperty2.default)(this, "focusComposer", () => { this.editorRef.current?.focus(); }); if (this.props.mxClient.isCryptoEnabled() && this.props.mxClient.isRoomEncrypted(this.props.room.roomId)) { this.prepareToEncrypt = (0, _lodash.throttle)(() => { this.props.mxClient.getCrypto()?.prepareToEncrypt(this.props.room); }, 60000, { leading: true, trailing: false }); } window.addEventListener("beforeunload", this.saveStoredEditorState); const partCreator = new _parts2.CommandPartCreator(this.props.room, this.props.mxClient); const _parts = this.restoreStoredEditorState(partCreator) || []; this.model = new _model.default(_parts, partCreator); this.dispatcherRef = _dispatcher.default.register(this.onAction); this.sendHistoryManager = new _SendHistoryManager.default(this.props.room.roomId, "mx_cider_history_"); } componentDidUpdate(prevProps) { const replyingToThread = this.props.relation?.key === _matrix.THREAD_RELATION_TYPE.name; const differentEventTarget = this.props.relation?.event_id !== prevProps.relation?.event_id; const threadChanged = replyingToThread && differentEventTarget; if (threadChanged) { const partCreator = new _parts2.CommandPartCreator(this.props.room, this.props.mxClient); const parts = this.restoreStoredEditorState(partCreator) || []; this.model.reset(parts); this.editorRef.current?.focus(); } } // we keep sent messages/commands in a separate history (separate from undo history) // so you can alt+up/down in them selectSendHistory(up) { const delta = up ? -1 : 1; // True if we are not currently selecting history, but composing a message if (this.sendHistoryManager.currentIndex === this.sendHistoryManager.history.length) { // We can't go any further - there isn't any more history, so nop. if (!up) { return false; } this.currentlyComposedEditorState = this.model.serializeParts(); } else if (this.currentlyComposedEditorState && this.sendHistoryManager.currentIndex + delta === this.sendHistoryManager.history.length) { // True when we return to the message being composed currently this.model.reset(this.currentlyComposedEditorState); this.sendHistoryManager.currentIndex = this.sendHistoryManager.history.length; return true; } const { parts, replyEventId } = this.sendHistoryManager.getItem(delta); _dispatcher.default.dispatch({ action: "reply_to_event", event: replyEventId ? this.props.room.findEventById(replyEventId) : null, context: this.context.timelineRenderingType }); if (parts) { this.model.reset(parts); this.editorRef.current?.focus(); } return true; } sendQuickReaction() { const timeline = this.context.liveTimeline; if (!timeline) return; const events = timeline.getEvents(); const reaction = this.model.parts[1].text; for (let i = events.length - 1; i >= 0; i--) { if (events[i].getType() === _matrix.EventType.RoomMessage) { let shouldReact = true; const lastMessage = events[i]; const userId = _MatrixClientPeg.MatrixClientPeg.safeGet().getSafeUserId(); const messageReactions = this.props.room.relations.getChildEventsForEvent(lastMessage.getId(), _matrix.RelationType.Annotation, _matrix.EventType.Reaction); // if we have already sent this reaction, don't redact but don't re-send if (messageReactions) { const myReactionEvents = messageReactions.getAnnotationsBySender()?.[userId] || new Set(); const myReactionKeys = [...myReactionEvents].filter(event => !event.isRedacted()).map(event => event.getRelation()?.key); shouldReact = !myReactionKeys.includes(reaction); } if (shouldReact) { _MatrixClientPeg.MatrixClientPeg.safeGet().sendEvent(lastMessage.getRoomId(), _matrix.EventType.Reaction, { "m.relates_to": { rel_type: _matrix.RelationType.Annotation, event_id: lastMessage.getId(), key: reaction } }); _dispatcher.default.dispatch({ action: "message_sent" }); } break; } } } async sendMessage() { const model = this.model; if (model.isEmpty) { return; } const posthogEvent = { eventName: "Composer", isEditing: false, messageType: "Text", isReply: !!this.props.replyToEvent, inThread: this.props.relation?.rel_type === _matrix.THREAD_RELATION_TYPE.name }; if (posthogEvent.inThread && this.props.relation.event_id) { const threadRoot = this.props.room.findEventById(this.props.relation.event_id); posthogEvent.startsThread = threadRoot?.getThread()?.events.length === 1; } _PosthogAnalytics.PosthogAnalytics.instance.trackEvent(posthogEvent); // Replace emoticon at the end of the message if (_SettingsStore.default.getValue("MessageComposerInput.autoReplaceEmoji")) { const indexOfLastPart = model.parts.length - 1; const positionInLastPart = model.parts[indexOfLastPart].text.length; this.editorRef.current?.replaceEmoticon(new _position.default(indexOfLastPart, positionInLastPart), _BasicMessageComposer.REGEX_EMOTICON); } const replyToEvent = this.props.replyToEvent; let shouldSend = true; let content = null; if (!(0, _serialize.containsEmote)(model) && (0, _commands.isSlashCommand)(this.model)) { const [cmd, args, commandText] = (0, _commands.getSlashCommand)(this.model); if (cmd) { const threadId = this.props.relation?.rel_type === _matrix.THREAD_RELATION_TYPE.name ? this.props.relation?.event_id : null; let commandSuccessful; [content, commandSuccessful] = await (0, _commands.runSlashCommand)(_MatrixClientPeg.MatrixClientPeg.safeGet(), cmd, args, this.props.room.roomId, threadId ?? null); if (!commandSuccessful) { return; // errored } if (content && [_SlashCommands.CommandCategories.messages, _SlashCommands.CommandCategories.effects].includes(cmd.category)) { // Attach any mentions which might be contained in the command content. attachMentions(this.props.mxClient.getSafeUserId(), content, model, replyToEvent); attachRelation(content, this.props.relation); if (replyToEvent) { (0, _Reply.addReplyToMessageContent)(content, replyToEvent, { permalinkCreator: this.props.permalinkCreator, // Exclude the legacy fallback for custom event types such as those used by /fireworks includeLegacyFallback: content.msgtype?.startsWith("m.") ?? true }); } } 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 (isQuickReaction(model)) { shouldSend = false; this.sendQuickReaction(); } if (shouldSend) { const { roomId } = this.props.room; if (!content) { content = createMessageContent(this.props.mxClient.getSafeUserId(), model, replyToEvent, this.props.relation, this.props.permalinkCreator, this.props.includeReplyLegacyFallback); } // don't bother sending an empty message if (!content.body.trim()) return; if (_SettingsStore.default.getValue("Performance.addSendMessageTimingMetadata")) { (0, _sendTimePerformanceMetrics.decorateStartSendingTime)(content); } const threadId = this.props.relation?.rel_type === _matrix.THREAD_RELATION_TYPE.name ? this.props.relation.event_id : null; const prom = (0, _localRoom.doMaybeLocalRoomAction)(roomId, actualRoomId => this.props.mxClient.sendMessage(actualRoomId, threadId ?? null, content), this.props.mxClient); if (replyToEvent) { // Clear reply_to_event as we put the message into the queue // if the send fails, retry will handle resending. _dispatcher.default.dispatch({ action: "reply_to_event", event: null, context: this.context.timelineRenderingType }); } _dispatcher.default.dispatch({ action: "message_sent" }); _effects.CHAT_EFFECTS.forEach(effect => { if ((0, _utils.containsEmoji)(content, effect.emojis)) { // For initial threads launch, chat effects are disabled // see #19731 const isNotThread = this.props.relation?.rel_type !== _matrix.THREAD_RELATION_TYPE.name; if (isNotThread) { _dispatcher.default.dispatch({ action: `effects.${effect.command}` }); } } }); if (_SettingsStore.default.getValue("Performance.addSendMessageTimingMetadata")) { prom.then(resp => { (0, _sendTimePerformanceMetrics.sendRoundTripMetric)(this.props.mxClient, roomId, resp.event_id); }); } } this.sendHistoryManager.save(model, replyToEvent); // clear composer model.reset([]); this.editorRef.current?.clearUndoHistory(); this.editorRef.current?.focus(); this.clearStoredEditorState(); if (shouldSend && _SettingsStore.default.getValue("scrollToBottomOnMessageSent")) { _dispatcher.default.dispatch({ action: "scroll_to_bottom", timelineRenderingType: this.context.timelineRenderingType }); } } componentWillUnmount() { _dispatcher.default.unregister(this.dispatcherRef); window.removeEventListener("beforeunload", this.saveStoredEditorState); this.saveStoredEditorState(); } get editorStateKey() { let key = EDITOR_STATE_STORAGE_PREFIX + this.props.room.roomId; if (this.props.relation?.rel_type === _matrix.THREAD_RELATION_TYPE.name) { key += `_${this.props.relation.event_id}`; } return key; } clearStoredEditorState() { localStorage.removeItem(this.editorStateKey); } restoreStoredEditorState(partCreator) { const replyingToThread = this.props.relation?.key === _matrix.THREAD_RELATION_TYPE.name; if (replyingToThread) { return null; } const json = localStorage.getItem(this.editorStateKey); if (json) { try { const { parts: serializedParts, replyEventId } = JSON.parse(json); const parts = serializedParts.map(p => partCreator.deserializePart(p)); if (replyEventId) { _dispatcher.default.dispatch({ action: "reply_to_event", event: this.props.room.findEventById(replyEventId), context: this.context.timelineRenderingType }); } return parts; } catch (e) { _logger.logger.error(e); } } return null; } render() { const threadId = this.props.relation?.rel_type === _matrix.THREAD_RELATION_TYPE.name ? this.props.relation.event_id : undefined; return /*#__PURE__*/_react.default.createElement("div", { className: "mx_SendMessageComposer", onClick: this.focusComposer, onKeyDown: this.onKeyDown }, /*#__PURE__*/_react.default.createElement(_BasicMessageComposer.default, { onChange: this.onChange, ref: this.editorRef, model: this.model, room: this.props.room, threadId: threadId, label: this.props.placeholder, placeholder: this.props.placeholder, onPaste: this.onPaste, disabled: this.props.disabled })); } } exports.SendMessageComposer = SendMessageComposer; (0, _defineProperty2.default)(SendMessageComposer, "contextType", _RoomContext.default); (0, _defineProperty2.default)(SendMessageComposer, "defaultProps", { includeReplyLegacyFallback: true }); const SendMessageComposerWithMatrixClient = (0, _MatrixClientContext.withMatrixClientHOC)(SendMessageComposer); var _default = exports.default = SendMessageComposerWithMatrixClient; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfcmVhY3QiLCJfaW50ZXJvcFJlcXVpcmVXaWxkY2FyZCIsInJlcXVpcmUiLCJfbWF0cml4IiwiX2xvZGFzaCIsIl9sb2dnZXIiLCJfZGlzcGF0Y2hlciIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJfbW9kZWwiLCJfc2VyaWFsaXplIiwiX0Jhc2ljTWVzc2FnZUNvbXBvc2VyIiwiX3BhcnRzMiIsIl9FdmVudFV0aWxzIiwiX1NlbmRIaXN0b3J5TWFuYWdlciIsIl9TbGFzaENvbW1hbmRzIiwiX0NvbnRlbnRNZXNzYWdlcyIsIl9NYXRyaXhDbGllbnRDb250ZXh0IiwiX2FjdGlvbnMiLCJfdXRpbHMiLCJfZWZmZWN0cyIsIl9NYXRyaXhDbGllbnRQZWciLCJfS2V5QmluZGluZ3NNYW5hZ2VyIiwiX1NldHRpbmdzU3RvcmUiLCJfc2VuZFRpbWVQZXJmb3JtYW5jZU1ldHJpY3MiLCJfUm9vbUNvbnRleHQiLCJfcG9zaXRpb24iLCJfQ29tcG9zZXJJbnNlcnRQYXlsb2FkIiwiX2NvbW1hbmRzIiwiX0tleWJvYXJkU2hvcnRjdXRzIiwiX1Bvc3Rob2dBbmFseXRpY3MiLCJfUmVwbHkiLCJfbG9jYWxSb29tIiwiX2Jsb2JzIiwiX0h0bWxVdGlscyIsIl9nZXRSZXF1aXJlV2lsZGNhcmRDYWNoZSIsImUiLCJXZWFrTWFwIiwiciIsInQiLCJfX2VzTW9kdWxlIiwiZGVmYXVsdCIsImhhcyIsImdldCIsIm4iLCJfX3Byb3RvX18iLCJhIiwiT2JqZWN0IiwiZGVmaW5lUHJvcGVydHkiLCJnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IiLCJ1IiwiaGFzT3duUHJvcGVydHkiLCJjYWxsIiwiaSIsInNldCIsIm93bktleXMiLCJrZXlzIiwiZ2V0T3duUHJvcGVydHlTeW1ib2xzIiwibyIsImZpbHRlciIsImVudW1lcmFibGUiLCJwdXNoIiwiYXBwbHkiLCJfb2JqZWN0U3ByZWFkIiwiYXJndW1lbnRzIiwibGVuZ3RoIiwiZm9yRWFjaCIsIl9kZWZpbmVQcm9wZXJ0eTIiLCJnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3JzIiwiZGVmaW5lUHJvcGVydGllcyIsIkVESVRPUl9TVEFURV9TVE9SQUdFX1BSRUZJWCIsImV4cG9ydHMiLCJhdHRhY2hNZW50aW9ucyIsInNlbmRlciIsImNvbnRlbnQiLCJtb2RlbCIsInJlcGx5VG9FdmVudCIsImVkaXRlZENvbnRlbnQiLCJtZW50aW9ucyIsInVzZXJNZW50aW9ucyIsIlNldCIsInJvb21NZW50aW9uIiwiYWRkIiwidXNlcklkIiwidXNlcklkcyIsImdldENvbnRlbnQiLCJ1c2VyX2lkcyIsIkFycmF5IiwiaXNBcnJheSIsInBhcnQiLCJwYXJ0cyIsInR5cGUiLCJUeXBlIiwiVXNlclBpbGwiLCJyZXNvdXJjZUlkIiwiQXRSb29tUGlsbCIsImRlbGV0ZSIsIm5ld0NvbnRlbnQiLCJuZXdNZW50aW9ucyIsInNpemUiLCJyb29tIiwicHJldk1lbnRpb25zIiwiYXR0YWNoUmVsYXRpb24iLCJyZWxhdGlvbiIsImNyZWF0ZU1lc3NhZ2VDb250ZW50IiwicGVybWFsaW5rQ3JlYXRvciIsImluY2x1ZGVSZXBseUxlZ2FjeUZhbGxiYWNrIiwiaXNFbW90ZSIsImNvbnRhaW5zRW1vdGUiLCJzdHJpcEVtb3RlQ29tbWFuZCIsInN0YXJ0c1dpdGgiLCJzdHJpcFByZWZpeCIsInVuZXNjYXBlTWVzc2FnZSIsImJvZHkiLCJ0ZXh0U2VyaWFsaXplIiwibXNndHlwZSIsIk1zZ1R5cGUiLCJFbW90ZSIsIlRleHQiLCJmb3JtYXR0ZWRCb2R5IiwiaHRtbFNlcmlhbGl6ZUlmTmVlZGVkIiwiZm9yY2VIVE1MIiwidXNlTWFya2Rvd24iLCJTZXR0aW5nc1N0b3JlIiwiZ2V0VmFsdWUiLCJmb3JtYXQiLCJmb3JtYXR0ZWRfYm9keSIsImFkZFJlcGx5VG9NZXNzYWdlQ29udGVudCIsImluY2x1ZGVMZWdhY3lGYWxsYmFjayIsImlzUXVpY2tSZWFjdGlvbiIsInRleHQiLCJoYXNTaG9ydGN1dCIsImVtb2ppTWF0Y2giLCJtYXRjaCIsIkVNT0pJX1JFR0VYIiwic3Vic3RyaW5nIiwiU2VuZE1lc3NhZ2VDb21wb3NlciIsIlJlYWN0IiwiQ29tcG9uZW50IiwiY29uc3RydWN0b3IiLCJwcm9wcyIsImNvbnRleHQiLCJjcmVhdGVSZWYiLCJldmVudCIsImVkaXRvclJlZiIsImN1cnJlbnQiLCJpc0NvbXBvc2luZyIsInJlcGx5aW5nVG9UaHJlYWQiLCJrZXkiLCJUSFJFQURfUkVMQVRJT05fVFlQRSIsIm5hbWUiLCJhY3Rpb24iLCJnZXRLZXlCaW5kaW5nc01hbmFnZXIiLCJnZXRNZXNzYWdlQ29tcG9zZXJBY3Rpb24iLCJLZXlCaW5kaW5nQWN0aW9uIiwiU2VuZE1lc3NhZ2UiLCJzZW5kTWVzc2FnZSIsInByZXZlbnREZWZhdWx0IiwiU2VsZWN0UHJldlNlbmRIaXN0b3J5IiwiU2VsZWN0TmV4dFNlbmRIaXN0b3J5Iiwic2VsZWN0ZWQiLCJzZWxlY3RTZW5kSGlzdG9yeSIsIlNob3dTdGlja2VyUGlja2VyIiwidG9nZ2xlU3RpY2tlclBpY2tlck9wZW4iLCJFZGl0UHJldk1lc3NhZ2UiLCJpc1NlbGVjdGlvbkNvbGxhcHNlZCIsImlzQ2FyZXRBdFN0YXJ0IiwiZXZlbnRzIiwibGl2ZVRpbWVsaW5lIiwiZ2V0RXZlbnRzIiwiY29uY2F0IiwiZ2V0UGVuZGluZ0V2ZW50cyIsImVkaXRFdmVudCIsImZpbmRFZGl0YWJsZUV2ZW50IiwiaXNGb3J3YXJkIiwibWF0cml4Q2xpZW50IiwiTWF0cml4Q2xpZW50UGVnIiwic2FmZUdldCIsInVuZGVmaW5lZCIsImRpcyIsImRpc3BhdGNoIiwiQWN0aW9uIiwiRWRpdEV2ZW50IiwidGltZWxpbmVSZW5kZXJpbmdUeXBlIiwiQ2FuY2VsUmVwbHlPckVkaXQiLCJzdG9wUHJvcGFnYXRpb24iLCJpc0VtcHR5Iiwic2hvdWxkU2F2ZVN0b3JlZEVkaXRvclN0YXRlIiwiaXRlbSIsIlNlbmRIaXN0b3J5TWFuYWdlciIsImNyZWF0ZUl0ZW0iLCJsb2NhbFN0b3JhZ2UiLCJzZXRJdGVtIiwiZWRpdG9yU3RhdGVLZXkiLCJKU09OIiwic3RyaW5naWZ5IiwiY2xlYXJTdG9yZWRFZGl0b3JTdGF0ZSIsInBheWxvYWQiLCJkaXNhYmxlZCIsIkZvY3VzU2VuZE1lc3NhZ2VDb21wb3NlciIsIlRpbWVsaW5lUmVuZGVyaW5nVHlwZSIsIlJvb20iLCJmb2N1cyIsIkNvbXBvc2VySW5zZXJ0IiwiY29tcG9zZXJUeXBlIiwiQ29tcG9zZXJUeXBlIiwiU2VuZCIsImluc2VydE1lbnRpb24iLCJpbnNlcnRRdW90ZWRNZXNzYWdlIiwiaW5zZXJ0UGxhaW50ZXh0IiwiZGF0YSIsImZpbGVzIiwidHlwZXMiLCJpbmNsdWRlcyIsIkNvbnRlbnRNZXNzYWdlcyIsInNoYXJlZEluc3RhbmNlIiwic2VuZENvbnRlbnRMaXN0VG9Sb29tIiwiZnJvbSIsInJvb21JZCIsIm14Q2xpZW50IiwiaW1nRWxlbWVudFN0ciIsImdldERhdGEiLCJwYXJzZXIiLCJET01QYXJzZXIiLCJpbWdEb2MiLCJwYXJzZUZyb21TdHJpbmciLCJnZXRFbGVtZW50c0J5VGFnTmFtZSIsInF1ZXJ5U2VsZWN0b3IiLCJzcmMiLCJjaGlsZE5vZGVzIiwiY29uc29sZSIsImxvZyIsImltZ1NyYyIsImZldGNoIiwidGhlbiIsInJlc3BvbnNlIiwiYmxvYiIsImltZ0Jsb2IiLCJzYWZldHlwZSIsImdldEJsb2JTYWZlTWltZVR5cGUiLCJleHQiLCJzcGxpdCIsInVybCIsImZpbGVuYW1lIiwiZmlsZSIsIkZpbGUiLCJzZW5kQ29udGVudFRvUm9vbSIsImVycm9yIiwic2VsZWN0aW9uIiwiaW5wdXRUeXBlIiwiZGlmZiIsInByZXBhcmVUb0VuY3J5cHQiLCJvbkNoYW5nZSIsImlzQ3J5cHRvRW5hYmxlZCIsImlzUm9vbUVuY3J5cHRlZCIsInRocm90dGxlIiwiZ2V0Q3J5cHRvIiwibGVhZGluZyIsInRyYWlsaW5nIiwid2luZG93IiwiYWRkRXZlbnRMaXN0ZW5lciIsInNhdmVTdG9yZWRFZGl0b3JTdGF0ZSIsInBhcnRDcmVhdG9yIiwiQ29tbWFuZFBhcnRDcmVhdG9yIiwicmVzdG9yZVN0b3JlZEVkaXRvclN0YXRlIiwiRWRpdG9yTW9kZWwiLCJkaXNwYXRjaGVyUmVmIiwicmVnaXN0ZXIiLCJvbkFjdGlvbiIsInNlbmRIaXN0b3J5TWFuYWdlciIsImNvbXBvbmVudERpZFVwZGF0ZSIsInByZXZQcm9wcyIsImRpZmZlcmVudEV2ZW50VGFyZ2V0IiwiZXZlbnRfaWQiLCJ0aHJlYWRDaGFuZ2VkIiwicmVzZXQiLCJ1cCIsImRlbHRhIiwiY3VycmVudEluZGV4IiwiaGlzdG9yeSIsImN1cnJlbnRseUNvbXBvc2VkRWRpdG9yU3RhdGUiLCJzZXJpYWxpemVQYXJ0cyIsInJlcGx5RXZlbnRJZCIsImdldEl0ZW0iLCJmaW5kRXZlbnRCeUlkIiwic2VuZFF1aWNrUmVhY3Rpb24iLCJ0aW1lbGluZSIsInJlYWN0aW9uIiwiZ2V0VHlwZSIsIkV2ZW50VHlwZSIsIlJvb21NZXNzYWdlIiwic2hvdWxkUmVhY3QiLCJsYXN0TWVzc2FnZSIsImdldFNhZmVVc2VySWQiLCJtZXNzYWdlUmVhY3Rpb25zIiwicmVsYXRpb25zIiwiZ2V0Q2hpbGRFdmVudHNGb3JFdmVudCIsImdldElkIiwiUmVsYXRpb25UeXBlIiwiQW5ub3RhdGlvbiIsIlJlYWN0aW9uIiwibXlSZWFjdGlvbkV2ZW50cyIsImdldEFubm90YXRpb25zQnlTZW5kZXIiLCJteVJlYWN0aW9uS2V5cyIsImlzUmVkYWN0ZWQiLCJtYXAiLCJnZXRSZWxhdGlvbiIsInNlbmRFdmVudCIsImdldFJvb21JZCIsInJlbF90eXBlIiwicG9zdGhvZ0V2ZW50IiwiZXZlbnROYW1lIiwiaXNFZGl0aW5nIiwibWVzc2FnZVR5cGUiLCJpc1JlcGx5IiwiaW5UaHJlYWQiLCJ0aHJlYWRSb290Iiwic3RhcnRzVGhyZWFkIiwiZ2V0VGhyZWFkIiwiUG9zdGhvZ0FuYWx5dGljcyIsImluc3RhbmNlIiwidHJhY2tFdmVudCIsImluZGV4T2ZMYXN0UGFydCIsInBvc2l0aW9uSW5MYXN0UGFydCIsInJlcGxhY2VFbW90aWNvbiIsIkRvY3VtZW50UG9zaXRpb24iLCJSRUdFWF9FTU9USUNPTiIsInNob3VsZFNlbmQiLCJpc1NsYXNoQ29tbWFuZCIsImNtZCIsImFyZ3MiLCJjb21tYW5kVGV4dCIsImdldFNsYXNoQ29tbWFuZCIsInRocmVhZElkIiwiY29tbWFuZFN1Y2Nlc3NmdWwiLCJydW5TbGFzaENvbW1hbmQiLCJDb21tYW5kQ2F0ZWdvcmllcyIsIm1lc3NhZ2VzIiwiZWZmZWN0cyIsImNhdGVnb3J5Iiwic2VuZEFueXdheSIsInNob3VsZFNlbmRBbnl3YXkiLCJGb2N1c0FDb21wb3NlciIsInRyaW0iLCJkZWNvcmF0ZVN0YXJ0U2VuZGluZ1RpbWUiLCJwcm9tIiwiZG9NYXliZUxvY2FsUm9vbUFjdGlvbiIsImFjdHVhbFJvb21JZCIsIkNIQVRfRUZGRUNUUyIsImVmZmVjdCIsImNvbnRhaW5zRW1vamkiLCJlbW9qaXMiLCJpc05vdFRocmVhZCIsImNvbW1hbmQiLCJyZXNwIiwic2VuZFJvdW5kVHJpcE1ldHJpYyIsInNhdmUiLCJjbGVhclVuZG9IaXN0b3J5IiwiY29tcG9uZW50V2lsbFVubW91bnQiLCJ1bnJlZ2lzdGVyIiwicmVtb3ZlRXZlbnRMaXN0ZW5lciIsInJlbW92ZUl0ZW0iLCJqc29uIiwic2VyaWFsaXplZFBhcnRzIiwicGFyc2UiLCJwIiwiZGVzZXJpYWxpemVQYXJ0IiwibG9nZ2VyIiwicmVuZGVyIiwiY3JlYXRlRWxlbWVudCIsImNsYXNzTmFtZSIsIm9uQ2xpY2siLCJmb2N1c0NvbXBvc2VyIiwib25LZXlEb3duIiwicmVmIiwibGFiZWwiLCJwbGFjZWhvbGRlciIsIm9uUGFzdGUiLCJSb29tQ29udGV4dCIsIlNlbmRNZXNzYWdlQ29tcG9zZXJXaXRoTWF0cml4Q2xpZW50Iiwid2l0aE1hdHJpeENsaWVudEhPQyIsIl9kZWZhdWx0Il0sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2NvbXBvbmVudHMvdmlld3Mvcm9vbXMvU2VuZE1lc3NhZ2VDb21wb3Nlci50c3giXSwic291cmNlc0NvbnRlbnQiOlsiLypcbkNvcHlyaWdodCAyMDI0IE5ldyBWZWN0b3IgTHRkLlxuQ29weXJpZ2h0IDIwMTktMjAyMyBUaGUgTWF0cml4Lm9yZyBGb3VuZGF0aW9uIEMuSS5DLlxuXG5TUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQUdQTC0zLjAtb25seSBPUiBHUEwtMy4wLW9ubHlcblBsZWFzZSBzZWUgTElDRU5TRSBmaWxlcyBpbiB0aGUgcmVwb3NpdG9yeSByb290IGZvciBmdWxsIGRldGFpbHMuXG4qL1xuXG5pbXBvcnQgUmVhY3QsIHsgY3JlYXRlUmVmLCBLZXlib2FyZEV2ZW50LCBTeW50aGV0aWNFdmVudCB9IGZyb20gXCJyZWFjdFwiO1xuaW1wb3J0IHtcbiAgICBJQ29udGVudCxcbiAgICBNYXRyaXhFdmVudCxcbiAgICBJRXZlbnRSZWxhdGlvbixcbiAgICBJTWVudGlvbnMsXG4gICAgUm9vbSxcbiAgICBFdmVudFR5cGUsXG4gICAgTXNnVHlwZSxcbiAgICBSZWxhdGlvblR5cGUsXG4gICAgVEhSRUFEX1JFTEFUSU9OX1RZUEUsXG59IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9tYXRyaXhcIjtcbmltcG9ydCB7IERlYm91bmNlZEZ1bmMsIHRocm90dGxlIH0gZnJvbSBcImxvZGFzaFwiO1xuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL2xvZ2dlclwiO1xuaW1wb3J0IHsgQ29tcG9zZXIgYXMgQ29tcG9zZXJFdmVudCB9IGZyb20gXCJAbWF0cml4LW9yZy9hbmFseXRpY3MtZXZlbnRzL3R5cGVzL3R5cGVzY3JpcHQvQ29tcG9zZXJcIjtcbmltcG9ydCB7IFJvb21NZXNzYWdlRXZlbnRDb250ZW50IH0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL3R5cGVzXCI7XG5cbmltcG9ydCBkaXMgZnJvbSBcIi4uLy4uLy4uL2Rpc3BhdGNoZXIvZGlzcGF0Y2hlclwiO1xuaW1wb3J0IEVkaXRvck1vZGVsIGZyb20gXCIuLi8uLi8uLi9lZGl0b3IvbW9kZWxcIjtcbmltcG9ydCB7XG4gICAgY29udGFpbnNFbW90ZSxcbiAgICBodG1sU2VyaWFsaXplSWZOZWVkZWQsXG4gICAgc3RhcnRzV2l0aCxcbiAgICBzdHJpcEVtb3RlQ29tbWFuZCxcbiAgICBzdHJpcFByZWZpeCxcbiAgICB0ZXh0U2VyaWFsaXplLFxuICAgIHVuZXNjYXBlTWVzc2FnZSxcbn0gZnJvbSBcIi4uLy4uLy4uL2VkaXRvci9zZXJpYWxpemVcIjtcbmltcG9ydCBCYXNpY01lc3NhZ2VDb21wb3NlciwgeyBSRUdFWF9FTU9USUNPTiB9IGZyb20gXCIuL0Jhc2ljTWVzc2FnZUNvbXBvc2VyXCI7XG5pbXBvcnQgeyBDb21tYW5kUGFydENyZWF0b3IsIFBhcnQsIFBhcnRDcmVhdG9yLCBTZXJpYWxpemVkUGFydCwgVHlwZSB9IGZyb20gXCIuLi8uLi8uLi9lZGl0b3IvcGFydHNcIjtcbmltcG9ydCB7IGZpbmRFZGl0YWJsZUV2ZW50IH0gZnJvbSBcIi4uLy4uLy4uL3V0aWxzL0V2ZW50VXRpbHNcIjtcbmltcG9ydCBTZW5kSGlzdG9yeU1hbmFnZXIgZnJvbSBcIi4uLy4uLy4uL1NlbmRIaXN0b3J5TWFuYWdlclwiO1xuaW1wb3J0IHsgQ29tbWFuZENhdGVnb3JpZXMgfSBmcm9tIFwiLi4vLi4vLi4vU2xhc2hDb21tYW5kc1wiO1xuaW1wb3J0IENvbnRlbnRNZXNzYWdlcyBmcm9tIFwiLi4vLi4vLi4vQ29udGVudE1lc3NhZ2VzXCI7XG5pbXBvcnQgeyB3aXRoTWF0cml4Q2xpZW50SE9DLCBNYXRyaXhDbGllbnRQcm9wcyB9IGZyb20gXCIuLi8uLi8uLi9jb250ZXh0cy9NYXRyaXhDbGllbnRDb250ZXh0XCI7XG5pbXBvcnQgeyBBY3Rpb24gfSBmcm9tIFwiLi4vLi4vLi4vZGlzcGF0Y2hlci9hY3Rpb25zXCI7XG5pbXBvcnQgeyBjb250YWluc0Vtb2ppIH0gZnJvbSBcIi4uLy4uLy4uL2VmZmVjdHMvdXRpbHNcIjtcbmltcG9ydCB7IENIQVRfRUZGRUNUUyB9IGZyb20gXCIuLi8uLi8uLi9lZmZlY3RzXCI7XG5pbXBvcnQgeyBNYXRyaXhDbGllbnRQZWcgfSBmcm9tIFwiLi4vLi4vLi4vTWF0cml4Q2xpZW50UGVnXCI7XG5pbXBvcnQgeyBnZXRLZXlCaW5kaW5nc01hbmFnZXIgfSBmcm9tIFwiLi4vLi4vLi4vS2V5QmluZGluZ3NNYW5hZ2VyXCI7XG5pbXBvcnQgU2V0dGluZ3NTdG9yZSBmcm9tIFwiLi4vLi4vLi4vc2V0dGluZ3MvU2V0dGluZ3NTdG9yZVwiO1xuaW1wb3J0IHsgUm9vbVBlcm1hbGlua0NyZWF0b3IgfSBmcm9tIFwiLi4vLi4vLi4vdXRpbHMvcGVybWFsaW5rcy9QZXJtYWxpbmtzXCI7XG5pbXBvcnQgeyBBY3Rpb25QYXlsb2FkIH0gZnJvbSBcIi4uLy4uLy4uL2Rpc3BhdGNoZXIvcGF5bG9hZHNcIjtcbmltcG9ydCB7IGRlY29yYXRlU3RhcnRTZW5kaW5nVGltZSwgc2VuZFJvdW5kVHJpcE1ldHJpYyB9IGZyb20gXCIuLi8uLi8uLi9zZW5kVGltZVBlcmZvcm1hbmNlTWV0cmljc1wiO1xuaW1wb3J0IFJvb21Db250ZXh0LCB7IFRpbWVsaW5lUmVuZGVyaW5nVHlwZSB9IGZyb20gXCIuLi8uLi8uLi9jb250ZXh0cy9Sb29tQ29udGV4dFwiO1xuaW1wb3J0IERvY3VtZW50UG9zaXRpb24gZnJvbSBcIi4uLy4uLy4uL2VkaXRvci9wb3NpdGlvblwiO1xuaW1wb3J0IHsgQ29tcG9zZXJUeXBlIH0gZnJvbSBcIi4uLy4uLy4uL2Rpc3BhdGNoZXIvcGF5bG9hZHMvQ29tcG9zZXJJbnNlcnRQYXlsb2FkXCI7XG5pbXBvcnQgeyBnZXRTbGFzaENvbW1hbmQsIGlzU2xhc2hDb21tYW5kLCBydW5TbGFzaENvbW1hbmQsIHNob3VsZFNlbmRBbnl3YXkgfSBmcm9tIFwiLi4vLi4vLi4vZWRpdG9yL2NvbW1hbmRzXCI7XG5pbXBvcnQgeyBLZXlCaW5kaW5nQWN0aW9uIH0gZnJvbSBcIi4uLy4uLy4uL2FjY2Vzc2liaWxpdHkvS2V5Ym9hcmRTaG9ydGN1dHNcIjtcbmltcG9ydCB7IFBvc3Rob2dBbmFseXRpY3MgfSBmcm9tIFwiLi4vLi4vLi4vUG9zdGhvZ0FuYWx5dGljc1wiO1xuaW1wb3J0IHsgYWRkUmVwbHlUb01lc3NhZ2VDb250ZW50IH0gZnJvbSBcIi4uLy4uLy4uL3V0aWxzL1JlcGx5XCI7XG5pbXBvcnQgeyBkb01heWJlTG9jYWxSb29tQWN0aW9uIH0gZnJvbSBcIi4uLy4uLy4uL3V0aWxzL2xvY2FsLXJvb21cIjtcbmltcG9ydCB7IENhcmV0IH0gZnJvbSBcIi4uLy4uLy4uL2VkaXRvci9jYXJldFwiO1xuaW1wb3J0IHsgSURpZmYgfSBmcm9tIFwiLi4vLi4vLi4vZWRpdG9yL2RpZmZcIjtcbmltcG9ydCB7IGdldEJsb2JTYWZlTWltZVR5cGUgfSBmcm9tIFwiLi4vLi4vLi4vdXRpbHMvYmxvYnNcIjtcbmltcG9ydCB7IEVNT0pJX1JFR0VYIH0gZnJvbSBcIi4uLy4uLy4uL0h0bWxVdGlsc1wiO1xuXG4vLyBUaGUgcHJlZml4IHVzZWQgd2hlbiBwZXJzaXN0aW5nIGVkaXRvciBkcmFmdHMgdG8gbG9jYWxzdG9yYWdlLlxuZXhwb3J0IGNvbnN0IEVESVRPUl9TVEFURV9TVE9SQUdFX1BSRUZJWCA9IFwibXhfY2lkZXJfc3RhdGVfXCI7XG5cbi8qKlxuICogQnVpbGQgdGhlIG1lbnRpb25zIGluZm9ybWF0aW9uIGJhc2VkIG9uIHRoZSBlZGl0b3IgbW9kZWwgKGFuZCBhbnkgcmVsYXRlZCBldmVudHMpOlxuICpcbiAqIDEuIFNlYXJjaCB0aGUgbW9kZWwgcGFydHMgZm9yIHJvb20gb3IgdXNlciBwaWxscyBhbmQgZmlsbCBpbiB0aGUgbWVudGlvbnMgb2JqZWN0LlxuICogMi4gSWYgdGhpcyBpcyBhIHJlcGx5IHRvIGFub3RoZXIgZXZlbnQsIGluY2x1ZGUgYW55IHVzZXIgbWVudGlvbnMgZnJvbSB0aGF0XG4gKiAgICAoYnV0IGRvIG5vdCBpbmNsdWRlIGEgcm9vbSBtZW50aW9uKS5cbiAqXG4gKiBAcGFyYW0gc2VuZGVyIC0gVGhlIE1hdHJpeCBJRCBvZiB0aGUgdXNlciBzZW5kaW5nIHRoZSBldmVudC5cbiAqIEBwYXJhbSBjb250ZW50IC0gVGhlIGV2ZW50IGNvbnRlbnQuXG4gKiBAcGFyYW0gbW9kZWwgLSBUaGUgZWRpdG9yIG1vZGVsIHRvIHNlYXJjaCBmb3IgbWVudGlvbnMsIG51bGwgaWYgdGhlcmUgaXMgbm8gZWRpdG9yLlxuICogQHBhcmFtIHJlcGx5VG9FdmVudCAtIFRoZSBldmVudCBiZWluZyByZXBsaWVkIHRvIG9yIHVuZGVmaW5lZCBpZiBpdCBpcyBub3QgYSByZXBseS5cbiAqIEBwYXJhbSBlZGl0ZWRDb250ZW50IC0gVGhlIGNvbnRlbnQgb2YgdGhlIHBhcmVudCBldmVudCBiZWluZyBlZGl0ZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhdHRhY2hNZW50aW9ucyhcbiAgICBzZW5kZXI6IHN0cmluZyxcbiAgICBjb250ZW50OiBJQ29udGVudCxcbiAgICBtb2RlbDogRWRpdG9yTW9kZWwgfCBudWxsLFxuICAgIHJlcGx5VG9FdmVudDogTWF0cml4RXZlbnQgfCB1bmRlZmluZWQsXG4gICAgZWRpdGVkQ29udGVudDogSUNvbnRlbnQgfCBudWxsID0gbnVsbCxcbik6IHZvaWQge1xuICAgIC8vIFdlIGFsd2F5cyBhdHRhY2ggdGhlIG1lbnRpb25zIGV2ZW4gaWYgdGhlIGhvbWUgc2VydmVyIGRvZXNuJ3QgeWV0IHN1cHBvcnRcbiAgICAvLyBpbnRlbnRpb25hbCBtZW50aW9ucy4gVGhpcyBpcyBzYWZlIGJlY2F1c2UgbS5tZW50aW9ucyBpcyBhbiBhZGRpdGl2ZSBjaGFuZ2VcbiAgICAvLyB0aGF0IHNob3VsZCBzaW1wbHkgYmUgaWdub3JlZCBieSBpbmNhcGFibGUgaG9tZSBzZXJ2ZXJzLlxuXG4gICAgLy8gVGhlIG1lbnRpb25zIHByb3BlcnR5ICphbHdheXMqIGdldHMgaW5jbHVkZWQgdG8gZGlzYWJsZSBsZWdhY3kgcHVzaCBydWxlcy5cbiAgICBjb25zdCBtZW50aW9uczogSU1lbnRpb25zID0gKGNvbnRlbnRbXCJtLm1lbnRpb25zXCJdID0ge30pO1xuXG4gICAgY29uc3QgdXNlck1lbnRpb25zID0gbmV3IFNldDxzdHJpbmc+KCk7XG4gICAgbGV0IHJvb21NZW50aW9uID0gZmFsc2U7XG5cbiAgICAvLyBJZiB0aGVyZSdzIGEgcmVwbHksIGluaXRpYWxpemUgdGhlIG1lbnRpb25lZCB1c2VycyBhcyB0aGUgc2VuZGVyIG9mIHRoYXRcbiAgICAvLyBldmVudCArIGFueSBtZW50aW9uZWQgdXNlcnMgaW4gdGhhdCBldmVudC5cbiAgICBpZiAocmVwbHlUb0V2ZW50KSB7XG4gICAgICAgIHVzZXJNZW50aW9ucy5hZGQocmVwbHlUb0V2ZW50LnNlbmRlciEudXNlcklkKTtcbiAgICAgICAgLy8gVE9ETyBXaGF0IGRvIHdlIGRvIGlmIHRoZSByZXBseSBldmVudCAqZG9lZXNuJ3QqIGhhdmUgdGhpcyBwcm9wZXJ0eT9cbiAgICAgICAgLy8gVHJ5IHRvIGZpc2ggb3V0IHJlcGxpZXMgZnJvbSB0aGUgY29udGVudHM/XG4gICAgICAgIGNvbnN0IHVzZXJJZHMgPSByZXBseVRvRXZlbnQuZ2V0Q29udGVudCgpW1wibS5tZW50aW9uc1wiXT8udXNlcl9pZHM7XG4gICAgICAgIGlmIChBcnJheS5pc0FycmF5KHVzZXJJZHMpKSB7XG4gICAgICAgICAgICB1c2VySWRzLmZvckVhY2goKHVzZXJJZCkgPT4gdXNlck1lbnRpb25zLmFkZCh1c2VySWQpKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vIElmIHVzZXIgcHJvdmlkZWQgY29udGVudCBpcyBhdmFpbGFibGUsIGNoZWNrIHRvIHNlZSBpZiBhbnkgdXNlcnMgYXJlIG1lbnRpb25lZC5cbiAgICBpZiAobW9kZWwpIHtcbiAgICAgICAgLy8gQWRkIGFueSBtZW50aW9uZWQgdXNlcnMgaW4gdGhlIGN1cnJlbnQgY29udGVudC5cbiAgICAgICAgZm9yIChjb25zdCBwYXJ0IG9mIG1vZGVsLnBhcnRzKSB7XG4gICAgICAgICAgICBpZiAocGFydC50eXBlID09PSBUeXBlLlVzZXJQaWxsKSB7XG4gICAgICAgICAgICAgICAgdXNlck1lbnRpb25zLmFkZChwYXJ0LnJlc291cmNlSWQpO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChwYXJ0LnR5cGUgPT09IFR5cGUuQXRSb29tUGlsbCkge1xuICAgICAgICAgICAgICAgIHJvb21NZW50aW9uID0gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vIEVuc3VyZSB0aGUgKmN1cnJlbnQqIHVzZXIgaXNuJ3QgbGlzdGVkIGluIHRoZSBtZW50aW9uZWQgdXNlcnMuXG4gICAgdXNlck1lbnRpb25zLmRlbGV0ZShzZW5kZXIpO1xuXG4gICAgLy8gRmluYWxseSwgaWYgdGhpcyBldmVudCBpcyBlZGl0aW5nIGEgcHJldmlvdXMgZXZlbnQsIG9ubHkgaW5jbHVkZSB1c2VycyB3aG9cbiAgICAvLyB3ZXJlIG5vdCBwcmV2aW91c2x5IG1lbnRpb25lZCBhbmQgYSByb29tIG1lbnRpb24gaWYgdGhlIHByZXZpb3VzIGV2ZW50IHdhc1xuICAgIC8vIG5vdCBhIHJvb20gbWVudGlvbi5cbiAgICBpZiAoZWRpdGVkQ29udGVudCkge1xuICAgICAgICAvLyBGaXJzdCwgdGhlIG5ldyBldmVudCBjb250ZW50IGdldHMgdGhlICpmdWxsKiBzZXQgb2YgdXNlcnMuXG4gICAgICAgIGNvbnN0IG5ld0NvbnRlbnQgPSBjb250ZW50W1wibS5uZXdfY29udGVudFwiXTtcbiAgICAgICAgY29uc3QgbmV3TWVudGlvbnM6IElNZW50aW9ucyA9IChuZXdDb250ZW50W1wibS5tZW50aW9uc1wiXSA9IHt9KTtcblxuICAgICAgICAvLyBPbmx5IGluY2x1ZGUgdGhlIHVzZXJzL3Jvb20gaWYgdGhlcmUgaXMgYW55IGNvbnRlbnQuXG4gICAgICAgIGlmICh1c2VyTWVudGlvbnMuc2l6ZSkge1xuICAgICAgICAgICAgbmV3TWVudGlvbnMudXNlcl9pZHMgPSBbLi4udXNlck1lbnRpb25zXTtcbiAgICAgICAgfVxuICAgICAgICBpZiAocm9vbU1lbnRpb24pIHtcbiAgICAgICAgICAgIG5ld01lbnRpb25zLnJvb20gPSB0cnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gRmV0Y2ggdGhlIG1lbnRpb25zIGZyb20gdGhlIG9yaWdpbmFsIGV2ZW50IGFuZCByZW1vdmUgYW55IHByZXZpb3VzbHlcbiAgICAgICAgLy8gbWVudGlvbmVkIHVzZXJzLlxuICAgICAgICBjb25zdCBwcmV2TWVudGlvbnMgPSBlZGl0ZWRDb250ZW50W1wibS5tZW50aW9uc1wiXTtcbiAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkocHJldk1lbnRpb25zPy51c2VyX2lkcykpIHtcbiAgICAgICAgICAgIHByZXZNZW50aW9ucyEudXNlcl9pZHMuZm9yRWFjaCgodXNlcklkKSA9PiB1c2VyTWVudGlvbnMuZGVsZXRlKHVzZXJJZCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gSWYgdGhlIG9yaWdpbmFsIGV2ZW50IG1lbnRpb25lZCB0aGUgcm9vbSwgbm90aGluZyB0byBkbyBoZXJlLlxuICAgICAgICBpZiAocHJldk1lbnRpb25zPy5yb29tKSB7XG4gICAgICAgICAgICByb29tTWVudGlvbiA9IGZhbHNlO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8gT25seSBpbmNsdWRlIHRoZSB1c2Vycy9yb29tIGlmIHRoZXJlIGlzIGFueSBjb250ZW50LlxuICAgIGlmICh1c2VyTWVudGlvbnMuc2l6ZSkge1xuICAgICAgICBtZW50aW9ucy51c2VyX2lkcyA9IFsuLi51c2VyTWVudGlvbnNdO1xuICAgIH1cbiAgICBpZiAocm9vbU1lbnRpb24pIHtcbiAgICAgICAgbWVudGlvbnMucm9vbSA9IHRydWU7XG4gICAgfVxufVxuXG4vLyBNZXJnZXMgZmF2b3VyaW5nIHRoZSBnaXZlbiByZWxhdGlvblxuZXhwb3J0IGZ1bmN0aW9uIGF0dGFjaFJlbGF0aW9uKGNvbnRlbnQ6IElDb250ZW50LCByZWxhdGlvbj86IElFdmVudFJlbGF0aW9uKTogdm9pZCB7XG4gICAgaWYgKHJlbGF0aW9uKSB7XG4gICAgICAgIGNvbnRlbnRbXCJtLnJlbGF0ZXNfdG9cIl0gPSB7XG4gICAgICAgICAgICAuLi4oY29udGVudFtcIm0ucmVsYXRlc190b1wiXSB8fCB7fSksXG4gICAgICAgICAgICAuLi5yZWxhdGlvbixcbiAgICAgICAgfTtcbiAgICB9XG59XG5cbi8vIGV4cG9ydGVkIGZvciB0ZXN0c1xuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZU1lc3NhZ2VDb250ZW50KFxuICAgIHNlbmRlcjogc3RyaW5nLFxuICAgIG1vZGVsOiBFZGl0b3JNb2RlbCxcbiAgICByZXBseVRvRXZlbnQ6IE1hdHJpeEV2ZW50IHwgdW5kZWZpbmVkLFxuICAgIHJlbGF0aW9uOiBJRXZlbnRSZWxhdGlvbiB8IHVuZGVmaW5lZCxcbiAgICBwZXJtYWxpbmtDcmVhdG9yPzogUm9vbVBlcm1hbGlua0NyZWF0b3IsXG4gICAgaW5jbHVkZVJlcGx5TGVnYWN5RmFsbGJhY2sgPSB0cnVlLFxuKTogUm9vbU1lc3NhZ2VFdmVudENvbnRlbnQge1xuICAgIGNvbnN0IGlzRW1vdGUgPSBjb250YWluc0Vtb3RlKG1vZGVsKTtcbiAgICBpZiAoaXNFbW90ZSkge1xuICAgICAgICBtb2RlbCA9IHN0cmlwRW1vdGVDb21tYW5kKG1vZGVsKTtcbiAgICB9XG4gICAgaWYgKHN0YXJ0c1dpdGgobW9kZWwsIFwiLy9cIikpIHtcbiAgICAgICAgbW9kZWwgPSBzdHJpcFByZWZpeChtb2RlbCwgXCIvXCIpO1xuICAgIH1cbiAgICBtb2RlbCA9IHVuZXNjYXBlTWVzc2FnZShtb2RlbCk7XG5cbiAgICBjb25zdCBib2R5ID0gdGV4dFNlcmlhbGl6ZShtb2RlbCk7XG5cbiAgICBjb25zdCBjb250ZW50OiBSb29tTWVzc2FnZUV2ZW50Q29udGVudCA9IHtcbiAgICAgICAgbXNndHlwZTogaXNFbW90ZSA/IE1zZ1R5cGUuRW1vdGUgOiBNc2dUeXBlLlRleHQsXG4gICAgICAgIGJvZHk6IGJvZHksXG4gICAgfTtcbiAgICBjb25zdCBmb3JtYXR0ZWRCb2R5ID0gaHRtbFNlcmlhbGl6ZUlmTmVlZGVkKG1vZGVsLCB7XG4gICAgICAgIGZvcmNlSFRNTDogISFyZXBseVRvRXZlbnQsXG4gICAgICAgIHVzZU1hcmtkb3duOiBTZXR0aW5nc1N0b3JlLmdldFZhbHVlKFwiTWVzc2FnZUNvbXBvc2VySW5wdXQudXNlTWFya2Rvd25cIiksXG4gICAgfSk7XG4gICAgaWYgKGZvcm1hdHRlZEJvZHkpIHtcbiAgICAgICAgY29udGVudC5mb3JtYXQgPSBcIm9yZy5tYXRyaXguY3VzdG9tLmh0bWxcIjtcbiAgICAgICAgY29udGVudC5mb3JtYXR0ZWRfYm9keSA9IGZvcm1hdHRlZEJvZHk7XG4gICAgfVxuXG4gICAgLy8gQnVpbGQgdGhlIG1lbnRpb25zIHByb3BlcnR5IGFuZCBhZGQgaXQgdG8gdGhlIGV2ZW50IGNvbnRlbnQuXG4gICAgYXR0YWNoTWVudGlvbnMoc2VuZGVyLCBjb250ZW50LCBtb2RlbCwgcmVwbHlUb0V2ZW50KTtcblxuICAgIGF0dGFjaFJlbGF0aW9uKGNvbnRlbnQsIHJlbGF0aW9uKTtcbiAgICBpZiAocmVwbHlUb0V2ZW50KSB7XG4gICAgICAgIGFkZFJlcGx5VG9NZXNzYWdlQ29udGVudChjb250ZW50LCByZXBseVRvRXZlbnQsIHtcbiAgICAgICAgICAgIHBlcm1hbGlua0NyZWF0b3IsXG4gICAgICAgICAgICBpbmNsdWRlTGVnYWN5RmFsbGJhY2s6IGluY2x1ZGVSZXBseUxlZ2FjeUZhbGxiYWNrLFxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICByZXR1cm4gY29udGVudDtcbn1cblxuLy8gZXhwb3J0ZWQgZm9yIHRlc3RzXG5leHBvcnQgZnVuY3Rpb24gaXNRdWlja1JlYWN0aW9uKG1vZGVsOiBFZGl0b3JNb2RlbCk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IHBhcnRzID0gbW9kZWwucGFydHM7XG4gICAgaWYgKHBhcnRzLmxlbmd0aCA9PSAwKSByZXR1cm4gZmFsc2U7XG4gICAgY29uc3QgdGV4dCA9IHRleHRTZXJpYWxpemUobW9kZWwpO1xuICAgIC8vIHNob3J0Y3V0IHRha2VzIHRoZSBmb3JtIFwiKzplbW9qaTpcIiBvciBcIisgOmVtb2ppOlwiXCJcbiAgICAvLyBjYW4gYmUgaW4gMSBvciAyIHBhcnRzXG4gICAgaWYgKHBhcnRzLmxlbmd0aCA8PSAyKSB7XG4gICAgICAgIGNvbnN0IGhhc1Nob3J0Y3V0ID0gdGV4dC5zdGFydHNXaXRoKFwiK1wiKSB8fCB0ZXh0LnN0YXJ0c1dpdGgoXCIrIFwiKTtcbiAgICAgICAgY29uc3QgZW1vamlNYXRjaCA9IHRleHQubWF0Y2goRU1PSklfUkVHRVgpO1xuICAgICAgICBpZiAoaGFzU2hvcnRjdXQgJiYgZW1vamlNYXRjaCAmJiBlbW9qaU1hdGNoLmxlbmd0aCA9PSAxKSB7XG4gICAgICAgICAgICByZXR1cm4gZW1vamlNYXRjaFswXSA9PT0gdGV4dC5zdWJzdHJpbmcoMSkgfHwgZW1vamlNYXRjaFswXSA9PT0gdGV4dC5zdWJzdHJpbmcoMik7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xufVxuXG5pbnRlcmZhY2UgSVNlbmRNZXNzYWdlQ29tcG9zZXJQcm9wcyBleHRlbmRzIE1hdHJpeENsaWVudFByb3BzIHtcbiAgICByb29tOiBSb29tO1xuICAgIHBsYWNlaG9sZGVyPzogc3RyaW5nO1xuICAgIHBlcm1hbGlua0N