matrix-react-sdk
Version:
SDK for matrix.org using React
183 lines (175 loc) • 28.4 kB
JavaScript
;
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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