UNPKG

matrix-react-sdk

Version:
352 lines (329 loc) 58.8 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.TextualEventFactory = exports.RoomCreateEventFactory = exports.MessageEventFactory = exports.JitsiEventFactory = exports.JSONEventFactory = void 0; exports.haveRendererForEvent = haveRendererForEvent; exports.isMessageEvent = isMessageEvent; exports.pickFactory = pickFactory; exports.renderReplyTile = renderReplyTile; exports.renderTile = renderTile; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _react = _interopRequireDefault(require("react")); var _matrix = require("matrix-js-sdk/src/matrix"); var _SettingsStore = _interopRequireDefault(require("../settings/SettingsStore")); var _RoomContext = require("../contexts/RoomContext"); var _MessageEvent = _interopRequireDefault(require("../components/views/messages/MessageEvent")); var _LegacyCallEvent = _interopRequireDefault(require("../components/views/messages/LegacyCallEvent")); var _CallEvent = require("../components/views/messages/CallEvent"); var _TextualEvent = _interopRequireDefault(require("../components/views/messages/TextualEvent")); var _EncryptionEvent = _interopRequireDefault(require("../components/views/messages/EncryptionEvent")); var _RoomPredecessorTile = require("../components/views/messages/RoomPredecessorTile"); var _RoomAvatarEvent = _interopRequireDefault(require("../components/views/messages/RoomAvatarEvent")); var _WidgetLayoutStore = require("../stores/widgets/WidgetLayoutStore"); var _BanList = require("../mjolnir/BanList"); var _MatrixClientPeg = require("../MatrixClientPeg"); var _MKeyVerificationRequest = _interopRequireDefault(require("../components/views/messages/MKeyVerificationRequest")); var _WidgetType = require("../widgets/WidgetType"); var _MJitsiWidgetEvent = _interopRequireDefault(require("../components/views/messages/MJitsiWidgetEvent")); var _TextForEvent = require("../TextForEvent"); var _EventUtils = require("../utils/EventUtils"); var _HiddenBody = _interopRequireDefault(require("../components/views/messages/HiddenBody")); var _ViewSourceEvent = _interopRequireDefault(require("../components/views/messages/ViewSourceEvent")); var _timeline = require("../utils/beacon/timeline"); var _shouldDisplayAsVoiceBroadcastTile = require("../voice-broadcast/utils/shouldDisplayAsVoiceBroadcastTile"); var _Call = require("../models/Call"); var _voiceBroadcast = require("../voice-broadcast"); /* 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. */ // Subset of EventTile's IProps plus some mixins const MessageEventFactory = (ref, props) => /*#__PURE__*/_react.default.createElement(_MessageEvent.default, (0, _extends2.default)({ ref: ref }, props)); exports.MessageEventFactory = MessageEventFactory; const LegacyCallEventFactory = (ref, props) => /*#__PURE__*/_react.default.createElement(_LegacyCallEvent.default, (0, _extends2.default)({ ref: ref }, props)); const CallEventFactory = (ref, props) => /*#__PURE__*/_react.default.createElement(_CallEvent.CallEvent, (0, _extends2.default)({ ref: ref }, props)); const TextualEventFactory = (ref, props) => /*#__PURE__*/_react.default.createElement(_TextualEvent.default, (0, _extends2.default)({ ref: ref }, props)); exports.TextualEventFactory = TextualEventFactory; const VerificationReqFactory = (_ref, props) => /*#__PURE__*/_react.default.createElement(_MKeyVerificationRequest.default, props); const HiddenEventFactory = (ref, props) => /*#__PURE__*/_react.default.createElement(_HiddenBody.default, (0, _extends2.default)({ ref: ref }, props)); // These factories are exported for reference comparison against pickFactory() const JitsiEventFactory = (ref, props) => /*#__PURE__*/_react.default.createElement(_MJitsiWidgetEvent.default, (0, _extends2.default)({ ref: ref }, props)); exports.JitsiEventFactory = JitsiEventFactory; const JSONEventFactory = (ref, props) => /*#__PURE__*/_react.default.createElement(_ViewSourceEvent.default, (0, _extends2.default)({ ref: ref }, props)); exports.JSONEventFactory = JSONEventFactory; const RoomCreateEventFactory = (_ref, props) => /*#__PURE__*/_react.default.createElement(_RoomPredecessorTile.RoomPredecessorTile, props); exports.RoomCreateEventFactory = RoomCreateEventFactory; const EVENT_TILE_TYPES = new Map([[_matrix.EventType.RoomMessage, MessageEventFactory], // note that verification requests are handled in pickFactory() [_matrix.EventType.Sticker, MessageEventFactory], [_matrix.M_POLL_START.name, MessageEventFactory], [_matrix.M_POLL_START.altName, MessageEventFactory], [_matrix.M_POLL_END.name, MessageEventFactory], [_matrix.M_POLL_END.altName, MessageEventFactory], [_matrix.EventType.CallInvite, LegacyCallEventFactory] // note that this requires a special factory type ]); const STATE_EVENT_TILE_TYPES = new Map([[_matrix.EventType.RoomEncryption, (ref, props) => /*#__PURE__*/_react.default.createElement(_EncryptionEvent.default, (0, _extends2.default)({ ref: ref }, props))], [_matrix.EventType.RoomCanonicalAlias, TextualEventFactory], [_matrix.EventType.RoomCreate, RoomCreateEventFactory], [_matrix.EventType.RoomMember, TextualEventFactory], [_matrix.EventType.RoomName, TextualEventFactory], [_matrix.EventType.RoomAvatar, (ref, props) => /*#__PURE__*/_react.default.createElement(_RoomAvatarEvent.default, (0, _extends2.default)({ ref: ref }, props))], [_matrix.EventType.RoomThirdPartyInvite, TextualEventFactory], [_matrix.EventType.RoomHistoryVisibility, TextualEventFactory], [_matrix.EventType.RoomTopic, TextualEventFactory], [_matrix.EventType.RoomPowerLevels, TextualEventFactory], [_matrix.EventType.RoomPinnedEvents, TextualEventFactory], [_matrix.EventType.RoomServerAcl, TextualEventFactory], // TODO: Enable support for m.widget event type (https://github.com/vector-im/element-web/issues/13111) ["im.vector.modular.widgets", TextualEventFactory], // note that Jitsi widgets are special in pickFactory() [_WidgetLayoutStore.WIDGET_LAYOUT_EVENT_TYPE, TextualEventFactory], [_matrix.EventType.RoomTombstone, TextualEventFactory], [_matrix.EventType.RoomJoinRules, TextualEventFactory], [_matrix.EventType.RoomGuestAccess, TextualEventFactory]]); for (const evType of _Call.ElementCall.CALL_EVENT_TYPE.names) { STATE_EVENT_TILE_TYPES.set(evType, CallEventFactory); } // Add all the Mjolnir stuff to the renderer too for (const evType of _BanList.ALL_RULE_TYPES) { STATE_EVENT_TILE_TYPES.set(evType, TextualEventFactory); } // These events should be recorded in the STATE_EVENT_TILE_TYPES const SINGULAR_STATE_EVENTS = new Set([_matrix.EventType.RoomEncryption, _matrix.EventType.RoomCanonicalAlias, _matrix.EventType.RoomCreate, _matrix.EventType.RoomName, _matrix.EventType.RoomAvatar, _matrix.EventType.RoomHistoryVisibility, _matrix.EventType.RoomTopic, _matrix.EventType.RoomPowerLevels, _matrix.EventType.RoomPinnedEvents, _matrix.EventType.RoomServerAcl, _WidgetLayoutStore.WIDGET_LAYOUT_EVENT_TYPE, _matrix.EventType.RoomTombstone, _matrix.EventType.RoomJoinRules, _matrix.EventType.RoomGuestAccess]); /** * Find an event tile factory for the given conditions. * @param mxEvent The event. * @param cli The matrix client to reference when needed. * @param showHiddenEvents Whether hidden events should be shown. * @param asHiddenEv When true, treat the event as always hidden. * @returns The factory, or falsy if not possible. */ function pickFactory(mxEvent, cli, showHiddenEvents, asHiddenEv) { const evType = mxEvent.getType(); // cache this to reduce call stack execution hits // Note: we avoid calling SettingsStore unless absolutely necessary - this code is on the critical path. if (asHiddenEv && showHiddenEvents) { return JSONEventFactory; } const noEventFactoryFactory = () => showHiddenEvents ? JSONEventFactory : undefined; // just don't render things that we shouldn't render // We run all the event type checks first as they might override the factory entirely. const moderationState = (0, _EventUtils.getMessageModerationState)(mxEvent, cli); if (moderationState === _EventUtils.MessageModerationState.HIDDEN_TO_CURRENT_USER) { return HiddenEventFactory; } if (evType === _matrix.EventType.RoomMessage) { // don't show verification requests we're not involved in, // not even when showing hidden events const content = mxEvent.getContent(); if (content?.msgtype === _matrix.MsgType.KeyVerificationRequest) { const me = cli.getUserId(); if (mxEvent.getSender() !== me && content["to"] !== me) { return noEventFactoryFactory(); // not for/from us } else { // override the factory return VerificationReqFactory; } } } if (evType === _matrix.EventType.RoomCreate) { const dynamicPredecessorsEnabled = _SettingsStore.default.getValue("feature_dynamic_room_predecessors"); const predecessor = cli.getRoom(mxEvent.getRoomId())?.findPredecessor(dynamicPredecessorsEnabled); if (!predecessor) { return noEventFactoryFactory(); } } // TODO: Enable support for m.widget event type (https://github.com/vector-im/element-web/issues/13111) if (evType === "im.vector.modular.widgets") { let type = mxEvent.getContent()["type"]; if (!type) { // deleted/invalid widget - try the past widget type type = mxEvent.getPrevContent()["type"]; } if (_WidgetType.WidgetType.JITSI.matches(type)) { // override the factory return JitsiEventFactory; } } // Try and pick a state event factory, if we can. if (mxEvent.isState()) { if ((0, _timeline.shouldDisplayAsBeaconTile)(mxEvent)) { return MessageEventFactory; } if ((0, _shouldDisplayAsVoiceBroadcastTile.shouldDisplayAsVoiceBroadcastTile)(mxEvent)) { return MessageEventFactory; } else if ((0, _voiceBroadcast.shouldDisplayAsVoiceBroadcastStoppedText)(mxEvent)) { return TextualEventFactory; } if (SINGULAR_STATE_EVENTS.has(evType) && mxEvent.getStateKey() !== "") { return noEventFactoryFactory(); // improper event type to render } if (STATE_EVENT_TILE_TYPES.get(evType) === TextualEventFactory && !(0, _TextForEvent.hasText)(mxEvent, cli, showHiddenEvents)) { return noEventFactoryFactory(); } return STATE_EVENT_TILE_TYPES.get(evType) ?? noEventFactoryFactory(); } // Blanket override for all events. The MessageEvent component handles redacted states for us. if (mxEvent.isRedacted()) { return MessageEventFactory; } if (mxEvent.isRelation(_matrix.RelationType.Replace)) { return noEventFactoryFactory(); } if (mxEvent.getContent()[_voiceBroadcast.VoiceBroadcastChunkEventType]) { // hide voice broadcast chunks return noEventFactoryFactory(); } if (!showHiddenEvents && mxEvent.isDecryptionFailure() && (0, _voiceBroadcast.isRelatedToVoiceBroadcast)(mxEvent, cli)) { // hide utd events related to a broadcast return noEventFactoryFactory(); } return EVENT_TILE_TYPES.get(evType) ?? noEventFactoryFactory(); } /** * Render an event as a tile * @param renderType The render type. Used to inform properties given to the eventual component. * @param props The properties to provide to the eventual component. * @param showHiddenEvents Whether hidden events should be shown. * @param cli Optional client instance to use, otherwise the default MatrixClientPeg will be used. * @returns The tile as JSX, or falsy if unable to render. */ function renderTile(renderType, props, showHiddenEvents, cli) { cli = cli ?? _MatrixClientPeg.MatrixClientPeg.safeGet(); // because param defaults don't do the correct thing const factory = pickFactory(props.mxEvent, cli, showHiddenEvents); if (!factory) return undefined; // Note that we split off the ones we actually care about here just to be sure that we're // not going to accidentally send things we shouldn't from lazy callers. Eg: EventTile's // lazy calls of `renderTile(..., this.props)` will have a lot more than we actually care // about. const { ref, mxEvent, forExport, replacingEventId, editState, highlights, highlightLink, showUrlPreview, permalinkCreator, onHeightChanged, callEventGrouper, getRelationsForEvent, isSeeingThroughMessageHiddenForModeration, timestamp, inhibitInteraction } = props; switch (renderType) { case _RoomContext.TimelineRenderingType.File: case _RoomContext.TimelineRenderingType.Notification: case _RoomContext.TimelineRenderingType.Thread: // We only want a subset of props, so we don't end up causing issues for downstream components. return factory(props.ref, { mxEvent, highlights, highlightLink, showUrlPreview, onHeightChanged, editState, replacingEventId, getRelationsForEvent, isSeeingThroughMessageHiddenForModeration, permalinkCreator, inhibitInteraction }); default: // NEARLY ALL THE OPTIONS! return factory(ref, { mxEvent, forExport, replacingEventId, editState, highlights, highlightLink, showUrlPreview, permalinkCreator, onHeightChanged, callEventGrouper, getRelationsForEvent, isSeeingThroughMessageHiddenForModeration, timestamp, inhibitInteraction }); } } /** * A version of renderTile() specifically for replies. * @param props The properties to specify on the eventual object. * @param showHiddenEvents Whether hidden events should be shown. * @param cli Optional client instance to use, otherwise the default MatrixClientPeg will be used. * @returns The tile as JSX, or falsy if unable to render. */ function renderReplyTile(props, showHiddenEvents, cli) { cli = cli ?? _MatrixClientPeg.MatrixClientPeg.safeGet(); // because param defaults don't do the correct thing const factory = pickFactory(props.mxEvent, cli, showHiddenEvents); if (!factory) return undefined; // See renderTile() for why we split off so much const { ref, mxEvent, highlights, highlightLink, onHeightChanged, showUrlPreview, overrideBodyTypes, overrideEventTypes, replacingEventId, maxImageHeight, getRelationsForEvent, isSeeingThroughMessageHiddenForModeration, permalinkCreator } = props; return factory(ref, { mxEvent, highlights, highlightLink, onHeightChanged, showUrlPreview, overrideBodyTypes, overrideEventTypes, replacingEventId, maxImageHeight, getRelationsForEvent, isSeeingThroughMessageHiddenForModeration, permalinkCreator }); } // XXX: this'll eventually be dynamic based on the fields once we have extensible event types const messageTypes = [_matrix.EventType.RoomMessage, _matrix.EventType.Sticker]; function isMessageEvent(ev) { return messageTypes.includes(ev.getType()) || _matrix.M_POLL_START.matches(ev.getType()) || _matrix.M_POLL_END.matches(ev.getType()); } function haveRendererForEvent(mxEvent, matrixClient, showHiddenEvents) { // Only show "Message deleted" tile for plain message events, encrypted events, // and state events as they'll likely still contain enough keys to be relevant. if (mxEvent.isRedacted() && !mxEvent.isEncrypted() && !isMessageEvent(mxEvent) && !mxEvent.isState()) { return false; } // No tile for replacement events since they update the original tile if (mxEvent.isRelation(_matrix.RelationType.Replace)) return false; const handler = pickFactory(mxEvent, matrixClient, showHiddenEvents); if (!handler) return false; if (handler === TextualEventFactory) { return (0, _TextForEvent.hasText)(mxEvent, matrixClient, showHiddenEvents); } else if (handler === STATE_EVENT_TILE_TYPES.get(_matrix.EventType.RoomCreate)) { const dynamicPredecessorsEnabled = _SettingsStore.default.getValue("feature_dynamic_room_predecessors"); const predecessor = matrixClient.getRoom(mxEvent.getRoomId())?.findPredecessor(dynamicPredecessorsEnabled); return Boolean(predecessor); } else if (_Call.ElementCall.CALL_EVENT_TYPE.names.some(eventType => handler === STATE_EVENT_TILE_TYPES.get(eventType))) { const intent = mxEvent.getContent()["m.intent"]; const newlyStarted = Object.keys(mxEvent.getPrevContent()).length === 0; // Only interested in events that mark the start of a non-room call return newlyStarted && typeof intent === "string" && intent !== _matrix.GroupCallIntent.Room; } else if (handler === JSONEventFactory) { return false; } else { return true; } } //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfcmVhY3QiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwicmVxdWlyZSIsIl9tYXRyaXgiLCJfU2V0dGluZ3NTdG9yZSIsIl9Sb29tQ29udGV4dCIsIl9NZXNzYWdlRXZlbnQiLCJfTGVnYWN5Q2FsbEV2ZW50IiwiX0NhbGxFdmVudCIsIl9UZXh0dWFsRXZlbnQiLCJfRW5jcnlwdGlvbkV2ZW50IiwiX1Jvb21QcmVkZWNlc3NvclRpbGUiLCJfUm9vbUF2YXRhckV2ZW50IiwiX1dpZGdldExheW91dFN0b3JlIiwiX0Jhbkxpc3QiLCJfTWF0cml4Q2xpZW50UGVnIiwiX01LZXlWZXJpZmljYXRpb25SZXF1ZXN0IiwiX1dpZGdldFR5cGUiLCJfTUppdHNpV2lkZ2V0RXZlbnQiLCJfVGV4dEZvckV2ZW50IiwiX0V2ZW50VXRpbHMiLCJfSGlkZGVuQm9keSIsIl9WaWV3U291cmNlRXZlbnQiLCJfdGltZWxpbmUiLCJfc2hvdWxkRGlzcGxheUFzVm9pY2VCcm9hZGNhc3RUaWxlIiwiX0NhbGwiLCJfdm9pY2VCcm9hZGNhc3QiLCJNZXNzYWdlRXZlbnRGYWN0b3J5IiwicmVmIiwicHJvcHMiLCJkZWZhdWx0IiwiY3JlYXRlRWxlbWVudCIsIl9leHRlbmRzMiIsImV4cG9ydHMiLCJMZWdhY3lDYWxsRXZlbnRGYWN0b3J5IiwiQ2FsbEV2ZW50RmFjdG9yeSIsIkNhbGxFdmVudCIsIlRleHR1YWxFdmVudEZhY3RvcnkiLCJWZXJpZmljYXRpb25SZXFGYWN0b3J5IiwiX3JlZiIsIkhpZGRlbkV2ZW50RmFjdG9yeSIsIkppdHNpRXZlbnRGYWN0b3J5IiwiSlNPTkV2ZW50RmFjdG9yeSIsIlJvb21DcmVhdGVFdmVudEZhY3RvcnkiLCJSb29tUHJlZGVjZXNzb3JUaWxlIiwiRVZFTlRfVElMRV9UWVBFUyIsIk1hcCIsIkV2ZW50VHlwZSIsIlJvb21NZXNzYWdlIiwiU3RpY2tlciIsIk1fUE9MTF9TVEFSVCIsIm5hbWUiLCJhbHROYW1lIiwiTV9QT0xMX0VORCIsIkNhbGxJbnZpdGUiLCJTVEFURV9FVkVOVF9USUxFX1RZUEVTIiwiUm9vbUVuY3J5cHRpb24iLCJSb29tQ2Fub25pY2FsQWxpYXMiLCJSb29tQ3JlYXRlIiwiUm9vbU1lbWJlciIsIlJvb21OYW1lIiwiUm9vbUF2YXRhciIsIlJvb21UaGlyZFBhcnR5SW52aXRlIiwiUm9vbUhpc3RvcnlWaXNpYmlsaXR5IiwiUm9vbVRvcGljIiwiUm9vbVBvd2VyTGV2ZWxzIiwiUm9vbVBpbm5lZEV2ZW50cyIsIlJvb21TZXJ2ZXJBY2wiLCJXSURHRVRfTEFZT1VUX0VWRU5UX1RZUEUiLCJSb29tVG9tYnN0b25lIiwiUm9vbUpvaW5SdWxlcyIsIlJvb21HdWVzdEFjY2VzcyIsImV2VHlwZSIsIkVsZW1lbnRDYWxsIiwiQ0FMTF9FVkVOVF9UWVBFIiwibmFtZXMiLCJzZXQiLCJBTExfUlVMRV9UWVBFUyIsIlNJTkdVTEFSX1NUQVRFX0VWRU5UUyIsIlNldCIsInBpY2tGYWN0b3J5IiwibXhFdmVudCIsImNsaSIsInNob3dIaWRkZW5FdmVudHMiLCJhc0hpZGRlbkV2IiwiZ2V0VHlwZSIsIm5vRXZlbnRGYWN0b3J5RmFjdG9yeSIsInVuZGVmaW5lZCIsIm1vZGVyYXRpb25TdGF0ZSIsImdldE1lc3NhZ2VNb2RlcmF0aW9uU3RhdGUiLCJNZXNzYWdlTW9kZXJhdGlvblN0YXRlIiwiSElEREVOX1RPX0NVUlJFTlRfVVNFUiIsImNvbnRlbnQiLCJnZXRDb250ZW50IiwibXNndHlwZSIsIk1zZ1R5cGUiLCJLZXlWZXJpZmljYXRpb25SZXF1ZXN0IiwibWUiLCJnZXRVc2VySWQiLCJnZXRTZW5kZXIiLCJkeW5hbWljUHJlZGVjZXNzb3JzRW5hYmxlZCIsIlNldHRpbmdzU3RvcmUiLCJnZXRWYWx1ZSIsInByZWRlY2Vzc29yIiwiZ2V0Um9vbSIsImdldFJvb21JZCIsImZpbmRQcmVkZWNlc3NvciIsInR5cGUiLCJnZXRQcmV2Q29udGVudCIsIldpZGdldFR5cGUiLCJKSVRTSSIsIm1hdGNoZXMiLCJpc1N0YXRlIiwic2hvdWxkRGlzcGxheUFzQmVhY29uVGlsZSIsInNob3VsZERpc3BsYXlBc1ZvaWNlQnJvYWRjYXN0VGlsZSIsInNob3VsZERpc3BsYXlBc1ZvaWNlQnJvYWRjYXN0U3RvcHBlZFRleHQiLCJoYXMiLCJnZXRTdGF0ZUtleSIsImdldCIsImhhc1RleHQiLCJpc1JlZGFjdGVkIiwiaXNSZWxhdGlvbiIsIlJlbGF0aW9uVHlwZSIsIlJlcGxhY2UiLCJWb2ljZUJyb2FkY2FzdENodW5rRXZlbnRUeXBlIiwiaXNEZWNyeXB0aW9uRmFpbHVyZSIsImlzUmVsYXRlZFRvVm9pY2VCcm9hZGNhc3QiLCJyZW5kZXJUaWxlIiwicmVuZGVyVHlwZSIsIk1hdHJpeENsaWVudFBlZyIsInNhZmVHZXQiLCJmYWN0b3J5IiwiZm9yRXhwb3J0IiwicmVwbGFjaW5nRXZlbnRJZCIsImVkaXRTdGF0ZSIsImhpZ2hsaWdodHMiLCJoaWdobGlnaHRMaW5rIiwic2hvd1VybFByZXZpZXciLCJwZXJtYWxpbmtDcmVhdG9yIiwib25IZWlnaHRDaGFuZ2VkIiwiY2FsbEV2ZW50R3JvdXBlciIsImdldFJlbGF0aW9uc0ZvckV2ZW50IiwiaXNTZWVpbmdUaHJvdWdoTWVzc2FnZUhpZGRlbkZvck1vZGVyYXRpb24iLCJ0aW1lc3RhbXAiLCJpbmhpYml0SW50ZXJhY3Rpb24iLCJUaW1lbGluZVJlbmRlcmluZ1R5cGUiLCJGaWxlIiwiTm90aWZpY2F0aW9uIiwiVGhyZWFkIiwicmVuZGVyUmVwbHlUaWxlIiwib3ZlcnJpZGVCb2R5VHlwZXMiLCJvdmVycmlkZUV2ZW50VHlwZXMiLCJtYXhJbWFnZUhlaWdodCIsIm1lc3NhZ2VUeXBlcyIsImlzTWVzc2FnZUV2ZW50IiwiZXYiLCJpbmNsdWRlcyIsImhhdmVSZW5kZXJlckZvckV2ZW50IiwibWF0cml4Q2xpZW50IiwiaXNFbmNyeXB0ZWQiLCJoYW5kbGVyIiwiQm9vbGVhbiIsInNvbWUiLCJldmVudFR5cGUiLCJpbnRlbnQiLCJuZXdseVN0YXJ0ZWQiLCJPYmplY3QiLCJrZXlzIiwibGVuZ3RoIiwiR3JvdXBDYWxsSW50ZW50IiwiUm9vbSJdLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9ldmVudHMvRXZlbnRUaWxlRmFjdG9yeS50c3giXSwic291cmNlc0NvbnRlbnQiOlsiLypcbkNvcHlyaWdodCAyMDI0IE5ldyBWZWN0b3IgTHRkLlxuQ29weXJpZ2h0IDIwMjIgVGhlIE1hdHJpeC5vcmcgRm91bmRhdGlvbiBDLkkuQy5cblxuU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFHUEwtMy4wLW9ubHkgT1IgR1BMLTMuMC1vbmx5XG5QbGVhc2Ugc2VlIExJQ0VOU0UgZmlsZXMgaW4gdGhlIHJlcG9zaXRvcnkgcm9vdCBmb3IgZnVsbCBkZXRhaWxzLlxuKi9cblxuaW1wb3J0IFJlYWN0IGZyb20gXCJyZWFjdFwiO1xuaW1wb3J0IHtcbiAgICBNYXRyaXhFdmVudCxcbiAgICBFdmVudFR5cGUsXG4gICAgTXNnVHlwZSxcbiAgICBSZWxhdGlvblR5cGUsXG4gICAgTWF0cml4Q2xpZW50LFxuICAgIEdyb3VwQ2FsbEludGVudCxcbiAgICBNX1BPTExfRU5ELFxuICAgIE1fUE9MTF9TVEFSVCxcbn0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL21hdHJpeFwiO1xuaW1wb3J0IHsgT3B0aW9uYWwgfSBmcm9tIFwibWF0cml4LWV2ZW50cy1zZGtcIjtcblxuaW1wb3J0IFNldHRpbmdzU3RvcmUgZnJvbSBcIi4uL3NldHRpbmdzL1NldHRpbmdzU3RvcmVcIjtcbmltcG9ydCBMZWdhY3lDYWxsRXZlbnRHcm91cGVyIGZyb20gXCIuLi9jb21wb25lbnRzL3N0cnVjdHVyZXMvTGVnYWN5Q2FsbEV2ZW50R3JvdXBlclwiO1xuaW1wb3J0IHsgRXZlbnRUaWxlUHJvcHMgfSBmcm9tIFwiLi4vY29tcG9uZW50cy92aWV3cy9yb29tcy9FdmVudFRpbGVcIjtcbmltcG9ydCB7IFRpbWVsaW5lUmVuZGVyaW5nVHlwZSB9IGZyb20gXCIuLi9jb250ZXh0cy9Sb29tQ29udGV4dFwiO1xuaW1wb3J0IE1lc3NhZ2VFdmVudCBmcm9tIFwiLi4vY29tcG9uZW50cy92aWV3cy9tZXNzYWdlcy9NZXNzYWdlRXZlbnRcIjtcbmltcG9ydCBMZWdhY3lDYWxsRXZlbnQgZnJvbSBcIi4uL2NvbXBvbmVudHMvdmlld3MvbWVzc2FnZXMvTGVnYWN5Q2FsbEV2ZW50XCI7XG5pbXBvcnQgeyBDYWxsRXZlbnQgfSBmcm9tIFwiLi4vY29tcG9uZW50cy92aWV3cy9tZXNzYWdlcy9DYWxsRXZlbnRcIjtcbmltcG9ydCBUZXh0dWFsRXZlbnQgZnJvbSBcIi4uL2NvbXBvbmVudHMvdmlld3MvbWVzc2FnZXMvVGV4dHVhbEV2ZW50XCI7XG5pbXBvcnQgRW5jcnlwdGlvbkV2ZW50IGZyb20gXCIuLi9jb21wb25lbnRzL3ZpZXdzL21lc3NhZ2VzL0VuY3J5cHRpb25FdmVudFwiO1xuaW1wb3J0IHsgUm9vbVByZWRlY2Vzc29yVGlsZSB9IGZyb20gXCIuLi9jb21wb25lbnRzL3ZpZXdzL21lc3NhZ2VzL1Jvb21QcmVkZWNlc3NvclRpbGVcIjtcbmltcG9ydCBSb29tQXZhdGFyRXZlbnQgZnJvbSBcIi4uL2NvbXBvbmVudHMvdmlld3MvbWVzc2FnZXMvUm9vbUF2YXRhckV2ZW50XCI7XG5pbXBvcnQgeyBXSURHRVRfTEFZT1VUX0VWRU5UX1RZUEUgfSBmcm9tIFwiLi4vc3RvcmVzL3dpZGdldHMvV2lkZ2V0TGF5b3V0U3RvcmVcIjtcbmltcG9ydCB7IEFMTF9SVUxFX1RZUEVTIH0gZnJvbSBcIi4uL21qb2xuaXIvQmFuTGlzdFwiO1xuaW1wb3J0IHsgTWF0cml4Q2xpZW50UGVnIH0gZnJvbSBcIi4uL01hdHJpeENsaWVudFBlZ1wiO1xuaW1wb3J0IE1LZXlWZXJpZmljYXRpb25SZXF1ZXN0IGZyb20gXCIuLi9jb21wb25lbnRzL3ZpZXdzL21lc3NhZ2VzL01LZXlWZXJpZmljYXRpb25SZXF1ZXN0XCI7XG5pbXBvcnQgeyBXaWRnZXRUeXBlIH0gZnJvbSBcIi4uL3dpZGdldHMvV2lkZ2V0VHlwZVwiO1xuaW1wb3J0IE1KaXRzaVdpZGdldEV2ZW50IGZyb20gXCIuLi9jb21wb25lbnRzL3ZpZXdzL21lc3NhZ2VzL01KaXRzaVdpZGdldEV2ZW50XCI7XG5pbXBvcnQgeyBoYXNUZXh0IH0gZnJvbSBcIi4uL1RleHRGb3JFdmVudFwiO1xuaW1wb3J0IHsgZ2V0TWVzc2FnZU1vZGVyYXRpb25TdGF0ZSwgTWVzc2FnZU1vZGVyYXRpb25TdGF0ZSB9IGZyb20gXCIuLi91dGlscy9FdmVudFV0aWxzXCI7XG5pbXBvcnQgSGlkZGVuQm9keSBmcm9tIFwiLi4vY29tcG9uZW50cy92aWV3cy9tZXNzYWdlcy9IaWRkZW5Cb2R5XCI7XG5pbXBvcnQgVmlld1NvdXJjZUV2ZW50IGZyb20gXCIuLi9jb21wb25lbnRzL3ZpZXdzL21lc3NhZ2VzL1ZpZXdTb3VyY2VFdmVudFwiO1xuaW1wb3J0IHsgc2hvdWxkRGlzcGxheUFzQmVhY29uVGlsZSB9IGZyb20gXCIuLi91dGlscy9iZWFjb24vdGltZWxpbmVcIjtcbmltcG9ydCB7IHNob3VsZERpc3BsYXlBc1ZvaWNlQnJvYWRjYXN0VGlsZSB9IGZyb20gXCIuLi92b2ljZS1icm9hZGNhc3QvdXRpbHMvc2hvdWxkRGlzcGxheUFzVm9pY2VCcm9hZGNhc3RUaWxlXCI7XG5pbXBvcnQgeyBFbGVtZW50Q2FsbCB9IGZyb20gXCIuLi9tb2RlbHMvQ2FsbFwiO1xuaW1wb3J0IHtcbiAgICBpc1JlbGF0ZWRUb1ZvaWNlQnJvYWRjYXN0LFxuICAgIHNob3VsZERpc3BsYXlBc1ZvaWNlQnJvYWRjYXN0U3RvcHBlZFRleHQsXG4gICAgVm9pY2VCcm9hZGNhc3RDaHVua0V2ZW50VHlwZSxcbn0gZnJvbSBcIi4uL3ZvaWNlLWJyb2FkY2FzdFwiO1xuXG4vLyBTdWJzZXQgb2YgRXZlbnRUaWxlJ3MgSVByb3BzIHBsdXMgc29tZSBtaXhpbnNcbmV4cG9ydCBpbnRlcmZhY2UgRXZlbnRUaWxlVHlwZVByb3BzXG4gICAgZXh0ZW5kcyBQaWNrPFxuICAgICAgICBFdmVudFRpbGVQcm9wcyxcbiAgICAgICAgfCBcIm14RXZlbnRcIlxuICAgICAgICB8IFwiaGlnaGxpZ2h0c1wiXG4gICAgICAgIHwgXCJoaWdobGlnaHRMaW5rXCJcbiAgICAgICAgfCBcInNob3dVcmxQcmV2aWV3XCJcbiAgICAgICAgfCBcIm9uSGVpZ2h0Q2hhbmdlZFwiXG4gICAgICAgIHwgXCJmb3JFeHBvcnRcIlxuICAgICAgICB8IFwiZ2V0UmVsYXRpb25zRm9yRXZlbnRcIlxuICAgICAgICB8IFwiZWRpdFN0YXRlXCJcbiAgICAgICAgfCBcInJlcGxhY2luZ0V2ZW50SWRcIlxuICAgICAgICB8IFwicGVybWFsaW5rQ3JlYXRvclwiXG4gICAgICAgIHwgXCJjYWxsRXZlbnRHcm91cGVyXCJcbiAgICAgICAgfCBcImlzU2VlaW5nVGhyb3VnaE1lc3NhZ2VIaWRkZW5Gb3JNb2RlcmF0aW9uXCJcbiAgICAgICAgfCBcImluaGliaXRJbnRlcmFjdGlvblwiXG4gICAgPiB7XG4gICAgcmVmPzogUmVhY3QuUmVmT2JqZWN0PGFueT47IC8vIGBhbnlgIGJlY2F1c2UgaXQncyBlZmZlY3RpdmVseSBpbXBvc3NpYmxlIHRvIGNvbnZpbmNlIFRTIG9mIGEgcmVhc29uYWJsZSB0eXBlXG4gICAgdGltZXN0YW1wPzogSlNYLkVsZW1lbnQ7XG4gICAgbWF4SW1hZ2VIZWlnaHQ/OiBudW1iZXI7IC8vIHBpeGVsc1xuICAgIG92ZXJyaWRlQm9keVR5cGVzPzogUmVjb3JkPHN0cmluZywgdHlwZW9mIFJlYWN0LkNvbXBvbmVudD47XG4gICAgb3ZlcnJpZGVFdmVudFR5cGVzPzogUmVjb3JkPHN0cmluZywgdHlwZW9mIFJlYWN0LkNvbXBvbmVudD47XG59XG5cbnR5cGUgRmFjdG9yeVByb3BzID0gT21pdDxFdmVudFRpbGVUeXBlUHJvcHMsIFwicmVmXCI+O1xudHlwZSBGYWN0b3J5PFggPSBGYWN0b3J5UHJvcHM+ID0gKHJlZjogT3B0aW9uYWw8UmVhY3QuUmVmT2JqZWN0PGFueT4+LCBwcm9wczogWCkgPT4gSlNYLkVsZW1lbnQ7XG5cbmV4cG9ydCBjb25zdCBNZXNzYWdlRXZlbnRGYWN0b3J5OiBGYWN0b3J5ID0gKHJlZiwgcHJvcHMpID0+IDxNZXNzYWdlRXZlbnQgcmVmPXtyZWZ9IHsuLi5wcm9wc30gLz47XG5jb25zdCBMZWdhY3lDYWxsRXZlbnRGYWN0b3J5OiBGYWN0b3J5PEZhY3RvcnlQcm9wcyAmIHsgY2FsbEV2ZW50R3JvdXBlcjogTGVnYWN5Q2FsbEV2ZW50R3JvdXBlciB9PiA9IChyZWYsIHByb3BzKSA9PiAoXG4gICAgPExlZ2FjeUNhbGxFdmVudCByZWY9e3JlZn0gey4uLnByb3BzfSAvPlxuKTtcbmNvbnN0IENhbGxFdmVudEZhY3Rvcnk6IEZhY3RvcnkgPSAocmVmLCBwcm9wcykgPT4gPENhbGxFdmVudCByZWY9e3JlZn0gey4uLnByb3BzfSAvPjtcbmV4cG9ydCBjb25zdCBUZXh0dWFsRXZlbnRGYWN0b3J5OiBGYWN0b3J5ID0gKHJlZiwgcHJvcHMpID0+IDxUZXh0dWFsRXZlbnQgcmVmPXtyZWZ9IHsuLi5wcm9wc30gLz47XG5jb25zdCBWZXJpZmljYXRpb25SZXFGYWN0b3J5OiBGYWN0b3J5ID0gKF9yZWYsIHByb3BzKSA9PiA8TUtleVZlcmlmaWNhdGlvblJlcXVlc3Qgey4uLnByb3BzfSAvPjtcbmNvbnN0IEhpZGRlbkV2ZW50RmFjdG9yeTogRmFjdG9yeSA9IChyZWYsIHByb3BzKSA9PiA8SGlkZGVuQm9keSByZWY9e3JlZn0gey4uLnByb3BzfSAvPjtcblxuLy8gVGhlc2UgZmFjdG9yaWVzIGFyZSBleHBvcnRlZCBmb3IgcmVmZXJlbmNlIGNvbXBhcmlzb24gYWdhaW5zdCBwaWNrRmFjdG9yeSgpXG5leHBvcnQgY29uc3QgSml0c2lFdmVudEZhY3Rvcnk6IEZhY3RvcnkgPSAocmVmLCBwcm9wcykgPT4gPE1KaXRzaVdpZGdldEV2ZW50IHJlZj17cmVmfSB7Li4ucHJvcHN9IC8+O1xuZXhwb3J0IGNvbnN0IEpTT05FdmVudEZhY3Rvcnk6IEZhY3RvcnkgPSAocmVmLCBwcm9wcykgPT4gPFZpZXdTb3VyY2VFdmVudCByZWY9e3JlZn0gey4uLnByb3BzfSAvPjtcbmV4cG9ydCBjb25zdCBSb29tQ3JlYXRlRXZlbnRGYWN0b3J5OiBGYWN0b3J5ID0gKF9yZWYsIHByb3BzKSA9PiA8Um9vbVByZWRlY2Vzc29yVGlsZSB7Li4ucHJvcHN9IC8+O1xuXG5jb25zdCBFVkVOVF9USUxFX1RZUEVTID0gbmV3IE1hcDxzdHJpbmcsIEZhY3Rvcnk+KFtcbiAgICBbRXZlbnRUeXBlLlJvb21NZXNzYWdlLCBNZXNzYWdlRXZlbnRGYWN0b3J5XSwgLy8gbm90ZSB0aGF0IHZlcmlmaWNhdGlvbiByZXF1ZXN0cyBhcmUgaGFuZGxlZCBpbiBwaWNrRmFjdG9yeSgpXG4gICAgW0V2ZW50VHlwZS5TdGlja2VyLCBNZXNzYWdlRXZlbnRGYWN0b3J5XSxcbiAgICBbTV9QT0xMX1NUQVJULm5hbWUsIE1lc3NhZ2VFdmVudEZhY3RvcnldLFxuICAgIFtNX1BPTExfU1RBUlQuYWx0TmFtZSwgTWVzc2FnZUV2ZW50RmFjdG9yeV0sXG4gICAgW01fUE9MTF9FTkQubmFtZSwgTWVzc2FnZUV2ZW50RmFjdG9yeV0sXG4gICAgW01fUE9MTF9FTkQuYWx0TmFtZSwgTWVzc2FnZUV2ZW50RmFjdG9yeV0sXG4gICAgW0V2ZW50VHlwZS5DYWxsSW52aXRlLCBMZWdhY3lDYWxsRXZlbnRGYWN0b3J5IGFzIEZhY3RvcnldLCAvLyBub3RlIHRoYXQgdGhpcyByZXF1aXJlcyBhIHNwZWNpYWwgZmFjdG9yeSB0eXBlXG5dKTtcblxuY29uc3QgU1RBVEVfRVZFTlRfVElMRV9UWVBFUyA9IG5ldyBNYXA8c3RyaW5nLCBGYWN0b3J5PihbXG4gICAgW0V2ZW50VHlwZS5Sb29tRW5jcnlwdGlvbiwgKHJlZiwgcHJvcHMpID0+IDxFbmNyeXB0aW9uRXZlbnQgcmVmPXtyZWZ9IHsuLi5wcm9wc30gLz5dLFxuICAgIFtFdmVudFR5cGUuUm9vbUNhbm9uaWNhbEFsaWFzLCBUZXh0dWFsRXZlbnRGYWN0b3J5XSxcbiAgICBbRXZlbnRUeXBlLlJvb21DcmVhdGUsIFJvb21DcmVhdGVFdmVudEZhY3RvcnldLFxuICAgIFtFdmVudFR5cGUuUm9vbU1lbWJlciwgVGV4dHVhbEV2ZW50RmFjdG9yeV0sXG4gICAgW0V2ZW50VHlwZS5Sb29tTmFtZSwgVGV4dHVhbEV2ZW50RmFjdG9yeV0sXG4gICAgW0V2ZW50VHlwZS5Sb29tQXZhdGFyLCAocmVmLCBwcm9wcykgPT4gPFJvb21BdmF0YXJFdmVudCByZWY9e3JlZn0gey4uLnByb3BzfSAvPl0sXG4gICAgW0V2ZW50VHlwZS5Sb29tVGhpcmRQYXJ0eUludml0ZSwgVGV4dHVhbEV2ZW50RmFjdG9yeV0sXG4gICAgW0V2ZW50VHlwZS5Sb29tSGlzdG9yeVZpc2liaWxpdHksIFRleHR1YWxFdmVudEZhY3RvcnldLFxuICAgIFtFdmVudFR5cGUuUm9vbVRvcGljLCBUZXh0dWFsRXZlbnRGYWN0b3J5XSxcbiAgICBbRXZlbnRUeXBlLlJvb21Qb3dlckxldmVscywgVGV4dHVhbEV2ZW50RmFjdG9yeV0sXG4gICAgW0V2ZW50VHlwZS5Sb29tUGlubmVkRXZlbnRzLCBUZXh0dWFsRXZlbnRGYWN0b3J5XSxcbiAgICBbRXZlbnRUeXBlLlJvb21TZXJ2ZXJBY2wsIFRleHR1YWxFdmVudEZhY3RvcnldLFxuICAgIC8vIFRPRE86IEVuYWJsZSBzdXBwb3J0IGZvciBtLndpZGdldCBldmVudCB0eXBlIChodHRwczovL2dpdGh1Yi5jb20vdmVjdG9yLWltL2VsZW1lbnQtd2ViL2lzc3Vlcy8xMzExMSlcbiAgICBbXCJpbS52ZWN0b3IubW9kdWxhci53aWRnZXRzXCIsIFRleHR1YWxFdmVudEZhY3RvcnldLCAvLyBub3RlIHRoYXQgSml0c2kgd2lkZ2V0cyBhcmUgc3BlY2lhbCBpbiBwaWNrRmFjdG9yeSgpXG4gICAgW1dJREdFVF9MQVlPVVRfRVZFTlRfVFlQRSwgVGV4dHVhbEV2ZW50RmFjdG9yeV0sXG4gICAgW0V2ZW50VHlwZS5Sb29tVG9tYnN0b25lLCBUZXh0dWFsRXZlbnRGYWN0b3J5XSxcbiAgICBbRXZlbnRUeXBlLlJvb21Kb2luUnVsZXMsIFRleHR1YWxFdmVudEZhY3RvcnldLFxuICAgIFtFdmVudFR5cGUuUm9vbUd1ZXN0QWNjZXNzLCBUZXh0dWFsRXZlbnRGYWN0b3J5XSxcbl0pO1xuXG5mb3IgKGNvbnN0IGV2VHlwZSBvZiBFbGVtZW50Q2FsbC5DQUxMX0VWRU5UX1RZUEUubmFtZXMpIHtcbiAgICBTVEFURV9FVkVOVF9USUxFX1RZUEVTLnNldChldlR5cGUsIENhbGxFdmVudEZhY3RvcnkpO1xufVxuXG4vLyBBZGQgYWxsIHRoZSBNam9sbmlyIHN0dWZmIHRvIHRoZSByZW5kZXJlciB0b29cbmZvciAoY29uc3QgZXZUeXBlIG9mIEFMTF9SVUxFX1RZUEVTKSB7XG4gICAgU1RBVEVfRVZFTlRfVElMRV9UWVBFUy5zZXQoZXZUeXBlLCBUZXh0dWFsRXZlbnRGYWN0b3J5KTtcbn1cblxuLy8gVGhlc2UgZXZlbnRzIHNob3VsZCBiZSByZWNvcmRlZCBpbiB0aGUgU1RBVEVfRVZFTlRfVElMRV9UWVBFU1xuY29uc3QgU0lOR1VMQVJfU1RBVEVfRVZFTlRTID0gbmV3IFNldChbXG4gICAgRXZlbnRUeXBlLlJvb21FbmNyeXB0aW9uLFxuICAgIEV2ZW50VHlwZS5Sb29tQ2Fub25pY2FsQWxpYXMsXG4gICAgRXZlbnRUeXBlLlJvb21DcmVhdGUsXG4gICAgRXZlbnRUeXBlLlJvb21OYW1lLFxuICAgIEV2ZW50VHlwZS5Sb29tQXZhdGFyLFxuICAgIEV2ZW50VHlwZS5Sb29tSGlzdG9yeVZpc2liaWxpdHksXG4gICAgRXZlbnRUeXBlLlJvb21Ub3BpYyxcbiAgICBFdmVudFR5cGUuUm9vbVBvd2VyTGV2ZWxzLFxuICAgIEV2ZW50VHlwZS5Sb29tUGlubmVkRXZlbnRzLFxuICAgIEV2ZW50VHlwZS5Sb29tU2VydmVyQWNsLFxuICAgIFdJREdFVF9MQVlPVVRfRVZFTlRfVFlQRSxcbiAgICBFdmVudFR5cGUuUm9vbVRvbWJzdG9uZSxcbiAgICBFdmVudFR5cGUuUm9vbUpvaW5SdWxlcyxcbiAgICBFdmVudFR5cGUuUm9vbUd1ZXN0QWNjZXNzLFxuXSk7XG5cbi8qKlxuICogRmluZCBhbiBldmVudCB0aWxlIGZhY3RvcnkgZm9yIHRoZSBnaXZlbiBjb25kaXRpb25zLlxuICogQHBhcmFtIG14RXZlbnQgVGhlIGV2ZW50LlxuICogQHBhcmFtIGNsaSBUaGUgbWF0cml4IGNsaWVudCB0byByZWZlcmVuY2Ugd2hlbiBuZWVkZWQuXG4gKiBAcGFyYW0gc2hvd0hpZGRlbkV2ZW50cyBXaGV0aGVyIGhpZGRlbiBldmVudHMgc2hvdWxkIGJlIHNob3duLlxuICogQHBhcmFtIGFzSGlkZGVuRXYgV2hlbiB0cnVlLCB0cmVhdCB0aGUgZXZlbnQgYXMgYWx3YXlzIGhpZGRlbi5cbiAqIEByZXR1cm5zIFRoZSBmYWN0b3J5LCBvciBmYWxzeSBpZiBub3QgcG9zc2libGUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwaWNrRmFjdG9yeShcbiAgICBteEV2ZW50OiBNYXRyaXhFdmVudCxcbiAgICBjbGk6IE1hdHJpeENsaWVudCxcbiAgICBzaG93SGlkZGVuRXZlbnRzOiBib29sZWFuLFxuICAgIGFzSGlkZGVuRXY/OiBib29sZWFuLFxuKTogT3B0aW9uYWw8RmFjdG9yeT4ge1xuICAgIGNvbnN0IGV2VHlwZSA9IG14RXZlbnQuZ2V0VHlwZSgpOyAvLyBjYWNoZSB0aGlzIHRvIHJlZHVjZSBjYWxsIHN0YWNrIGV4ZWN1dGlvbiBoaXRzXG5cbiAgICAvLyBOb3RlOiB3ZSBhdm9pZCBjYWxsaW5nIFNldHRpbmdzU3RvcmUgdW5sZXNzIGFic29sdXRlbHkgbmVjZXNzYXJ5IC0gdGhpcyBjb2RlIGlzIG9uIHRoZSBjcml0aWNhbCBwYXRoLlxuXG4gICAgaWYgKGFzSGlkZGVuRXYgJiYgc2hvd0hpZGRlbkV2ZW50cykge1xuICAgICAgICByZXR1cm4gSlNPTkV2ZW50RmFjdG9yeTtcbiAgICB9XG5cbiAgICBjb25zdCBub0V2ZW50RmFjdG9yeUZhY3Rvcnk6ICgpID0+IE9wdGlvbmFsPEZhY3Rvcnk+ID0gKCkgPT4gKHNob3dIaWRkZW5FdmVudHMgPyBKU09ORXZlbnRGYWN0b3J5IDogdW5kZWZpbmVkKTsgLy8ganVzdCBkb24ndCByZW5kZXIgdGhpbmdzIHRoYXQgd2Ugc2hvdWxkbid0IHJlbmRlclxuXG4gICAgLy8gV2UgcnVuIGFsbCB0aGUgZXZlbnQgdHlwZSBjaGVja3MgZmlyc3QgYXMgdGhleSBtaWdodCBvdmVycmlkZSB0aGUgZmFjdG9yeSBlbnRpcmVseS5cblxuICAgIGNvbnN0IG1vZGVyYXRpb25TdGF0ZSA9IGdldE1lc3NhZ2VNb2RlcmF0aW9uU3RhdGUobXhFdmVudCwgY2xpKTtcbiAgICBpZiAobW9kZXJhdGlvblN0YXRlID09PSBNZXNzYWdlTW9kZXJhdGlvblN0YXRlLkhJRERFTl9UT19DVVJSRU5UX1VTRVIpIHtcbiAgICAgICAgcmV0dXJuIEhpZGRlbkV2ZW50RmFjdG9yeTtcbiAgICB9XG5cbiAgICBpZiAoZXZUeXBlID09PSBFdmVudFR5cGUuUm9vbU1lc3NhZ2UpIHtcbiAgICAgICAgLy8gZG9uJ3Qgc2hvdyB2ZXJpZmljYXRpb24gcmVxdWVzdHMgd2UncmUgbm90IGludm9sdmVkIGluLFxuICAgICAgICAvLyBub3QgZXZlbiB3aGVuIHNob3dpbmcgaGlkZGVuIGV2ZW50c1xuICAgICAgICBjb25zdCBjb250ZW50ID0gbXhFdmVudC5nZXRDb250ZW50KCk7XG4gICAgICAgIGlmIChjb250ZW50Py5tc2d0eXBlID09PSBNc2dUeXBlLktleVZlcmlmaWNhdGlvblJlcXVlc3QpIHtcbiAgICAgICAgICAgIGNvbnN0IG1lID0gY2xpLmdldFVzZXJJZCgpO1xuICAgICAgICAgICAgaWYgKG14RXZlbnQuZ2V0U2VuZGVyKCkgIT09IG1lICYmIGNvbnRlbnRbXCJ0b1wiXSAhPT0gbWUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gbm9FdmVudEZhY3RvcnlGYWN0b3J5KCk7IC8vIG5vdCBmb3IvZnJvbSB1c1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAvLyBvdmVycmlkZSB0aGUgZmFjdG9yeVxuICAgICAgICAgICAgICAgIHJldHVybiBWZXJpZmljYXRpb25SZXFGYWN0b3J5O1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGV2VHlwZSA9PT0gRXZlbnRUeXBlLlJvb21DcmVhdGUpIHtcbiAgICAgICAgY29uc3QgZHluYW1pY1ByZWRlY2Vzc29yc0VuYWJsZWQgPSBTZXR0aW5nc1N0b3JlLmdldFZhbHVlKFwiZmVhdHVyZV9keW5hbWljX3Jvb21fcHJlZGVjZXNzb3JzXCIpO1xuICAgICAgICBjb25zdCBwcmVkZWNlc3NvciA9IGNsaS5nZXRSb29tKG14RXZlbnQuZ2V0Um9vbUlkKCkpPy5maW5kUHJlZGVjZXNzb3IoZHluYW1pY1ByZWRlY2Vzc29yc0VuYWJsZWQpO1xuICAgICAgICBpZiAoIXByZWRlY2Vzc29yKSB7XG4gICAgICAgICAgICByZXR1cm4gbm9FdmVudEZhY3RvcnlGYWN0b3J5KCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBUT0RPOiBFbmFibGUgc3VwcG9ydCBmb3IgbS53aWRnZXQgZXZlbnQgdHlwZSAoaHR0cHM6Ly9naXRodWIuY29tL3ZlY3Rvci1pbS9lbGVtZW50LXdlYi9pc3N1ZXMvMTMxMTEpXG4gICAgaWYgKGV2VHlwZSA9PT0gXCJpbS52ZWN0b3IubW9kdWxhci53aWRnZXRzXCIpIHtcbiAgICAgICAgbGV0IHR5cGUgPSBteEV2ZW50LmdldENvbnRlbnQoKVtcInR5cGVcIl07XG4gICAgICAgIGlmICghdHlwZSkge1xuICAgICAgICAgICAgLy8gZGVsZXRlZC9pbnZhbGlkIHdpZGdldCAtIHRyeSB0aGUgcGFzdCB3aWRnZXQgdHlwZVxuICAgICAgICAgICAgdHlwZSA9IG14RXZlbnQuZ2V0UHJldkNvbnRlbnQoKVtcInR5cGVcIl07XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoV2lkZ2V0VHlwZS5KSVRTSS5tYXRjaGVzKHR5cGUpKSB7XG4gICAgICAgICAgICAvLyBvdmVycmlkZSB0aGUgZmFjdG9yeVxuICAgICAgICAgICAgcmV0dXJuIEppdHNpRXZlbnRGYWN0b3J5O1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8gVHJ5IGFuZCBwaWNrIGEgc3RhdGUgZXZlbnQgZmFjdG9yeSwgaWYgd2UgY2FuLlxuICAgIGlmIChteEV2ZW50LmlzU3RhdGUoKSkge1xuICAgICAgICBpZiAoc2hvdWxkRGlzcGxheUFzQmVhY29uVGlsZShteEV2ZW50KSkge1xuICAgICAgICAgICAgcmV0dXJuIE1lc3NhZ2VFdmVudEZhY3Rvcnk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoc2hvdWxkRGlzcGxheUFzVm9pY2VCcm9hZGNhc3RUaWxlKG14RXZlbnQpKSB7XG4gICAgICAgICAgICByZXR1cm4gTWVzc2FnZUV2ZW50RmFjdG9yeTtcbiAgICAgICAgfSBlbHNlIGlmIChzaG91bGREaXNwbGF5QXNWb2ljZUJyb2FkY2FzdFN0b3BwZWRUZXh0KG14RXZlbnQpKSB7XG4gICAgICAgICAgICByZXR1cm4gVGV4dHVhbEV2ZW50RmFjdG9yeTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChTSU5HVUxBUl9TVEFURV9FVkVOVFMuaGFzKGV2VHlwZSkgJiYgbXhFdmVudC5nZXRTdGF0ZUtleSgpICE9PSBcIlwiKSB7XG4gICAgICAgICAgICByZXR1cm4gbm9FdmVudEZhY3RvcnlGYWN0b3J5KCk7IC8vIGltcHJvcGVyIGV2ZW50IHR5cGUgdG8gcmVuZGVyXG4gICAgICAgIH1cblxuICAgICAgICBpZiAoU1RBVEVfRVZFTlRfVElMRV9UWVBFUy5nZXQoZXZUeXBlKSA9PT0gVGV4dHVhbEV2ZW50RmFjdG9yeSAmJiAhaGFzVGV4dChteEV2ZW50LCBjbGksIHNob3dIaWRkZW5FdmVudHMpKSB7XG4gICAgICAgICAgICByZXR1cm4gbm9FdmVudEZhY3RvcnlGYWN0b3J5KCk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gU1RBVEVfRVZFTlRfVElMRV9UWVBFUy5nZXQoZXZUeXBlKSA/PyBub0V2ZW50RmFjdG9yeUZhY3RvcnkoKTtcbiAgICB9XG5cbiAgICAvLyBCbGFua2V0IG92ZXJyaWRlIGZvciBhbGwgZXZlbnRzLiBUaGUgTWVzc2FnZUV2ZW50IGNvbXBvbmVudCBoYW5kbGVzIHJlZGFjdGVkIHN0YXRlcyBmb3IgdXMuXG4gICAgaWYgKG14RXZlbnQuaXNSZWRhY3RlZCgpKSB7XG4gICAgICAgIHJldHVybiBNZXNzYWdlRXZlbnRGYWN0b3J5O1xuICAgIH1cblxuICAgIGlmIChteEV2ZW50LmlzUmVsYXRpb24oUmVsYXRpb25UeXBlLlJlcGxhY2UpKSB7XG4gICAgICAgIHJldHVybiBub0V2ZW50RmFjdG9yeUZhY3RvcnkoKTtcbiAgICB9XG5cbiAgICBpZiAobXhFdmVudC5nZXRDb250ZW50KClbVm9pY2VCcm9hZGNhc3RDaHVua0V2ZW50VHlwZV0pIHtcbiAgICAgICAgLy8gaGlkZSB2b2ljZSBicm9hZGNhc3QgY2h1bmtzXG4gICAgICAgIHJldHVybiBub0V2ZW50RmFjdG9yeUZhY3RvcnkoKTtcbiAgICB9XG5cbiAgICBpZiAoIXNob3dIaWRkZW5FdmVudHMgJiYgbXhFdmVudC5pc0RlY3J5cHRpb25GYWlsdXJlKCkgJiYgaXNSZWxhdGVkVG9Wb2ljZUJyb2FkY2FzdChteEV2ZW50LCBjbGkpKSB7XG4gICAgICAgIC8vIGhpZGUgdXRkIGV2ZW50cyByZWxhdGVkIHRvIGEgYnJvYWRjYXN0XG4gICAgICAgIHJldHVybiBub0V2ZW50RmFjdG9yeUZhY3RvcnkoKTtcbiAgICB9XG5cbiAgICByZXR1cm4gRVZFTlRfVElMRV9UWVBFUy5nZXQoZXZUeXBlKSA/PyBub0V2ZW50RmFjdG9yeUZhY3RvcnkoKTtcbn1cblxuLyoqXG4gKiBSZW5kZXIgYW4gZXZlbnQgYXMgYSB0aWxlXG4gKiBAcGFyYW0gcmVuZGVyVHlwZSBUaGUgcmVuZGVyIHR5cGUuIFVzZWQgdG8gaW5mb3JtIHByb3BlcnRpZXMgZ2l2ZW4gdG8gdGhlIGV2ZW50dWFsIGNvbXBvbmVudC5cbiAqIEBwYXJhbSBwcm9wcyBUaGUgcHJvcGVydGllcyB0byBwcm92aWRlIHRvIHRoZSBldmVudHVhbCBjb21wb25lbnQuXG4gKiBAcGFyYW0gc2hvd0hpZGRlbkV2ZW50cyBXaGV0aGVyIGhpZGRlbiBldmVudHMgc2hvdWxkIGJlIHNob3duLlxuICogQHBhcmFtIGNsaSBPcHRpb25hbCBjbGllbnQgaW5zdGFuY2UgdG8gdXNlLCBvdGhlcndpc2UgdGhlIGRlZmF1bHQgTWF0cml4Q2xpZW50UGVnIHdpbGwgYmUgdXNlZC5cbiAqIEByZXR1cm5zIFRoZSB0aWxlIGFzIEpTWCwgb3IgZmFsc3kgaWYgdW5hYmxlIHRvIHJlbmRlci5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlbmRlclRpbGUoXG4gICAgcmVuZGVyVHlwZTogVGltZWxpbmVSZW5kZXJpbmdUeXBlLFxuICAgIHByb3BzOiBFdmVudFRpbGVUeXBlUHJvcHMsXG4gICAgc2hvd0hpZGRlbkV2ZW50czogYm9vbGVhbixcbiAgICBjbGk/OiBNYXRyaXhDbGllbnQsXG4pOiBPcHRpb25hbDxKU1guRWxlbWVudD4ge1xuICAgIGNsaSA9IGNsaSA/PyBNYXRyaXhDbGllbnRQZWcuc2FmZUdldCgpOyAvLyBiZWNhdXNlIHBhcmFtIGRlZmF1bHRzIGRvbid0IGRvIHRoZSBjb3JyZWN0IHRoaW5nXG5cbiAgICBjb25zdCBmYWN0b3J5ID0gcGlja0ZhY3RvcnkocHJvcHMubXhFdmVudCwgY2xpLCBzaG93SGlkZGVuRXZlbnRzKTtcbiAgICBpZiAoIWZhY3RvcnkpIHJldHVybiB1bmRlZmluZWQ7XG5cbiAgICAvLyBOb3RlIHRoYXQgd2Ugc3BsaXQgb2ZmIHRoZSBvbmVzIHdlIGFjdHVhbGx5IGNhcmUgYWJvdXQgaGVyZSBqdXN0IHRvIGJlIHN1cmUgdGhhdCB3ZSdyZVxuICAgIC8vIG5vdCBnb2luZyB0byBhY2NpZGVudGFsbHkgc2VuZCB0aGluZ3Mgd2Ugc2hvdWxkbid0IGZyb20gbGF6eSBjYWxsZXJzLiBFZzogRXZlbnRUaWxlJ3NcbiAgICAvLyBsYXp5IGNhbGxzIG9mIGByZW5kZXJUaWxlKC4uLiwgdGhpcy5wcm9wcylgIHdpbGwgaGF2ZSBhIGxvdCBtb3JlIHRoYW4gd2UgYWN0dWFsbHkgY2FyZVxuICAgIC8vIGFib3V0LlxuICAgIGNvbnN0IHtcbiAgICAgICAgcmVmLFxuICAgICAgICBteEV2ZW50LFxuICAgICAgICBmb3JFeHBvcnQsXG4gICAgICAgIHJlcGxhY2luZ0V2ZW50SWQsXG4gICAgICAgIGVkaXRTdGF0ZSxcbiAgICAgICAgaGlnaGxpZ2h0cyxcbiAgICAgICAgaGlnaGxpZ2h0TGluayxcbiAgICAgICAgc2hvd1VybFByZXZpZXcsXG4gICAgICAgIHBlcm1hbGlua0NyZWF0b3IsXG4gICAgICAgIG9uSGVpZ2h0Q2hhbmdlZCxcbiAgICAgICAgY2FsbEV2ZW50R3JvdXBlcixcbiAgICAgICAgZ2V0UmVsYXRpb25zRm9yRXZlbnQsXG4gICAgICAgIGlzU2VlaW5nVGhyb3VnaE1lc3NhZ2VIaWRkZW5Gb3JNb2RlcmF0aW9uLFxuICAgICAgICB0aW1lc3RhbXAsXG4gICAgICAgIGluaGliaXRJbnRlcmFjdGlvbixcbiAgICB9ID0gcHJvcHM7XG5cbiAgICBzd2l0Y2ggKHJlbmRlclR5cGUpIHtcbiAgICAgICAgY2FzZSBUaW1lbGluZVJlbmRlcmluZ1R5cGUuRmlsZTpcbiAgICAgICAgY2FzZSBUaW1lbGluZVJlbmRlcmluZ1R5cGUuTm90aWZpY2F0aW9uOlxuICAgICAgICBjYXNlIFRpbWVsaW5lUmVuZGVyaW5nVHlwZS5UaHJlYWQ6XG4gICAgICAgICAgICAvLyBXZSBvbmx5IHdhbnQgYSBzdWJzZXQgb2YgcHJvcHMsIHNvIHdlIGRvbid0IGVuZCB1cCBjYXVzaW5nIGlzc3VlcyBmb3IgZG93bnN0cmVhbSBjb21wb25lbnRzLlxuICAgICAgICAgICAgcmV0dXJuIGZhY3RvcnkocHJvcHMucmVmLCB7XG4gICAgICAgICAgICAgICAgbXhFdmVudCxcbiAgICAgICAgICAgICAgICBoaWdobGlnaHRzLFxuICAgICAgICAgICAgICAgIGhpZ2hsaWdodExpbmssXG4gICAgICAgICAgICAgICAgc2hvd1VybFByZXZpZXcsXG4gICAgICAgICAgICAgICAgb25IZWlnaHRDaGFuZ2VkLFxuICAgICAgICAgICAgICAgIGVkaXRTdGF0ZSxcbiAgICAgICAgICAgICAgICByZXBsYWNpbmdFdmVudElkLFxuICAgICAgICAgICAgICAgIGdldFJlbGF0aW9uc0ZvckV2ZW50LFxuICAgICAgICAgICAgICAgIGlzU2VlaW5nVGhyb3VnaE1lc3NhZ2VIaWRkZW5Gb3JNb2RlcmF0aW9uLFxuICAgICAgICAgICAgICAgIHBlcm1hbGlua0NyZWF0b3IsXG4gICAgICAgICAgICAgICAgaW5oaWJpdEludGVyYWN0aW9uLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAvLyBORUFSTFkgQUxMIFRIRSBPUFRJT05TIVxuICAgICAgICAgICAgcmV0dXJuIGZhY3RvcnkocmVmLCB7XG4gICAgICAgICAgICAgICAgbXhFdmVudCxcbiAgICAgICAgICAgICAgICBmb3JFeHBvcnQsXG4gICAgICAgICAgICAgICAgcmVwbGFjaW5nRXZlbnRJZCxcbiAgICAgICAgICAgICAgICBlZGl0U3RhdGUsXG4gICAgICAgICAgICAgICAgaGlnaGxpZ2h0cyxcbiAgICAgICAgICAgICAgICBoaWdobGlnaHRMaW5rLFxuICAgICAgICAgICAgICAgIHNob3dVcmxQcmV2aWV3LFxuICAgICAgICAgICAgICAgIHBlcm1hbGlua0NyZWF0b3IsXG4gICAgICAgICAgICAgICAgb25IZWlnaHRDaGFuZ2VkLFxuICAgICAgICAgICAgICAgIGNhbGxFdmVudEdyb3VwZXIsXG4gICAgICAgICAgICAgICAgZ2V0UmVsYXRpb25zRm9yRXZlbnQsXG4gICAgICAgICAgICAgICAgaXNTZWVpbmdUaHJvdWdoTWVzc2FnZUhpZGRlbkZvck1vZGVyYXRpb24sXG4gICAgICAgICAgICAgICAgdGltZXN0YW1wLFxuICAgICAgICAgICAgICAgIGluaGliaXRJbnRlcmFjdGlvbixcbiAgICAgICAgICAgIH0pO1xuICAgIH1cbn1cblxuLyoqXG4gKiBBIHZlcnNpb24gb2YgcmVuZGVyVGlsZSgpIHNwZWNpZmljYWxseSBmb3IgcmVwbGllcy5cbiAqIEBwYXJhbSBwcm9wcyBUaGUgcHJvcGVydGllcyB0byBzcGVjaWZ5IG9uIHRoZSBldmVudHVhbCBvYmplY3QuXG4gKiBAcGFyYW0gc2hvd0hpZGRlbkV2ZW50cyBXaGV0aGVyIGhpZGRlbiBldmVudHMgc2hvdWxkIGJlIHNob3duLlxuICogQHBhcmFtIGNsaSBPcHRpb25hbCBjbGllbnQgaW5zdGFuY2UgdG8gdXNlLCBvdGhlcndpc2UgdGhlIGRlZmF1bHQgTWF0cml4Q2xpZW50UGVnIHdpbGwgYmUgdXNlZC5cbiAqIEByZXR1cm5zIFRoZSB0aWxlIGFzIEpTWCwgb3IgZmFsc3kgaWYgdW5hYmxlIHRvIHJlbmRlci5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlbmRlclJlcGx5VGlsZShcbiAgICBwcm9wczogRXZlbnRUaWxlVHlwZVByb3BzLFxuICAgIHNob3dIaWRkZW5FdmVudHM6IGJvb2xlYW4sXG4gICAgY2xpPzogTWF0cml4Q2xpZW50LFxuKTogT3B0aW9uYWw8SlNYLkVsZW1lbnQ+IHtcbiAgICBjbGkgPSBjbGkgPz8gTWF0cml4Q2xpZW50UGVnLnNhZmVHZXQoKTsgLy8gYmVjYXVzZSBwYXJhbSBkZWZhdWx0cyBkb24ndCBkbyB0aGUgY29ycmVjdCB0aGluZ1xuXG4gICAgY29uc3QgZmFjdG9yeSA9IHBpY2tGYWN0b3J5KHByb3BzLm14RXZlbnQsIGNsaSwgc2hvd0hpZGRlbkV2ZW50cyk7XG4gICAgaWYgKCFmYWN0b3J5KSByZXR1cm4gdW5kZWZpbmVkO1xuXG4gICAgLy8gU2VlIHJlbmRlclRpbGUoKSBmb3Igd2h5IHdlIHNwbGl0IG9mZiBzbyBtdWNoXG4gICAgY29uc3Qge1xuICAgICAgICByZWYsXG4gICAgICAgIG14RXZlbnQsXG4gICAgICAgIGhpZ2hsaWdodHMsXG4gICAgICAgIGhpZ2hsaWdodExpbmssXG4gICAgICAgIG9uSGVpZ2h0Q2hhbmdlZCxcbiAgICAgICAgc2hvd1VybFByZXZpZXcsXG4gICAgICAgIG92ZXJyaWRlQm9keVR5cGVzLFxuICAgICAgICBvdmVycmlkZUV2ZW50VHlwZXMsXG4gICAgICAgIHJlcGxhY2luZ0V2ZW50SWQsXG4gICAgICAgIG1heEltYWdlSGVpZ2h0LFxuICAgICAgICBnZXRSZWxhdGlvbnNGb3JFdmVudCxcbiAgICAgICAgaXNTZWVpbmdUaHJvdWdoTWVzc2FnZUhpZGRlbkZvck1vZGVyYXRpb24sXG4gICAgICAgIHBlcm1hbGlua0NyZWF0b3IsXG4gICAgfSA9IHByb3BzO1xuXG4gICAgcmV0dXJuIGZhY3RvcnkocmVmLCB7XG4gICAgICAgIG14RXZlbnQsXG4gICAgICAgIGhpZ2hsaWdodHMsXG4gICAgICAgIGhpZ2hsaWdodExpbmssXG4gICAgICAgIG9uSGVpZ2h0Q2hhbmdlZCxcbiAgICAgICAgc2hvd1VybFByZXZpZXcsXG4gICAgICAgIG92ZXJyaWRlQm9keVR5cGVzLFxuICAgICAgICBvdmVycmlkZUV2ZW50VHlwZXMsXG4gICAgICAgIHJlcGxhY2luZ0V2ZW50SWQsXG4gICAgICAgIG1heEltYWdlSGVpZ2h0LFxuICAgICAgICBnZXRSZWxhdGlvbnNGb3JFdmVudCxcbiAgICAgICAgaXNTZWVpbmdUaHJvdWdoTWVzc2FnZUhpZGRlbkZvck1vZGVyYXRpb24sXG4gICAgICAgIHBlcm1hbGlua0NyZWF0b3IsXG4gICAgfSk7XG59XG5cbi8vIFhYWDogdGhpcydsbCBldmVudHVhbGx5IGJlIGR5bmFtaWMgYmFzZWQgb24gdGhlIGZpZWxkcyBvbmNlIHdlIGhhdmUgZXh0ZW5zaWJsZSBldmVudCB0eXBlc1xuY29uc3QgbWVzc2FnZVR5cGVzID0gW0V2ZW50VHlwZS5Sb29tTWVzc2FnZSwgRXZlbnRUeXBlLlN0aWNrZXJdO1xuZXhwb3J0IGZ1bmN0aW9uIGlzTWVzc2FnZUV2ZW50KGV2OiBNYXRyaXhFdmVudCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiAoXG4gICAgICAgIG1lc3NhZ2VUeXBlcy5pbmNsdWRlcyhldi5nZXRUeXBlKCkgYXMgRXZlbnRUeXBlKSB8fFxuICAgICAgICBNX1BPTExfU1RBUlQubWF0Y2hlcyhldi5nZXRUeXBlKCkpIHx8XG4gICAgICAgIE1fUE9MTF9FTkQubWF0Y2hlcyhldi5nZXRUeXBlKCkpXG4gICAgKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGhhdmVSZW5kZXJlckZvckV2ZW50KFxuICAgIG14RXZlbnQ6IE1hdHJpeEV2ZW50LFxuICAgIG1hdHJpeENsaWVudDogTWF0cml4Q2xpZW50LFxuICAgIHNob3dIaWRkZW5FdmVudHM6IGJvb2xlYW4sXG4pOiBib29sZWFuIHtcbiAgICAvLyBPbmx5IHNob3cgXCJNZXNzYWdlIGRlbGV0ZWRcIiB0aWxlIGZvciBwbGFpbiBtZXNzYWdlIGV2ZW50cywgZW5jcnlwdGVkIGV2ZW50cyxcbiAgICAvLyBhbmQgc3RhdGUgZXZlbnRzIGFzIHRoZXknbGwgbGlrZWx5IHN0aWxsIGNvbnRhaW4gZW5vdWdoIGtleXMgdG8gYmUgcmVsZXZhbnQuXG4gICAgaWYgKG14RXZlbnQuaXNSZWRhY3RlZCgpICYmICFteEV2ZW50LmlzRW5jcnlwdGVkKCkgJiYgIWlzTWVzc2FnZUV2ZW50KG14RXZlbnQpICYmICFteEV2ZW50LmlzU3RhdGUoKSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgLy8gTm8gdGlsZSBmb3IgcmVwbGFjZW1lbnQgZXZlbnRzIHNpbmNlIHRoZXkgdXBkYXRlIHRoZSBvcmlnaW5hbCB0aWxlXG4gICAgaWYgKG14RXZlbnQuaXNSZWxhdGlvbihSZWxhdGlvblR5cGUuUmVwbGFjZSkpIHJldHVybiBmYWxzZTtcblxuICAgIGNvbnN0IGhhbmRsZXIgPSBwaWNrRmFjdG9yeShteEV2ZW50LCBtYXRyaXhDbGllbnQsIHNob3dIaWRkZW5FdmVudHMpO1xuICAgIGlmICghaGFuZGxlcikgcmV0dXJuIGZhbHNlO1xuICAgIGlmIChoYW5kbGVyID09PSBUZXh0dWFsRXZlbnRGYWN0b3J5KSB7XG4gICAgICAgIHJldHVybiBoYXNUZXh0KG14RXZlbnQsIG1hdHJpeENsaWVudCwgc2hvd0hpZGRlbkV2ZW50cyk7XG4gICAgfSBlbHNlIGlmIChoYW5kbGVyID09PSBTVEFURV9FVkVOVF9USUxFX1RZUEVTLmdldChFdmVudFR5cGUuUm9vbUNyZWF0ZSkpIHtcbiAgICAgICAgY29uc3QgZHluYW1pY1ByZWRlY2Vzc29yc0VuYWJsZWQgPSBTZXR0aW5nc1N0b3JlLmdldFZhbHVlKFwiZmVhdHVyZV9keW5hbWljX3Jvb21fcHJlZGVjZXNzb3JzXCIpO1xuICAgICAgICBjb25zdCBwcmVkZWNlc3NvciA9IG1hdHJpeENsaWVudC5nZXRSb29tKG14RXZlbnQuZ2V0Um9vbUlkKCkpPy5maW5kUHJlZGVjZXNzb3IoZHluYW1pY1ByZWRlY2Vzc29yc0VuYWJsZWQpO1xuICAgICAgICByZXR1cm4gQm9vbGVhbihwcmVkZWNlc3Nvcik7XG4gICAgfSBlbHNlIGlmIChcbiAgICAgICAgRWxlbWVudENhbGwuQ0FMTF9FVkVOVF9UWVBFLm5hbWVzLnNvbWUoKGV2ZW50VHlwZSkgPT4gaGFuZGxlciA9PT0gU1RBVEVfRVZFTlRfVElMRV9UWVBFUy5nZXQoZXZlbnRUeXBlKSlcbiAgICApIHtcbiAgICAgICAgY29uc3QgaW50ZW50ID0gbXhFdmVudC5nZXRDb250ZW50KClbXCJtLmludGVudFwiXTtcbiAgICAgICAgY29uc3QgbmV3bHlTdGFydGVkID0gT2JqZWN0LmtleXMobXhFdmVudC5nZXRQcmV2Q29udGVudCgpKS5sZW5ndGggPT09IDA7XG4gICAgICAgIC8vIE9ubHkgaW50ZXJlc3RlZCBpbiBldmVudHMgdGhhdCBtYXJrIHRoZSBzdGFydCBvZiBhIG5vbi1yb29tIGNhbGxcbiAgICAgICAgcmV0dXJuIG5ld2x5U3RhcnRlZCAmJiB0eXBlb2YgaW50ZW50ID09PSBcInN0cmluZ1wiICYmIGludGVudCAhPT0gR3JvdXBDYWxsSW50ZW50LlJvb207XG4gICAgfSBlbHNlIGlmIChoYW5kbGVyID09PSBKU09ORXZlbnRGYWN0b3J5KSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG59XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7QUFR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