UNPKG

matrix-react-sdk

Version:
183 lines (175 loc) 28.4 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.focusComposer = focusComposer; exports.handleClipboardEvent = handleClipboardEvent; exports.handleEventWithAutocomplete = handleEventWithAutocomplete; exports.isEventToHandleAsClipboardEvent = isEventToHandleAsClipboardEvent; exports.setCursorPositionAtTheEnd = setCursorPositionAtTheEnd; var _KeyBindingsManager = require("../../../../../KeyBindingsManager"); var _KeyboardShortcuts = require("../../../../../accessibility/KeyboardShortcuts"); var _blobs = require("../../../../../utils/blobs"); var _ContentMessages = _interopRequireDefault(require("../../../../../ContentMessages")); var _Typeguards = require("../../../../../Typeguards"); /* Copyright 2024 New Vector Ltd. Copyright 2022 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 focusComposer(composerElement, renderingType, roomContext, timeoutId) { if (renderingType === roomContext.timelineRenderingType) { // Immediately set the focus, so if you start typing it // will appear in the composer composerElement.current?.focus(); // If we call focus immediate, the focus _is_ in the right // place, but the cursor is invisible, presumably because // some other event is still processing. // The following line ensures that the cursor is actually // visible in composer. if (timeoutId.current) { clearTimeout(timeoutId.current); } timeoutId.current = window.setTimeout(() => composerElement.current?.focus(), 200); } } function setCursorPositionAtTheEnd(element) { const range = document.createRange(); range.selectNodeContents(element); range.collapse(false); const selection = document.getSelection(); selection.removeAllRanges(); selection.addRange(range); element.focus(); } /** * When the autocomplete modal is open we need to be able to properly * handle events that are dispatched. This allows the user to move the selection * in the autocomplete and select using enter. * * @param autocompleteRef - a ref to the autocomplete of interest * @param event - the keyboard event that has been dispatched * @returns boolean - whether or not the autocomplete has handled the event */ function handleEventWithAutocomplete(autocompleteRef, // we get a React Keyboard event from plain text composer, a Keyboard Event from the rich text composer event) { const autocompleteIsOpen = autocompleteRef?.current && !autocompleteRef.current.state.hide; if (!autocompleteIsOpen) { return false; } let handled = false; const autocompleteAction = (0, _KeyBindingsManager.getKeyBindingsManager)().getAutocompleteAction(event); const component = autocompleteRef.current; if (component && component.countCompletions() > 0) { switch (autocompleteAction) { case _KeyboardShortcuts.KeyBindingAction.ForceCompleteAutocomplete: case _KeyboardShortcuts.KeyBindingAction.CompleteAutocomplete: autocompleteRef.current.onConfirmCompletion(); handled = true; break; case _KeyboardShortcuts.KeyBindingAction.PrevSelectionInAutocomplete: autocompleteRef.current.moveSelection(-1); handled = true; break; case _KeyboardShortcuts.KeyBindingAction.NextSelectionInAutocomplete: autocompleteRef.current.moveSelection(1); handled = true; break; case _KeyboardShortcuts.KeyBindingAction.CancelAutocomplete: autocompleteRef.current.onEscape(event); handled = true; break; default: break; // don't return anything, allow event to pass through } } if (handled) { event.preventDefault(); event.stopPropagation(); } return handled; } /** * Takes an event and handles image pasting. Returns a boolean to indicate if it has handled * the event or not. Must accept either clipboard or input events in order to prevent issue: * https://github.com/vector-im/element-web/issues/25327 * * @param event - event to process * @param data - data from the event to process * @param roomContext - room in which the event occurs * @param mxClient - current matrix client * @param eventRelation - used to send the event to the correct place eg timeline vs thread * @returns - boolean to show if the event was handled or not */ function handleClipboardEvent(event, data, roomContext, mxClient, eventRelation) { // Logic in this function follows that of `SendMessageComposer.onPaste` const { room, timelineRenderingType, replyToEvent } = roomContext; function handleError(error) { if (error instanceof Error) { console.log(error.message); } else if (typeof error === "string") { console.log(error); } } if (event.type !== "paste" || data === null || room === undefined) { return false; } // 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), room.roomId, eventRelation, mxClient, timelineRenderingType).catch(handleError); return true; } // 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) { handleError("Failed to handle pasted content as Safari inserted content"); 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, room.roomId, eventRelation, mxClient, replyToEvent).catch(handleError); }).catch(handleError); }).catch(handleError); return true; } return false; } /** * Util to determine if an input event or clipboard event must be handled as a clipboard event. * Due to https://github.com/vector-im/element-web/issues/25327, certain paste events * must be listenened for with an onBeforeInput handler and so will be caught as input events. * * @param event - the event to test, can be a WysiwygEvent if it comes from the rich text editor, or * input or clipboard events if from the plain text editor * @returns - true if event should be handled as a clipboard event */ function isEventToHandleAsClipboardEvent(event) { const isInputEventForClipboard = event instanceof InputEvent && event.inputType === "insertFromPaste" && (0, _Typeguards.isNotNull)(event.dataTransfer); const isClipboardEvent = event instanceof ClipboardEvent; return isClipboardEvent || isInputEventForClipboard; } //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfS2V5QmluZGluZ3NNYW5hZ2VyIiwicmVxdWlyZSIsIl9LZXlib2FyZFNob3J0Y3V0cyIsIl9ibG9icyIsIl9Db250ZW50TWVzc2FnZXMiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwiX1R5cGVndWFyZHMiLCJmb2N1c0NvbXBvc2VyIiwiY29tcG9zZXJFbGVtZW50IiwicmVuZGVyaW5nVHlwZSIsInJvb21Db250ZXh0IiwidGltZW91dElkIiwidGltZWxpbmVSZW5kZXJpbmdUeXBlIiwiY3VycmVudCIsImZvY3VzIiwiY2xlYXJUaW1lb3V0Iiwid2luZG93Iiwic2V0VGltZW91dCIsInNldEN1cnNvclBvc2l0aW9uQXRUaGVFbmQiLCJlbGVtZW50IiwicmFuZ2UiLCJkb2N1bWVudCIsImNyZWF0ZVJhbmdlIiwic2VsZWN0Tm9kZUNvbnRlbnRzIiwiY29sbGFwc2UiLCJzZWxlY3Rpb24iLCJnZXRTZWxlY3Rpb24iLCJyZW1vdmVBbGxSYW5nZXMiLCJhZGRSYW5nZSIsImhhbmRsZUV2ZW50V2l0aEF1dG9jb21wbGV0ZSIsImF1dG9jb21wbGV0ZVJlZiIsImV2ZW50IiwiYXV0b2NvbXBsZXRlSXNPcGVuIiwic3RhdGUiLCJoaWRlIiwiaGFuZGxlZCIsImF1dG9jb21wbGV0ZUFjdGlvbiIsImdldEtleUJpbmRpbmdzTWFuYWdlciIsImdldEF1dG9jb21wbGV0ZUFjdGlvbiIsImNvbXBvbmVudCIsImNvdW50Q29tcGxldGlvbnMiLCJLZXlCaW5kaW5nQWN0aW9uIiwiRm9yY2VDb21wbGV0ZUF1dG9jb21wbGV0ZSIsIkNvbXBsZXRlQXV0b2NvbXBsZXRlIiwib25Db25maXJtQ29tcGxldGlvbiIsIlByZXZTZWxlY3Rpb25JbkF1dG9jb21wbGV0ZSIsIm1vdmVTZWxlY3Rpb24iLCJOZXh0U2VsZWN0aW9uSW5BdXRvY29tcGxldGUiLCJDYW5jZWxBdXRvY29tcGxldGUiLCJvbkVzY2FwZSIsInByZXZlbnREZWZhdWx0Iiwic3RvcFByb3BhZ2F0aW9uIiwiaGFuZGxlQ2xpcGJvYXJkRXZlbnQiLCJkYXRhIiwibXhDbGllbnQiLCJldmVudFJlbGF0aW9uIiwicm9vbSIsInJlcGx5VG9FdmVudCIsImhhbmRsZUVycm9yIiwiZXJyb3IiLCJFcnJvciIsImNvbnNvbGUiLCJsb2ciLCJtZXNzYWdlIiwidHlwZSIsInVuZGVmaW5lZCIsImZpbGVzIiwibGVuZ3RoIiwidHlwZXMiLCJpbmNsdWRlcyIsIkNvbnRlbnRNZXNzYWdlcyIsInNoYXJlZEluc3RhbmNlIiwic2VuZENvbnRlbnRMaXN0VG9Sb29tIiwiQXJyYXkiLCJmcm9tIiwicm9vbUlkIiwiY2F0Y2giLCJpbWdFbGVtZW50U3RyIiwiZ2V0RGF0YSIsInBhcnNlciIsIkRPTVBhcnNlciIsImltZ0RvYyIsInBhcnNlRnJvbVN0cmluZyIsImdldEVsZW1lbnRzQnlUYWdOYW1lIiwicXVlcnlTZWxlY3RvciIsInNyYyIsInN0YXJ0c1dpdGgiLCJjaGlsZE5vZGVzIiwiaW1nU3JjIiwiZmV0Y2giLCJ0aGVuIiwicmVzcG9uc2UiLCJibG9iIiwiaW1nQmxvYiIsInNhZmV0eXBlIiwiZ2V0QmxvYlNhZmVNaW1lVHlwZSIsImV4dCIsInNwbGl0IiwicGFydHMiLCJ1cmwiLCJmaWxlbmFtZSIsImZpbGUiLCJGaWxlIiwic2VuZENvbnRlbnRUb1Jvb20iLCJpc0V2ZW50VG9IYW5kbGVBc0NsaXBib2FyZEV2ZW50IiwiaXNJbnB1dEV2ZW50Rm9yQ2xpcGJvYXJkIiwiSW5wdXRFdmVudCIsImlucHV0VHlwZSIsImlzTm90TnVsbCIsImRhdGFUcmFuc2ZlciIsImlzQ2xpcGJvYXJkRXZlbnQiLCJDbGlwYm9hcmRFdmVudCJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9jb21wb25lbnRzL3ZpZXdzL3Jvb21zL3d5c2l3eWdfY29tcG9zZXIvaG9va3MvdXRpbHMudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLypcbkNvcHlyaWdodCAyMDI0IE5ldyBWZWN0b3IgTHRkLlxuQ29weXJpZ2h0IDIwMjIgVGhlIE1hdHJpeC5vcmcgRm91bmRhdGlvbiBDLkkuQy5cblxuU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFHUEwtMy4wLW9ubHkgT1IgR1BMLTMuMC1vbmx5XG5QbGVhc2Ugc2VlIExJQ0VOU0UgZmlsZXMgaW4gdGhlIHJlcG9zaXRvcnkgcm9vdCBmb3IgZnVsbCBkZXRhaWxzLlxuKi9cblxuaW1wb3J0IHsgTXV0YWJsZVJlZk9iamVjdCwgUmVmT2JqZWN0IH0gZnJvbSBcInJlYWN0XCI7XG5pbXBvcnQgeyBJRXZlbnRSZWxhdGlvbiwgTWF0cml4Q2xpZW50IH0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL21hdHJpeFwiO1xuaW1wb3J0IHsgV3lzaXd5Z0V2ZW50IH0gZnJvbSBcIkB2ZWN0b3ItaW0vbWF0cml4LXd5c2l3eWdcIjtcblxuaW1wb3J0IHsgVGltZWxpbmVSZW5kZXJpbmdUeXBlIH0gZnJvbSBcIi4uLy4uLy4uLy4uLy4uL2NvbnRleHRzL1Jvb21Db250ZXh0XCI7XG5pbXBvcnQgeyBJUm9vbVN0YXRlIH0gZnJvbSBcIi4uLy4uLy4uLy4uL3N0cnVjdHVyZXMvUm9vbVZpZXdcIjtcbmltcG9ydCBBdXRvY29tcGxldGUgZnJvbSBcIi4uLy4uL0F1dG9jb21wbGV0ZVwiO1xuaW1wb3J0IHsgZ2V0S2V5QmluZGluZ3NNYW5hZ2VyIH0gZnJvbSBcIi4uLy4uLy4uLy4uLy4uL0tleUJpbmRpbmdzTWFuYWdlclwiO1xuaW1wb3J0IHsgS2V5QmluZGluZ0FjdGlvbiB9IGZyb20gXCIuLi8uLi8uLi8uLi8uLi9hY2Nlc3NpYmlsaXR5L0tleWJvYXJkU2hvcnRjdXRzXCI7XG5pbXBvcnQgeyBnZXRCbG9iU2FmZU1pbWVUeXBlIH0gZnJvbSBcIi4uLy4uLy4uLy4uLy4uL3V0aWxzL2Jsb2JzXCI7XG5pbXBvcnQgQ29udGVudE1lc3NhZ2VzIGZyb20gXCIuLi8uLi8uLi8uLi8uLi9Db250ZW50TWVzc2FnZXNcIjtcbmltcG9ydCB7IGlzTm90TnVsbCB9IGZyb20gXCIuLi8uLi8uLi8uLi8uLi9UeXBlZ3VhcmRzXCI7XG5cbmV4cG9ydCBmdW5jdGlvbiBmb2N1c0NvbXBvc2VyKFxuICAgIGNvbXBvc2VyRWxlbWVudDogTXV0YWJsZVJlZk9iamVjdDxIVE1MRWxlbWVudCB8IG51bGw+LFxuICAgIHJlbmRlcmluZ1R5cGU6IFRpbWVsaW5lUmVuZGVyaW5nVHlwZSxcbiAgICByb29tQ29udGV4dDogSVJvb21TdGF0ZSxcbiAgICB0aW1lb3V0SWQ6IE11dGFibGVSZWZPYmplY3Q8bnVtYmVyIHwgbnVsbD4sXG4pOiB2b2lkIHtcbiAgICBpZiAocmVuZGVyaW5nVHlwZSA9PT0gcm9vbUNvbnRleHQudGltZWxpbmVSZW5kZXJpbmdUeXBlKSB7XG4gICAgICAgIC8vIEltbWVkaWF0ZWx5IHNldCB0aGUgZm9jdXMsIHNvIGlmIHlvdSBzdGFydCB0eXBpbmcgaXRcbiAgICAgICAgLy8gd2lsbCBhcHBlYXIgaW4gdGhlIGNvbXBvc2VyXG4gICAgICAgIGNvbXBvc2VyRWxlbWVudC5jdXJyZW50Py5mb2N1cygpO1xuICAgICAgICAvLyBJZiB3ZSBjYWxsIGZvY3VzIGltbWVkaWF0ZSwgdGhlIGZvY3VzIF9pc18gaW4gdGhlIHJpZ2h0XG4gICAgICAgIC8vIHBsYWNlLCBidXQgdGhlIGN1cnNvciBpcyBpbnZpc2libGUsIHByZXN1bWFibHkgYmVjYXVzZVxuICAgICAgICAvLyBzb21lIG90aGVyIGV2ZW50IGlzIHN0aWxsIHByb2Nlc3NpbmcuXG4gICAgICAgIC8vIFRoZSBmb2xsb3dpbmcgbGluZSBlbnN1cmVzIHRoYXQgdGhlIGN1cnNvciBpcyBhY3R1YWxseVxuICAgICAgICAvLyB2aXNpYmxlIGluIGNvbXBvc2VyLlxuICAgICAgICBpZiAodGltZW91dElkLmN1cnJlbnQpIHtcbiAgICAgICAgICAgIGNsZWFyVGltZW91dCh0aW1lb3V0SWQuY3VycmVudCk7XG4gICAgICAgIH1cbiAgICAgICAgdGltZW91dElkLmN1cnJlbnQgPSB3aW5kb3cuc2V0VGltZW91dCgoKSA9PiBjb21wb3NlckVsZW1lbnQuY3VycmVudD8uZm9jdXMoKSwgMjAwKTtcbiAgICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBzZXRDdXJzb3JQb3NpdGlvbkF0VGhlRW5kKGVsZW1lbnQ6IEhUTUxFbGVtZW50KTogdm9pZCB7XG4gICAgY29uc3QgcmFuZ2UgPSBkb2N1bWVudC5jcmVhdGVSYW5nZSgpO1xuICAgIHJhbmdlLnNlbGVjdE5vZGVDb250ZW50cyhlbGVtZW50KTtcbiAgICByYW5nZS5jb2xsYXBzZShmYWxzZSk7XG4gICAgY29uc3Qgc2VsZWN0aW9uID0gZG9jdW1lbnQuZ2V0U2VsZWN0aW9uKCkhO1xuICAgIHNlbGVjdGlvbi5yZW1vdmVBbGxSYW5nZXMoKTtcbiAgICBzZWxlY3Rpb24uYWRkUmFuZ2UocmFuZ2UpO1xuXG4gICAgZWxlbWVudC5mb2N1cygpO1xufVxuXG4vKipcbiAqIFdoZW4gdGhlIGF1dG9jb21wbGV0ZSBtb2RhbCBpcyBvcGVuIHdlIG5lZWQgdG8gYmUgYWJsZSB0byBwcm9wZXJseVxuICogaGFuZGxlIGV2ZW50cyB0aGF0IGFyZSBkaXNwYXRjaGVkLiBUaGlzIGFsbG93cyB0aGUgdXNlciB0byBtb3ZlIHRoZSBzZWxlY3Rpb25cbiAqIGluIHRoZSBhdXRvY29tcGxldGUgYW5kIHNlbGVjdCB1c2luZyBlbnRlci5cbiAqXG4gKiBAcGFyYW0gYXV0b2NvbXBsZXRlUmVmIC0gYSByZWYgdG8gdGhlIGF1dG9jb21wbGV0ZSBvZiBpbnRlcmVzdFxuICogQHBhcmFtIGV2ZW50IC0gdGhlIGtleWJvYXJkIGV2ZW50IHRoYXQgaGFzIGJlZW4gZGlzcGF0Y2hlZFxuICogQHJldHVybnMgYm9vbGVhbiAtIHdoZXRoZXIgb3Igbm90IHRoZSBhdXRvY29tcGxldGUgaGFzIGhhbmRsZWQgdGhlIGV2ZW50XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBoYW5kbGVFdmVudFdpdGhBdXRvY29tcGxldGUoXG4gICAgYXV0b2NvbXBsZXRlUmVmOiBSZWZPYmplY3Q8QXV0b2NvbXBsZXRlPixcbiAgICAvLyB3ZSBnZXQgYSBSZWFjdCBLZXlib2FyZCBldmVudCBmcm9tIHBsYWluIHRleHQgY29tcG9zZXIsIGEgS2V5Ym9hcmQgRXZlbnQgZnJvbSB0aGUgcmljaCB0ZXh0IGNvbXBvc2VyXG4gICAgZXZlbnQ6IEtleWJvYXJkRXZlbnQgfCBSZWFjdC5LZXlib2FyZEV2ZW50PEhUTUxEaXZFbGVtZW50Pixcbik6IGJvb2xlYW4ge1xuICAgIGNvbnN0IGF1dG9jb21wbGV0ZUlzT3BlbiA9IGF1dG9jb21wbGV0ZVJlZj8uY3VycmVudCAmJiAhYXV0b2NvbXBsZXRlUmVmLmN1cnJlbnQuc3RhdGUuaGlkZTtcblxuICAgIGlmICghYXV0b2NvbXBsZXRlSXNPcGVuKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBsZXQgaGFuZGxlZCA9IGZhbHNlO1xuICAgIGNvbnN0IGF1dG9jb21wbGV0ZUFjdGlvbiA9IGdldEtleUJpbmRpbmdzTWFuYWdlcigpLmdldEF1dG9jb21wbGV0ZUFjdGlvbihldmVudCk7XG4gICAgY29uc3QgY29tcG9uZW50ID0gYXV0b2NvbXBsZXRlUmVmLmN1cnJlbnQ7XG5cbiAgICBpZiAoY29tcG9uZW50ICYmIGNvbXBvbmVudC5jb3VudENvbXBsZXRpb25zKCkgPiAwKSB7XG4gICAgICAgIHN3aXRjaCAoYXV0b2NvbXBsZXRlQWN0aW9uKSB7XG4gICAgICAgICAgICBjYXNlIEtleUJpbmRpbmdBY3Rpb24uRm9yY2VDb21wbGV0ZUF1dG9jb21wbGV0ZTpcbiAgICAgICAgICAgIGNhc2UgS2V5QmluZGluZ0FjdGlvbi5Db21wbGV0ZUF1dG9jb21wbGV0ZTpcbiAgICAgICAgICAgICAgICBhdXRvY29tcGxldGVSZWYuY3VycmVudC5vbkNvbmZpcm1Db21wbGV0aW9uKCk7XG4gICAgICAgICAgICAgICAgaGFuZGxlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIEtleUJpbmRpbmdBY3Rpb24uUHJldlNlbGVjdGlvbkluQXV0b2NvbXBsZXRlOlxuICAgICAgICAgICAgICAgIGF1dG9jb21wbGV0ZVJlZi5jdXJyZW50Lm1vdmVTZWxlY3Rpb24oLTEpO1xuICAgICAgICAgICAgICAgIGhhbmRsZWQgPSB0cnVlO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBLZXlCaW5kaW5nQWN0aW9uLk5leHRTZWxlY3Rpb25JbkF1dG9jb21wbGV0ZTpcbiAgICAgICAgICAgICAgICBhdXRvY29tcGxldGVSZWYuY3VycmVudC5tb3ZlU2VsZWN0aW9uKDEpO1xuICAgICAgICAgICAgICAgIGhhbmRsZWQgPSB0cnVlO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBLZXlCaW5kaW5nQWN0aW9uLkNhbmNlbEF1dG9jb21wbGV0ZTpcbiAgICAgICAgICAgICAgICBhdXRvY29tcGxldGVSZWYuY3VycmVudC5vbkVzY2FwZShldmVudCBhcyB7fSBhcyBSZWFjdC5LZXlib2FyZEV2ZW50KTtcbiAgICAgICAgICAgICAgICBoYW5kbGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgYnJlYWs7IC8vIGRvbid0IHJldHVybiBhbnl0aGluZywgYWxsb3cgZXZlbnQgdG8gcGFzcyB0aHJvdWdoXG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoaGFuZGxlZCkge1xuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICB9XG5cbiAgICByZXR1cm4gaGFuZGxlZDtcbn1cblxuLyoqXG4gKiBUYWtlcyBhbiBldmVudCBhbmQgaGFuZGxlcyBpbWFnZSBwYXN0aW5nLiBSZXR1cm5zIGEgYm9vbGVhbiB0byBpbmRpY2F0ZSBpZiBpdCBoYXMgaGFuZGxlZFxuICogdGhlIGV2ZW50IG9yIG5vdC4gTXVzdCBhY2NlcHQgZWl0aGVyIGNsaXBib2FyZCBvciBpbnB1dCBldmVudHMgaW4gb3JkZXIgdG8gcHJldmVudCBpc3N1ZTpcbiAqIGh0dHBzOi8vZ2l0aHViLmNvbS92ZWN0b3ItaW0vZWxlbWVudC13ZWIvaXNzdWVzLzI1MzI3XG4gKlxuICogQHBhcmFtIGV2ZW50IC0gZXZlbnQgdG8gcHJvY2Vzc1xuICogQHBhcmFtIGRhdGEgLSBkYXRhIGZyb20gdGhlIGV2ZW50IHRvIHByb2Nlc3NcbiAqIEBwYXJhbSByb29tQ29udGV4dCAtIHJvb20gaW4gd2hpY2ggdGhlIGV2ZW50IG9jY3Vyc1xuICogQHBhcmFtIG14Q2xpZW50IC0gY3VycmVudCBtYXRyaXggY2xpZW50XG4gKiBAcGFyYW0gZXZlbnRSZWxhdGlvbiAtIHVzZWQgdG8gc2VuZCB0aGUgZXZlbnQgdG8gdGhlIGNvcnJlY3QgcGxhY2UgZWcgdGltZWxpbmUgdnMgdGhyZWFkXG4gKiBAcmV0dXJucyAtIGJvb2xlYW4gdG8gc2hvdyBpZiB0aGUgZXZlbnQgd2FzIGhhbmRsZWQgb3Igbm90XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBoYW5kbGVDbGlwYm9hcmRFdmVudChcbiAgICBldmVudDogQ2xpcGJvYXJkRXZlbnQgfCBJbnB1dEV2ZW50LFxuICAgIGRhdGE6IERhdGFUcmFuc2ZlciB8IG51bGwsXG4gICAgcm9vbUNvbnRleHQ6IElSb29tU3RhdGUsXG4gICAgbXhDbGllbnQ6IE1hdHJpeENsaWVudCxcbiAgICBldmVudFJlbGF0aW9uPzogSUV2ZW50UmVsYXRpb24sXG4pOiBib29sZWFuIHtcbiAgICAvLyBMb2dpYyBpbiB0aGlzIGZ1bmN0aW9uIGZvbGxvd3MgdGhhdCBvZiBgU2VuZE1lc3NhZ2VDb21wb3Nlci5vblBhc3RlYFxuICAgIGNvbnN0IHsgcm9vbSwgdGltZWxpbmVSZW5kZXJpbmdUeXBlLCByZXBseVRvRXZlbnQgfSA9IHJvb21Db250ZXh0O1xuXG4gICAgZnVuY3Rpb24gaGFuZGxlRXJyb3IoZXJyb3I6IHVua25vd24pOiB2b2lkIHtcbiAgICAgICAgaWYgKGVycm9yIGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKGVycm9yLm1lc3NhZ2UpO1xuICAgICAgICB9IGVsc2UgaWYgKHR5cGVvZiBlcnJvciA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgY29uc29sZS5sb2coZXJyb3IpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGV2ZW50LnR5cGUgIT09IFwicGFzdGVcIiB8fCBkYXRhID09PSBudWxsIHx8IHJvb20gPT09IHVuZGVmaW5lZCkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgLy8gUHJpb3JpdGl6ZSB0ZXh0IG9uIHRoZSBjbGlwYm9hcmQgb3ZlciBmaWxlcyBpZiBSVEYgaXMgcHJlc2VudCBhcyBPZmZpY2Ugb24gbWFjT1MgcHV0cyBhIGJpdG1hcFxuICAgIC8vIGluIHRoZSBjbGlwYm9hcmQgYXMgd2VsbCBhcyB0aGUgY29udGVudCBiZWluZyBjb3BpZWQuIE1vZGVybiB2ZXJzaW9ucyBvZiBPZmZpY2Ugc2VlbSB0byBub3QgZG8gdGhpcyBhbnltb3JlLlxuICAgIC8vIFdlIGNoZWNrIHRleHQvcnRmIGluc3RlYWQgb2YgdGV4dC9wbGFpbiBhcyB3aGVuIGNvcHkrcGFzdGluZyBhIGZpbGUgZnJvbSBGaW5kZXIgb3IgR25vbWUgSW1hZ2UgVmlld2VyXG4gICAgLy8gaXQgcHV0cyB0aGUgZmlsZW5hbWUgaW4gYXMgdGV4dC9wbGFpbiB3aGljaCB3ZSB3YW50IHRvIGlnbm9yZS5cbiAgICBpZiAoZGF0YS5maWxlcy5sZW5ndGggJiYgIWRhdGEudHlwZXMuaW5jbHVkZXMoXCJ0ZXh0L3J0ZlwiKSkge1xuICAgICAgICBDb250ZW50TWVzc2FnZXMuc2hhcmVkSW5zdGFuY2UoKVxuICAgICAgICAgICAgLnNlbmRDb250ZW50TGlzdFRvUm9vbShBcnJheS5mcm9tKGRhdGEuZmlsZXMpLCByb29tLnJvb21JZCwgZXZlbnRSZWxhdGlvbiwgbXhDbGllbnQsIHRpbWVsaW5lUmVuZGVyaW5nVHlwZSlcbiAgICAgICAgICAgIC5jYXRjaChoYW5kbGVFcnJvcik7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIC8vIFNhZmFyaSBgSW5zZXJ0IGZyb20gaVBob25lIG9yIGlQYWRgXG4gICAgLy8gZGF0YS5nZXREYXRhKFwidGV4dC9odG1sXCIpIHJldHVybnMgYSBzdHJpbmcgbGlrZTogPGltZyBzcmM9XCJibG9iOmh0dHBzOi8vLi4uXCI+XG4gICAgaWYgKGRhdGEudHlwZXMuaW5jbHVkZXMoXCJ0ZXh0L2h0bWxcIikpIHtcbiAgICAgICAgY29uc3QgaW1nRWxlbWVudFN0ciA9IGRhdGEuZ2V0RGF0YShcInRleHQvaHRtbFwiKTtcbiAgICAgICAgY29uc3QgcGFyc2VyID0gbmV3IERPTVBhcnNlcigpO1xuICAgICAgICBjb25zdCBpbWdEb2MgPSBwYXJzZXIucGFyc2VGcm9tU3RyaW5nKGltZ0VsZW1lbnRTdHIsIFwidGV4dC9odG1sXCIpO1xuXG4gICAgICAgIGlmIChcbiAgICAgICAgICAgIGltZ0RvYy5nZXRFbGVtZW50c0J5VGFnTmFtZShcImltZ1wiKS5sZW5ndGggIT09IDEgfHxcbiAgICAgICAgICAgICFpbWdEb2MucXVlcnlTZWxlY3RvcihcImltZ1wiKT8uc3JjLnN0YXJ0c1dpdGgoXCJibG9iOlwiKSB8fFxuICAgICAgICAgICAgaW1nRG9jLmNoaWxkTm9kZXMubGVuZ3RoICE9PSAxXG4gICAgICAgICkge1xuICAgICAgICAgICAgaGFuZGxlRXJyb3IoXCJGYWlsZWQgdG8gaGFuZGxlIHBhc3RlZCBjb250ZW50IGFzIFNhZmFyaSBpbnNlcnRlZCBjb250ZW50XCIpO1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGltZ1NyYyA9IGltZ0RvYy5xdWVyeVNlbGVjdG9yKFwiaW1nXCIpIS5zcmM7XG5cbiAgICAgICAgZmV0Y2goaW1nU3JjKVxuICAgICAgICAgICAgLnRoZW4oKHJlc3BvbnNlKSA9PiB7XG4gICAgICAgICAgICAgICAgcmVzcG9uc2VcbiAgICAgICAgICAgICAgICAgICAgLmJsb2IoKVxuICAgICAgICAgICAgICAgICAgICAudGhlbigoaW1nQmxvYikgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgdHlwZSA9IGltZ0Jsb2IudHlwZTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHNhZmV0eXBlID0gZ2V0QmxvYlNhZmVNaW1lVHlwZSh0eXBlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGV4dCA9IHR5cGUuc3BsaXQoXCIvXCIpWzFdO1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgcGFydHMgPSByZXNwb25zZS51cmwuc3BsaXQoXCIvXCIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgZmlsZW5hbWUgPSBwYXJ0c1twYXJ0cy5sZW5ndGggLSAxXTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGZpbGUgPSBuZXcgRmlsZShbaW1nQmxvYl0sIGZpbGVuYW1lICsgXCIuXCIgKyBleHQsIHsgdHlwZTogc2FmZXR5cGUgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBDb250ZW50TWVzc2FnZXMuc2hhcmVkSW5zdGFuY2UoKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5zZW5kQ29udGVudFRvUm9vbShmaWxlLCByb29tLnJvb21JZCwgZXZlbnRSZWxhdGlvbiwgbXhDbGllbnQsIHJlcGx5VG9FdmVudClcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAuY2F0Y2goaGFuZGxlRXJyb3IpO1xuICAgICAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgICAgICAuY2F0Y2goaGFuZGxlRXJyb3IpO1xuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIC5jYXRjaChoYW5kbGVFcnJvcik7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIHJldHVybiBmYWxzZTtcbn1cblxuLyoqXG4gKiBVdGlsIHRvIGRldGVybWluZSBpZiBhbiBpbnB1dCBldmVudCBvciBjbGlwYm9hcmQgZXZlbnQgbXVzdCBiZSBoYW5kbGVkIGFzIGEgY2xpcGJvYXJkIGV2ZW50LlxuICogRHVlIHRvIGh0dHBzOi8vZ2l0aHViLmNvbS92ZWN0b3ItaW0vZWxlbWVudC13ZWIvaXNzdWVzLzI1MzI3LCBjZXJ0YWluIHBhc3RlIGV2ZW50c1xuICogbXVzdCBiZSBsaXN0ZW5lbmVkIGZvciB3aXRoIGFuIG9uQmVmb3JlSW5wdXQgaGFuZGxlciBhbmQgc28gd2lsbCBiZSBjYXVnaHQgYXMgaW5wdXQgZXZlbnRzLlxuICpcbiAqIEBwYXJhbSBldmVudCAtIHRoZSBldmVudCB0byB0ZXN0LCBjYW4gYmUgYSBXeXNpd3lnRXZlbnQgaWYgaXQgY29tZXMgZnJvbSB0aGUgcmljaCB0ZXh0IGVkaXRvciwgb3JcbiAqIGlucHV0IG9yIGNsaXBib2FyZCBldmVudHMgaWYgZnJvbSB0aGUgcGxhaW4gdGV4dCBlZGl0b3JcbiAqIEByZXR1cm5zIC0gdHJ1ZSBpZiBldmVudCBzaG91bGQgYmUgaGFuZGxlZCBhcyBhIGNsaXBib2FyZCBldmVudFxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNFdmVudFRvSGFuZGxlQXNDbGlwYm9hcmRFdmVudChcbiAgICBldmVudDogV3lzaXd5Z0V2ZW50IHwgSW5wdXRFdmVudCB8IENsaXBib2FyZEV2ZW50LFxuKTogZXZlbnQgaXMgSW5wdXRFdmVudCB8IENsaXBib2FyZEV2ZW50IHtcbiAgICBjb25zdCBpc0lucHV0RXZlbnRGb3JDbGlwYm9hcmQgPVxuICAgICAgICBldmVudCBpbnN0YW5jZW9mIElucHV0RXZlbnQgJiYgZXZlbnQuaW5wdXRUeXBlID09PSBcImluc2VydEZyb21QYXN0ZVwiICYmIGlzTm90TnVsbChldmVudC5kYXRhVHJhbnNmZXIpO1xuICAgIGNvbnN0IGlzQ2xpcGJvYXJkRXZlbnQgPSBldmVudCBpbnN0YW5jZW9mIENsaXBib2FyZEV2ZW50O1xuXG4gICAgcmV0dXJuIGlzQ2xpcGJvYXJkRXZlbnQgfHwgaXNJbnB1dEV2ZW50Rm9yQ2xpcGJvYXJkO1xufVxuIl0s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