UNPKG

matrix-react-sdk

Version:
487 lines (379 loc) 57.1 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.StopGapWidget = exports.ElementWidget = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _matrixWidgetApi = require("matrix-widget-api"); var _StopGapWidgetDriver = require("./StopGapWidgetDriver"); var _events = require("events"); var _WidgetMessagingStore = require("./WidgetMessagingStore"); var _RoomViewStore = _interopRequireDefault(require("../RoomViewStore")); var _MatrixClientPeg = require("../../MatrixClientPeg"); var _OwnProfileStore = require("../OwnProfileStore"); var _WidgetUtils = _interopRequireDefault(require("../../utils/WidgetUtils")); var _IntegrationManagers = require("../../integrations/IntegrationManagers"); var _SettingsStore = _interopRequireDefault(require("../../settings/SettingsStore")); var _WidgetType = require("../../widgets/WidgetType"); var _ActiveWidgetStore = _interopRequireDefault(require("../ActiveWidgetStore")); var _objects = require("../../utils/objects"); var _dispatcher = _interopRequireDefault(require("../../dispatcher/dispatcher")); var _ElementWidgetActions = require("./ElementWidgetActions"); var _ModalWidgetStore = require("../ModalWidgetStore"); var _ThemeWatcher = _interopRequireDefault(require("../../settings/watchers/ThemeWatcher")); var _theme = require("../../theme"); var _CountlyAnalytics = _interopRequireDefault(require("../../CountlyAnalytics")); var _ElementWidgetCapabilities = require("./ElementWidgetCapabilities"); var _identifiers = require("../../identifiers"); var _languageHandler = require("../../languageHandler"); function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } // TODO: Don't use this because it's wrong class ElementWidget extends _matrixWidgetApi.Widget { constructor(rawDefinition /*: IWidget*/ ) { super(rawDefinition); this.rawDefinition /*:: */ = rawDefinition /*:: */ ; } get templateUrl() /*: string*/ { if (_WidgetType.WidgetType.JITSI.matches(this.type)) { return _WidgetUtils.default.getLocalJitsiWrapperUrl({ forLocalRender: true, auth: super.rawData?.auth // this.rawData can call templateUrl, do this to prevent looping }); } return super.templateUrl; } get popoutTemplateUrl() /*: string*/ { if (_WidgetType.WidgetType.JITSI.matches(this.type)) { return _WidgetUtils.default.getLocalJitsiWrapperUrl({ forLocalRender: false, // The only important difference between this and templateUrl() auth: super.rawData?.auth }); } return this.templateUrl; // use this instead of super to ensure we get appropriate templating } get rawData() /*: IWidgetData*/ { let conferenceId = super.rawData['conferenceId']; if (conferenceId === undefined) { // we'll need to parse the conference ID out of the URL for v1 Jitsi widgets const parsedUrl = new URL(super.templateUrl); // use super to get the raw widget URL conferenceId = parsedUrl.searchParams.get("confId"); } let domain = super.rawData['domain']; if (domain === undefined) { // v1 widgets default to jitsi.riot.im regardless of user settings domain = "jitsi.riot.im"; } let theme = new _ThemeWatcher.default().getEffectiveTheme(); if (theme.startsWith("custom-")) { const customTheme = (0, _theme.getCustomTheme)(theme.substr(7)); // Jitsi only understands light/dark theme = customTheme.is_dark ? "dark" : "light"; } // only allow light/dark through, defaulting to dark as that was previously the only state // accounts for legacy-light/legacy-dark themes too if (theme.includes("light")) { theme = "light"; } else { theme = "dark"; } return _objectSpread(_objectSpread({}, super.rawData), {}, { theme, conferenceId, domain }); } getCompleteUrl(params /*: ITemplateParams*/ , asPopout = false) /*: string*/ { return (0, _matrixWidgetApi.runTemplate)(asPopout ? this.popoutTemplateUrl : this.templateUrl, _objectSpread(_objectSpread({}, this.rawDefinition), {}, { data: this.rawData }), params); } } exports.ElementWidget = ElementWidget; class StopGapWidget extends _events.EventEmitter { constructor(appTileProps /*: IAppTileProps*/ ) { super(); this.appTileProps /*:: */ = appTileProps /*:: */ ; (0, _defineProperty2.default)(this, "messaging", void 0); (0, _defineProperty2.default)(this, "mockWidget", void 0); (0, _defineProperty2.default)(this, "scalarToken", void 0); (0, _defineProperty2.default)(this, "roomId", void 0); (0, _defineProperty2.default)(this, "kind", void 0); (0, _defineProperty2.default)(this, "onOpenModal", async (ev /*: CustomEvent<IModalWidgetOpenRequest>*/ ) => { ev.preventDefault(); if (_ModalWidgetStore.ModalWidgetStore.instance.canOpenModalWidget()) { _ModalWidgetStore.ModalWidgetStore.instance.openModalWidget(ev.detail.data, this.mockWidget); this.messaging.transport.reply(ev.detail, {}); // ack } else { this.messaging.transport.reply(ev.detail, { error: { message: "Unable to open modal at this time" } }); } }); (0, _defineProperty2.default)(this, "onEvent", (ev /*: MatrixEvent*/ ) => { _MatrixClientPeg.MatrixClientPeg.get().decryptEventIfNeeded(ev); if (ev.isBeingDecrypted() || ev.isDecryptionFailure()) return; if (ev.getRoomId() !== this.eventListenerRoomId) return; this.feedEvent(ev); }); (0, _defineProperty2.default)(this, "onEventDecrypted", (ev /*: MatrixEvent*/ ) => { if (ev.isDecryptionFailure()) return; if (ev.getRoomId() !== this.eventListenerRoomId) return; this.feedEvent(ev); }); let app = appTileProps.app; // Backwards compatibility: not all old widgets have a creatorUserId if (!app.creatorUserId) { app = (0, _objects.objectShallowClone)(app); // clone to prevent accidental mutation app.creatorUserId = _MatrixClientPeg.MatrixClientPeg.get().getUserId(); } this.mockWidget = new ElementWidget(app); this.roomId = appTileProps.room?.roomId; this.kind = appTileProps.userWidget ? _matrixWidgetApi.WidgetKind.Account : _matrixWidgetApi.WidgetKind.Room; // probably } get eventListenerRoomId() /*: string*/ { // When widgets are listening to events, we need to make sure they're only // receiving events for the right room. In particular, room widgets get locked // to the room they were added in while account widgets listen to the currently // active room. if (this.roomId) return this.roomId; return _RoomViewStore.default.getRoomId(); } get widgetApi() /*: ClientWidgetApi*/ { return this.messaging; } /** * The URL to use in the iframe */ get embedUrl() /*: string*/ { return this.runUrlTemplate({ asPopout: false }); } /** * The URL to use in the popout */ get popoutUrl() /*: string*/ { return this.runUrlTemplate({ asPopout: true }); } runUrlTemplate(opts = { asPopout: false }) /*: string*/ { const templated = this.mockWidget.getCompleteUrl({ widgetRoomId: this.roomId, currentUserId: _MatrixClientPeg.MatrixClientPeg.get().getUserId(), userDisplayName: _OwnProfileStore.OwnProfileStore.instance.displayName, userHttpAvatarUrl: _OwnProfileStore.OwnProfileStore.instance.getHttpAvatarUrl(), clientId: _identifiers.ELEMENT_CLIENT_ID, clientTheme: _SettingsStore.default.getValue("theme"), clientLanguage: (0, _languageHandler.getUserLanguage)() }, opts?.asPopout); const parsed = new URL(templated); // Add in some legacy support sprinkles (for non-popout widgets) // TODO: Replace these with proper widget params // See https://github.com/matrix-org/matrix-doc/pull/1958/files#r405714833 if (!opts?.asPopout) { parsed.searchParams.set('widgetId', this.mockWidget.id); parsed.searchParams.set('parentUrl', window.location.href.split('#', 2)[0]); // Give the widget a scalar token if we're supposed to (more legacy) // TODO: Stop doing this if (this.scalarToken) { parsed.searchParams.set('scalar_token', this.scalarToken); } } // Replace the encoded dollar signs back to dollar signs. They have no special meaning // in HTTP, but URL parsers encode them anyways. return parsed.toString().replace(/%24/g, '$'); } get isManagedByManager() /*: boolean*/ { return !!this.scalarToken; } get started() /*: boolean*/ { return !!this.messaging; } get widgetId() { return this.messaging.widget.id; } start(iframe /*: HTMLIFrameElement*/ ) { if (this.started) return; const allowedCapabilities = this.appTileProps.whitelistCapabilities || []; const driver = new _StopGapWidgetDriver.StopGapWidgetDriver(allowedCapabilities, this.mockWidget, this.kind, this.roomId); this.messaging = new _matrixWidgetApi.ClientWidgetApi(this.mockWidget, iframe, driver); this.messaging.on("preparing", () => this.emit("preparing")); this.messaging.on("ready", () => this.emit("ready")); this.messaging.on(`action:${_matrixWidgetApi.WidgetApiFromWidgetAction.OpenModalWidget}`, this.onOpenModal); _WidgetMessagingStore.WidgetMessagingStore.instance.storeMessaging(this.mockWidget, this.messaging); if (!this.appTileProps.userWidget && this.appTileProps.room) { _ActiveWidgetStore.default.setRoomId(this.mockWidget.id, this.appTileProps.room.roomId); } // Always attach a handler for ViewRoom, but permission check it internally this.messaging.on(`action:${_ElementWidgetActions.ElementWidgetActions.ViewRoom}`, (ev /*: CustomEvent<IViewRoomApiRequest>*/ ) => { ev.preventDefault(); // stop the widget API from auto-rejecting this // Check up front if this is even a valid request const targetRoomId = (ev.detail.data || {}).room_id; if (!targetRoomId) { return this.messaging.transport.reply(ev.detail, { error: { message: "Room ID not supplied." } }); } // Check the widget's permission if (!this.messaging.hasCapability(_ElementWidgetCapabilities.ElementWidgetCapabilities.CanChangeViewedRoom)) { return this.messaging.transport.reply(ev.detail, { error: { message: "This widget does not have permission for this action (denied)." } }); } // at this point we can change rooms, so do that _dispatcher.default.dispatch({ action: 'view_room', room_id: targetRoomId }); // acknowledge so the widget doesn't freak out this.messaging.transport.reply(ev.detail, {}); }); // Attach listeners for feeding events - the underlying widget classes handle permissions for us _MatrixClientPeg.MatrixClientPeg.get().on('event', this.onEvent); _MatrixClientPeg.MatrixClientPeg.get().on('Event.decrypted', this.onEventDecrypted); this.messaging.on(`action:${_matrixWidgetApi.WidgetApiFromWidgetAction.UpdateAlwaysOnScreen}`, (ev /*: CustomEvent<IStickyActionRequest>*/ ) => { if (this.messaging.hasCapability(_matrixWidgetApi.MatrixCapabilities.AlwaysOnScreen)) { if (_WidgetType.WidgetType.JITSI.matches(this.mockWidget.type)) { _CountlyAnalytics.default.instance.trackJoinCall(this.appTileProps.room.roomId, true, true); } _ActiveWidgetStore.default.setWidgetPersistence(this.mockWidget.id, ev.detail.data.value); ev.preventDefault(); this.messaging.transport.reply(ev.detail, {}); // ack } }); // TODO: Replace this event listener with appropriate driver functionality once the API // establishes a sane way to send events back and forth. this.messaging.on(`action:${_matrixWidgetApi.WidgetApiFromWidgetAction.SendSticker}`, (ev /*: CustomEvent<IStickerActionRequest>*/ ) => { if (this.messaging.hasCapability(_matrixWidgetApi.MatrixCapabilities.StickerSending)) { // Acknowledge first ev.preventDefault(); this.messaging.transport.reply(ev.detail, {}); // Send the sticker _dispatcher.default.dispatch({ action: 'm.sticker', data: ev.detail.data, widgetId: this.mockWidget.id }); } }); if (_WidgetType.WidgetType.STICKERPICKER.matches(this.mockWidget.type)) { this.messaging.on(`action:${_ElementWidgetActions.ElementWidgetActions.OpenIntegrationManager}`, (ev /*: CustomEvent<IWidgetApiRequest>*/ ) => { // Acknowledge first ev.preventDefault(); this.messaging.transport.reply(ev.detail, {}); // First close the stickerpicker _dispatcher.default.dispatch({ action: "stickerpicker_close" }); // Now open the integration manager // TODO: Spec this interaction. const data = ev.detail.data; const integType = data?.integType; const integId = data?.integId; // TODO: Open the right integration manager for the widget if (_SettingsStore.default.getValue("feature_many_integration_managers")) { _IntegrationManagers.IntegrationManagers.sharedInstance().openAll(_MatrixClientPeg.MatrixClientPeg.get().getRoom(_RoomViewStore.default.getRoomId()), `type_${integType}`, integId); } else { _IntegrationManagers.IntegrationManagers.sharedInstance().getPrimaryManager().open(_MatrixClientPeg.MatrixClientPeg.get().getRoom(_RoomViewStore.default.getRoomId()), `type_${integType}`, integId); } }); } } async prepare() /*: Promise<void>*/ { if (this.scalarToken) return; const existingMessaging = _WidgetMessagingStore.WidgetMessagingStore.instance.getMessaging(this.mockWidget); if (existingMessaging) this.messaging = existingMessaging; try { if (_WidgetUtils.default.isScalarUrl(this.mockWidget.templateUrl)) { const managers = _IntegrationManagers.IntegrationManagers.sharedInstance(); if (managers.hasManager()) { // TODO: Pick the right manager for the widget const defaultManager = managers.getPrimaryManager(); if (_WidgetUtils.default.isScalarUrl(defaultManager.apiUrl)) { const scalar = defaultManager.getScalarClient(); this.scalarToken = await scalar.getScalarToken(); } } } } catch (e) { // All errors are non-fatal console.error("Error preparing widget communications: ", e); } } stop(opts = { forceDestroy: false }) { if (!opts?.forceDestroy && _ActiveWidgetStore.default.getPersistentWidgetId() === this.mockWidget.id) { console.log("Skipping destroy - persistent widget"); return; } if (!this.started) return; _WidgetMessagingStore.WidgetMessagingStore.instance.stopMessaging(this.mockWidget); _ActiveWidgetStore.default.delRoomId(this.mockWidget.id); if (_MatrixClientPeg.MatrixClientPeg.get()) { _MatrixClientPeg.MatrixClientPeg.get().off('event', this.onEvent); _MatrixClientPeg.MatrixClientPeg.get().off('Event.decrypted', this.onEventDecrypted); } } feedEvent(ev /*: MatrixEvent*/ ) { if (!this.messaging) return; const raw = ev.event; this.messaging.feedEvent(raw).catch(e => { console.error("Error sending event to widget: ", e); }); } } exports.StopGapWidget = StopGapWidget; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9zdG9yZXMvd2lkZ2V0cy9TdG9wR2FwV2lkZ2V0LnRzIl0sIm5hbWVzIjpbIkVsZW1lbnRXaWRnZXQiLCJXaWRnZXQiLCJjb25zdHJ1Y3RvciIsInJhd0RlZmluaXRpb24iLCJ0ZW1wbGF0ZVVybCIsIldpZGdldFR5cGUiLCJKSVRTSSIsIm1hdGNoZXMiLCJ0eXBlIiwiV2lkZ2V0VXRpbHMiLCJnZXRMb2NhbEppdHNpV3JhcHBlclVybCIsImZvckxvY2FsUmVuZGVyIiwiYXV0aCIsInJhd0RhdGEiLCJwb3BvdXRUZW1wbGF0ZVVybCIsImNvbmZlcmVuY2VJZCIsInVuZGVmaW5lZCIsInBhcnNlZFVybCIsIlVSTCIsInNlYXJjaFBhcmFtcyIsImdldCIsImRvbWFpbiIsInRoZW1lIiwiVGhlbWVXYXRjaGVyIiwiZ2V0RWZmZWN0aXZlVGhlbWUiLCJzdGFydHNXaXRoIiwiY3VzdG9tVGhlbWUiLCJzdWJzdHIiLCJpc19kYXJrIiwiaW5jbHVkZXMiLCJnZXRDb21wbGV0ZVVybCIsInBhcmFtcyIsImFzUG9wb3V0IiwiZGF0YSIsIlN0b3BHYXBXaWRnZXQiLCJFdmVudEVtaXR0ZXIiLCJhcHBUaWxlUHJvcHMiLCJldiIsInByZXZlbnREZWZhdWx0IiwiTW9kYWxXaWRnZXRTdG9yZSIsImluc3RhbmNlIiwiY2FuT3Blbk1vZGFsV2lkZ2V0Iiwib3Blbk1vZGFsV2lkZ2V0IiwiZGV0YWlsIiwibW9ja1dpZGdldCIsIm1lc3NhZ2luZyIsInRyYW5zcG9ydCIsInJlcGx5IiwiZXJyb3IiLCJtZXNzYWdlIiwiTWF0cml4Q2xpZW50UGVnIiwiZGVjcnlwdEV2ZW50SWZOZWVkZWQiLCJpc0JlaW5nRGVjcnlwdGVkIiwiaXNEZWNyeXB0aW9uRmFpbHVyZSIsImdldFJvb21JZCIsImV2ZW50TGlzdGVuZXJSb29tSWQiLCJmZWVkRXZlbnQiLCJhcHAiLCJjcmVhdG9yVXNlcklkIiwiZ2V0VXNlcklkIiwicm9vbUlkIiwicm9vbSIsImtpbmQiLCJ1c2VyV2lkZ2V0IiwiV2lkZ2V0S2luZCIsIkFjY291bnQiLCJSb29tIiwiUm9vbVZpZXdTdG9yZSIsIndpZGdldEFwaSIsImVtYmVkVXJsIiwicnVuVXJsVGVtcGxhdGUiLCJwb3BvdXRVcmwiLCJvcHRzIiwidGVtcGxhdGVkIiwid2lkZ2V0Um9vbUlkIiwiY3VycmVudFVzZXJJZCIsInVzZXJEaXNwbGF5TmFtZSIsIk93blByb2ZpbGVTdG9yZSIsImRpc3BsYXlOYW1lIiwidXNlckh0dHBBdmF0YXJVcmwiLCJnZXRIdHRwQXZhdGFyVXJsIiwiY2xpZW50SWQiLCJFTEVNRU5UX0NMSUVOVF9JRCIsImNsaWVudFRoZW1lIiwiU2V0dGluZ3NTdG9yZSIsImdldFZhbHVlIiwiY2xpZW50TGFuZ3VhZ2UiLCJwYXJzZWQiLCJzZXQiLCJpZCIsIndpbmRvdyIsImxvY2F0aW9uIiwiaHJlZiIsInNwbGl0Iiwic2NhbGFyVG9rZW4iLCJ0b1N0cmluZyIsInJlcGxhY2UiLCJpc01hbmFnZWRCeU1hbmFnZXIiLCJzdGFydGVkIiwid2lkZ2V0SWQiLCJ3aWRnZXQiLCJzdGFydCIsImlmcmFtZSIsImFsbG93ZWRDYXBhYmlsaXRpZXMiLCJ3aGl0ZWxpc3RDYXBhYmlsaXRpZXMiLCJkcml2ZXIiLCJTdG9wR2FwV2lkZ2V0RHJpdmVyIiwiQ2xpZW50V2lkZ2V0QXBpIiwib24iLCJlbWl0IiwiV2lkZ2V0QXBpRnJvbVdpZGdldEFjdGlvbiIsIk9wZW5Nb2RhbFdpZGdldCIsIm9uT3Blbk1vZGFsIiwiV2lkZ2V0TWVzc2FnaW5nU3RvcmUiLCJzdG9yZU1lc3NhZ2luZyIsIkFjdGl2ZVdpZGdldFN0b3JlIiwic2V0Um9vbUlkIiwiRWxlbWVudFdpZGdldEFjdGlvbnMiLCJWaWV3Um9vbSIsInRhcmdldFJvb21JZCIsInJvb21faWQiLCJoYXNDYXBhYmlsaXR5IiwiRWxlbWVudFdpZGdldENhcGFiaWxpdGllcyIsIkNhbkNoYW5nZVZpZXdlZFJvb20iLCJkZWZhdWx0RGlzcGF0Y2hlciIsImRpc3BhdGNoIiwiYWN0aW9uIiwib25FdmVudCIsIm9uRXZlbnREZWNyeXB0ZWQiLCJVcGRhdGVBbHdheXNPblNjcmVlbiIsIk1hdHJpeENhcGFiaWxpdGllcyIsIkFsd2F5c09uU2NyZWVuIiwiQ291bnRseUFuYWx5dGljcyIsInRyYWNrSm9pbkNhbGwiLCJzZXRXaWRnZXRQZXJzaXN0ZW5jZSIsInZhbHVlIiwiU2VuZFN0aWNrZXIiLCJTdGlja2VyU2VuZGluZyIsIlNUSUNLRVJQSUNLRVIiLCJPcGVuSW50ZWdyYXRpb25NYW5hZ2VyIiwiaW50ZWdUeXBlIiwiaW50ZWdJZCIsIkludGVncmF0aW9uTWFuYWdlcnMiLCJzaGFyZWRJbnN0YW5jZSIsIm9wZW5BbGwiLCJnZXRSb29tIiwiZ2V0UHJpbWFyeU1hbmFnZXIiLCJvcGVuIiwicHJlcGFyZSIsImV4aXN0aW5nTWVzc2FnaW5nIiwiZ2V0TWVzc2FnaW5nIiwiaXNTY2FsYXJVcmwiLCJtYW5hZ2VycyIsImhhc01hbmFnZXIiLCJkZWZhdWx0TWFuYWdlciIsImFwaVVybCIsInNjYWxhciIsImdldFNjYWxhckNsaWVudCIsImdldFNjYWxhclRva2VuIiwiZSIsImNvbnNvbGUiLCJzdG9wIiwiZm9yY2VEZXN0cm95IiwiZ2V0UGVyc2lzdGVudFdpZGdldElkIiwibG9nIiwic3RvcE1lc3NhZ2luZyIsImRlbFJvb21JZCIsIm9mZiIsInJhdyIsImV2ZW50IiwiY2F0Y2giXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7O0FBaUJBOztBQWlCQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFFQTs7QUFDQTs7Ozs7O0FBZ0JBO0FBQ08sTUFBTUEsYUFBTixTQUE0QkMsdUJBQTVCLENBQW1DO0FBQ3RDQyxFQUFBQSxXQUFXLENBQVNDO0FBQVQ7QUFBQSxJQUFpQztBQUN4QyxVQUFNQSxhQUFOO0FBRHdDLFNBQXhCQTtBQUF3QjtBQUFBLE1BQXhCQTtB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QUFMLENBQWVXLFNBQWYsQ0FBeUJnSCxHQUF6QixFQUE4QkUsS0FBOUIsQ0FBb0NYLENBQUMsSUFBSTtBQUNyQ0MsTUFBQUEsT0FBTyxDQUFDaEgsS0FBUixDQUFjLGlDQUFkLEVBQWlEK0csQ0FBakQ7QUFDSCxLQUZEO0FBR0g7O0FBeFIyQyIsInNvdXJjZXNDb250ZW50IjpbIi8qXG4gKiBDb3B5cmlnaHQgMjAyMCwgMjAyMSBUaGUgTWF0cml4Lm9yZyBGb3VuZGF0aW9uIEMuSS5DLlxuICpcbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4gKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4gKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbiAqXG4gKiAgICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKi9cblxuaW1wb3J0IHsgUm9vbSB9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9tb2RlbHMvcm9vbVwiO1xuaW1wb3J0IHtcbiAgICBDbGllbnRXaWRnZXRBcGksXG4gICAgSVN0aWNrZXJBY3Rpb25SZXF1ZXN0LFxuICAgIElTdGlja3lBY3Rpb25SZXF1ZXN0LFxuICAgIElUZW1wbGF0ZVBhcmFtcyxcbiAgICBJV2lkZ2V0LFxuICAgIElXaWRnZXRBcGlSZXF1ZXN0LFxuICAgIElXaWRnZXRBcGlSZXF1ZXN0RW1wdHlEYXRhLFxuICAgIElXaWRnZXREYXRhLFxuICAgIE1hdHJpeENhcGFiaWxpdGllcyxcbiAgICBydW5UZW1wbGF0ZSxcbiAgICBXaWRnZXQsXG4gICAgV2lkZ2V0QXBpRnJvbVdpZGdldEFjdGlvbixcbiAgICBJTW9kYWxXaWRnZXRPcGVuUmVxdWVzdCxcbiAgICBJV2lkZ2V0QXBpRXJyb3JSZXNwb25zZURhdGEsXG4gICAgV2lkZ2V0S2luZCxcbn0gZnJvbSBcIm1hdHJpeC13aWRnZXQtYXBpXCI7XG5pbXBvcnQgeyBTdG9wR2FwV2lkZ2V0RHJpdmVyIH0gZnJvbSBcIi4vU3RvcEdhcFdpZGdldERyaXZlclwiO1xuaW1wb3J0IHsgRXZlbnRFbWl0dGVyIH0gZnJvbSBcImV2ZW50c1wiO1xuaW1wb3J0IHsgV2lkZ2V0TWVzc2FnaW5nU3RvcmUgfSBmcm9tIFwiLi9XaWRnZXRNZXNzYWdpbmdTdG9yZVwiO1xuaW1wb3J0IFJvb21WaWV3U3RvcmUgZnJvbSBcIi4uL1Jvb21WaWV3U3RvcmVcIjtcbmltcG9ydCB7IE1hdHJpeENsaWVudFBlZyB9IGZyb20gXCIuLi8uLi9NYXRyaXhDbGllbnRQZWdcIjtcbmltcG9ydCB7IE93blByb2ZpbGVTdG9yZSB9IGZyb20gXCIuLi9Pd25Qcm9maWxlU3RvcmVcIjtcbmltcG9ydCBXaWRnZXRVdGlscyBmcm9tICcuLi8uLi91dGlscy9XaWRnZXRVdGlscyc7XG5pbXBvcnQgeyBJbnRlZ3JhdGlvbk1hbmFnZXJzIH0gZnJvbSBcIi4uLy4uL2ludGVncmF0aW9ucy9JbnRlZ3JhdGlvbk1hbmFnZXJzXCI7XG5pbXBvcnQgU2V0dGluZ3NTdG9yZSBmcm9tIFwiLi4vLi4vc2V0dGluZ3MvU2V0dGluZ3NTdG9yZVwiO1xuaW1wb3J0IHsgV2lkZ2V0VHlwZSB9IGZyb20gXCIuLi8uLi93aWRnZXRzL1dpZGdldFR5cGVcIjtcbmltcG9ydCBBY3RpdmVXaWRnZXRTdG9yZSBmcm9tIFwiLi4vQWN0aXZlV2lkZ2V0U3RvcmVcIjtcbmltcG9ydCB7IG9iamVjdFNoYWxsb3dDbG9uZSB9IGZyb20gXCIuLi8uLi91dGlscy9vYmplY3RzXCI7XG5pbXBvcnQgZGVmYXVsdERpc3BhdGNoZXIgZnJvbSBcIi4uLy4uL2Rpc3BhdGNoZXIvZGlzcGF0Y2hlclwiO1xuaW1wb3J0IHsgRWxlbWVudFdpZGdldEFjdGlvbnMsIElWaWV3Um9vbUFwaVJlcXVlc3QgfSBmcm9tIFwiLi9FbGVtZW50V2lkZ2V0QWN0aW9uc1wiO1xuaW1wb3J0IHtNb2RhbFdpZGdldFN0b3JlfSBmcm9tIFwiLi4vTW9kYWxXaWRnZXRTdG9yZVwiO1xuaW1wb3J0IFRoZW1lV2F0Y2hlciBmcm9tIFwiLi4vLi4vc2V0dGluZ3Mvd2F0Y2hlcnMvVGhlbWVXYXRjaGVyXCI7XG5pbXBvcnQge2dldEN1c3RvbVRoZW1lfSBmcm9tIFwiLi4vLi4vdGhlbWVcIjtcbmltcG9ydCBDb3VudGx5QW5hbHl0aWNzIGZyb20gXCIuLi8uLi9Db3VudGx5QW5hbHl0aWNzXCI7XG5pbXBvcnQgeyBFbGVtZW50V2lkZ2V0Q2FwYWJpbGl0aWVzIH0gZnJvbSBcIi4vRWxlbWVudFdpZGdldENhcGFiaWxpdGllc1wiO1xuaW1wb3J0IHsgTWF0cml4RXZlbnQgfSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvbW9kZWxzL2V2ZW50XCI7XG5pbXBvcnQgeyBFTEVNRU5UX0NMSUVOVF9JRCB9IGZyb20gXCIuLi8uLi9pZGVudGlmaWVyc1wiO1xuaW1wb3J0IHsgZ2V0VXNlckxhbmd1YWdlIH0gZnJvbSBcIi4uLy4uL2xhbmd1YWdlSGFuZGxlclwiO1xuXG4vLyBUT0RPOiBEZXN0cm95IGFsbCBvZiB0aGlzIGNvZGVcblxuaW50ZXJmYWNlIElBcHBUaWxlUHJvcHMge1xuICAgIC8vIE5vdGU6IHRoZXNlIGFyZSBvbmx5IHRoZSBwcm9wcyB3ZSBjYXJlIGFib3V0XG5cbiAgICBhcHA6IElXaWRnZXQ7XG4gICAgcm9vbTogUm9vbTtcbiAgICB1c2VySWQ6IHN0cmluZztcbiAgICBjcmVhdG9yVXNlcklkOiBzdHJpbmc7XG4gICAgd2FpdEZvcklmcmFtZUxvYWQ6IGJvb2xlYW47XG4gICAgd2hpdGVsaXN0Q2FwYWJpbGl0aWVzOiBzdHJpbmdbXTtcbiAgICB1c2VyV2lkZ2V0OiBib29sZWFuO1xufVxuXG4vLyBUT0RPOiBEb24ndCB1c2UgdGhpcyBiZWNhdXNlIGl0J3Mgd3JvbmdcbmV4cG9ydCBjbGFzcyBFbGVtZW50V2lkZ2V0IGV4dGVuZHMgV2lkZ2V0IHtcbiAgICBjb25zdHJ1Y3Rvcihwcml2YXRlIHJhd0RlZmluaXRpb246IElXaWRnZXQpIHtcbiAgICAgICAgc3VwZXIocmF3RGVmaW5pdGlvbik7XG4gICAgfVxuXG4gICAgcHVibGljIGdldCB0ZW1wbGF0ZVVybCgpOiBzdHJpbmcge1xuICAgICAgICBpZiAoV2lkZ2V0VHlwZS5KSVRTSS5tYXRjaGVzKHRoaXMudHlwZSkpIHtcbiAgICAgICAgICAgIHJldHVybiBXaWRnZXRVdGlscy5nZXRMb2NhbEppdHNpV3JhcHBlclVybCh7XG4gICAgICAgICAgICAgICAgZm9yTG9jYWxSZW5kZXI6IHRydWUsXG4gICAgICAgICAgICAgICAgYXV0aDogc3VwZXIucmF3RGF0YT8uYXV0aCBhcyBzdHJpbmcsIC8vIHRoaXMucmF3RGF0YSBjYW4gY2FsbCB0ZW1wbGF0ZVVybCwgZG8gdGhpcyB0byBwcmV2ZW50IGxvb3BpbmdcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBzdXBlci50ZW1wbGF0ZVVybDtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0IHBvcG91dFRlbXBsYXRlVXJsKCk6IHN0cmluZyB7XG4gICAgICAgIGlmIChXaWRnZXRUeXBlLkpJVFNJLm1hdGNoZXModGhpcy50eXBlKSkge1xuICAgICAgICAgICAgcmV0dXJuIFdpZGdldFV0aWxzLmdldExvY2FsSml0c2lXcmFwcGVyVXJsKHtcbiAgICAgICAgICAgICAgICBmb3JMb2NhbFJlbmRlcjogZmFsc2UsIC8vIFRoZSBvbmx5IGltcG9ydGFudCBkaWZmZXJlbmNlIGJldHdlZW4gdGhpcyBhbmQgdGVtcGxhdGVVcmwoKVxuICAgICAgICAgICAgICAgIGF1dGg6IHN1cGVyLnJhd0RhdGE/LmF1dGggYXMgc3RyaW5nLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXMudGVtcGxhdGVVcmw7IC8vIHVzZSB0aGlzIGluc3RlYWQgb2Ygc3VwZXIgdG8gZW5zdXJlIHdlIGdldCBhcHByb3ByaWF0ZSB0ZW1wbGF0aW5nXG4gICAgfVxuXG4gICAgcHVibGljIGdldCByYXdEYXRhKCk6IElXaWRnZXREYXRhIHtcbiAgICAgICAgbGV0IGNvbmZlcmVuY2VJZCA9IHN1cGVyLnJhd0RhdGFbJ2NvbmZlcmVuY2VJZCddO1xuICAgICAgICBpZiAoY29uZmVyZW5jZUlkID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIC8vIHdlJ2xsIG5lZWQgdG8gcGFyc2UgdGhlIGNvbmZlcmVuY2UgSUQgb3V0IG9mIHRoZSBVUkwgZm9yIHYxIEppdHNpIHdpZGdldHNcbiAgICAgICAgICAgIGNvbnN0IHBhcnNlZFVybCA9IG5ldyBVUkwoc3VwZXIudGVtcGxhdGVVcmwpOyAvLyB1c2Ugc3VwZXIgdG8gZ2V0IHRoZSByYXcgd2lkZ2V0IFVSTFxuICAgICAgICAgICAgY29uZmVyZW5jZUlkID0gcGFyc2VkVXJsLnNlYXJjaFBhcmFtcy5nZXQoXCJjb25mSWRcIik7XG4gICAgICAgIH1cbiAgICAgICAgbGV0IGRvbWFpbiA9IHN1cGVyLnJhd0RhdGFbJ2RvbWFpbiddO1xuICAgICAgICBpZiAoZG9tYWluID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIC8vIHYxIHdpZGdldHMgZGVmYXVsdCB0byBqaXRzaS5yaW90LmltIHJlZ2FyZGxlc3Mgb2YgdXNlciBzZXR0aW5nc1xuICAgICAgICAgICAgZG9tYWluID0gXCJqaXRzaS5yaW90LmltXCI7XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgdGhlbWUgPSBuZXcgVGhlbWVXYXRjaGVyKCkuZ2V0RWZmZWN0aXZlVGhlbWUoKTtcbiAgICAgICAgaWYgKHRoZW1lLnN0YXJ0c1dpdGgoXCJjdXN0b20tXCIpKSB7XG4gICAgICAgICAgICBjb25zdCBjdXN0b21UaGVtZSA9IGdldEN1c3RvbVRoZW1lKHRoZW1lLnN1YnN0cig3KSk7XG4gICAgICAgICAgICAvLyBKaXRzaSBvbmx5IHVuZGVyc3RhbmRzIGxpZ2h0L2RhcmtcbiAgICAgICAgICAgIHRoZW1lID0gY3VzdG9tVGhlbWUuaXNfZGFyayA/IFwiZGFya1wiIDogXCJsaWdodFwiO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gb25seSBhbGxvdyBsaWdodC9kYXJrIHRocm91Z2gsIGRlZmF1bHRpbmcgdG8gZGFyayBhcyB0aGF0IHdhcyBwcmV2aW91c2x5IHRoZSBvbmx5IHN0YXRlXG4gICAgICAgIC8vIGFjY291bnRzIGZvciBsZWdhY3ktbGlnaHQvbGVnYWN5LWRhcmsgdGhlbWVzIHRvb1xuICAgICAgICBpZiAodGhlbWUuaW5jbHVkZXMoXCJsaWdodFwiKSkge1xuICAgICAgICAgICAgdGhlbWUgPSBcImxpZ2h0XCI7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGVtZSA9IFwiZGFya1wiO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIC4uLnN1cGVyLnJhd0RhdGEsXG4gICAgICAgICAgICB0aGVtZSxcbiAgICAgICAgICAgIGNvbmZlcmVuY2VJZCxcbiAgICAgICAgICAgIGRvbWFpbixcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0Q29tcGxldGVVcmwocGFyYW1zOiBJVGVtcGxhdGVQYXJhbXMsIGFzUG9wb3V0PWZhbHNlKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIHJ1blRlbXBsYXRlKGFzUG9wb3V0ID8gdGhpcy5wb3BvdXRUZW1wbGF0ZVVybCA6IHRoaXMudGVtcGxhdGVVcmwsIHtcbiAgICAgICAgICAgIC4uLnRoaXMucmF3RGVmaW5pdGlvbixcbiAgICAgICAgICAgIGRhdGE6IHRoaXMucmF3RGF0YSxcbiAgICAgICAgfSwgcGFyYW1zKTtcbiAgICB9XG59XG5cbmV4cG9ydCBjbGFzcyBTdG9wR2FwV2lkZ2V0IGV4dGVuZHMgRXZlbnRFbWl0dGVyIHtcbiAgICBwcml2YXRlIG1lc3NhZ2luZzogQ2xpZW50V2lkZ2V0QXBpO1xuICAgIHByaXZhdGUgbW9ja1dpZGdldDogRWxlbWVudFdpZGdldDtcbiAgICBwcml2YXRlIHNjYWxhclRva2VuOiBzdHJpbmc7XG4gICAgcHJpdmF0ZSByb29tSWQ/OiBzdHJpbmc7XG4gICAgcHJpdmF0ZSBraW5kOiBXaWRnZXRLaW5kO1xuXG4gICAgY29uc3RydWN0b3IocHJpdmF0ZSBhcHBUaWxlUHJvcHM6IElBcHBUaWxlUHJvcHMpIHtcbiAgICAgICAgc3VwZXIoKTtcbiAgICAgICAgbGV0IGFwcCA9IGFwcFRpbGVQcm9wcy5hcHA7XG5cbiAgICAgICAgLy8gQmFja3dhcmRzIGNvbXBhdGliaWxpdHk6IG5vdCBhbGwgb2xkIHdpZGdldHMgaGF2ZSBhIGNyZWF0b3JVc2VySWRcbiAgICAgICAgaWYgKCFhcHAuY3JlYXRvclVzZXJJZCkge1xuICAgICAgICAgICAgYXBwID0gb2JqZWN0U2hhbGxvd0Nsb25lKGFwcCk7IC8vIGNsb25lIHRvIHByZXZlbnQgYWNjaWRlbnRhbCBtdXRhdGlvblxuICAgICAgICAgICAgYXBwLmNyZWF0b3JVc2VySWQgPSBNYXRyaXhDbGllbnRQZWcuZ2V0KCkuZ2V0VXNlcklkKCk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLm1vY2tXaWRnZXQgPSBuZXcgRWxlbWVudFdpZGdldChhcHApO1xuICAgICAgICB0aGlzLnJvb21JZCA9IGFwcFRpbGVQcm9wcy5yb29tPy5yb29tSWQ7XG4gICAgICAgIHRoaXMua2luZCA9IGFwcFRpbGVQcm9wcy51c2VyV2lkZ2V0ID8gV2lkZ2V0S2luZC5BY2NvdW50IDogV2lkZ2V0S2luZC5Sb29tOyAvLyBwcm9iYWJseVxuICAgIH1cblxuICAgIHByaXZhdGUgZ2V0IGV2ZW50TGlzdGVuZXJSb29tSWQoKTogc3RyaW5nIHtcbiAgICAgICAgLy8gV2hlbiB3aWRnZXRzIGFyZSBsaXN0ZW5pbmcgdG8gZXZlbnRzLCB3ZSBuZWVkIHRvIG1ha2Ugc3VyZSB0aGV5J3JlIG9ubHlcbiAgICAgICAgLy8gcmVjZWl2aW5nIGV2ZW50cyBmb3IgdGhlIHJpZ2h0IHJvb20uIEluIHBhcnRpY3VsYXIsIHJvb20gd2lkZ2V0cyBnZXQgbG9ja2VkXG4gICAgICAgIC8vIHRvIHRoZSByb29tIHRoZXkgd2VyZSBhZGRlZCBpbiB3aGlsZSBhY2NvdW50IHdpZGdldHMgbGlzdGVuIHRvIHRoZSBjdXJyZW50bHlcbiAgICAgICAgLy8gYWN0aXZlIHJvb20uXG5cbiAgICAgICAgaWYgKHRoaXMucm9vbUlkKSByZXR1cm4gdGhpcy5yb29tSWQ7XG5cbiAgICAgICAgcmV0dXJuIFJvb21WaWV3U3RvcmUuZ2V0Um9vbUlkKCk7XG4gICAgfVxuXG4gICAgcHVibGljIGdldCB3aWRnZXRBcGkoKTogQ2xpZW50V2lkZ2V0QXBpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMubWVzc2FnaW5nO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFRoZSBVUkwgdG8gdXNlIGluIHRoZSBpZnJhbWVcbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0IGVtYmVkVXJsKCk6IHN0cmluZyB7XG4gICAgICAgIHJldHVybiB0aGlzLnJ1blVybFRlbXBsYXRlKHthc1BvcG91dDogZmFsc2V9KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBUaGUgVVJMIHRvIHVzZSBpbiB0aGUgcG9wb3V0XG4gICAgICovXG4gICAgcHVibGljIGdldCBwb3BvdXRVcmwoKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucnVuVXJsVGVtcGxhdGUoe2FzUG9wb3V0OiB0cnVlfSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBydW5VcmxUZW1wbGF0ZShvcHRzID0ge2FzUG9wb3V0OiBmYWxzZX0pOiBzdHJpbmcge1xuICAgICAgICBjb25zdCB0ZW1wbGF0ZWQgPSB0aGlzLm1vY2tXaWRnZXQuZ2V0Q29tcGxldGVVcmwoe1xuICAgICAgICAgICAgd2lkZ2V0Um9vbUlkOiB0aGlzLnJvb21JZCxcbiAgICAgICAgICAgIGN1cnJlbnRVc2VySWQ6IE1hdHJpeENsaWVudFBlZy5nZXQoKS5nZXRVc2VySWQoKSxcbiAgICAgICAgICAgIHVzZXJEaXNwbGF5TmFtZTogT3duUHJvZmlsZVN0b3JlLmluc3RhbmNlLmRpc3BsYXlOYW1lLFxuICAgICAgICAgICAgdXNlckh0dHBBdmF0YXJVcmw6IE93blByb2ZpbGVTdG9yZS5pbnN0YW5jZS5nZXRIdHRwQXZhdGFyVXJsKCksXG4gICAgICAgICAgICBjbGllbnRJZDogRUxFTUVOVF9DTElFTlRfSUQsXG4gICAgICAgICAgICBjbGllbnRUaGVtZTogU2V0dGluZ3NTdG9yZS5nZXRWYWx1ZShcInRoZW1lXCIpLFxuICAgICAgICAgICAgY2xpZW50TGFuZ3VhZ2U6IGdldFVzZXJMYW5ndWFnZSgpLFxuICAgICAgICB9LCBvcHRzPy5hc1BvcG91dCk7XG5cbiAgICAgICAgY29uc3QgcGFyc2VkID0gbmV3IFVSTCh0ZW1wbGF0ZWQpO1xuXG4gICAgICAgIC8vIEFkZCBpbiBzb21lIGxlZ2FjeSBzdXBwb3J0IHNwcmlua2xlcyAoZm9yIG5vbi1wb3BvdXQgd2lkZ2V0cylcbiAgICAgICAgLy8gVE9ETzogUmVwbGFjZSB0aGVzZSB3aXRoIHByb3BlciB3aWRnZXQgcGFyYW1zXG4gICAgICAgIC8vIFNlZSBodHRwczovL2dpdGh1Yi5jb20vbWF0cml4LW9yZy9tYXRyaXgtZG9jL3B1bGwvMTk1OC9maWxlcyNyNDA1NzE0ODMzXG4gICAgICAgIGlmICghb3B0cz8uYXNQb3BvdXQpIHtcbiAgICAgICAgICAgIHBhcnNlZC5zZWFyY2hQYXJhbXMuc2V0KCd3aWRnZXRJZCcsIHRoaXMubW9ja1dpZGdldC5pZCk7XG4gICAgICAgICAgICBwYXJzZWQuc2VhcmNoUGFyYW1zLnNldCgncGFyZW50VXJsJywgd2luZG93LmxvY2F0aW9uLmhyZWYuc3BsaXQoJyMnLCAyKVswXSk7XG5cbiAgICAgICAgICAgIC8vIEdpdmUgdGhlIHdpZGdldCBhIHNjYWxhciB0b2tlbiBpZiB3ZSdyZSBzdXBwb3NlZCB0byAobW9yZSBsZWdhY3kpXG4gICAgICAgICAgICAvLyBUT0RPOiBTdG9wIGRvaW5nIHRoaXNcbiAgICAgICAgICAgIGlmICh0aGlzLnNjYWxhclRva2VuKSB7XG4gICAgICAgICAgICAgICAgcGFyc2VkLnNlYXJjaFBhcmFtcy5zZXQoJ3NjYWxhcl90b2tlbicsIHRoaXMuc2NhbGFyVG9rZW4pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gUmVwbGFjZSB0aGUgZW5jb2RlZCBkb2xsYXIgc2lnbnMgYmFjayB0byBkb2xsYXIgc2lnbnMuIFRoZXkgaGF2ZSBubyBzcGVjaWFsIG1lYW5pbmdcbiAgICAgICAgLy8gaW4gSFRUUCwgYnV0IFVSTCBwYXJzZXJzIGVuY29kZSB0aGVtIGFueXdheXMuXG4gICAgICAgIHJldHVybiBwYXJzZWQudG9TdHJpbmcoKS5yZXBsYWNlKC8lMjQvZywgJyQnKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0IGlzTWFuYWdlZEJ5TWFuYWdlcigpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuICEhdGhpcy5zY2FsYXJUb2tlbjtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0IHN0YXJ0ZWQoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiAhIXRoaXMubWVzc2FnaW5nO1xuICAgIH1cblxuICAgIHByaXZhdGUgZ2V0IHdpZGdldElkKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5tZXNzYWdpbmcud2lkZ2V0LmlkO1xuICAgIH1cblxuICAgIHByaXZhdGUgb25PcGVuTW9kYWwgPSBhc3luYyAoZXY6IEN1c3RvbUV2ZW50PElNb2RhbFdpZGdldE9wZW5SZXF1ZXN0PikgPT4ge1xuICAgICAgICBldi5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICBpZiAoTW9kYWxXaWRnZXRTdG9yZS5pbnN0YW5jZS5jYW5PcGVuTW9kYWxXaWRnZXQoKSkge1xuICAgICAgICAgICAgTW9kYWxXaWRnZXRTdG9yZS5pbnN0YW5jZS5vcGVuTW9kYWxXaWRnZXQoZXYuZGV0YWlsLmRhdGEsIHRoaXMubW9ja1dpZGdldCk7XG4gICAgICAgICAgICB0aGlzLm1lc3NhZ2luZy50cmFuc3BvcnQucmVwbHkoZXYuZGV0YWlsLCB7fSk7IC8vIGFja1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5tZXNzYWdpbmcudHJhbnNwb3J0LnJlcGx5KGV2LmRldGFpbCwge1xuICAgICAgICAgICAgICAgIGVycm9yOiB7XG4gICAgICAgICAgICAgICAgICAgIG1lc3NhZ2U6IFwiVW5hYmxlIHRvIG9wZW4gbW9kYWwgYXQgdGhpcyB0aW1lXCIsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH0pXG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgcHVibGljIHN0YXJ0KGlmcmFtZTogSFRNTElGcmFtZUVsZW1lbnQpIHtcbiAgICAgICAgaWYgKHRoaXMuc3RhcnRlZCkgcmV0dXJuO1xuICAgICAgICBjb25zdCBhbGxvd2VkQ2FwYWJpbGl0aWVzID0gdGhpcy5hcHBUaWxlUHJvcHMud2hpdGVsaXN0Q2FwYWJpbGl0aWVzIHx8IFtdO1xuICAgICAgICBjb25zdCBkcml2ZXIgPSBuZXcgU3RvcEdhcFdpZGdldERyaXZlcihhbGxvd2VkQ2FwYWJpbGl0aWVzLCB0aGlzLm1vY2tXaWRnZXQsIHRoaXMua2luZCwgdGhpcy5yb29tSWQpO1xuICAgICAgICB0aGlzLm1lc3NhZ2luZyA9IG5ldyBDbGllbnRXaWRnZXRBcGkodGhpcy5tb2NrV2lkZ2V0LCBpZnJhbWUsIGRyaXZlcik7XG4gICAgICAgIHRoaXMubWVzc2FnaW5nLm9uKFwicHJlcGFyaW5nXCIsICgpID0+IHRoaXMuZW1pdChcInByZXBhcmluZ1wiKSk7XG4gICAgICAgIHRoaXMubWVzc2FnaW5nLm9uKFwicmVhZHlcIiwgKCkgPT4gdGhpcy5lbWl0KFwicmVhZHlcIikpO1xuICAgICAgICB0aGlzLm1lc3NhZ2luZy5vbihgYWN0aW9uOiR7V2lkZ2V0QXBpRnJvbVdpZGdldEFjdGlvbi5PcGVuTW9kYWxXaWRnZXR9YCwgdGhpcy5vbk9wZW5Nb2RhbCk7XG4gICAgICAgIFdpZGdldE1lc3NhZ2luZ1N0b3JlLmluc3RhbmNlLnN0b3JlTWVzc2FnaW5nKHRoaXMubW9ja1dpZGdldCwgdGhpcy5tZXNzYWdpbmcpO1xuXG4gICAgICAgIGlmICghdGhpcy5hcHBUaWxlUHJvcHMudXNlcldpZGdldCAmJiB0aGlzLmFwcFRpbGVQcm9wcy5yb29tKSB7XG4gICAgICAgICAgICBBY3RpdmVXaWRnZXRTdG9yZS5zZXRSb29tSWQodGhpcy5tb2NrV2lkZ2V0LmlkLCB0aGlzLmFwcFRpbGVQcm9wcy5yb29tLnJvb21JZCk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBBbHdheXMgYXR0YWNoIGEgaGFuZGxlciBmb3IgVmlld1Jvb20sIGJ1dCBwZXJtaXNzaW9uIGNoZWNrIGl0IGludGVybmFsbHlcbiAgICAgICAgdGhpcy5tZXNzYWdpbmcub24oYGFjdGlvbjoke0VsZW1lbnRXaWRnZXRBY3Rpb25zLlZpZXdSb29tfWAsIChldjogQ3VzdG9tRXZlbnQ8SVZpZXdSb29tQXBpUmVxdWVzdD4pID0+IHtcbiAgICAgICAgICAgIGV2LnByZXZlbnREZWZhdWx0KCk7IC8vIHN0b3AgdGhlIHdpZGdldCBBUEkgZnJvbSBhdXRvLXJlamVjdGluZyB0aGlzXG5cbiAgICAgICAgICAgIC8vIENoZWNrIHVwIGZyb250IGlmIHRoaXMgaXMgZXZlbiBhIHZhbGlkIHJlcXVlc3RcbiAgICAgICAgICAgIGNvbnN0IHRhcmdldFJvb21JZCA9IChldi5kZXRhaWwuZGF0YSB8fCB7fSkucm9vbV9pZDtcbiAgICAgICAgICAgIGlmICghdGFyZ2V0Um9vbUlkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMubWVzc2FnaW5nLnRyYW5zcG9ydC5yZXBseShldi5kZXRhaWwsIDxJV2lkZ2V0QXBpRXJyb3JSZXNwb25zZURhdGE+e1xuICAgICAgICAgICAgICAgICAgICBlcnJvcjoge21lc3NhZ2U6IFwiUm9vbSBJRCBub3Qgc3VwcGxpZWQuXCJ9LFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBDaGVjayB0aGUgd2lkZ2V0J3MgcGVybWlzc2lvblxuICAgICAgICAgICAgaWYgKCF0aGlzLm1lc3NhZ2luZy5oYXNDYXBhYmlsaXR5KEVsZW1lbnRXaWRnZXRDYXBhYmlsaXRpZXMuQ2FuQ2hhbmdlVmlld2VkUm9vbSkpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5tZXNzYWdpbmcudHJhbnNwb3J0LnJlcGx5KGV2LmRldGFpbCwgPElXaWRnZXRBcGlFcnJvclJlc3BvbnNlRGF0YT57XG4gICAgICAgICAgICAgICAgICAgIGVycm9yOiB7bWVzc2FnZTogXCJUaGlzIHdpZGdldCBkb2VzIG5vdCBoYXZlIHBlcm1pc3Npb24gZm9yIHRoaXMgYWN0aW9uIChkZW5pZWQpLlwifSxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gYXQgdGhpcyBwb2ludCB3ZSBjYW4gY2hhbmdlIHJvb21zLCBzbyBkbyB0aGF0XG4gICAgICAgICAgICBkZWZhdWx0RGlzcGF0Y2hlci5kaXNwYXRjaCh7XG4gICAgICAgICAgICAgICAgYWN0aW9uOiAndmlld19yb29tJyxcbiAgICAgICAgICAgICAgICByb29tX2lkOiB0YXJnZXRSb29tSWQsXG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgLy8gYWNrbm93bGVkZ2Ugc28gdGhlIHdpZGdldCBkb2Vzbid0IGZyZWFrIG91dFxuICAgICAgICAgICAgdGhpcy5tZXNzYWdpbmcudHJhbnNwb3J0LnJlcGx5KGV2LmRldGFpbCwgPElXaWRnZXRBcGlSZXF1ZXN0RW1wdHlEYXRhPnt9KTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gQXR0YWNoIGxpc3RlbmVycyBmb3IgZmVlZGluZyBldmVudHMgLSB0aGUgdW5kZXJseWluZyB3aWRnZXQgY2xhc3NlcyBoYW5kbGUgcGVybWlzc2lvbnMgZm9yIHVzXG4gICAgICAgIE1hdHJpeENsaWVudFBlZy5nZXQoKS5vbignZXZlbnQnLCB0aGlzLm9uRXZlbnQpO1xuICAgICAgICBNYXRyaXhDbGllbnRQZWcuZ2V0KCkub24oJ0V2ZW50LmRlY3J5cHRlZCcsIHRoaXMub25FdmVudERlY3J5cHRlZCk7XG5cbiAgICAgICAgdGhpcy5tZXNzYWdpbmcub24oYGFjdGlvbjoke1dpZGdldEFwaUZyb21XaWRnZXRBY3Rpb24uVXBkYXRlQWx3YXlzT25TY3JlZW59YCxcbiAgICAgICAgICAgIChldjogQ3VzdG9tRXZlbnQ8SVN0aWNreUFjdGlvblJlcXVlc3Q+KSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMubWVzc2FnaW5nLmhhc0NhcGFiaWxpdHkoTWF0cml4Q2FwYWJpbGl0aWVzLkFsd2F5c09uU2NyZWVuKSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoV2lkZ2V0VHlwZS5KSVRTSS5tYXRjaGVzKHRoaXMubW9ja1dpZGdldC50eXBlKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgQ291bnRseUFuYWx5dGljcy5pbnN0YW5jZS50cmFja0pvaW5