matrix-react-sdk
Version:
SDK for matrix.org using React
552 lines (428 loc) • 63.6 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _react = _interopRequireDefault(require("react"));
var sdk = _interopRequireWildcard(require("../../../index"));
var _languageHandler = require("../../../languageHandler");
var _propTypes = _interopRequireDefault(require("prop-types"));
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 _EditorStateTransfer = _interopRequireDefault(require("../../../utils/EditorStateTransfer"));
var _classnames = _interopRequireDefault(require("classnames"));
var _event = require("matrix-js-sdk/src/models/event");
var _BasicMessageComposer = _interopRequireDefault(require("./BasicMessageComposer"));
var _MatrixClientContext = _interopRequireDefault(require("../../../contexts/MatrixClientContext"));
var _SlashCommands = require("../../../SlashCommands");
var _actions = require("../../../dispatcher/actions");
var _CountlyAnalytics = _interopRequireDefault(require("../../../CountlyAnalytics"));
var _KeyBindingsManager = require("../../../KeyBindingsManager");
var _replaceableComponent = require("../../../utils/replaceableComponent");
var _SendHistoryManager = _interopRequireDefault(require("../../../SendHistoryManager"));
var _Modal = _interopRequireDefault(require("../../../Modal"));
var _dec, _class, _class2, _temp;
function _isReply(mxEvent) {
const relatesTo = mxEvent.getContent()["m.relates_to"];
const isReply = !!(relatesTo && relatesTo["m.in_reply_to"]);
return isReply;
}
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 "";
}
function createEditContent(model, editedEvent) {
const isEmote = (0, _serialize.containsEmote)(model);
if (isEmote) {
model = (0, _serialize.stripEmoteCommand)(model);
}
const isReply = _isReply(editedEvent);
let plainPrefix = "";
let htmlPrefix = "";
if (isReply) {
plainPrefix = getTextReplyFallback(editedEvent);
htmlPrefix = getHtmlReplyFallback(editedEvent);
}
const body = (0, _serialize.textSerialize)(model);
const newContent = {
"msgtype": isEmote ? "m.emote" : "m.text",
"body": body
};
const contentBody = {
msgtype: newContent.msgtype,
body: `${plainPrefix} * ${body}`
};
const formattedBody = (0, _serialize.htmlSerializeIfNeeded)(model, {
forceHTML: isReply
});
if (formattedBody) {
newContent.format = "org.matrix.custom.html";
newContent.formatted_body = formattedBody;
contentBody.format = newContent.format;
contentBody.formatted_body = `${htmlPrefix} * ${formattedBody}`;
}
return Object.assign({
"m.new_content": newContent,
"m.relates_to": {
"rel_type": "m.replace",
"event_id": editedEvent.getId()
}
}, contentBody);
}
let EditMessageComposer = (_dec = (0, _replaceableComponent.replaceableComponent)("views.rooms.EditMessageComposer"), _dec(_class = (_temp = _class2 = class EditMessageComposer extends _react.default.Component {
constructor(props, context) {
super(props, context);
(0, _defineProperty2.default)(this, "_setEditorRef", ref => {
this._editorRef = ref;
});
(0, _defineProperty2.default)(this, "_onKeyDown", event => {
// ignore any keypress while doing IME compositions
if (this._editorRef.isComposing(event)) {
return;
}
const action = (0, _KeyBindingsManager.getKeyBindingsManager)().getMessageComposerAction(event);
switch (action) {
case _KeyBindingsManager.MessageComposerAction.Send:
this._sendEdit();
event.preventDefault();
break;
case _KeyBindingsManager.MessageComposerAction.CancelEditing:
this._cancelEdit();
break;
case _KeyBindingsManager.MessageComposerAction.EditPrevMessage:
{
if (this._editorRef.isModified() || !this._editorRef.isCaretAtStart()) {
return;
}
const previousEvent = (0, _EventUtils.findEditableEvent)(this._getRoom(), false, this.props.editState.getEvent().getId());
if (previousEvent) {
_dispatcher.default.dispatch({
action: 'edit_event',
event: previousEvent
});
event.preventDefault();
}
break;
}
case _KeyBindingsManager.MessageComposerAction.EditNextMessage:
{
if (this._editorRef.isModified() || !this._editorRef.isCaretAtEnd()) {
return;
}
const nextEvent = (0, _EventUtils.findEditableEvent)(this._getRoom(), true, this.props.editState.getEvent().getId());
if (nextEvent) {
_dispatcher.default.dispatch({
action: 'edit_event',
event: nextEvent
});
} else {
_dispatcher.default.dispatch({
action: 'edit_event',
event: null
});
_dispatcher.default.fire(_actions.Action.FocusComposer);
}
event.preventDefault();
break;
}
}
});
(0, _defineProperty2.default)(this, "_cancelEdit", () => {
this._clearStoredEditorState();
_dispatcher.default.dispatch({
action: "edit_event",
event: null
});
_dispatcher.default.fire(_actions.Action.FocusComposer);
});
(0, _defineProperty2.default)(this, "_sendEdit", async () => {
const startTime = _CountlyAnalytics.default.getTimestamp();
const editedEvent = this.props.editState.getEvent();
const editContent = createEditContent(this.model, editedEvent);
const newContent = editContent["m.new_content"];
let shouldSend = true; // 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) && this._isSlashCommand()) {
const [cmd, args, commandText] = this._getSlashCommand();
if (cmd) {
if (cmd.category === _SlashCommands.CommandCategories.messages) {
editContent["m.new_content"] = await this._runSlashCommand(cmd, args, roomId);
} else {
this._runSlashCommand(cmd, args, roomId);
shouldSend = false;
}
} else {
// ask the user if their unknown command should be sent as a message
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
const {
finished
} = _Modal.default.createTrackedDialog("Unknown command", "", QuestionDialog, {
title: (0, _languageHandler._t)("Unknown Command"),
description: /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)("Unrecognised command: %(commandText)s", {
commandText
})), /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)("You can use <code>/help</code> to list available commands. " + "Did you mean to send this as a message?", {}, {
code: t => /*#__PURE__*/_react.default.createElement("code", null, t)
})), /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)("Hint: Begin your message with <code>//</code> to start it with a slash.", {}, {
code: t => /*#__PURE__*/_react.default.createElement("code", null, t)
}))),
button: (0, _languageHandler._t)('Send as message')
});
const [sendAnyway] = await finished; // if !sendAnyway bail to let the user edit the composer and try again
if (!sendAnyway) return;
}
}
if (shouldSend) {
this._cancelPreviousPendingEdit();
const prom = this.context.sendMessage(roomId, editContent);
this._clearStoredEditorState();
_dispatcher.default.dispatch({
action: "message_sent"
});
_CountlyAnalytics.default.instance.trackSendMessage(startTime, prom, roomId, true, false, editContent);
}
} // close the event editing and focus composer
_dispatcher.default.dispatch({
action: "edit_event",
event: null
});
_dispatcher.default.fire(_actions.Action.FocusComposer);
});
(0, _defineProperty2.default)(this, "_onChange", () => {
if (!this.state.saveDisabled || !this._editorRef || !this._editorRef.isModified()) {
return;
}
this.setState({
saveDisabled: false
});
});
this.model = null;
this._editorRef = null;
this.state = {
saveDisabled: true
};
this._createEditorModel();
window.addEventListener("beforeunload", this._saveStoredEditorState);
}
_getRoom() {
return this.context.getRoom(this.props.editState.getEvent().getRoomId());
}
get _editorRoomKey() {
return `mx_edit_room_${this._getRoom().roomId}`;
}
get _editorStateKey() {
return `mx_edit_state_${this.props.editState.getEvent().getId()}`;
}
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) {
console.error("Error parsing editing state: ", e);
}
}
}
_clearStoredEditorState() {
localStorage.removeItem(this._editorRoomKey);
localStorage.removeItem(this._editorStateKey);
}
_clearPreviousEdit() {
if (localStorage.getItem(this._editorRoomKey)) {
localStorage.removeItem(`mx_edit_state_${localStorage.getItem(this._editorRoomKey)}`);
}
}
_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));
}
_isSlashCommand() {
const parts = this.model.parts;
const firstPart = parts[0];
if (firstPart) {
if (firstPart.type === "command" && firstPart.text.startsWith("/") && !firstPart.text.startsWith("//")) {
return true;
}
if (firstPart.text.startsWith("/") && !firstPart.text.startsWith("//") && (firstPart.type === "plain" || firstPart.type === "pill-candidate")) {
return true;
}
}
return false;
}
_isContentModified(newContent) {
// if nothing has changed then bail
const oldContent = this.props.editState.getEvent().getContent();
if (!this._editorRef.isModified() || oldContent["msgtype"] === newContent["msgtype"] && oldContent["body"] === newContent["body"] && oldContent["format"] === newContent["format"] && oldContent["formatted_body"] === newContent["formatted_body"]) {
return false;
}
return true;
}
_getSlashCommand() {
const commandText = this.model.parts.reduce((text, part) => {
// use mxid to textify user pills in a command
if (part.type === "user-pill") {
return text + part.resourceId;
}
return text + part.text;
}, "");
const {
cmd,
args
} = (0, _SlashCommands.getCommand)(commandText);
return [cmd, args, commandText];
}
async _runSlashCommand(cmd, args, roomId) {
const result = cmd.run(roomId, args);
let messageContent;
let error = result.error;
if (result.promise) {
try {
if (cmd.category === _SlashCommands.CommandCategories.messages) {
messageContent = await result.promise;
} else {
await result.promise;
}
} catch (err) {
error = err;
}
}
if (error) {
console.error("Command failure: %s", error);
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); // assume the error is a server error when the command is async
const isServerError = !!result.promise;
const title = isServerError ? (0, _languageHandler._td)("Server error") : (0, _languageHandler._td)("Command error");
let errText;
if (typeof error === 'string') {
errText = error;
} else if (error.message) {
errText = error.message;
} else {
errText = (0, _languageHandler._t)("Server unavailable, overloaded, or something else went wrong.");
}
_Modal.default.createTrackedDialog(title, '', ErrorDialog, {
title: (0, _languageHandler._t)(title),
description: errText
});
} else {
console.log("Command success.");
if (messageContent) return messageContent;
}
}
_cancelPreviousPendingEdit() {
const originalEvent = this.props.editState.getEvent();
const previousEdit = originalEvent.replacingEvent();
if (previousEdit && (previousEdit.status === _event.EventStatus.QUEUED || previousEdit.status === _event.EventStatus.NOT_SENT)) {
this.context.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) {
caret = (0, _dom.getCaretOffsetAndText)(this._editorRef, 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, parts);
window.removeEventListener("beforeunload", this._saveStoredEditorState);
if (this._shouldSaveStoredEditorState) {
this._saveStoredEditorState();
}
}
_createEditorModel() {
const {
editState
} = this.props;
const room = this._getRoom();
const partCreator = new _parts.CommandPartCreator(room, this.context);
let parts;
if (editState.hasEditorState()) {
// if restoring state from a previous editor,
// restore serialized parts from the state
parts = editState.getSerializedParts().map(p => partCreator.deserializePart(p));
} else {
//otherwise, either restore serialized parts from localStorage or parse the body of the event
parts = this._restoreStoredEditorState(partCreator) || (0, _deserialize.parseEvent)(editState.getEvent(), partCreator);
}
this.model = new _model.default(parts, partCreator);
this._saveStoredEditorState();
}
_getInitialCaretPosition() {
const {
editState
} = this.props;
let caretPosition;
if (editState.hasEditorState() && editState.getCaret()) {
// if restoring state from a previous editor,
// restore caret position from the state
const caret = editState.getCaret();
caretPosition = this.model.positionForOffset(caret.offset, caret.atNodeEnd);
} else {
// otherwise, set it at the end
caretPosition = this.model.getPositionAtEnd();
}
return caretPosition;
}
render() {
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
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._setEditorRef,
model: this.model,
room: this._getRoom(),
initialCaret: this.props.editState.getCaret(),
label: (0, _languageHandler._t)("Edit message"),
onChange: this._onChange
}), /*#__PURE__*/_react.default.createElement("div", {
className: "mx_EditMessageComposer_buttons"
}, /*#__PURE__*/_react.default.createElement(AccessibleButton, {
kind: "secondary",
onClick: this._cancelEdit
}, (0, _languageHandler._t)("Cancel")), /*#__PURE__*/_react.default.createElement(AccessibleButton, {
kind: "primary",
onClick: this._sendEdit,
disabled: this.state.saveDisabled
}, (0, _languageHandler._t)("Save"))));
}
}, (0, _defineProperty2.default)(_class2, "propTypes", {
// the message event being edited
editState: _propTypes.default.instanceOf(_EditorStateTransfer.default).isRequired
}), (0, _defineProperty2.default)(_class2, "contextType", _MatrixClientContext.default), _temp)) || _class);
exports.default = EditMessageComposer;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9jb21wb25lbnRzL3ZpZXdzL3Jvb21zL0VkaXRNZXNzYWdlQ29tcG9zZXIuanMiXSwibmFtZXMiOlsiX2lzUmVwbHkiLCJteEV2ZW50IiwicmVsYXRlc1RvIiwiZ2V0Q29udGVudCIsImlzUmVwbHkiLCJnZXRIdG1sUmVwbHlGYWxsYmFjayIsImh0bWwiLCJmb3JtYXR0ZWRfYm9keSIsInJvb3ROb2RlIiwiRE9NUGFyc2VyIiwicGFyc2VGcm9tU3RyaW5nIiwiYm9keSIsIm14UmVwbHkiLCJxdWVyeVNlbGVjdG9yIiwib3V0ZXJIVE1MIiwiZ2V0VGV4dFJlcGx5RmFsbGJhY2siLCJsaW5lcyIsInNwbGl0IiwibWFwIiwibCIsInRyaW0iLCJsZW5ndGgiLCJzdGFydHNXaXRoIiwiY3JlYXRlRWRpdENvbnRlbnQiLCJtb2RlbCIsImVkaXRlZEV2ZW50IiwiaXNFbW90ZSIsInBsYWluUHJlZml4IiwiaHRtbFByZWZpeCIsIm5ld0NvbnRlbnQiLCJjb250ZW50Qm9keSIsIm1zZ3R5cGUiLCJmb3JtYXR0ZWRCb2R5IiwiZm9yY2VIVE1MIiwiZm9ybWF0IiwiT2JqZWN0IiwiYXNzaWduIiwiZ2V0SWQiLCJFZGl0TWVzc2FnZUNvbXBvc2VyIiwiUmVhY3QiLCJDb21wb25lbnQiLCJjb25zdHJ1Y3RvciIsInByb3BzIiwiY29udGV4dCIsInJlZiIsIl9lZGl0b3JSZWYiLCJldmVudCIsImlzQ29tcG9zaW5nIiwiYWN0aW9uIiwiZ2V0TWVzc2FnZUNvbXBvc2VyQWN0aW9uIiwiTWVzc2FnZUNvbXBvc2VyQWN0aW9uIiwiU2VuZCIsIl9zZW5kRWRpdCIsInByZXZlbnREZWZhdWx0IiwiQ2FuY2VsRWRpdGluZyIsIl9jYW5jZWxFZGl0IiwiRWRpdFByZXZNZXNzYWdlIiwiaXNNb2RpZmllZCIsImlzQ2FyZXRBdFN0YXJ0IiwicHJldmlvdXNFdmVudCIsIl9nZXRSb29tIiwiZWRpdFN0YXRlIiwiZ2V0RXZlbnQiLCJkaXMiLCJkaXNwYXRjaCIsIkVkaXROZXh0TWVzc2FnZSIsImlzQ2FyZXRBdEVuZCIsIm5leHRFdmVudCIsImZpcmUiLCJBY3Rpb24iLCJGb2N1c0NvbXBvc2VyIiwiX2NsZWFyU3RvcmVkRWRpdG9yU3RhdGUiLCJzdGFydFRpbWUiLCJDb3VudGx5QW5hbHl0aWNzIiwiZ2V0VGltZXN0YW1wIiwiZWRpdENvbnRlbnQiLCJzaG91bGRTZW5kIiwiX2lzQ29udGVudE1vZGlmaWVkIiwicm9vbUlkIiwiZ2V0Um9vbUlkIiwiX2lzU2xhc2hDb21tYW5kIiwiY21kIiwiYXJncyIsImNvbW1hbmRUZXh0IiwiX2dldFNsYXNoQ29tbWFuZCIsImNhdGVnb3J5IiwiQ29tbWFuZENhdGVnb3JpZXMiLCJtZXNzYWdlcyIsIl9ydW5TbGFzaENvbW1hbmQiLCJRdWVzdGlvbkRpYWxvZyIsInNkayIsImdldENvbXBvbmVudCIsImZpbmlzaGVkIiwiTW9kYWwiLCJjcmVhdGVUcmFja2VkRGlhbG9nIiwidGl0bGUiLCJkZXNjcmlwdGlvbiIsImNvZGUiLCJ0IiwiYnV0dG9uIiwic2VuZEFueXdheSIsIl9jYW5jZWxQcmV2aW91c1BlbmRpbmdFZGl0IiwicHJvbSIsInNlbmRNZXNzYWdlIiwiaW5zdGFuY2UiLCJ0cmFja1NlbmRNZXNzYWdlIiwic3RhdGUiLCJzYXZlRGlzYWJsZWQiLCJzZXRTdGF0ZSIsIl9jcmVhdGVFZGl0b3JNb2RlbCIsIndpbmRvdyIsImFkZEV2ZW50TGlzdGVuZXIiLCJfc2F2ZVN0b3JlZEVkaXRvclN0YXRlIiwiZ2V0Um9vbSIsIl9lZGl0b3JSb29tS2V5IiwiX2VkaXRvclN0YXRlS2V5IiwiX3Nob3VsZFNhdmVTdG9yZWRFZGl0b3JTdGF0ZSIsImxvY2FsU3RvcmFnZSIsImdldEl0ZW0iLCJfcmVzdG9yZVN0b3JlZEVkaXRvclN0YXRlIiwicGFydENyZWF0b3IiLCJqc29uIiwicGFydHMiLCJzZXJpYWxpemVkUGFydHMiLCJKU09OIiwicGFyc2UiLCJwIiwiZGVzZXJpYWxpemVQYXJ0IiwiZSIsImNvbnNvbGUiLCJlcnJvciIsInJlbW92ZUl0ZW0iLCJfY2xlYXJQcmV2aW91c0VkaXQiLCJpdGVtIiwiU2VuZEhpc3RvcnlNYW5hZ2VyIiwiY3JlYXRlSXRlbSIsInNldEl0ZW0iLCJzdHJpbmdpZnkiLCJmaXJzdFBhcnQiLCJ0eXBlIiwidGV4dCIsIm9sZENvbnRlbnQiLCJyZWR1Y2UiLCJwYXJ0IiwicmVzb3VyY2VJZCIsInJlc3VsdCIsInJ1biIsIm1lc3NhZ2VDb250ZW50IiwicHJvbWlzZSIsImVyciIsIkVycm9yRGlhbG9nIiwiaXNTZXJ2ZXJFcnJvciIsImVyclRleHQiLCJtZXNzYWdlIiwibG9nIiwib3JpZ2luYWxFdmVudCIsInByZXZpb3VzRWRpdCIsInJlcGxhY2luZ0V2ZW50Iiwic3RhdHVzIiwiRXZlbnRTdGF0dXMiLCJRVUVVRUQiLCJOT1RfU0VOVCIsImNhbmNlbFBlbmRpbmdFdmVudCIsImNvbXBvbmVudFdpbGxVbm1vdW50Iiwic2VsIiwiZG9jdW1lbnQiLCJnZXRTZWxlY3Rpb24iLCJjYXJldCIsImZvY3VzTm9kZSIsInNlcmlhbGl6ZVBhcnRzIiwic2V0RWRpdG9yU3RhdGUiLCJyZW1vdmVFdmVudExpc3RlbmVyIiwicm9vbSIsIkNvbW1hbmRQYXJ0Q3JlYXRvciIsImhhc0VkaXRvclN0YXRlIiwiZ2V0U2VyaWFsaXplZFBhcnRzIiwiRWRpdG9yTW9kZWwiLCJfZ2V0SW5pdGlhbENhcmV0UG9zaXRpb24iLCJjYXJldFBvc2l0aW9uIiwiZ2V0Q2FyZXQiLCJwb3NpdGlvbkZvck9mZnNldCIsIm9mZnNldCIsImF0Tm9kZUVuZCIsImdldFBvc2l0aW9uQXRFbmQiLCJyZW5kZXIiLCJBY2Nlc3NpYmxlQnV0dG9uIiwiY2xhc3NOYW1lIiwiX29uS2V5RG93biIsIl9zZXRFZGl0b3JSZWYiLCJfb25DaGFuZ2UiLCJQcm9wVHlwZXMiLCJpbnN0YW5jZU9mIiwiRWRpdG9yU3RhdGVUcmFuc2ZlciIsImlzUmVxdWlyZWQiLCJNYXRyaXhDbGllbnRDb250ZXh0Il0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7O0FBZ0JB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QUFEO0FBQWtCLE1BQUEsSUFBSSxFQUFDLFNBQXZCO0FBQWlDLE1BQUEsT0FBTyxFQUFFLEtBQUtILFNBQS9DO0FBQTBELE1BQUEsUUFBUSxFQUFFLEtBQUtzRCxLQUFMLENBQVdDO0FBQS9FLE9BQ0sseUJBQUcsTUFBSCxDQURMLENBRkosQ0FUSSxDQUFSO0FBZ0JIOztBQWxXNEQsQyxzREFDMUM7QUFDZjtBQUNBOUMsRUFBQUEsU0FBUyxFQUFFaUksbUJBQVVDLFVBQVYsQ0FBcUJDLDRCQUFyQixFQUEwQ0M7QUFGdEMsQyx5REFLRUMsNEIiLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuQ29weXJpZ2h0IDIwMTkgTmV3IFZlY3RvciBMdGRcbkNvcHlyaWdodCAyMDE5IFRoZSBNYXRyaXgub3JnIEZvdW5kYXRpb24gQy5JLkMuXG5cbkxpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG55b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG5Zb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcblxuICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuXG5Vbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlXG5kaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiBcIkFTIElTXCIgQkFTSVMsXG5XSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC5cblNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmRcbmxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxuKi9cbmltcG9ydCBSZWFjdCBmcm9tICdyZWFjdCc7XG5pbXBvcnQgKiBhcyBzZGsgZnJvbSAnLi4vLi4vLi4vaW5kZXgnO1xuaW1wb3J0IHtfdCwgX3RkfSBmcm9tICcuLi8uLi8uLi9sYW5ndWFnZUhhbmRsZXInO1xuaW1wb3J0IFByb3BUeXBlcyBmcm9tICdwcm9wLXR5cGVzJztcbmltcG9ydCBkaXMgZnJvbSAnLi4vLi4vLi4vZGlzcGF0Y2hlci9kaXNwYXRjaGVyJztcbmltcG9ydCBFZGl0b3JNb2RlbCBmcm9tICcuLi8uLi8uLi9lZGl0b3IvbW9kZWwnO1xuaW1wb3J0IHtnZXRDYXJldE9mZnNldEFuZFRleHR9IGZyb20gJy4uLy4uLy4uL2VkaXRvci9kb20nO1xuaW1wb3J0IHtodG1sU2VyaWFsaXplSWZOZWVkZWQsIHRleHRTZXJpYWxpemUsIGNvbnRhaW5zRW1vdGUsIHN0cmlwRW1vdGVDb21tYW5kfSBmcm9tICcuLi8uLi8uLi9lZGl0b3Ivc2VyaWFsaXplJztcbmltcG9ydCB7ZmluZEVkaXRhYmxlRXZlbnR9IGZyb20gJy4uLy4uLy4uL3V0aWxzL0V2ZW50VXRpbHMnO1xuaW1wb3J0IHtwYXJzZUV2ZW50fSBmcm9tICcuLi8uLi8uLi9lZGl0b3IvZGVzZXJpYWxpemUnO1xuaW1wb3J0IHtDb21tYW5kUGFydENyZWF0b3J9IGZyb20gJy4uLy4uLy4uL2VkaXRvci9wYXJ0cyc7XG5pbXBvcnQgRWRpdG9yU3RhdGVUcmFuc2ZlciBmcm9tICcuLi8uLi8uLi91dGlscy9FZGl0b3JTdGF0ZVRyYW5zZmVyJztcbmltcG9ydCBjbGFzc05hbWVzIGZyb20gJ2NsYXNzbmFtZXMnO1xuaW1wb3J0IHtFdmVudFN0YXR1c30gZnJvbSAnbWF0cml4LWpzLXNkay9zcmMvbW9kZWxzL2V2ZW50JztcbmltcG9ydCBCYXNpY01lc3NhZ2VDb21wb3NlciBmcm9tIFwiLi9CYXNpY01lc3NhZ2VDb21wb3NlclwiO1xuaW1wb3J0IE1hdHJpeENsaWVudENvbnRleHQgZnJvbSBcIi4uLy4uLy4uL2NvbnRleHRzL01hdHJpeENsaWVudENvbnRleHRcIjtcbmltcG9ydCB7Q29tbWFuZENhdGVnb3JpZXMsIGdldENvbW1hbmR9IGZyb20gJy4uLy4uLy4uL1NsYXNoQ29tbWFuZHMnO1xuaW1wb3J0IHtBY3Rpb259IGZyb20gXCIuLi8uLi8uLi9kaXNwYXRjaGVyL2FjdGlvbnNcIjtcbmltcG9ydCBDb3VudGx5QW5hbHl0aWNzIGZyb20gXCIuLi8uLi8uLi9Db3VudGx5QW5hbHl0aWNzXCI7XG5pbXBvcnQge2dldEtleUJpbmRpbmdzTWFuYWdlciwgTWVzc2FnZUNvbXBvc2VyQWN0aW9ufSBmcm9tICcuLi8uLi8uLi9LZXlCaW5kaW5nc01hbmFnZXInO1xuaW1wb3J0IHtyZXBsYWNlYWJsZUNvbXBvbmVudH0gZnJvbSBcIi4uLy4uLy4uL3V0aWxzL3JlcGxhY2VhYmxlQ29tcG9uZW50XCI7XG5pbXBvcnQgU2VuZEhpc3RvcnlNYW5hZ2VyIGZyb20gJy4uLy4uLy4uL1NlbmRIaXN0b3J5TWFuYWdlcic7XG5pbXBvcnQgTW9kYWwgZnJvbSAnLi4vLi4vLi4vTW9kYWwnO1xuXG5mdW5jdGlvbiBfaXNSZXBseShteEV2ZW50KSB7XG4gICAgY29uc3QgcmVsYXRlc1RvID0gbXhFdmVudC5nZXRDb250ZW50KClbXCJtLnJlbGF0ZXNfdG9cIl07XG4gICAgY29uc3QgaXNSZXBseSA9ICEhKHJlbGF0ZXNUbyAmJiByZWxhdGVzVG9bXCJtLmluX3JlcGx5X3RvXCJdKTtcbiAgICByZXR1cm4gaXNSZXBseTtcbn1cblxuZnVuY3Rpb24gZ2V0SHRtbFJlcGx5RmFsbGJhY2sobXhFdmVudCkge1xuICAgIGNvbnN0IGh0bWwgPSBteEV2ZW50LmdldENvbnRlbnQoKS5mb3JtYXR0ZWRfYm9keTtcbiAgICBpZiAoIWh0bWwpIHtcbiAgICAgICAgcmV0dXJuIFwiXCI7XG4gICAgfVxuICAgIGNvbnN0IHJvb3ROb2RlID0gbmV3IERPTVBhcnNlcigpLnBhcnNlRnJvbVN0cmluZyhodG1sLCBcInRleHQvaHRtbFwiKS5ib2R5O1xuICAgIGNvbnN0IG14UmVwbHkgPSByb290Tm9kZS5xdWVyeVNlbGVjdG9yKFwibXgtcmVwbHlcIik7XG4gICAgcmV0dXJuIChteFJlcGx5ICYmIG14UmVwbHkub3V0ZXJIVE1MKSB8fCBcIlwiO1xufVxuXG5mdW5jdGlvbiBnZXRUZXh0UmVwbHlGYWxsYmFjayhteEV2ZW50KSB7XG4gICAgY29uc3QgYm9keSA9IG14RXZlbnQuZ2V0Q29udGVudCgpLmJvZHk7XG4gICAgY29uc3QgbGluZXMgPSBib2R5LnNwbGl0KFwiXFxuXCIpLm1hcChsID0+IGwudHJpbSgpKTtcbiAgICBpZiAobGluZXMubGVuZ3RoID4gMiAmJiBsaW5lc1swXS5zdGFydHNXaXRoKFwiPiBcIikgJiYgbGluZXNbMV0ubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIHJldHVybiBgJHtsaW5lc1swXX1cXG5cXG5gO1xuICAgIH1cbiAgICByZXR1cm4gXCJcIjtcbn1cblxuZnVuY3Rpb24gY3JlYXRlRWRpdENvbnRlbnQobW9kZWwsIGVkaXRlZEV2ZW50KSB7XG4gICAgY29uc3QgaXNFbW90ZSA9IGNvbnRhaW5zRW1vdGUobW9kZWwpO1xuICAgIGlmIChpc0Vtb3RlKSB7XG4gICAgICAgIG1vZGVsID0gc3RyaXBFbW90ZUNvbW1hbmQobW9kZWwpO1xuICAgIH1cbiAgICBjb25zdCBpc1JlcGx5ID0gX2lzUmVwbHkoZWRpdGVkRXZlbnQpO1xuICAgIGxldCBwbGFpblByZWZpeCA9IFwiXCI7XG4gICAgbGV0IGh0bWxQcmVmaXggPSBcIlwiO1xuXG4gICAgaWYgKGlzUmVwbHkpIHtcbiAgICAgICAgcGxhaW5QcmVmaXggPSBnZXRUZXh0UmVwbHlGYWxsYmFjayhlZGl0ZWRFdmVudCk7XG4gICAgICAgIGh0bWxQcmVmaXggPSBnZXRIdG1sUmVwbHlGYWxsYmFjayhlZGl0ZWRFdmVudCk7XG4gICAgfVxuXG4gICAgY29uc3QgYm9keSA9IHRleHRTZXJpYWxpemUobW9kZWwpO1xuXG4gICAgY29uc3QgbmV3Q29udGVudCA9IHtcbiAgICAgICAgXCJtc2d0eXBlXCI6IGlzRW1vdGUgPyBcIm0uZW1vdGVcIiA6IFwibS50ZXh0XCIsXG4gICAgICAgIFwiYm9keVwiOiBib2R5LFxuICAgIH07XG4gICAgY29uc3QgY29udGVudEJvZHkgPSB7XG4gICAgICAgIG1zZ3R5cGU6IG5ld0NvbnRlbnQubXNndHlwZSxcbiAgICAgICAgYm9keTogYCR7cGxhaW5QcmVmaXh9ICogJHtib2R5fWAsXG4gICAgfTtcblxuICAgIGNvbnN0IGZvcm1hdHRlZEJvZHkgPSBodG1sU2VyaWFsaXplSWZOZWVkZWQobW9kZWwsIHtmb3JjZUhUTUw6IGlzUmVwbHl9KTtcbiAgICBpZiAoZm9ybWF0dGVkQm9keSkge1xuICAgICAgICBuZXdDb250ZW50LmZvcm1hdCA9IFwib3JnLm1hdHJpeC5jdXN0b20uaHRtbFwiO1xuICAgICAgICBuZXdDb250ZW50LmZvcm1hdHRlZF9ib2R5ID0gZm9ybWF0dGVkQm9keTtcbiAgICAgICAgY29udGVudEJvZHkuZm9ybWF0ID0gbmV3Q29udGVudC5mb3JtYXQ7XG4gICAgICAgIGNvbnRlbnRCb2R5LmZvcm1hdHRlZF9ib2R5ID0gYCR7aHRtbFByZWZpeH0gKiAke2Zvcm1hdHRlZEJvZHl9YDtcbiAgICB9XG5cbiAgICByZXR1cm4gT2JqZWN0LmFzc2lnbih7XG4gICAgICAgIFwibS5uZXdfY29udGVudFwiOiBuZXdDb250ZW50LFxuICAgICAgICBcIm0ucmVsYXRlc190b1wiOiB7XG4gICAgICAgICAgICBcInJlbF90eXBlXCI6IFwibS5yZXBsYWNlXCIsXG4gICAgICAgICAgICBcImV2ZW50X2lkXCI6IGVkaXRlZEV2ZW50LmdldElkKCksXG4gICAgICAgIH0sXG4gICAgfSwgY29udGVudEJvZHkpO1xufVxuXG5AcmVwbGFjZWFibGVDb21wb25lbnQoXCJ2aWV3cy5yb29tcy5FZGl0TWVzc2FnZUNvbXBvc2VyXCIpXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBFZGl0TWVzc2FnZUNvbXBvc2VyIGV4dGVuZHMgUmVhY3QuQ29tcG9uZW50IHtcbiAgICBzdGF0aWMgcHJvcFR5cGVzID0ge1xuICAgICAgICAvLyB0aGUgbWVzc2FnZSBldmVudCBiZWluZyBlZGl0ZWRcbiAgICAgICAgZWRpdFN0YXRlOiBQcm9wVHlwZXMuaW5zdGFuY2VPZihFZGl0b3JTdGF0ZVRyYW5zZmVyKS5pc1JlcXVpcmVkLFxuICAgIH07XG5cbiAgICBzdGF0aWMgY29udGV4dFR5cGUgPSBNYXRyaXhDbGllbnRDb250ZXh0O1xuXG4gICAgY29uc3RydWN0b3IocHJvcHMsIGNvbnRleHQpIHtcbiAgICAgICAgc3VwZXIocHJvcHMsIGNvbnRleHQpO1xuICAgICAgICB0aGlzLm1vZGVsID0gbnVsbDtcbiAgICAgICAgdGhpcy5fZWRpdG9yUmVmID0gbnVsbDtcblxuICAgICAgICB0aGlzLnN0YXRlID0ge1xuICAgICAgICAgICAgc2F2ZURpc2FibGVkOiB0cnVlLFxuICAgICAgICB9O1xuICAgICAgICB0aGlzLl9jcmVhdGVFZGl0b3JNb2RlbCgpO1xuICAgICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihcImJlZm9yZXVubG9hZFwiLCB0aGlzLl9zYXZlU3RvcmVkRWRpdG9yU3RhdGUpO1xuICAgIH1cblxuICAgIF9zZXRFZGl0b3JSZWYgPSByZWYgPT4ge1xuICAgICAgICB0aGlzLl9lZGl0b3JSZWYgPSByZWY7XG4gICAgfTtcblxuICAgIF9nZXRSb29tKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5jb250ZXh0LmdldFJvb20odGhpcy5wcm9wcy5lZGl0U3RhdGUuZ2V0RXZlbnQoKS5nZXRSb29tSWQoKSk7XG4gICAgfVxuXG4gICAgX29uS2V5RG93biA9IChldmVudCkgPT4ge1xuICAgICAgICAvLyBpZ25vcmUgYW55IGtleXByZXNzIHdoaWxlIGRvaW5nIElNRSBjb21wb3NpdGlvbnNcbiAgICAgICAgaWYgKHRoaXMuX2VkaXRvclJlZi5pc0NvbXBvc2luZyhldmVudCkpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBhY3Rpb24gPSBnZXRLZXlCaW5kaW5nc01hbmFnZXIoKS5nZXRNZXNzYWdlQ29tcG9zZXJBY3Rpb24oZXZlbnQpO1xuICAgICAgICBzd2l0Y2ggKGFjdGlvbikge1xuICAgICAgICAgICAgY2FzZSBNZXNzYWdlQ29tcG9zZXJBY3Rpb24uU2VuZDpcbiAgICAgICAgICAgICAgICB0aGlzLl9zZW5kRWRpdCgpO1xuICAgICAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIE1lc3NhZ2VDb21wb3NlckFjdGlvbi5DYW5jZWxFZGl0aW5nOlxuICAgICAgICAgICAgICAgIHRoaXMuX2NhbmNlbEVkaXQoKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgTWVzc2FnZUNvbXBvc2VyQWN0aW9uLkVkaXRQcmV2TWVzc2FnZToge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLl9lZGl0b3JSZWYuaXNNb2RpZmllZCgpIHx8ICF0aGlzLl9lZGl0b3JSZWYuaXNDYXJldEF0U3RhcnQoKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNvbnN0IHByZXZpb3VzRXZlbnQgPSBmaW5kRWRpdGFibGVFdmVudCh0aGlzLl9nZXRSb29tKCksIGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICB0aGlzLnByb3BzLmVkaXRTdGF0ZS5nZXRFdmVudCgpLmdldElkKCkpO1xuICAgICAgICAgICAgICAgIGlmIChwcmV2aW91c0V2ZW50KSB7XG4gICAgICAgICAgICAgICAgICAgIGRpcy5kaXNwYXRjaCh7YWN0aW9uOiAnZWRpdF9ldmVudCcsIGV2ZW50OiBwcmV2aW91c0V2ZW50fSk7XG4gICAgICAgICAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FzZSBNZXNzYWdlQ29tcG9zZXJBY3Rpb24uRWRpdE5leHRNZXNzYWdlOiB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuX2VkaXRvclJlZi5pc01vZGlmaWVkKCkgfHwgIXRoaXMuX2VkaXRvclJlZi5pc0NhcmV0QXRFbmQoKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNvbnN0IG5leHRFdmVudCA9IGZpbmRFZGl0YWJsZUV2ZW50KHRoaXMuX2dldFJvb20oKSwgdHJ1ZSwgdGhpcy5wcm9wcy5lZGl0U3RhdGUuZ2V0RXZlbnQoKS5nZXRJZCgpKTtcbiAgICAgICAgICAgICAgICBpZiAobmV4dEV2ZW50KSB7XG4gICAgICAgICAgICAgICAgICAgIGRpcy5kaXNwYXRjaCh7YWN0aW9uOiAnZWRpdF9ldmVudCcsIGV2ZW50OiBuZXh0RXZlbnR9KTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBkaXMuZGlzcGF0Y2goe2FjdGlvbjogJ2VkaXRfZXZlbnQnLCBldmVudDogbnVsbH0pO1xuICAgICAgICAgICAgICAgICAgICBkaXMuZmlyZShBY3Rpb24uRm9jdXNDb21wb3Nlcik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBnZXQgX2VkaXRvclJvb21LZXkoKSB7XG4gICAgICAgIHJldHVybiBgbXhfZWRpdF9yb29tXyR7dGhpcy5fZ2V0Um9vbSgpLnJvb21JZH1gO1xuICAgIH1cblxuICAgIGdldCBfZWRpdG9yU3RhdGVLZXkoKSB7XG4gICAgICAgIHJldHVybiBgbXhfZWRpdF9zdGF0ZV8ke3RoaXMucHJvcHMuZWRpdFN0YXRlLmdldEV2ZW50KCkuZ2V0SWQoKX1gO1xuICAgIH1cblxuICAgIF9jYW5jZWxFZGl0ID0gKCkgPT4ge1xuICAgICAgICB0aGlzLl9jbGVhclN0b3JlZEVkaXRvclN0YXRlKCk7XG4gICAgICAgIGRpcy5kaXNwYXRjaCh7YWN0aW9uOiBcImVkaXRfZXZlbnRcIiwgZXZlbnQ6IG51bGx9KTtcbiAgICAgICAgZGlzLmZpcmUoQWN0aW9uLkZvY3VzQ29tcG9zZXIpO1xuICAgIH1cblxuICAgIGdldCBfc2hvdWxkU2F2ZVN0b3JlZEVkaXRvclN0YXRlKCkge1xuICAgICAgICByZXR1cm4gbG9jYWxTdG9yYWdlLmdldEl0ZW0odGhpcy5fZWRpdG9yUm9vbUtleSkgIT09IG51bGw7XG4gICAgfVxuXG4gICAgX3Jlc3RvcmVTdG9yZWRFZGl0b3JTdGF0ZShwYXJ0Q3JlYXRvcikge1xuICAgICAgICBjb25zdCBqc29uID0gbG9jYWxTdG9yYWdlLmdldEl0ZW0odGhpcy5fZWRpdG9yU3RhdGVLZXkpO1xuICAgICAgICBpZiAoanNvbikge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICBjb25zdCB7cGFydHM6IHNlcmlhbGl6ZWRQYXJ0c30gPSBKU09OLnBhcnNlKGpzb24pO1xuICAgICAgICAgICAgICAgIGNvbnN0IHBhcnRzID0gc2VyaWFsaXplZFBhcnRzLm1hcChwID0+IHBhcnRDcmVhdG9yLmRlc2VyaWFsaXplUGFydChwKSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHBhcnRzO1xuICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJFcnJvciBwYXJzaW5nIGVkaXRpbmcgc3RhdGU6IFwiLCBlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIF9jbGVhclN0b3JlZEVkaXRvclN0YXRlKCkge1xuICAgICAgICBsb2NhbFN0b3JhZ2UucmVtb3ZlSXRlbSh0aGlzLl9lZGl0b3JSb29tS2V5KTtcbiAgICAgICAgbG9jYWxTdG9yYWdlLnJlbW92ZUl0ZW0odGhpcy5fZWRpdG9yU3RhdGVLZXkpO1xuICAgIH1cblxuICAgIF9jbGVhclByZXZpb3VzRWRpdCgpIHtcbiAgICAgICAgaWYgKGxvY2FsU3RvcmFnZS5nZXRJdGVtKHRoaXMuX2VkaXRvclJvb21LZXkpKSB7XG4gICAgICAgICAgICBsb2NhbFN0b3JhZ2UucmVtb3ZlSXRlbShgbXhfZWRpdF9zdGF0ZV8ke2xvY2FsU3RvcmFnZS5nZXRJdGVtKHRoaXMuX2VkaXRvclJvb21LZXkpfWApO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgX3NhdmVTdG9yZWRFZGl0b3JTdGF0ZSgpIHtcbiAgICAgICAgY29uc3QgaXRlbSA9IFNlbmRIaXN0b3J5TWFuYWdlci5jcmVhdGVJdGVtKHRoaXMubW9kZWwpO1xuICAgICAgICB0aGlzLl9jbGVhclByZXZpb3VzRWRpdCgpO1xuICAgICAgICBsb2NhbFN0b3JhZ2Uuc2V0SXRlbSh0aGlzLl9lZGl0b3JSb29tS2V5LCB0aGlzLnByb3BzLmVkaXRTdGF0ZS5nZXRFdmVudCgpLmdldElkKCkpO1xuICAgICAgICBsb2NhbFN0b3JhZ2Uuc2V0SXRlbSh0aGlzLl9lZGl0b3JTdGF0ZUtleSwgSlNPTi5zdHJpbmdpZnkoaXRlbSkp