UNPKG

matrix-react-sdk

Version:
402 lines (399 loc) 73.7 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _react = _interopRequireDefault(require("react")); var _reactDom = _interopRequireDefault(require("react-dom")); var _matrix = require("matrix-js-sdk/src/matrix"); var _server = require("react-dom/server"); var _logger = require("matrix-js-sdk/src/logger"); var _escapeHtml = _interopRequireDefault(require("escape-html")); var _compoundWeb = require("@vector-im/compound-web"); var _Exporter = _interopRequireDefault(require("./Exporter")); var _Media = require("../../customisations/Media"); var _Layout = require("../../settings/enums/Layout"); var _MessagePanel = require("../../components/structures/MessagePanel"); var _DateUtils = require("../../DateUtils"); var _Permalinks = require("../permalinks/Permalinks"); var _languageHandler = require("../../languageHandler"); var Avatar = _interopRequireWildcard(require("../../Avatar")); var _EventTile = _interopRequireDefault(require("../../components/views/rooms/EventTile")); var _DateSeparator = _interopRequireDefault(require("../../components/views/messages/DateSeparator")); var _BaseAvatar = _interopRequireDefault(require("../../components/views/avatars/BaseAvatar")); var _MatrixClientContext = _interopRequireDefault(require("../../contexts/MatrixClientContext")); var _exportCSS = _interopRequireDefault(require("./exportCSS")); var _TextForEvent = require("../../TextForEvent"); var _EventTileFactory = require("../../events/EventTileFactory"); var _exportJS = _interopRequireDefault(require("!!raw-loader!./exportJS")); function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } /* Copyright 2024 New Vector Ltd. Copyright 2021-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. */ class HTMLExporter extends _Exporter.default { constructor(room, exportType, exportOptions, setProgressText) { super(room, exportType, exportOptions, setProgressText); (0, _defineProperty2.default)(this, "avatars", void 0); (0, _defineProperty2.default)(this, "permalinkCreator", void 0); (0, _defineProperty2.default)(this, "totalSize", void 0); (0, _defineProperty2.default)(this, "mediaOmitText", void 0); this.avatars = new Map(); this.permalinkCreator = new _Permalinks.RoomPermalinkCreator(this.room); this.totalSize = 0; this.mediaOmitText = !this.exportOptions.attachmentsIncluded ? (0, _languageHandler._t)("export_chat|media_omitted") : (0, _languageHandler._t)("export_chat|media_omitted_file_size"); } async getRoomAvatar() { let blob = undefined; const avatarUrl = Avatar.avatarUrlForRoom(this.room, 32, 32, "crop"); const avatarPath = "room.png"; if (avatarUrl) { try { const image = await fetch(avatarUrl); blob = await image.blob(); this.totalSize += blob.size; this.addFile(avatarPath, blob); } catch (err) { _logger.logger.log("Failed to fetch room's avatar" + err); } } const avatar = /*#__PURE__*/_react.default.createElement(_BaseAvatar.default, { size: "32px", name: this.room.name, title: this.room.name, url: blob ? avatarPath : "" }); return (0, _server.renderToStaticMarkup)(avatar); } async wrapHTML(content, currentPage, nbPages) { const roomAvatar = await this.getRoomAvatar(); const exportDate = (0, _DateUtils.formatFullDateNoDayNoTime)(new Date()); const creator = this.room.currentState.getStateEvents(_matrix.EventType.RoomCreate, "")?.getSender(); const creatorName = (creator ? this.room.getMember(creator)?.rawDisplayName : creator) || creator; const exporter = this.room.client.getSafeUserId(); const exporterName = this.room.getMember(exporter)?.rawDisplayName; const topic = this.room.currentState.getStateEvents(_matrix.EventType.RoomTopic, "")?.getContent()?.topic || ""; const safeCreatedText = (0, _escapeHtml.default)((0, _languageHandler._t)("export_chat|creator_summary", { creatorName })); const safeExporter = (0, _escapeHtml.default)(exporter); const safeRoomName = (0, _escapeHtml.default)(this.room.name); const safeTopic = (0, _escapeHtml.default)(topic); const safeExportedText = (0, _server.renderToStaticMarkup)( /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)("export_chat|export_info", { exportDate }, { roomName: () => /*#__PURE__*/_react.default.createElement("strong", null, safeRoomName), exporterDetails: () => /*#__PURE__*/_react.default.createElement("a", { href: `https://matrix.to/#/${encodeURIComponent(exporter)}`, target: "_blank", rel: "noopener noreferrer" }, exporterName ? /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("strong", null, (0, _escapeHtml.default)(exporterName)), "I ", " (" + safeExporter + ")") : /*#__PURE__*/_react.default.createElement("strong", null, safeExporter)) }))); const safeTopicText = topic ? (0, _languageHandler._t)("export_chat|topic", { topic: safeTopic }) : ""; const previousMessagesLink = (0, _server.renderToStaticMarkup)(currentPage !== 0 ? /*#__PURE__*/_react.default.createElement("div", { style: { textAlign: "center" } }, /*#__PURE__*/_react.default.createElement("a", { href: `./messages${currentPage === 1 ? "" : currentPage}.html`, style: { fontWeight: "bold" } }, (0, _languageHandler._t)("export_chat|previous_page"))) : /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null)); const nextMessagesLink = (0, _server.renderToStaticMarkup)(currentPage < nbPages - 1 ? /*#__PURE__*/_react.default.createElement("div", { style: { textAlign: "center", margin: "10px" } }, /*#__PURE__*/_react.default.createElement("a", { href: "./messages" + (currentPage + 2) + ".html", style: { fontWeight: "bold" } }, (0, _languageHandler._t)("export_chat|next_page"))) : /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null)); return ` <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link href="css/style.css" rel="stylesheet" /> <script src="js/script.js"></script> <title>${(0, _languageHandler._t)("export_chat|html_title")}</title> </head> <body style="height: 100vh;" class="cpd-theme-light"> <div id="matrixchat" style="height: 100%; overflow: auto"> <div class="mx_MatrixChat_wrapper" aria-hidden="false"> <div class="mx_MatrixChat"> <main class="mx_RoomView"> <div class="mx_LegacyRoomHeader light-panel"> <div class="mx_LegacyRoomHeader_wrapper" aria-owns="mx_RightPanel"> <div class="mx_LegacyRoomHeader_avatar"> <div class="mx_DecoratedRoomAvatar"> ${roomAvatar} </div> </div> <div class="mx_LegacyRoomHeader_name"> <div dir="auto" class="mx_LegacyRoomHeader_nametext" title="${safeRoomName}" > ${safeRoomName} </div> </div> <div class="mx_LegacyRoomHeader_topic" dir="auto"> ${safeTopic} </div> </div> </div> ${previousMessagesLink} <div class="mx_MainSplit"> <div class="mx_RoomView_body"> <div class="mx_RoomView_timeline mx_RoomView_timeline_rr_enabled" > <div class=" mx_AutoHideScrollbar mx_ScrollPanel mx_RoomView_messagePanel " > <div class="mx_RoomView_messageListWrapper"> <ol class="mx_RoomView_MessageList" aria-live="polite" role="list" > ${currentPage == 0 ? `<div class="mx_NewRoomIntro"> ${roomAvatar} <h2> ${safeRoomName} </h2> <p> ${safeCreatedText} <br/><br/> ${safeExportedText} </p> <br/> <p> ${safeTopicText} </p> </div>` : ""} ${content} </ol> </div> </div> </div> <div class="mx_RoomView_statusArea"> <div class="mx_RoomView_statusAreaBox"> <div class="mx_RoomView_statusAreaBox_line"></div> </div> </div> </div> </div> ${nextMessagesLink} </main> </div> </div> </div> <div id="snackbar"/> </body> </html>`; } getAvatarURL(event) { const member = event.sender; const avatarUrl = member?.getMxcAvatarUrl(); return avatarUrl ? (0, _Media.mediaFromMxc)(avatarUrl).getThumbnailOfSourceHttp(30, 30, "crop") : null; } async saveAvatarIfNeeded(event) { const member = event.sender; if (!this.avatars.has(member.userId)) { try { const avatarUrl = this.getAvatarURL(event); this.avatars.set(member.userId, true); const image = await fetch(avatarUrl); const blob = await image.blob(); this.addFile(`users/${member.userId.replace(/:/g, "-")}.png`, blob); } catch (err) { _logger.logger.log("Failed to fetch user's avatar" + err); } } } getDateSeparator(event) { const ts = event.getTs(); const dateSeparator = /*#__PURE__*/_react.default.createElement("li", { key: ts }, /*#__PURE__*/_react.default.createElement(_DateSeparator.default, { forExport: true, key: ts, roomId: event.getRoomId(), ts: ts })); return (0, _server.renderToStaticMarkup)(dateSeparator); } needsDateSeparator(event, prevEvent) { if (!prevEvent) return true; return (0, _DateUtils.wantsDateSeparator)(prevEvent.getDate() || undefined, event.getDate() || undefined); } getEventTile(mxEv, continuation) { return /*#__PURE__*/_react.default.createElement("div", { className: "mx_Export_EventWrapper", id: mxEv.getId() }, /*#__PURE__*/_react.default.createElement(_MatrixClientContext.default.Provider, { value: this.room.client }, /*#__PURE__*/_react.default.createElement(_compoundWeb.TooltipProvider, null, /*#__PURE__*/_react.default.createElement(_EventTile.default, { mxEvent: mxEv, continuation: continuation, isRedacted: mxEv.isRedacted(), replacingEventId: mxEv.replacingEventId(), forExport: true, alwaysShowTimestamps: true, showUrlPreview: false, checkUnmounting: () => false, isTwelveHour: false, last: false, lastInSection: false, permalinkCreator: this.permalinkCreator, lastSuccessful: false, isSelectedEvent: false, showReactions: false, layout: _Layout.Layout.Group, showReadReceipts: false })))); } async getEventTileMarkup(mxEv, continuation, filePath) { const avatarUrl = this.getAvatarURL(mxEv); const hasAvatar = !!avatarUrl; if (hasAvatar) await this.saveAvatarIfNeeded(mxEv); const EventTile = this.getEventTile(mxEv, continuation); let eventTileMarkup; if (mxEv.getContent().msgtype == _matrix.MsgType.Emote || mxEv.getContent().msgtype == _matrix.MsgType.Notice || mxEv.getContent().msgtype === _matrix.MsgType.Text) { // to linkify textual events, we'll need lifecycle methods which won't be invoked in renderToString // So, we'll have to render the component into a temporary root element const tempRoot = document.createElement("div"); _reactDom.default.render(EventTile, tempRoot); eventTileMarkup = tempRoot.innerHTML; } else { eventTileMarkup = (0, _server.renderToStaticMarkup)(EventTile); } if (filePath) { const mxc = mxEv.getContent().url ?? mxEv.getContent().file?.url; eventTileMarkup = eventTileMarkup.split(mxc).join(filePath); } eventTileMarkup = eventTileMarkup.replace(/<span class="mx_MFileBody_info_icon".*?>.*?<\/span>/, ""); if (hasAvatar) { eventTileMarkup = eventTileMarkup.replace(encodeURI(avatarUrl).replace(/&/g, "&amp;"), `users/${mxEv.sender.userId.replace(/:/g, "-")}.png`); } return eventTileMarkup; } createModifiedEvent(text, mxEv, italic = true) { const modifiedContent = { msgtype: _matrix.MsgType.Text, body: `${text}`, format: "org.matrix.custom.html", formatted_body: `${text}` }; if (italic) { modifiedContent.formatted_body = "<em>" + modifiedContent.formatted_body + "</em>"; modifiedContent.body = "*" + modifiedContent.body + "*"; } const modifiedEvent = new _matrix.MatrixEvent(); modifiedEvent.event = mxEv.event; modifiedEvent.sender = mxEv.sender; modifiedEvent.event.type = "m.room.message"; modifiedEvent.event.content = modifiedContent; return modifiedEvent; } async createMessageBody(mxEv, joined = false) { let eventTile; try { if (this.isAttachment(mxEv)) { if (this.exportOptions.attachmentsIncluded) { try { const blob = await this.getMediaBlob(mxEv); if (this.totalSize + blob.size > this.exportOptions.maxSize) { eventTile = await this.getEventTileMarkup(this.createModifiedEvent(this.mediaOmitText, mxEv), joined); } else { this.totalSize += blob.size; const filePath = this.getFilePath(mxEv); eventTile = await this.getEventTileMarkup(mxEv, joined, filePath); if (this.totalSize == this.exportOptions.maxSize) { this.exportOptions.attachmentsIncluded = false; } this.addFile(filePath, blob); } } catch (e) { _logger.logger.log("Error while fetching file" + e); eventTile = await this.getEventTileMarkup(this.createModifiedEvent((0, _languageHandler._t)("export_chat|error_fetching_file"), mxEv), joined); } } else { eventTile = await this.getEventTileMarkup(this.createModifiedEvent(this.mediaOmitText, mxEv), joined); } } else { eventTile = await this.getEventTileMarkup(mxEv, joined); } } catch (e) { // TODO: Handle callEvent errors _logger.logger.error(e); eventTile = await this.getEventTileMarkup(this.createModifiedEvent((0, _TextForEvent.textForEvent)(mxEv, this.room.client), mxEv, false), joined); } return eventTile; } async createHTML(events, start, currentPage, nbPages) { let content = ""; let prevEvent = null; for (let i = start; i < Math.min(start + 1000, events.length); i++) { const event = events[i]; this.updateProgress((0, _languageHandler._t)("export_chat|processing_event_n", { number: i + 1, total: events.length }), false, true); if (this.cancelled) return this.cleanUp(); if (!(0, _EventTileFactory.haveRendererForEvent)(event, this.room.client, false)) continue; content += this.needsDateSeparator(event, prevEvent) ? this.getDateSeparator(event) : ""; const shouldBeJoined = !this.needsDateSeparator(event, prevEvent) && (0, _MessagePanel.shouldFormContinuation)(prevEvent, event, this.room.client, false); const body = await this.createMessageBody(event, shouldBeJoined); this.totalSize += Buffer.byteLength(body); content += body; prevEvent = event; } return this.wrapHTML(content, currentPage, nbPages); } async export() { this.updateProgress((0, _languageHandler._t)("export_chat|starting_export")); const fetchStart = performance.now(); const res = await this.getRequiredEvents(); const fetchEnd = performance.now(); this.updateProgress((0, _languageHandler._t)("export_chat|fetched_n_events_in_time", { count: res.length, seconds: (fetchEnd - fetchStart) / 1000 }), true, false); this.updateProgress((0, _languageHandler._t)("export_chat|creating_html")); const usedClasses = new Set(); for (let page = 0; page < res.length / 1000; page++) { const html = await this.createHTML(res, page * 1000, page, res.length / 1000); const document = new DOMParser().parseFromString(html, "text/html"); document.querySelectorAll("*").forEach(element => { element.classList.forEach(c => usedClasses.add(c)); }); this.addFile(`messages${page ? page + 1 : ""}.html`, new Blob([html])); } const exportCSS = await (0, _exportCSS.default)(usedClasses); this.addFile("css/style.css", new Blob([exportCSS])); this.addFile("js/script.js", new Blob([_exportJS.default])); await this.downloadZIP(); const exportEnd = performance.now(); if (this.cancelled) { _logger.logger.info("Export cancelled successfully"); } else { this.updateProgress((0, _languageHandler._t)("export_chat|export_successful")); this.updateProgress((0, _languageHandler._t)("export_chat|exported_n_events_in_time", { count: res.length, seconds: (exportEnd - fetchStart) / 1000 })); } this.cleanUp(); } } exports.default = HTMLExporter; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfcmVhY3QiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwicmVxdWlyZSIsIl9yZWFjdERvbSIsIl9tYXRyaXgiLCJfc2VydmVyIiwiX2xvZ2dlciIsIl9lc2NhcGVIdG1sIiwiX2NvbXBvdW5kV2ViIiwiX0V4cG9ydGVyIiwiX01lZGlhIiwiX0xheW91dCIsIl9NZXNzYWdlUGFuZWwiLCJfRGF0ZVV0aWxzIiwiX1Blcm1hbGlua3MiLCJfbGFuZ3VhZ2VIYW5kbGVyIiwiQXZhdGFyIiwiX2ludGVyb3BSZXF1aXJlV2lsZGNhcmQiLCJfRXZlbnRUaWxlIiwiX0RhdGVTZXBhcmF0b3IiLCJfQmFzZUF2YXRhciIsIl9NYXRyaXhDbGllbnRDb250ZXh0IiwiX2V4cG9ydENTUyIsIl9UZXh0Rm9yRXZlbnQiLCJfRXZlbnRUaWxlRmFjdG9yeSIsIl9leHBvcnRKUyIsIl9nZXRSZXF1aXJlV2lsZGNhcmRDYWNoZSIsImUiLCJXZWFrTWFwIiwiciIsInQiLCJfX2VzTW9kdWxlIiwiZGVmYXVsdCIsImhhcyIsImdldCIsIm4iLCJfX3Byb3RvX18iLCJhIiwiT2JqZWN0IiwiZGVmaW5lUHJvcGVydHkiLCJnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IiLCJ1IiwiaGFzT3duUHJvcGVydHkiLCJjYWxsIiwiaSIsInNldCIsIkhUTUxFeHBvcnRlciIsIkV4cG9ydGVyIiwiY29uc3RydWN0b3IiLCJyb29tIiwiZXhwb3J0VHlwZSIsImV4cG9ydE9wdGlvbnMiLCJzZXRQcm9ncmVzc1RleHQiLCJfZGVmaW5lUHJvcGVydHkyIiwiYXZhdGFycyIsIk1hcCIsInBlcm1hbGlua0NyZWF0b3IiLCJSb29tUGVybWFsaW5rQ3JlYXRvciIsInRvdGFsU2l6ZSIsIm1lZGlhT21pdFRleHQiLCJhdHRhY2htZW50c0luY2x1ZGVkIiwiX3QiLCJnZXRSb29tQXZhdGFyIiwiYmxvYiIsInVuZGVmaW5lZCIsImF2YXRhclVybCIsImF2YXRhclVybEZvclJvb20iLCJhdmF0YXJQYXRoIiwiaW1hZ2UiLCJmZXRjaCIsInNpemUiLCJhZGRGaWxlIiwiZXJyIiwibG9nZ2VyIiwibG9nIiwiYXZhdGFyIiwiY3JlYXRlRWxlbWVudCIsIm5hbWUiLCJ0aXRsZSIsInVybCIsInJlbmRlclRvU3RhdGljTWFya3VwIiwid3JhcEhUTUwiLCJjb250ZW50IiwiY3VycmVudFBhZ2UiLCJuYlBhZ2VzIiwicm9vbUF2YXRhciIsImV4cG9ydERhdGUiLCJmb3JtYXRGdWxsRGF0ZU5vRGF5Tm9UaW1lIiwiRGF0ZSIsImNyZWF0b3IiLCJjdXJyZW50U3RhdGUiLCJnZXRTdGF0ZUV2ZW50cyIsIkV2ZW50VHlwZSIsIlJvb21DcmVhdGUiLCJnZXRTZW5kZXIiLCJjcmVhdG9yTmFtZSIsImdldE1lbWJlciIsInJhd0Rpc3BsYXlOYW1lIiwiZXhwb3J0ZXIiLCJjbGllbnQiLCJnZXRTYWZlVXNlcklkIiwiZXhwb3J0ZXJOYW1lIiwidG9waWMiLCJSb29tVG9waWMiLCJnZXRDb250ZW50Iiwic2FmZUNyZWF0ZWRUZXh0IiwiZXNjYXBlSHRtbCIsInNhZmVFeHBvcnRlciIsInNhZmVSb29tTmFtZSIsInNhZmVUb3BpYyIsInNhZmVFeHBvcnRlZFRleHQiLCJyb29tTmFtZSIsImV4cG9ydGVyRGV0YWlscyIsImhyZWYiLCJlbmNvZGVVUklDb21wb25lbnQiLCJ0YXJnZXQiLCJyZWwiLCJGcmFnbWVudCIsInNhZmVUb3BpY1RleHQiLCJwcmV2aW91c01lc3NhZ2VzTGluayIsInN0eWxlIiwidGV4dEFsaWduIiwiZm9udFdlaWdodCIsIm5leHRNZXNzYWdlc0xpbmsiLCJtYXJnaW4iLCJnZXRBdmF0YXJVUkwiLCJldmVudCIsIm1lbWJlciIsInNlbmRlciIsImdldE14Y0F2YXRhclVybCIsIm1lZGlhRnJvbU14YyIsImdldFRodW1ibmFpbE9mU291cmNlSHR0cCIsInNhdmVBdmF0YXJJZk5lZWRlZCIsInVzZXJJZCIsInJlcGxhY2UiLCJnZXREYXRlU2VwYXJhdG9yIiwidHMiLCJnZXRUcyIsImRhdGVTZXBhcmF0b3IiLCJrZXkiLCJmb3JFeHBvcnQiLCJyb29tSWQiLCJnZXRSb29tSWQiLCJuZWVkc0RhdGVTZXBhcmF0b3IiLCJwcmV2RXZlbnQiLCJ3YW50c0RhdGVTZXBhcmF0b3IiLCJnZXREYXRlIiwiZ2V0RXZlbnRUaWxlIiwibXhFdiIsImNvbnRpbnVhdGlvbiIsImNsYXNzTmFtZSIsImlkIiwiZ2V0SWQiLCJQcm92aWRlciIsInZhbHVlIiwiVG9vbHRpcFByb3ZpZGVyIiwibXhFdmVudCIsImlzUmVkYWN0ZWQiLCJyZXBsYWNpbmdFdmVudElkIiwiYWx3YXlzU2hvd1RpbWVzdGFtcHMiLCJzaG93VXJsUHJldmlldyIsImNoZWNrVW5tb3VudGluZyIsImlzVHdlbHZlSG91ciIsImxhc3QiLCJsYXN0SW5TZWN0aW9uIiwibGFzdFN1Y2Nlc3NmdWwiLCJpc1NlbGVjdGVkRXZlbnQiLCJzaG93UmVhY3Rpb25zIiwibGF5b3V0IiwiTGF5b3V0IiwiR3JvdXAiLCJzaG93UmVhZFJlY2VpcHRzIiwiZ2V0RXZlbnRUaWxlTWFya3VwIiwiZmlsZVBhdGgiLCJoYXNBdmF0YXIiLCJFdmVudFRpbGUiLCJldmVudFRpbGVNYXJrdXAiLCJtc2d0eXBlIiwiTXNnVHlwZSIsIkVtb3RlIiwiTm90aWNlIiwiVGV4dCIsInRlbXBSb290IiwiZG9jdW1lbnQiLCJSZWFjdERPTSIsInJlbmRlciIsImlubmVySFRNTCIsIm14YyIsImZpbGUiLCJzcGxpdCIsImpvaW4iLCJlbmNvZGVVUkkiLCJjcmVhdGVNb2RpZmllZEV2ZW50IiwidGV4dCIsIml0YWxpYyIsIm1vZGlmaWVkQ29udGVudCIsImJvZHkiLCJmb3JtYXQiLCJmb3JtYXR0ZWRfYm9keSIsIm1vZGlmaWVkRXZlbnQiLCJNYXRyaXhFdmVudCIsInR5cGUiLCJjcmVhdGVNZXNzYWdlQm9keSIsImpvaW5lZCIsImV2ZW50VGlsZSIsImlzQXR0YWNobWVudCIsImdldE1lZGlhQmxvYiIsIm1heFNpemUiLCJnZXRGaWxlUGF0aCIsImVycm9yIiwidGV4dEZvckV2ZW50IiwiY3JlYXRlSFRNTCIsImV2ZW50cyIsInN0YXJ0IiwiTWF0aCIsIm1pbiIsImxlbmd0aCIsInVwZGF0ZVByb2dyZXNzIiwibnVtYmVyIiwidG90YWwiLCJjYW5jZWxsZWQiLCJjbGVhblVwIiwiaGF2ZVJlbmRlcmVyRm9yRXZlbnQiLCJzaG91bGRCZUpvaW5lZCIsInNob3VsZEZvcm1Db250aW51YXRpb24iLCJCdWZmZXIiLCJieXRlTGVuZ3RoIiwiZXhwb3J0IiwiZmV0Y2hTdGFydCIsInBlcmZvcm1hbmNlIiwibm93IiwicmVzIiwiZ2V0UmVxdWlyZWRFdmVudHMiLCJmZXRjaEVuZCIsImNvdW50Iiwic2Vjb25kcyIsInVzZWRDbGFzc2VzIiwiU2V0IiwicGFnZSIsImh0bWwiLCJET01QYXJzZXIiLCJwYXJzZUZyb21TdHJpbmciLCJxdWVyeVNlbGVjdG9yQWxsIiwiZm9yRWFjaCIsImVsZW1lbnQiLCJjbGFzc0xpc3QiLCJjIiwiYWRkIiwiQmxvYiIsImV4cG9ydENTUyIsImdldEV4cG9ydENTUyIsImV4cG9ydEpTIiwiZG93bmxvYWRaSVAiLCJleHBvcnRFbmQiLCJpbmZvIiwiZXhwb3J0cyJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy91dGlscy9leHBvcnRVdGlscy9IdG1sRXhwb3J0LnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuQ29weXJpZ2h0IDIwMjQgTmV3IFZlY3RvciBMdGQuXG5Db3B5cmlnaHQgMjAyMS0yMDIzIFRoZSBNYXRyaXgub3JnIEZvdW5kYXRpb24gQy5JLkMuXG5cblNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBR1BMLTMuMC1vbmx5IE9SIEdQTC0zLjAtb25seVxuUGxlYXNlIHNlZSBMSUNFTlNFIGZpbGVzIGluIHRoZSByZXBvc2l0b3J5IHJvb3QgZm9yIGZ1bGwgZGV0YWlscy5cbiovXG5cbmltcG9ydCBSZWFjdCBmcm9tIFwicmVhY3RcIjtcbmltcG9ydCBSZWFjdERPTSBmcm9tIFwicmVhY3QtZG9tXCI7XG5pbXBvcnQgeyBSb29tLCBNYXRyaXhFdmVudCwgRXZlbnRUeXBlLCBNc2dUeXBlIH0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL21hdHJpeFwiO1xuaW1wb3J0IHsgcmVuZGVyVG9TdGF0aWNNYXJrdXAgfSBmcm9tIFwicmVhY3QtZG9tL3NlcnZlclwiO1xuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL2xvZ2dlclwiO1xuaW1wb3J0IGVzY2FwZUh0bWwgZnJvbSBcImVzY2FwZS1odG1sXCI7XG5pbXBvcnQgeyBUb29sdGlwUHJvdmlkZXIgfSBmcm9tIFwiQHZlY3Rvci1pbS9jb21wb3VuZC13ZWJcIjtcblxuaW1wb3J0IEV4cG9ydGVyIGZyb20gXCIuL0V4cG9ydGVyXCI7XG5pbXBvcnQgeyBtZWRpYUZyb21NeGMgfSBmcm9tIFwiLi4vLi4vY3VzdG9taXNhdGlvbnMvTWVkaWFcIjtcbmltcG9ydCB7IExheW91dCB9IGZyb20gXCIuLi8uLi9zZXR0aW5ncy9lbnVtcy9MYXlvdXRcIjtcbmltcG9ydCB7IHNob3VsZEZvcm1Db250aW51YXRpb24gfSBmcm9tIFwiLi4vLi4vY29tcG9uZW50cy9zdHJ1Y3R1cmVzL01lc3NhZ2VQYW5lbFwiO1xuaW1wb3J0IHsgZm9ybWF0RnVsbERhdGVOb0RheU5vVGltZSwgd2FudHNEYXRlU2VwYXJhdG9yIH0gZnJvbSBcIi4uLy4uL0RhdGVVdGlsc1wiO1xuaW1wb3J0IHsgUm9vbVBlcm1hbGlua0NyZWF0b3IgfSBmcm9tIFwiLi4vcGVybWFsaW5rcy9QZXJtYWxpbmtzXCI7XG5pbXBvcnQgeyBfdCB9IGZyb20gXCIuLi8uLi9sYW5ndWFnZUhhbmRsZXJcIjtcbmltcG9ydCAqIGFzIEF2YXRhciBmcm9tIFwiLi4vLi4vQXZhdGFyXCI7XG5pbXBvcnQgRXZlbnRUaWxlIGZyb20gXCIuLi8uLi9jb21wb25lbnRzL3ZpZXdzL3Jvb21zL0V2ZW50VGlsZVwiO1xuaW1wb3J0IERhdGVTZXBhcmF0b3IgZnJvbSBcIi4uLy4uL2NvbXBvbmVudHMvdmlld3MvbWVzc2FnZXMvRGF0ZVNlcGFyYXRvclwiO1xuaW1wb3J0IEJhc2VBdmF0YXIgZnJvbSBcIi4uLy4uL2NvbXBvbmVudHMvdmlld3MvYXZhdGFycy9CYXNlQXZhdGFyXCI7XG5pbXBvcnQgeyBFeHBvcnRUeXBlLCBJRXhwb3J0T3B0aW9ucyB9IGZyb20gXCIuL2V4cG9ydFV0aWxzXCI7XG5pbXBvcnQgTWF0cml4Q2xpZW50Q29udGV4dCBmcm9tIFwiLi4vLi4vY29udGV4dHMvTWF0cml4Q2xpZW50Q29udGV4dFwiO1xuaW1wb3J0IGdldEV4cG9ydENTUyBmcm9tIFwiLi9leHBvcnRDU1NcIjtcbmltcG9ydCB7IHRleHRGb3JFdmVudCB9IGZyb20gXCIuLi8uLi9UZXh0Rm9yRXZlbnRcIjtcbmltcG9ydCB7IGhhdmVSZW5kZXJlckZvckV2ZW50IH0gZnJvbSBcIi4uLy4uL2V2ZW50cy9FdmVudFRpbGVGYWN0b3J5XCI7XG5cbmltcG9ydCBleHBvcnRKUyBmcm9tIFwiISFyYXctbG9hZGVyIS4vZXhwb3J0SlNcIjtcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgSFRNTEV4cG9ydGVyIGV4dGVuZHMgRXhwb3J0ZXIge1xuICAgIHByb3RlY3RlZCBhdmF0YXJzOiBNYXA8c3RyaW5nLCBib29sZWFuPjtcbiAgICBwcm90ZWN0ZWQgcGVybWFsaW5rQ3JlYXRvcjogUm9vbVBlcm1hbGlua0NyZWF0b3I7XG4gICAgcHJvdGVjdGVkIHRvdGFsU2l6ZTogbnVtYmVyO1xuICAgIHByb3RlY3RlZCBtZWRpYU9taXRUZXh0OiBzdHJpbmc7XG5cbiAgICBwdWJsaWMgY29uc3RydWN0b3IoXG4gICAgICAgIHJvb206IFJvb20sXG4gICAgICAgIGV4cG9ydFR5cGU6IEV4cG9ydFR5cGUsXG4gICAgICAgIGV4cG9ydE9wdGlvbnM6IElFeHBvcnRPcHRpb25zLFxuICAgICAgICBzZXRQcm9ncmVzc1RleHQ6IFJlYWN0LkRpc3BhdGNoPFJlYWN0LlNldFN0YXRlQWN0aW9uPHN0cmluZz4+LFxuICAgICkge1xuICAgICAgICBzdXBlcihyb29tLCBleHBvcnRUeXBlLCBleHBvcnRPcHRpb25zLCBzZXRQcm9ncmVzc1RleHQpO1xuICAgICAgICB0aGlzLmF2YXRhcnMgPSBuZXcgTWFwPHN0cmluZywgYm9vbGVhbj4oKTtcbiAgICAgICAgdGhpcy5wZXJtYWxpbmtDcmVhdG9yID0gbmV3IFJvb21QZXJtYWxpbmtDcmVhdG9yKHRoaXMucm9vbSk7XG4gICAgICAgIHRoaXMudG90YWxTaXplID0gMDtcbiAgICAgICAgdGhpcy5tZWRpYU9taXRUZXh0ID0gIXRoaXMuZXhwb3J0T3B0aW9ucy5hdHRhY2htZW50c0luY2x1ZGVkXG4gICAgICAgICAgICA/IF90KFwiZXhwb3J0X2NoYXR8bWVkaWFfb21pdHRlZFwiKVxuICAgICAgICAgICAgOiBfdChcImV4cG9ydF9jaGF0fG1lZGlhX29taXR0ZWRfZmlsZV9zaXplXCIpO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBhc3luYyBnZXRSb29tQXZhdGFyKCk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgICAgIGxldCBibG9iOiBCbG9iIHwgdW5kZWZpbmVkID0gdW5kZWZpbmVkO1xuICAgICAgICBjb25zdCBhdmF0YXJVcmwgPSBBdmF0YXIuYXZhdGFyVXJsRm9yUm9vbSh0aGlzLnJvb20sIDMyLCAzMiwgXCJjcm9wXCIpO1xuICAgICAgICBjb25zdCBhdmF0YXJQYXRoID0gXCJyb29tLnBuZ1wiO1xuICAgICAgICBpZiAoYXZhdGFyVXJsKSB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIGNvbnN0IGltYWdlID0gYXdhaXQgZmV0Y2goYXZhdGFyVXJsKTtcbiAgICAgICAgICAgICAgICBibG9iID0gYXdhaXQgaW1hZ2UuYmxvYigpO1xuICAgICAgICAgICAgICAgIHRoaXMudG90YWxTaXplICs9IGJsb2Iuc2l6ZTtcbiAgICAgICAgICAgICAgICB0aGlzLmFkZEZpbGUoYXZhdGFyUGF0aCwgYmxvYik7XG4gICAgICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgICAgICBsb2dnZXIubG9nKFwiRmFpbGVkIHRvIGZldGNoIHJvb20ncyBhdmF0YXJcIiArIGVycik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgYXZhdGFyID0gKFxuICAgICAgICAgICAgPEJhc2VBdmF0YXIgc2l6ZT1cIjMycHhcIiBuYW1lPXt0aGlzLnJvb20ubmFtZX0gdGl0bGU9e3RoaXMucm9vbS5uYW1lfSB1cmw9e2Jsb2IgPyBhdmF0YXJQYXRoIDogXCJcIn0gLz5cbiAgICAgICAgKTtcbiAgICAgICAgcmV0dXJuIHJlbmRlclRvU3RhdGljTWFya3VwKGF2YXRhcik7XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIGFzeW5jIHdyYXBIVE1MKGNvbnRlbnQ6IHN0cmluZywgY3VycmVudFBhZ2U6IG51bWJlciwgbmJQYWdlczogbnVtYmVyKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICAgICAgY29uc3Qgcm9vbUF2YXRhciA9IGF3YWl0IHRoaXMuZ2V0Um9vbUF2YXRhcigpO1xuICAgICAgICBjb25zdCBleHBvcnREYXRlID0gZm9ybWF0RnVsbERhdGVOb0RheU5vVGltZShuZXcgRGF0ZSgpKTtcbiAgICAgICAgY29uc3QgY3JlYXRvciA9IHRoaXMucm9vbS5jdXJyZW50U3RhdGUuZ2V0U3RhdGVFdmVudHMoRXZlbnRUeXBlLlJvb21DcmVhdGUsIFwiXCIpPy5nZXRTZW5kZXIoKTtcbiAgICAgICAgY29uc3QgY3JlYXRvck5hbWUgPSAoY3JlYXRvciA/IHRoaXMucm9vbS5nZXRNZW1iZXIoY3JlYXRvcik/LnJhd0Rpc3BsYXlOYW1lIDogY3JlYXRvcikgfHwgY3JlYXRvcjtcbiAgICAgICAgY29uc3QgZXhwb3J0ZXIgPSB0aGlzLnJvb20uY2xpZW50LmdldFNhZmVVc2VySWQoKTtcbiAgICAgICAgY29uc3QgZXhwb3J0ZXJOYW1lID0gdGhpcy5yb29tLmdldE1lbWJlcihleHBvcnRlcik/LnJhd0Rpc3BsYXlOYW1lO1xuICAgICAgICBjb25zdCB0b3BpYyA9IHRoaXMucm9vbS5jdXJyZW50U3RhdGUuZ2V0U3RhdGVFdmVudHMoRXZlbnRUeXBlLlJvb21Ub3BpYywgXCJcIik/LmdldENvbnRlbnQoKT8udG9waWMgfHwgXCJcIjtcblxuICAgICAgICBjb25zdCBzYWZlQ3JlYXRlZFRleHQgPSBlc2NhcGVIdG1sKFxuICAgICAgICAgICAgX3QoXCJleHBvcnRfY2hhdHxjcmVhdG9yX3N1bW1hcnlcIiwge1xuICAgICAgICAgICAgICAgIGNyZWF0b3JOYW1lLFxuICAgICAgICAgICAgfSksXG4gICAgICAgICk7XG4gICAgICAgIGNvbnN0IHNhZmVFeHBvcnRlciA9IGVzY2FwZUh0bWwoZXhwb3J0ZXIpO1xuICAgICAgICBjb25zdCBzYWZlUm9vbU5hbWUgPSBlc2NhcGVIdG1sKHRoaXMucm9vbS5uYW1lKTtcbiAgICAgICAgY29uc3Qgc2FmZVRvcGljID0gZXNjYXBlSHRtbCh0b3BpYyk7XG4gICAgICAgIGNvbnN0IHNhZmVFeHBvcnRlZFRleHQgPSByZW5kZXJUb1N0YXRpY01hcmt1cChcbiAgICAgICAgICAgIDxwPlxuICAgICAgICAgICAgICAgIHtfdChcbiAgICAgICAgICAgICAgICAgICAgXCJleHBvcnRfY2hhdHxleHBvcnRfaW5mb1wiLFxuICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICBleHBvcnREYXRlLFxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICByb29tTmFtZTogKCkgPT4gPHN0cm9uZz57c2FmZVJvb21OYW1lfTwvc3Ryb25nPixcbiAgICAgICAgICAgICAgICAgICAgICAgIGV4cG9ydGVyRGV0YWlsczogKCkgPT4gKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxhXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhyZWY9e2BodHRwczovL21hdHJpeC50by8jLyR7ZW5jb2RlVVJJQ29tcG9uZW50KGV4cG9ydGVyKX1gfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YXJnZXQ9XCJfYmxhbmtcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWw9XCJub29wZW5lciBub3JlZmVycmVyXCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHtleHBvcnRlck5hbWUgPyAoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8PlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzdHJvbmc+e2VzY2FwZUh0bWwoZXhwb3J0ZXJOYW1lKX08L3N0cm9uZz5JIHtcIiAoXCIgKyBzYWZlRXhwb3J0ZXIgKyBcIilcIn1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApIDogKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHN0cm9uZz57c2FmZUV4cG9ydGVyfTwvc3Ryb25nPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvYT5cbiAgICAgICAgICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgKX1cbiAgICAgICAgICAgIDwvcD4sXG4gICAgICAgICk7XG5cbiAgICAgICAgY29uc3Qgc2FmZVRvcGljVGV4dCA9IHRvcGljID8gX3QoXCJleHBvcnRfY2hhdHx0b3BpY1wiLCB7IHRvcGljOiBzYWZlVG9waWMgfSkgOiBcIlwiO1xuICAgICAgICBjb25zdCBwcmV2aW91c01lc3NhZ2VzTGluayA9IHJlbmRlclRvU3RhdGljTWFya3VwKFxuICAgICAgICAgICAgY3VycmVudFBhZ2UgIT09IDAgPyAoXG4gICAgICAgICAgICAgICAgPGRpdiBzdHlsZT17eyB0ZXh0QWxpZ246IFwiY2VudGVyXCIgfX0+XG4gICAgICAgICAgICAgICAgICAgIDxhIGhyZWY9e2AuL21lc3NhZ2VzJHtjdXJyZW50UGFnZSA9PT0gMSA/IFwiXCIgOiBjdXJyZW50UGFnZX0uaHRtbGB9IHN0eWxlPXt7IGZvbnRXZWlnaHQ6IFwiYm9sZFwiIH19PlxuICAgICAgICAgICAgICAgICAgICAgICAge190KFwiZXhwb3J0X2NoYXR8cHJldmlvdXNfcGFnZVwiKX1cbiAgICAgICAgICAgICAgICAgICAgPC9hPlxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgKSA6IChcbiAgICAgICAgICAgICAgICA8PjwvPlxuICAgICAgICAgICAgKSxcbiAgICAgICAgKTtcblxuICAgICAgICBjb25zdCBuZXh0TWVzc2FnZXNMaW5rID0gcmVuZGVyVG9TdGF0aWNNYXJrdXAoXG4gICAgICAgICAgICBjdXJyZW50UGFnZSA8IG5iUGFnZXMgLSAxID8gKFxuICAgICAgICAgICAgICAgIDxkaXYgc3R5bGU9e3sgdGV4dEFsaWduOiBcImNlbnRlclwiLCBtYXJnaW46IFwiMTBweFwiIH19PlxuICAgICAgICAgICAgICAgICAgICA8YSBocmVmPXtcIi4vbWVzc2FnZXNcIiArIChjdXJyZW50UGFnZSArIDIpICsgXCIuaHRtbFwifSBzdHlsZT17eyBmb250V2VpZ2h0OiBcImJvbGRcIiB9fT5cbiAgICAgICAgICAgICAgICAgICAgICAgIHtfdChcImV4cG9ydF9jaGF0fG5leHRfcGFnZVwiKX1cbiAgICAgICAgICAgICAgICAgICAgPC9hPlxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgKSA6IChcbiAgICAgICAgICAgICAgICA8PjwvPlxuICAgICAgICAgICAgKSxcbiAgICAgICAgKTtcblxuICAgICAgICByZXR1cm4gYFxuICAgICAgICAgIDwhRE9DVFlQRSBodG1sPlxuICAgICAgICAgICAgPGh0bWwgbGFuZz1cImVuXCI+XG4gICAgICAgICAgICA8aGVhZD5cbiAgICAgICAgICAgICAgICA8bWV0YSBjaGFyc2V0PVwiVVRGLThcIiAvPlxuICAgICAgICAgICAgICAgIDxtZXRhIGh0dHAtZXF1aXY9XCJYLVVBLUNvbXBhdGlibGVcIiBjb250ZW50PVwiSUU9ZWRnZVwiIC8+XG4gICAgICAgICAgICAgICAgPG1ldGEgbmFtZT1cInZpZXdwb3J0XCIgY29udGVudD1cIndpZHRoPWRldmljZS13aWR0aCwgaW5pdGlhbC1zY2FsZT0xLjBcIiAvPlxuICAgICAgICAgICAgICAgIDxsaW5rIGhyZWY9XCJjc3Mvc3R5bGUuY3NzXCIgcmVsPVwic3R5bGVzaGVldFwiIC8+XG4gICAgICAgICAgICAgICAgPHNjcmlwdCBzcmM9XCJqcy9zY3JpcHQuanNcIj48L3NjcmlwdD5cbiAgICAgICAgICAgICAgICA8dGl0bGU+JHtfdChcImV4cG9ydF9jaGF0fGh0bWxfdGl0bGVcIil9PC90aXRsZT5cbiAgICAgICAgICAgIDwvaGVhZD5cbiAgICAgICAgICAgIDxib2R5IHN0eWxlPVwiaGVpZ2h0OiAxMDB2aDtcIiBjbGFzcz1cImNwZC10aGVtZS1saWdodFwiPlxuICAgICAgICAgICAgICAgIDxkaXYgaWQ9XCJtYXRyaXhjaGF0XCIgc3R5bGU9XCJoZWlnaHQ6IDEwMCU7IG92ZXJmbG93OiBhdXRvXCI+XG4gICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJteF9NYXRyaXhDaGF0X3dyYXBwZXJcIiBhcmlhLWhpZGRlbj1cImZhbHNlXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwibXhfTWF0cml4Q2hhdFwiPlxuICAgICAgICAgICAgICAgICAgICAgICAgPG1haW4gY2xhc3M9XCJteF9Sb29tVmlld1wiPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJteF9MZWdhY3lSb29tSGVhZGVyIGxpZ2h0LXBhbmVsXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cIm14X0xlZ2FjeVJvb21IZWFkZXJfd3JhcHBlclwiIGFyaWEtb3ducz1cIm14X1JpZ2h0UGFuZWxcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cIm14X0xlZ2FjeVJvb21IZWFkZXJfYXZhdGFyXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJteF9EZWNvcmF0ZWRSb29tQXZhdGFyXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICR7cm9vbUF2YXRhcn1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwibXhfTGVnYWN5Um9vbUhlYWRlcl9uYW1lXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXZcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpcj1cImF1dG9cIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xhc3M9XCJteF9MZWdhY3lSb29tSGVhZGVyX25hbWV0ZXh0XCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlPVwiJHtzYWZlUm9vbU5hbWV9XCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJHtzYWZlUm9vbU5hbWV9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cIm14X0xlZ2FjeVJvb21IZWFkZXJfdG9waWNcIiBkaXI9XCJhdXRvXCI+ICR7c2FmZVRvcGljfSA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAke3ByZXZpb3VzTWVzc2FnZXNMaW5rfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJteF9NYWluU3BsaXRcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwibXhfUm9vbVZpZXdfYm9keVwiPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ZGl2XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsYXNzPVwibXhfUm9vbVZpZXdfdGltZWxpbmUgbXhfUm9vbVZpZXdfdGltZWxpbmVfcnJfZW5hYmxlZFwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xhc3M9XCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG14X0F1dG9IaWRlU2Nyb2xsYmFyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBteF9TY3JvbGxQYW5lbFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXhfUm9vbVZpZXdfbWVzc2FnZVBhbmVsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwibXhfUm9vbVZpZXdfbWVzc2FnZUxpc3RXcmFwcGVyXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8b2xcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGFzcz1cIm14X1Jvb21WaWV3X01lc3NhZ2VMaXN0XCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcmlhLWxpdmU9XCJwb2xpdGVcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvbGU9XCJsaXN0XCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICR7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VycmVudFBhZ2UgPT0gMFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA/IGA8ZGl2IGNsYXNzPVwibXhfTmV3Um9vbUludHJvXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICR7cm9vbUF2YXRhcn1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGgyPiAke3NhZmVSb29tTmFtZX0gPC9oMj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHA+ICR7c2FmZUNyZWF0ZWRUZXh0fSA8YnIvPjxici8+ICR7c2FmZUV4cG9ydGVkVGV4dH0gPC9wPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8YnIvPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8cD4gJHtzYWZlVG9waWNUZXh0fSA8L3A+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+YFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA6IFwiXCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICR7Y29udGVudH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvb2w+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwibXhfUm9vbVZpZXdfc3RhdHVzQXJlYVwiPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwibXhfUm9vbVZpZXdfc3RhdHVzQXJlYUJveFwiPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cIm14X1Jvb21WaWV3X3N0YXR1c0FyZWFCb3hfbGluZVwiPjwvZGl2PlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJHtuZXh0TWVzc2FnZXNMaW5rfVxuICAgICAgICAgICAgICAgICAgICAgICAgPC9tYWluPlxuICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgIDxkaXYgaWQ9XCJzbmFja2JhclwiLz5cbiAgICAgICAgICAgIDwvYm9keT5cbiAgICAgICAgPC9odG1sPmA7XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIGdldEF2YXRhclVSTChldmVudDogTWF0cml4RXZlbnQpOiBzdHJpbmcgfCBudWxsIHtcbiAgICAgICAgY29uc3QgbWVtYmVyID0gZXZlbnQuc2VuZGVyO1xuICAgICAgICBjb25zdCBhdmF0YXJVcmwgPSBtZW1iZXI/LmdldE14Y0F2YXRhclVybCgpO1xuICAgICAgICByZXR1cm4gYXZhdGFyVXJsID8gbWVkaWFGcm9tTXhjKGF2YXRhclVybCkuZ2V0VGh1bWJuYWlsT2ZTb3VyY2VIdHRwKDMwLCAzMCwgXCJjcm9wXCIpIDogbnVsbDtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgYXN5bmMgc2F2ZUF2YXRhcklmTmVlZGVkKGV2ZW50OiBNYXRyaXhFdmVudCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBjb25zdCBtZW1iZXIgPSBldmVudC5zZW5kZXIhO1xuICAgICAgICBpZiAoIXRoaXMuYXZhdGFycy5oYXMobWVtYmVyLnVzZXJJZCkpIHtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgY29uc3QgYXZhdGFyVXJsID0gdGhpcy5nZXRBdmF0YXJVUkwoZXZlbnQpO1xuICAgICAgICAgICAgICAgIHRoaXMuYXZhdGFycy5zZXQobWVtYmVyLnVzZXJJZCwgdHJ1ZSk7XG4gICAgICAgICAgICAgICAgY29uc3QgaW1hZ2UgPSBhd2FpdCBmZXRjaChhdmF0YXJVcmwhKTtcbiAgICAgICAgICAgICAgICBjb25zdCBibG9iID0gYXdhaXQgaW1hZ2UuYmxvYigpO1xuICAgICAgICAgICAgICAgIHRoaXMuYWRkRmlsZShgdXNlcnMvJHttZW1iZXIudXNlcklkLnJlcGxhY2UoLzovZywgXCItXCIpfS5wbmdgLCBibG9iKTtcbiAgICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgICAgIGxvZ2dlci5sb2coXCJGYWlsZWQgdG8gZmV0Y2ggdXNlcidzIGF2YXRhclwiICsgZXJyKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByb3RlY3RlZCBnZXREYXRlU2VwYXJhdG9yKGV2ZW50OiBNYXRyaXhFdmVudCk6IHN0cmluZyB7XG4gICAgICAgIGNvbnN0IHRzID0gZXZlbnQuZ2V0VHMoKTtcbiAgICAgICAgY29uc3QgZGF0ZVNlcGFyYXRvciA9IChcbiAgICAgICAgICAgIDxsaSBrZXk9e3RzfT5cbiAgICAgICAgICAgICAgICA8RGF0ZVNlcGFyYXRvciBmb3JFeHBvcnQ9e3RydWV9IGtleT17dHN9IHJvb21JZD17ZXZlbnQuZ2V0Um9vbUlkKCkhfSB0cz17dHN9IC8+XG4gICAgICAgICAgICA8L2xpPlxuICAgICAgICApO1xuICAgICAgICByZXR1cm4gcmVuZGVyVG9TdGF0aWNNYXJrdXAoZGF0ZVNlcGFyYXRvcik7XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIG5lZWRzRGF0ZVNlcGFyYXRvcihldmVudDogTWF0cml4RXZlbnQsIHByZXZFdmVudDogTWF0cml4RXZlbnQgfCBudWxsKTogYm9vbGVhbiB7XG4gICAgICAgIGlmICghcHJldkV2ZW50KSByZXR1cm4gdHJ1ZTtcbiAgICAgICAgcmV0dXJuIHdhbnRzRGF0ZVNlcGFyYXRvcihwcmV2RXZlbnQuZ2V0RGF0ZSgpIHx8IHVuZGVmaW5lZCwgZXZlbnQuZ2V0RGF0ZSgpIHx8IHVuZGVmaW5lZCk7XG4gICAgfVxuXG4gICAgcHVibGljIGdldEV2ZW50VGlsZShteEV2OiBNYXRyaXhFdmVudCwgY29udGludWF0aW9uOiBib29sZWFuKTogSlNYLkVsZW1lbnQge1xuICAgICAgICByZXR1cm4gKFxuICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9XCJteF9FeHBvcnRfRXZlbnRXcmFwcGVyXCIgaWQ9e214RXYuZ2V0SWQoKX0+XG4gICAgICAgICAgICAgICAgPE1hdHJpeENsaWVudENvbnRleHQuUHJvdmlkZXIgdmFsdWU9e3RoaXMucm9vbS5jbGllbnR9PlxuICAgICAgICAgICAgICAgICAgICA8VG9vbHRpcFByb3ZpZGVyPlxuICAgICAgICAgICAgICAgICAgICAgICAgPEV2ZW50VGlsZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG14RXZlbnQ9e214RXZ9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udGludWF0aW9uPXtjb250aW51YXRpb259XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaXNSZWRhY3RlZD17bXhFdi5pc1JlZGFjdGVkKCl9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwbGFjaW5nRXZlbnRJZD17bXhFdi5yZXBsYWNpbmdFdmVudElkKCl9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9yRXhwb3J0PXt0cnVlfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFsd2F5c1Nob3dUaW1lc3RhbXBzPXt0cnVlfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3dVcmxQcmV2aWV3PXtmYWxzZX1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjaGVja1VubW91bnRpbmc9eygpID0+IGZhbHNlfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlzVHdlbHZlSG91cj17ZmFsc2V9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFzdD17ZmFsc2V9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFzdEluU2VjdGlvbj17ZmFsc2V9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcGVybWFsaW5rQ3JlYXRvcj17dGhpcy5wZXJtYWxpbmtDcmVhdG9yfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhc3RTdWNjZXNzZnVsPXtmYWxzZX1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpc1NlbGVjdGVkRXZlbnQ9e2ZhbHNlfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3dSZWFjdGlvbnM9e2ZhbHNlfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxheW91dD17TGF5b3V0Lkdyb3VwfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3dSZWFkUmVjZWlwdHM9e2ZhbHNlfVxuICAgICAgICAgICAgICAgICAgICAgICAgLz5cbiAgICAgICAgICAgICAgICAgICAgPC9Ub29sdGlwUHJvdmlkZXI+XG4gICAgICAgICAgICAgICAgPC9NYXRyaXhDbGllbnRDb250ZXh0LlByb3ZpZGVyPlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIGFzeW5jIGdldEV2ZW50VGlsZU1hcmt1cChteEV2OiBNYXRyaXhFdmVudCwgY29udGludWF0aW9uOiBib29sZWFuLCBmaWxlUGF0aD86IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgICAgIGNvbnN0IGF2YXRhclVybCA9IHRoaXMuZ2V0QXZhdGFyVVJMKG14RXYpO1xuICAgICAgICBjb25zdCBoYXNBdmF0YXIgPSAhIWF2YXRhclVybDtcbiAgICAgICAgaWYgKGhhc0F2YXRhcikgYXdhaXQgdGhpcy5zYXZlQXZhdGFySWZOZWVkZWQobXhFdik7XG4gICAgICAgIGNvbnN0IEV2ZW50VGlsZSA9IHRoaXMuZ2V0RXZlbnRUaWxlKG14RXYsIGNvbnRpbnVhdGlvbik7XG4gICAgICAgIGxldCBldmVudFRpbGVNYXJrdXA6IHN0cmluZztcblxuICAgICAgICBpZiAoXG4gICAgICAgICAgICBteEV2LmdldENvbnRlbnQoKS5tc2d0eXBlID09IE1zZ1R5cGUuRW1vdGUgfHxcbiAgICAgICAgICAgIG14RXYuZ2V0Q29udGVudCgpLm1zZ3R5cGUgPT0gTXNnVHlwZS5Ob3RpY2UgfHxcbiAgICAgICAgICAgIG14RXYuZ2V0Q29udGVudCgpLm1zZ3R5cGUgPT09IE1zZ1R5cGUuVGV4dFxuICAgICAgICApIHtcbiAgICAgICAgICAgIC8vIHRvIGxpbmtpZnkgdGV4dHVhbCBldmVudHMsIHdlJ2xsIG5lZWQgbGlmZWN5Y2xlIG1ldGhvZHMgd2hpY2ggd29uJ3QgYmUgaW52b2tlZCBpbiByZW5kZXJUb1N0cmluZ1xuICAgICAgICAgICAgLy8gU28sIHdlJ2xsIGhhdmUgdG8gcmVuZGVyIHRoZSBjb21wb25lbnQgaW50byBhIHRlbXBvcmFyeSByb290IGVsZW1lbnRcbiAgICAgICAgICAgIGNvbnN0IHRlbXBSb290ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImRpdlwiKTtcbiAgICAgICAgICAgIFJlYWN0RE9NLnJlbmRlcihFdmVudFRpbGUsIHRlbXBSb290KTtcbiAgICAgICAgICAgIGV2ZW50VGlsZU1hcmt1cCA9IHRlbXBSb290LmlubmVySFRNTDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGV2ZW50VGlsZU1hcmt1cCA9IHJlbmRlclRvU3RhdGljTWFya3VwKEV2ZW50VGlsZSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoZmlsZVBhdGgpIHtcbiAgICAgICAgICAgIGNvbnN0IG14YyA9IG14RXYuZ2V0Q29udGVudCgpLnVybCA/PyBteEV2LmdldENvbnRlbnQoKS5maWxlPy51cmw7XG4gICAgICAgICAgICBldmVudFRpbGVNYXJrdXAgPSBldmVudFRpbGVNYXJrdXAuc3BsaXQobXhjKS5qb2luKGZpbGVQYXRoKTtcbiAgICAgICAgfVxuICAgICAgICBldmVudFRpbGVNYXJrdXAgPSBldmVudFRpbGVNYXJrdXAucmVwbGFjZSgvPHNwYW4gY2xhc3M9XCJteF9NRmlsZUJvZHlfaW5mb19pY29uXCIuKj8+Lio/PFxcL3NwYW4+LywgXCJcIik7XG4gICAgICAgIGlmIChoYXNBdmF0YXIpIHtcbiAgICAgICAgICAgIGV2ZW50VGlsZU1hcmt1cCA9IGV2ZW50VGlsZU1hcmt1cC5yZXBsYWNlKFxuICAgICAgICAgICAgICAgIGVuY29kZVVSSShhdmF0YXJVcmwpLnJlcGxhY2UoLyYvZywgXCImYW1wO1wiKSxcbiAgICAgICAgICAgICAgICBgdXNlcnMvJHtteEV2LnNlbmRlciEudXNlcklkLnJlcGxhY2UoLzovZywgXCItXCIpfS5wbmdgLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZXZlbnRUaWxlTWFya3VwO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBjcmVhdGVNb2RpZmllZEV2ZW50KHRleHQ6IHN0cmluZywgbXhFdjogTWF0cml4RXZlbnQsIGl0YWxpYyA9IHRydWUpOiBNYXRyaXhFdmVudCB7XG4gICAgICAgIGNvbnN0IG1vZGlmaWVkQ29udGVudCA9IHtcbiAgICAgICAgICAgIG1zZ3R5cGU6IE1zZ1R5cGUuVGV4dCxcbiAgICAgICAgICAgIGJvZHk6IGAke3RleHR9YCxcbiAgICAgICAgICAgIGZvcm1hdDogXCJvcmcubWF0cml4LmN1c3RvbS5odG1sXCIsXG4gICAgICAgICAgICBmb3JtYXR0ZWRfYm9keTogYCR7dGV4dH1gLFxuICAgICAgICB9O1xuICAgICAgICBpZiAoaXRhbGljKSB7XG4gICAgICAgICAgICBtb2RpZmllZENvbnRlbnQuZm9ybWF0dGVkX2JvZHkgPSBcIjxlbT5cIiArIG1vZGlmaWVkQ29udGVudC5mb3JtYXR0ZWRfYm9keSArIFwiPC9lbT5cIjtcbiAgICAgICAgICAgIG1vZGlmaWVkQ29udGVudC5ib2R5ID0gXCIqXCIgKyBtb2RpZmllZENvbnRlbnQuYm9keSArIFwiKlwiO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IG1vZGlmaWVkRXZlbnQgPSBuZXcgTWF0cml4RXZlbnQoKTtcbiAgICAgICAgbW9kaWZpZWRFdmVudC5ldmVudCA9IG14RXYuZXZlbnQ7XG4gICAgICAgIG1vZGlmaWVkRXZlbnQuc2VuZGVyID0gbXhFdi5zZW5kZXI7XG4gICAgICAgIG1vZGlmaWVkRXZlbnQuZXZlbnQudHlwZSA9IFwibS5yb29tLm1lc3NhZ2VcIjtcbiAgICAgICAgbW9kaWZpZWRFdmVudC5ldmVudC5jb250ZW50ID0gbW9kaWZpZWRDb250ZW50O1xuICAgICAgICByZXR1cm4gbW9kaWZpZWRFdmVudDtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgYXN5bmMgY3JlYXRlTWVzc2FnZUJvZHkobXhFdjogTWF0cml4RXZlbnQsIGpvaW5lZCA9IGZhbHNlKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICAgICAgbGV0IGV2ZW50VGlsZTogc3RyaW5nO1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgaWYgKHRoaXMuaXNBdHRhY2htZW50KG14RXYpKSB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuZXhwb3J0T3B0aW9ucy5hdHRhY2htZW50c0luY2x1ZGVkKSB7XG4gICAgICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBibG9iID0gYXdhaXQgdGhpcy5nZXRNZWRpYUJsb2IobXhFdik7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy50b3RhbFNpemUgKyBibG9iLnNpemUgPiB0aGlzLmV4cG9ydE9wdGlvbnMubWF4U2l6ZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50VGlsZSA9IGF3YWl0IHRoaXMuZ2V0RXZlbnRUaWxlTWFya3VwKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmNyZWF0ZU1vZGlmaWVkRXZlbnQodGhpcy5tZWRpYU9taXRUZXh0LCBteEV2KSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgam9pbmVkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMudG90YWxTaXplICs9IGJsb2Iuc2l6ZTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBmaWxlUGF0aCA9IHRoaXMuZ2V0RmlsZVBhdGgobXhFdik7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnRUaWxlID0gYXdhaXQgdGhpcy5nZXRFdmVudFRpbGVNYXJrdXAobXhFdiwgam9pbmVkLCBmaWxlUGF0aCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMudG90YWxTaXplID09IHRoaXMuZXhwb3J0T3B0aW9ucy5tYXhTaXplKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZXhwb3J0T3B0aW9ucy5hdHRhY2htZW50c0luY2x1ZGVkID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuYWRkRmlsZShmaWxlUGF0aCwgYmxvYik7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGxvZ2dlci5sb2coXCJFcnJvciB3aGlsZSBmZXRjaGluZyBmaWxlXCIgKyBlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50VGlsZSA9IGF3YWl0IHRoaXMuZ2V0RXZlbnRUaWxlTWFya3VwKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuY3JlYXRlTW9kaWZpZWRFdmVudChfdChcImV4cG9ydF9jaGF0fGVycm9yX2ZldGNoaW5nX2ZpbGVcIiksIG14RXYpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGpvaW5lZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBldmVudFRpbGUgPSBhd2FpdCB0aGlzLmdldEV2ZW50VGlsZU1hcmt1cChcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuY3JlYXRlTW9kaWZpZWRFdmVudCh0aGlzLm1lZGlhT21pdFRleHQsIG14RXYpLFxuICAgICAgICAgICAgICAgICAgICAgICAgam9pbmVkLFxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgZXZlbnRUaWxlID0gYXdhaXQgdGhpcy5nZXRFdmVudFRpbGVNYXJrdXAobXhFdiwgam9pbmVkKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgLy8gVE9ETzogSGFuZGxlIGNhbGxFdmVudCBlcnJvcnNcbiAgICAgICAgICAgIGxvZ2dlci5lcnJvcihlKTtcbiAgICAgICAgICAgIGV2ZW50VGlsZSA9IGF3YWl0IHRoaXMuZ2V0RXZlbnRUaWxlTWFya3VwKFxuICAgICAgICAgICAgICAgIHRoaXMuY3JlYXRlTW9kaWZpZWRFdmVudCh0ZXh0Rm9yRXZlbnQobXhFdiwgdGhpcy5yb29tLmNsaWVudCksIG14RXYsIGZhbHNlKSxcbiAgICAgICAgICAgICAgICBqb2luZWQsXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGV2ZW50VGlsZTtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgYXN5bmMgY3JlYXRlSFRNTChcbiAgICAgICAgZXZlbnRzOiBNYXRyaXhFdmVudFtdLFxuICAgICAgICBzdGFydDogbnVtYmVyLFxuICAgICAgICBjdXJyZW50UGFnZTogbnVtYmVyLFxuICAgICAgICBuYlBhZ2VzOiBudW1iZXIsXG4gICAgKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICAgICAgbGV0IGNvbnRlbnQgPSBcIlwiO1xuICAgICAgICBsZXQgcHJldkV2ZW50OiBNYXRyaXhFdmVudCB8IG51bGwgPSBudWxsO1xuICAgICAgICBmb3IgKGxldCBpID0gc3RhcnQ7IGkgPCBNYXRoLm1pbihzdGFydCArIDEwMDAsIGV2ZW50cy5sZW5ndGgpOyBpKyspIHtcbiAgICAgICAgICAgIGNvbnN0IGV2ZW50ID0gZXZlbnRzW2ldO1xuICAgICAgICAgICAgdGhpcy51cGRhdGVQcm9ncmVzcyhcbiAgICAgICAgICAgICAgICBfdChcImV4cG9ydF9jaGF0fHByb2Nlc3NpbmdfZXZlbnRfblwiLCB7XG4gICAgICAgICAgICAgICAgICAgIG51bWJlcjogaSArIDEsXG4gICAgICAgICAgICAgICAgICAgIHRvdGFsOiBldmVudHMubGVuZ3RoLFxuICAgICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICAgIGZhbHNlLFxuICAgICAgICAgICAgICAgIHRydWUsXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgaWYgKHRoaXMuY2FuY2