UNPKG

matrix-react-sdk

Version:
641 lines (624 loc) 120 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _react = _interopRequireWildcard(require("react")); var _classnames = _interopRequireDefault(require("classnames")); var _matrixWidgetApi = require("matrix-widget-api"); var _matrix = require("matrix-js-sdk/src/matrix"); var _types = require("matrix-js-sdk/src/types"); var _logger = require("matrix-js-sdk/src/logger"); var _WidgetLifecycle = require("@matrix-org/react-sdk-module-api/lib/lifecycles/WidgetLifecycle"); var _overflowHorizontal = _interopRequireDefault(require("@vector-im/compound-design-tokens/assets/web/icons/overflow-horizontal")); var _AccessibleButton = _interopRequireDefault(require("./AccessibleButton")); var _languageHandler = require("../../../languageHandler"); var _AppPermission = _interopRequireDefault(require("./AppPermission")); var _AppWarning = _interopRequireDefault(require("./AppWarning")); var _Spinner = _interopRequireDefault(require("./Spinner")); var _dispatcher = _interopRequireDefault(require("../../../dispatcher/dispatcher")); var _ActiveWidgetStore = _interopRequireDefault(require("../../../stores/ActiveWidgetStore")); var _SettingsStore = _interopRequireDefault(require("../../../settings/SettingsStore")); var _ContextMenu = require("../../structures/ContextMenu"); var _PersistedElement = _interopRequireWildcard(require("./PersistedElement")); var _WidgetType = require("../../../widgets/WidgetType"); var _StopGapWidget = require("../../../stores/widgets/StopGapWidget"); var _WidgetContextMenu = require("../context_menus/WidgetContextMenu"); var _WidgetAvatar = _interopRequireDefault(require("../avatars/WidgetAvatar")); var _LegacyCallHandler = _interopRequireDefault(require("../../../LegacyCallHandler")); var _WidgetStore = require("../../../stores/WidgetStore"); var _minimiseCollapse = require("../../../../res/img/element-icons/minimise-collapse.svg"); var _maximiseExpand = require("../../../../res/img/element-icons/maximise-expand.svg"); var _minusButton = require("../../../../res/img/element-icons/minus-button.svg"); var _externalLink = require("../../../../res/img/feather-customised/widget/external-link.svg"); var _WidgetLayoutStore = require("../../../stores/widgets/WidgetLayoutStore"); var _OwnProfileStore = require("../../../stores/OwnProfileStore"); var _AsyncStore = require("../../../stores/AsyncStore"); var _WidgetUtils = _interopRequireDefault(require("../../../utils/WidgetUtils")); var _MatrixClientContext = _interopRequireDefault(require("../../../contexts/MatrixClientContext")); var _actions = require("../../../dispatcher/actions"); var _ElementWidgetCapabilities = require("../../../stores/widgets/ElementWidgetCapabilities"); var _WidgetMessagingStore = require("../../../stores/widgets/WidgetMessagingStore"); var _SDKContext = require("../../../contexts/SDKContext"); var _ModuleRunner = require("../../../modules/ModuleRunner"); var _UrlUtils = require("../../../utils/UrlUtils"); var _RightPanelStore = _interopRequireDefault(require("../../../stores/right-panel/RightPanelStore.ts")); var _RightPanelStorePhases = require("../../../stores/right-panel/RightPanelStorePhases.ts"); 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; } function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } /* Copyright 2024 New Vector Ltd. Copyright 2020-2022 The Matrix.org Foundation C.I.C. Copyright 2019 Michael Telatynski <7t3chguy@gmail.com> Copyright 2018 New Vector Ltd Copyright 2017 Vector Creations Ltd SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only Please see LICENSE files in the repository root for full details. */ class AppTile extends _react.default.Component { constructor(_props, context) { super(_props, context); // Tiles in miniMode are floating, and therefore not docked (0, _defineProperty2.default)(this, "contextMenuButton", /*#__PURE__*/(0, _react.createRef)()); (0, _defineProperty2.default)(this, "iframe", void 0); // ref to the iframe (callback style) (0, _defineProperty2.default)(this, "allowedWidgetsWatchRef", void 0); (0, _defineProperty2.default)(this, "persistKey", void 0); (0, _defineProperty2.default)(this, "sgWidget", void 0); (0, _defineProperty2.default)(this, "dispatcherRef", void 0); (0, _defineProperty2.default)(this, "unmounted", false); (0, _defineProperty2.default)(this, "watchUserReady", () => { if (_OwnProfileStore.OwnProfileStore.instance.isProfileInfoFetched) { return; } _OwnProfileStore.OwnProfileStore.instance.once(_AsyncStore.UPDATE_EVENT, this.onUserReady); }); (0, _defineProperty2.default)(this, "onUserReady", () => { this.setState({ isUserProfileReady: true }); }); // This is a function to make the impact of calling SettingsStore slightly less (0, _defineProperty2.default)(this, "hasPermissionToLoad", props => { if (this.usingLocalWidget()) return true; if (!props.room) return true; // user widgets always have permissions const opts = { approved: undefined }; _ModuleRunner.ModuleRunner.instance.invoke(_WidgetLifecycle.WidgetLifecycle.PreLoadRequest, opts, new _StopGapWidget.ElementWidget(this.props.app)); if (opts.approved) return true; const currentlyAllowedWidgets = _SettingsStore.default.getValue("allowedWidgets", props.room.roomId); const allowed = (0, _WidgetStore.isAppWidget)(props.app) && props.app.eventId !== undefined && (currentlyAllowedWidgets[props.app.eventId] ?? false); return allowed || props.userId === props.creatorUserId; }); (0, _defineProperty2.default)(this, "onMyMembership", (room, membership) => { if ((membership === _types.KnownMembership.Leave || membership === _types.KnownMembership.Ban) && room.roomId === this.props.room?.roomId) { this.onUserLeftRoom(); } }); (0, _defineProperty2.default)(this, "onAllowedWidgetsChange", () => { const hasPermissionToLoad = this.hasPermissionToLoad(this.props); if (this.state.hasPermissionToLoad && !hasPermissionToLoad) { // Force the widget to be non-persistent (able to be deleted/forgotten) _ActiveWidgetStore.default.instance.destroyPersistentWidget(this.props.app.id, (0, _WidgetStore.isAppWidget)(this.props.app) ? this.props.app.roomId : null); _PersistedElement.default.destroyElement(this.persistKey); this.sgWidget?.stopMessaging(); } this.setState({ hasPermissionToLoad }); }); (0, _defineProperty2.default)(this, "iframeRefChange", ref => { this.iframe = ref; if (this.unmounted) return; if (ref) { this.startMessaging(); } else { this.resetWidget(this.props); } }); (0, _defineProperty2.default)(this, "onWidgetReady", () => { this.setState({ loading: false }); }); (0, _defineProperty2.default)(this, "updateRequiresClient", () => { this.setState({ requiresClient: !!this.sgWidget?.widgetApi?.hasCapability(_ElementWidgetCapabilities.ElementWidgetCapabilities.RequiresClient) }); }); (0, _defineProperty2.default)(this, "onAction", payload => { switch (payload.action) { case "m.sticker": if (payload.widgetId === this.props.app.id && this.sgWidget?.widgetApi?.hasCapability(_matrixWidgetApi.MatrixCapabilities.StickerSending)) { _dispatcher.default.dispatch({ action: "post_sticker_message", data: _objectSpread(_objectSpread({}, payload.data), {}, { threadId: this.props.threadId }) }); _dispatcher.default.dispatch({ action: "stickerpicker_close" }); } else { _logger.logger.warn("Ignoring sticker message. Invalid capability"); } break; case _actions.Action.AfterLeaveRoom: if (payload.room_id === this.props.room?.roomId) { // call this before we get it echoed down /sync, so it doesn't hang around as long and look jarring this.onUserLeftRoom(); } break; } }); (0, _defineProperty2.default)(this, "grantWidgetPermission", () => { const roomId = this.props.room?.roomId; const eventId = (0, _WidgetStore.isAppWidget)(this.props.app) ? this.props.app.eventId : undefined; _logger.logger.info("Granting permission for widget to load: " + eventId); const current = _SettingsStore.default.getValue("allowedWidgets", roomId); if (eventId !== undefined) current[eventId] = true; const level = _SettingsStore.default.firstSupportedLevel("allowedWidgets"); _SettingsStore.default.setValue("allowedWidgets", roomId ?? null, level, current).then(() => { this.setState({ hasPermissionToLoad: true }); // Fetch a token for the integration manager, now that we're allowed to this.startWidget(); }).catch(err => { _logger.logger.error(err); // We don't really need to do anything about this - the user will just hit the button again. }); }); // TODO replace with full screen interactions (0, _defineProperty2.default)(this, "onPopoutWidgetClick", () => { // Ensure Jitsi conferences are closed on pop-out, to not confuse the user to join them // twice from the same computer, which Jitsi can have problems with (audio echo/gain-loop). if (_WidgetType.WidgetType.JITSI.matches(this.props.app.type)) { this.reload(); } // Using Object.assign workaround as the following opens in a new window instead of a new tab. // window.open(this._getPopoutUrl(), '_blank', 'noopener=yes'); Object.assign(document.createElement("a"), { target: "_blank", href: this.sgWidget?.popoutUrl, rel: "noreferrer noopener" }).click(); }); (0, _defineProperty2.default)(this, "onToggleMaximisedClick", () => { if (!this.props.room) return; // ignore action - it shouldn't even be visible const targetContainer = _WidgetLayoutStore.WidgetLayoutStore.instance.isInContainer(this.props.room, this.props.app, _WidgetLayoutStore.Container.Center) ? _WidgetLayoutStore.Container.Top : _WidgetLayoutStore.Container.Center; _WidgetLayoutStore.WidgetLayoutStore.instance.moveToContainer(this.props.room, this.props.app, targetContainer); // If the right panel has a timeline, but we're about to show the timeline in the main view, pop the right panel if (targetContainer === _WidgetLayoutStore.Container.Top && _RightPanelStore.default.instance.currentCardForRoom(this.props.room.roomId).phase === _RightPanelStorePhases.RightPanelPhases.Timeline) { _RightPanelStore.default.instance.popCard(this.props.room.roomId); } }); (0, _defineProperty2.default)(this, "onMinimiseClicked", () => { if (!this.props.room) return; // ignore action - it shouldn't even be visible _WidgetLayoutStore.WidgetLayoutStore.instance.moveToContainer(this.props.room, this.props.app, _WidgetLayoutStore.Container.Right); }); (0, _defineProperty2.default)(this, "onContextMenuClick", () => { this.setState({ menuDisplayed: true }); }); (0, _defineProperty2.default)(this, "closeContextMenu", () => { this.setState({ menuDisplayed: false }); }); if (!this.props.miniMode) { _ActiveWidgetStore.default.instance.dockWidget(this.props.app.id, (0, _WidgetStore.isAppWidget)(this.props.app) ? this.props.app.roomId : null); } // The key used for PersistedElement this.persistKey = (0, _PersistedElement.getPersistKey)(_WidgetUtils.default.getWidgetUid(this.props.app)); try { this.sgWidget = new _StopGapWidget.StopGapWidget(this.props); this.setupSgListeners(); } catch (e) { _logger.logger.log("Failed to construct widget", e); this.sgWidget = null; } this.state = this.getNewState(_props); } onUserLeftRoom() { const isActiveWidget = _ActiveWidgetStore.default.instance.getWidgetPersistence(this.props.app.id, (0, _WidgetStore.isAppWidget)(this.props.app) ? this.props.app.roomId : null); if (isActiveWidget) { // We just left the room that the active widget was from. if (this.props.room && _SDKContext.SdkContextClass.instance.roomViewStore.getRoomId() !== this.props.room.roomId) { // If we are not actively looking at the room then destroy this widget entirely. this.endWidgetActions(); } else if (_WidgetType.WidgetType.JITSI.matches(this.props.app.type)) { // If this was a Jitsi then reload to end call. this.reload(); } else { // Otherwise just cancel its persistence. _ActiveWidgetStore.default.instance.destroyPersistentWidget(this.props.app.id, (0, _WidgetStore.isAppWidget)(this.props.app) ? this.props.app.roomId : null); } } } determineInitialRequiresClientState() { try { const mockWidget = new _StopGapWidget.ElementWidget(this.props.app); const widgetApi = _WidgetMessagingStore.WidgetMessagingStore.instance.getMessaging(mockWidget, this.props.room?.roomId); if (widgetApi) { // Load value from existing API to prevent resetting the requiresClient value on layout changes. return widgetApi.hasCapability(_ElementWidgetCapabilities.ElementWidgetCapabilities.RequiresClient); } } catch { // fallback to true } // requiresClient is initially set to true. This avoids the broken state of the popout // button being visible (for an instance) and then disappearing when the widget is loaded. // requiresClient <-> hide the popout button return true; } /** * Set initial component state when the App wUrl (widget URL) is being updated. * Component props *must* be passed (rather than relying on this.props). * @param {Object} newProps The new properties of the component * @return {Object} Updated component state to be set with setState */ getNewState(newProps) { return { initialising: true, // True while we are mangling the widget URL // Don't show loading at all if the widget is ready once the IFrame is loaded (waitForIframeLoad = true). // We only need the loading screen if the widget sends a contentLoaded event (waitForIframeLoad = false). loading: !this.props.waitForIframeLoad && !_PersistedElement.default.isMounted(this.persistKey), // Assume that widget has permission to load if we are the user who // added it to the room, or if explicitly granted by the user hasPermissionToLoad: this.hasPermissionToLoad(newProps), isUserProfileReady: _OwnProfileStore.OwnProfileStore.instance.isProfileInfoFetched, error: null, menuDisplayed: false, requiresClient: this.determineInitialRequiresClientState(), hasContextMenuOptions: (0, _WidgetContextMenu.showContextMenu)(this.context, this.props.room, newProps.app, newProps.userWidget, !newProps.userWidget, newProps.onDeleteClick) }; } isMixedContent() { const parentContentProtocol = window.location.protocol; const u = (0, _UrlUtils.parseUrl)(this.props.app.url); const childContentProtocol = u.protocol; if (parentContentProtocol === "https:" && childContentProtocol !== "https:") { _logger.logger.warn("Refusing to load mixed-content app:", parentContentProtocol, childContentProtocol, window.location, this.props.app.url); return true; } return false; } componentDidMount() { // Only fetch IM token on mount if we're showing and have permission to load if (this.sgWidget && this.state.hasPermissionToLoad) { this.startWidget(); } this.watchUserReady(); if (this.props.room) { this.context.on(_matrix.RoomEvent.MyMembership, this.onMyMembership); } this.allowedWidgetsWatchRef = _SettingsStore.default.watchSetting("allowedWidgets", null, this.onAllowedWidgetsChange); // Widget action listeners this.dispatcherRef = _dispatcher.default.register(this.onAction); } componentWillUnmount() { this.unmounted = true; if (!this.props.miniMode) { _ActiveWidgetStore.default.instance.undockWidget(this.props.app.id, (0, _WidgetStore.isAppWidget)(this.props.app) ? this.props.app.roomId : null); } // Only tear down the widget if no other component is keeping it alive, // because we support moving widgets between containers, in which case // another component will keep it loaded throughout the transition if (!_ActiveWidgetStore.default.instance.isLive(this.props.app.id, (0, _WidgetStore.isAppWidget)(this.props.app) ? this.props.app.roomId : null)) { this.endWidgetActions(); } // Widget action listeners if (this.dispatcherRef) _dispatcher.default.unregister(this.dispatcherRef); if (this.props.room) { this.context.off(_matrix.RoomEvent.MyMembership, this.onMyMembership); } if (this.allowedWidgetsWatchRef) _SettingsStore.default.unwatchSetting(this.allowedWidgetsWatchRef); _OwnProfileStore.OwnProfileStore.instance.removeListener(_AsyncStore.UPDATE_EVENT, this.onUserReady); } setupSgListeners() { this.sgWidget?.on("ready", this.onWidgetReady); this.sgWidget?.on("error:preparing", this.updateRequiresClient); // emits when the capabilities have been set up or changed this.sgWidget?.on("capabilitiesNotified", this.updateRequiresClient); } stopSgListeners() { if (!this.sgWidget) return; this.sgWidget?.off("ready", this.onWidgetReady); this.sgWidget.off("error:preparing", this.updateRequiresClient); this.sgWidget.off("capabilitiesNotified", this.updateRequiresClient); } resetWidget(newProps) { this.sgWidget?.stopMessaging(); this.stopSgListeners(); try { this.sgWidget = new _StopGapWidget.StopGapWidget(newProps); this.setupSgListeners(); this.startWidget(); } catch (e) { _logger.logger.error("Failed to construct widget", e); this.sgWidget = null; } } startWidget() { this.sgWidget?.prepare().then(() => { if (this.unmounted) return; this.setState({ initialising: false }); }); } startMessaging() { try { this.sgWidget?.startMessaging(this.iframe); } catch (e) { _logger.logger.error("Failed to start widget", e); } } componentDidUpdate(prevProps) { if (prevProps.app.url !== this.props.app.url) { this.getNewState(this.props); if (this.state.hasPermissionToLoad) { this.resetWidget(this.props); } } } /** * Ends all widget interaction, such as cancelling calls and disabling webcams. * @private * @returns {Promise<*>} Resolves when the widget is terminated, or timeout passed. */ async endWidgetActions() { // widget migration dev note: async to maintain signature // HACK: This is a really dirty way to ensure that Jitsi cleans up // its hold on the webcam. Without this, the widget holds a media // stream open, even after death. See https://github.com/vector-im/element-web/issues/7351 if (this.iframe) { // In practice we could just do `+= ''` to trick the browser // into thinking the URL changed, however I can foresee this // being optimized out by a browser. Instead, we'll just point // the iframe at a page that is reasonably safe to use in the // event the iframe doesn't wink away. // This is relative to where the Element instance is located. this.iframe.src = "about:blank"; } if (_WidgetType.WidgetType.JITSI.matches(this.props.app.type) && this.props.room) { _LegacyCallHandler.default.instance.hangupCallApp(this.props.room.roomId); } // Delete the widget from the persisted store for good measure. _PersistedElement.default.destroyElement(this.persistKey); _ActiveWidgetStore.default.instance.destroyPersistentWidget(this.props.app.id, (0, _WidgetStore.isAppWidget)(this.props.app) ? this.props.app.roomId : null); this.sgWidget?.stopMessaging({ forceDestroy: true }); } formatAppTileName() { let appTileName = "No name"; if (this.props.app.name && this.props.app.name.trim()) { appTileName = this.props.app.name.trim(); } return appTileName; } /** * Whether we're using a local version of the widget rather than loading the * actual widget URL * @returns {bool} true If using a local version of the widget */ usingLocalWidget() { return _WidgetType.WidgetType.JITSI.matches(this.props.app.type); } getTileTitle() { const name = this.formatAppTileName(); const titleSpacer = /*#__PURE__*/_react.default.createElement("span", null, "\xA0-\xA0"); let title = ""; if (this.props.widgetPageTitle && this.props.widgetPageTitle !== this.formatAppTileName()) { title = this.props.widgetPageTitle; } return /*#__PURE__*/_react.default.createElement("span", null, /*#__PURE__*/_react.default.createElement(_WidgetAvatar.default, { app: this.props.app, size: "20px" }), /*#__PURE__*/_react.default.createElement("h3", null, name), /*#__PURE__*/_react.default.createElement("span", null, title ? titleSpacer : "", title)); } reload() { this.endWidgetActions().then(() => { // reset messaging this.resetWidget(this.props); this.startMessaging(); if (this.iframe && this.sgWidget) { // Reload iframe this.iframe.src = this.sgWidget.embedUrl; } }); } render() { let appTileBody; // Note that there is advice saying allow-scripts shouldn't be used with allow-same-origin // because that would allow the iframe to programmatically remove the sandbox attribute, but // this would only be for content hosted on the same origin as the element client: anything // hosted on the same origin as the client will get the same access as if you clicked // a link to it. const sandboxFlags = "allow-forms allow-popups allow-popups-to-escape-sandbox " + "allow-same-origin allow-scripts allow-presentation allow-downloads"; // Additional iframe feature permissions // (see - https://sites.google.com/a/chromium.org/dev/Home/chromium-security/deprecating-permissions-in-cross-origin-iframes and https://wicg.github.io/feature-policy/) const iframeFeatures = "microphone; camera; encrypted-media; autoplay; display-capture; clipboard-write; " + "clipboard-read;"; const appTileBodyClass = (0, _classnames.default)({ "mx_AppTileBody": true, "mx_AppTileBody--large": !this.props.miniMode, "mx_AppTileBody--mini": this.props.miniMode, "mx_AppTileBody--loading": this.state.loading, // We don't want mx_AppTileBody (rounded corners) for call widgets "mx_AppTileBody--call": this.props.app.type === _WidgetType.WidgetType.CALL.preferred }); const appTileBodyStyles = {}; if (this.props.pointerEvents) { appTileBodyStyles.pointerEvents = this.props.pointerEvents; } const loadingElement = /*#__PURE__*/_react.default.createElement("div", { className: "mx_AppTileBody_fadeInSpinner" }, /*#__PURE__*/_react.default.createElement(_Spinner.default, { message: (0, _languageHandler._t)("common|loading") })); const widgetTitle = _WidgetUtils.default.getWidgetName(this.props.app); if (this.sgWidget === null) { appTileBody = /*#__PURE__*/_react.default.createElement("div", { className: appTileBodyClass, style: appTileBodyStyles }, /*#__PURE__*/_react.default.createElement(_AppWarning.default, { errorMsg: (0, _languageHandler._t)("widget|error_loading") })); } else if (!this.state.hasPermissionToLoad && this.props.room) { // only possible for room widgets, can assert this.props.room here const isEncrypted = this.context.isRoomEncrypted(this.props.room.roomId); appTileBody = /*#__PURE__*/_react.default.createElement("div", { className: appTileBodyClass, style: appTileBodyStyles }, /*#__PURE__*/_react.default.createElement(_AppPermission.default, { roomId: this.props.room.roomId, creatorUserId: this.props.creatorUserId, url: this.sgWidget.embedUrl, isRoomEncrypted: isEncrypted, onPermissionGranted: this.grantWidgetPermission })); } else if (this.state.initialising || !this.state.isUserProfileReady) { appTileBody = /*#__PURE__*/_react.default.createElement("div", { className: appTileBodyClass, style: appTileBodyStyles }, loadingElement); } else { if (this.isMixedContent()) { appTileBody = /*#__PURE__*/_react.default.createElement("div", { className: appTileBodyClass, style: appTileBodyStyles }, /*#__PURE__*/_react.default.createElement(_AppWarning.default, { errorMsg: (0, _languageHandler._t)("widget|error_mixed_content") })); } else { appTileBody = /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("div", { className: appTileBodyClass, style: appTileBodyStyles }, this.state.loading && loadingElement, /*#__PURE__*/_react.default.createElement("iframe", { title: widgetTitle, allow: iframeFeatures, ref: this.iframeRefChange, src: this.sgWidget.embedUrl, allowFullScreen: true, sandbox: sandboxFlags })), this.props.overlay); if (!this.props.userWidget) { // All room widgets can theoretically be allowed to remain on screen, so we // wrap them all in a PersistedElement from the get-go. If we wait, the iframe // will be re-mounted later, which means the widget has to start over, which is // bad. // Also wrap the PersistedElement in a div to fix the height, otherwise // AppTile's border is in the wrong place // For persisted apps in PiP we want the zIndex to be higher then for other persisted apps (100) // otherwise there are issues that the PiP view is drawn UNDER another widget (Persistent app) when dragged around. const zIndexAboveOtherPersistentElements = 101; appTileBody = /*#__PURE__*/_react.default.createElement("div", { className: "mx_AppTile_persistedWrapper" }, /*#__PURE__*/_react.default.createElement(_PersistedElement.default, { zIndex: this.props.miniMode ? zIndexAboveOtherPersistentElements : 9, persistKey: this.persistKey, moveRef: this.props.movePersistedElement }, appTileBody)); } } } let appTileClasses; if (this.props.miniMode) { appTileClasses = { mx_AppTile_mini: true }; } else if (this.props.fullWidth) { appTileClasses = { mx_AppTileFullWidth: true }; } else { appTileClasses = { mx_AppTile: true }; } appTileClasses = (0, _classnames.default)(appTileClasses); let contextMenu; if (this.state.menuDisplayed) { contextMenu = /*#__PURE__*/_react.default.createElement(_WidgetContextMenu.WidgetContextMenu, (0, _extends2.default)({}, (0, _ContextMenu.aboveLeftOf)(this.contextMenuButton.current.getBoundingClientRect()), { app: this.props.app, onFinished: this.closeContextMenu, showUnpin: !this.props.userWidget, userWidget: this.props.userWidget, onEditClick: this.props.onEditClick, onDeleteClick: this.props.onDeleteClick })); } const layoutButtons = []; if (this.props.showLayoutButtons) { const isMaximised = this.props.room && _WidgetLayoutStore.WidgetLayoutStore.instance.isInContainer(this.props.room, this.props.app, _WidgetLayoutStore.Container.Center); layoutButtons.push( /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, { key: "toggleMaximised", className: "mx_AppTileMenuBar_widgets_button", title: isMaximised ? (0, _languageHandler._t)("widget|unmaximise") : (0, _languageHandler._t)("action|maximise"), onClick: this.onToggleMaximisedClick }, isMaximised ? /*#__PURE__*/_react.default.createElement(_minimiseCollapse.Icon, { className: "mx_Icon mx_Icon_12" }) : /*#__PURE__*/_react.default.createElement(_maximiseExpand.Icon, { className: "mx_Icon mx_Icon_12" }))); layoutButtons.push( /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, { key: "minimise", className: "mx_AppTileMenuBar_widgets_button", title: (0, _languageHandler._t)("action|minimise"), onClick: this.onMinimiseClicked }, /*#__PURE__*/_react.default.createElement(_minusButton.Icon, { className: "mx_Icon mx_Icon_12" }))); } return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("div", { className: appTileClasses, id: this.props.app.id }, this.props.showMenubar && /*#__PURE__*/_react.default.createElement("div", { className: "mx_AppTileMenuBar" }, /*#__PURE__*/_react.default.createElement("span", { className: "mx_AppTileMenuBar_title", style: { pointerEvents: this.props.handleMinimisePointerEvents ? "all" : "none" } }, this.props.showTitle && this.getTileTitle()), /*#__PURE__*/_react.default.createElement("span", { className: "mx_AppTileMenuBar_widgets" }, layoutButtons, this.props.showPopout && !this.state.requiresClient && /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, { className: "mx_AppTileMenuBar_widgets_button", title: (0, _languageHandler._t)("widget|popout"), onClick: this.onPopoutWidgetClick }, /*#__PURE__*/_react.default.createElement(_externalLink.Icon, { className: "mx_Icon mx_Icon_12 mx_Icon--stroke" })), this.state.hasContextMenuOptions && /*#__PURE__*/_react.default.createElement(_ContextMenu.ContextMenuButton, { className: "mx_AppTileMenuBar_widgets_button", label: (0, _languageHandler._t)("common|options"), isExpanded: this.state.menuDisplayed, ref: this.contextMenuButton, onClick: this.onContextMenuClick }, /*#__PURE__*/_react.default.createElement(_overflowHorizontal.default, { className: "mx_Icon mx_Icon_12" })))), appTileBody), contextMenu); } } exports.default = AppTile; (0, _defineProperty2.default)(AppTile, "contextType", _MatrixClientContext.default); (0, _defineProperty2.default)(AppTile, "defaultProps", { waitForIframeLoad: true, showMenubar: true, showTitle: true, showPopout: true, handleMinimisePointerEvents: false, userWidget: false, miniMode: false, threadId: null, showLayoutButtons: true }); //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfcmVhY3QiLCJfaW50ZXJvcFJlcXVpcmVXaWxkY2FyZCIsInJlcXVpcmUiLCJfY2xhc3NuYW1lcyIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJfbWF0cml4V2lkZ2V0QXBpIiwiX21hdHJpeCIsIl90eXBlcyIsIl9sb2dnZXIiLCJfV2lkZ2V0TGlmZWN5Y2xlIiwiX292ZXJmbG93SG9yaXpvbnRhbCIsIl9BY2Nlc3NpYmxlQnV0dG9uIiwiX2xhbmd1YWdlSGFuZGxlciIsIl9BcHBQZXJtaXNzaW9uIiwiX0FwcFdhcm5pbmciLCJfU3Bpbm5lciIsIl9kaXNwYXRjaGVyIiwiX0FjdGl2ZVdpZGdldFN0b3JlIiwiX1NldHRpbmdzU3RvcmUiLCJfQ29udGV4dE1lbnUiLCJfUGVyc2lzdGVkRWxlbWVudCIsIl9XaWRnZXRUeXBlIiwiX1N0b3BHYXBXaWRnZXQiLCJfV2lkZ2V0Q29udGV4dE1lbnUiLCJfV2lkZ2V0QXZhdGFyIiwiX0xlZ2FjeUNhbGxIYW5kbGVyIiwiX1dpZGdldFN0b3JlIiwiX21pbmltaXNlQ29sbGFwc2UiLCJfbWF4aW1pc2VFeHBhbmQiLCJfbWludXNCdXR0b24iLCJfZXh0ZXJuYWxMaW5rIiwiX1dpZGdldExheW91dFN0b3JlIiwiX093blByb2ZpbGVTdG9yZSIsIl9Bc3luY1N0b3JlIiwiX1dpZGdldFV0aWxzIiwiX01hdHJpeENsaWVudENvbnRleHQiLCJfYWN0aW9ucyIsIl9FbGVtZW50V2lkZ2V0Q2FwYWJpbGl0aWVzIiwiX1dpZGdldE1lc3NhZ2luZ1N0b3JlIiwiX1NES0NvbnRleHQiLCJfTW9kdWxlUnVubmVyIiwiX1VybFV0aWxzIiwiX1JpZ2h0UGFuZWxTdG9yZSIsIl9SaWdodFBhbmVsU3RvcmVQaGFzZXMiLCJfZ2V0UmVxdWlyZVdpbGRjYXJkQ2FjaGUiLCJlIiwiV2Vha01hcCIsInIiLCJ0IiwiX19lc01vZHVsZSIsImRlZmF1bHQiLCJoYXMiLCJnZXQiLCJuIiwiX19wcm90b19fIiwiYSIsIk9iamVjdCIsImRlZmluZVByb3BlcnR5IiwiZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yIiwidSIsImhhc093blByb3BlcnR5IiwiY2FsbCIsImkiLCJzZXQiLCJvd25LZXlzIiwia2V5cyIsImdldE93blByb3BlcnR5U3ltYm9scyIsIm8iLCJmaWx0ZXIiLCJlbnVtZXJhYmxlIiwicHVzaCIsImFwcGx5IiwiX29iamVjdFNwcmVhZCIsImFyZ3VtZW50cyIsImxlbmd0aCIsImZvckVhY2giLCJfZGVmaW5lUHJvcGVydHkyIiwiZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9ycyIsImRlZmluZVByb3BlcnRpZXMiLCJBcHBUaWxlIiwiUmVhY3QiLCJDb21wb25lbnQiLCJjb25zdHJ1Y3RvciIsInByb3BzIiwiY29udGV4dCIsImNyZWF0ZVJlZiIsIk93blByb2ZpbGVTdG9yZSIsImluc3RhbmNlIiwiaXNQcm9maWxlSW5mb0ZldGNoZWQiLCJvbmNlIiwiVVBEQVRFX0VWRU5UIiwib25Vc2VyUmVhZHkiLCJzZXRTdGF0ZSIsImlzVXNlclByb2ZpbGVSZWFkeSIsInVzaW5nTG9jYWxXaWRnZXQiLCJyb29tIiwib3B0cyIsImFwcHJvdmVkIiwidW5kZWZpbmVkIiwiTW9kdWxlUnVubmVyIiwiaW52b2tlIiwiV2lkZ2V0TGlmZWN5Y2xlIiwiUHJlTG9hZFJlcXVlc3QiLCJFbGVtZW50V2lkZ2V0IiwiYXBwIiwiY3VycmVudGx5QWxsb3dlZFdpZGdldHMiLCJTZXR0aW5nc1N0b3JlIiwiZ2V0VmFsdWUiLCJyb29tSWQiLCJhbGxvd2VkIiwiaXNBcHBXaWRnZXQiLCJldmVudElkIiwidXNlcklkIiwiY3JlYXRvclVzZXJJZCIsIm1lbWJlcnNoaXAiLCJLbm93bk1lbWJlcnNoaXAiLCJMZWF2ZSIsIkJhbiIsIm9uVXNlckxlZnRSb29tIiwiaGFzUGVybWlzc2lvblRvTG9hZCIsInN0YXRlIiwiQWN0aXZlV2lkZ2V0U3RvcmUiLCJkZXN0cm95UGVyc2lzdGVudFdpZGdldCIsImlkIiwiUGVyc2lzdGVkRWxlbWVudCIsImRlc3Ryb3lFbGVtZW50IiwicGVyc2lzdEtleSIsInNnV2lkZ2V0Iiwic3RvcE1lc3NhZ2luZyIsInJlZiIsImlmcmFtZSIsInVubW91bnRlZCIsInN0YXJ0TWVzc2FnaW5nIiwicmVzZXRXaWRnZXQiLCJsb2FkaW5nIiwicmVxdWlyZXNDbGllbnQiLCJ3aWRnZXRBcGkiLCJoYXNDYXBhYmlsaXR5IiwiRWxlbWVudFdpZGdldENhcGFiaWxpdGllcyIsIlJlcXVpcmVzQ2xpZW50IiwicGF5bG9hZCIsImFjdGlvbiIsIndpZGdldElkIiwiTWF0cml4Q2FwYWJpbGl0aWVzIiwiU3RpY2tlclNlbmRpbmciLCJkaXMiLCJkaXNwYXRjaCIsImRhdGEiLCJ0aHJlYWRJZCIsImxvZ2dlciIsIndhcm4iLCJBY3Rpb24iLCJBZnRlckxlYXZlUm9vbSIsInJvb21faWQiLCJpbmZvIiwiY3VycmVudCIsImxldmVsIiwiZmlyc3RTdXBwb3J0ZWRMZXZlbCIsInNldFZhbHVlIiwidGhlbiIsInN0YXJ0V2lkZ2V0IiwiY2F0Y2giLCJlcnIiLCJlcnJvciIsIldpZGdldFR5cGUiLCJKSVRTSSIsIm1hdGNoZXMiLCJ0eXBlIiwicmVsb2FkIiwiYXNzaWduIiwiZG9jdW1lbnQiLCJjcmVhdGVFbGVtZW50IiwidGFyZ2V0IiwiaHJlZiIsInBvcG91dFVybCIsInJlbCIsImNsaWNrIiwidGFyZ2V0Q29udGFpbmVyIiwiV2lkZ2V0TGF5b3V0U3RvcmUiLCJpc0luQ29udGFpbmVyIiwiQ29udGFpbmVyIiwiQ2VudGVyIiwiVG9wIiwibW92ZVRvQ29udGFpbmVyIiwiUmlnaHRQYW5lbFN0b3JlIiwiY3VycmVudENhcmRGb3JSb29tIiwicGhhc2UiLCJSaWdodFBhbmVsUGhhc2VzIiwiVGltZWxpbmUiLCJwb3BDYXJkIiwiUmlnaHQiLCJtZW51RGlzcGxheWVkIiwibWluaU1vZGUiLCJkb2NrV2lkZ2V0IiwiZ2V0UGVyc2lzdEtleSIsIldpZGdldFV0aWxzIiwiZ2V0V2lkZ2V0VWlkIiwiU3RvcEdhcFdpZGdldCIsInNldHVwU2dMaXN0ZW5lcnMiLCJsb2ciLCJnZXROZXdTdGF0ZSIsImlzQWN0aXZlV2lkZ2V0IiwiZ2V0V2lkZ2V0UGVyc2lzdGVuY2UiLCJTZGtDb250ZXh0Q2xhc3MiLCJyb29tVmlld1N0b3JlIiwiZ2V0Um9vbUlkIiwiZW5kV2lkZ2V0QWN0aW9ucyIsImRldGVybWluZUluaXRpYWxSZXF1aXJlc0NsaWVudFN0YXRlIiwibW9ja1dpZGdldCIsIldpZGdldE1lc3NhZ2luZ1N0b3JlIiwiZ2V0TWVzc2FnaW5nIiwibmV3UHJvcHMiLCJpbml0aWFsaXNpbmciLCJ3YWl0Rm9ySWZyYW1lTG9hZCIsImlzTW91bnRlZCIsImhhc0NvbnRleHRNZW51T3B0aW9ucyIsInNob3dDb250ZXh0TWVudSIsInVzZXJXaWRnZXQiLCJvbkRlbGV0ZUNsaWNrIiwiaXNNaXhlZENvbnRlbnQiLCJwYXJlbnRDb250ZW50UHJvdG9jb2wiLCJ3aW5kb3ciLCJsb2NhdGlvbiIsInByb3RvY29sIiwicGFyc2VVcmwiLCJ1cmwiLCJjaGlsZENvbnRlbnRQcm90b2NvbCIsImNvbXBvbmVudERpZE1vdW50Iiwid2F0Y2hVc2VyUmVhZHkiLCJvbiIsIlJvb21FdmVudCIsIk15TWVtYmVyc2hpcCIsIm9uTXlNZW1iZXJzaGlwIiwiYWxsb3dlZFdpZGdldHNXYXRjaFJlZiIsIndhdGNoU2V0dGluZyIsIm9uQWxsb3dlZFdpZGdldHNDaGFuZ2UiLCJkaXNwYXRjaGVyUmVmIiwicmVnaXN0ZXIiLCJvbkFjdGlvbiIsImNvbXBvbmVudFdpbGxVbm1vdW50IiwidW5kb2NrV2lkZ2V0IiwiaXNMaXZlIiwidW5yZWdpc3RlciIsIm9mZiIsInVud2F0Y2hTZXR0aW5nIiwicmVtb3ZlTGlzdGVuZXIiLCJvbldpZGdldFJlYWR5IiwidXBkYXRlUmVxdWlyZXNDbGllbnQiLCJzdG9wU2dMaXN0ZW5lcnMiLCJwcmVwYXJlIiwiY29tcG9uZW50RGlkVXBkYXRlIiwicHJldlByb3BzIiwic3JjIiwiTGVnYWN5Q2FsbEhhbmRsZXIiLCJoYW5ndXBDYWxsQXBwIiwiZm9yY2VEZXN0cm95IiwiZm9ybWF0QXBwVGlsZU5hbWUiLCJhcHBUaWxlTmFtZSIsIm5hbWUiLCJ0cmltIiwiZ2V0VGlsZVRpdGxlIiwidGl0bGVTcGFjZXIiLCJ0aXRsZSIsIndpZGdldFBhZ2VUaXRsZSIsInNpemUiLCJlbWJlZFVybCIsInJlbmRlciIsImFwcFRpbGVCb2R5Iiwic2FuZGJveEZsYWdzIiwiaWZyYW1lRmVhdHVyZXMiLCJhcHBUaWxlQm9keUNsYXNzIiwiY2xhc3NOYW1lcyIsIkNBTEwiLCJwcmVmZXJyZWQiLCJhcHBUaWxlQm9keVN0eWxlcyIsInBvaW50ZXJFdmVudHMiLCJsb2FkaW5nRWxlbWVudCIsImNsYXNzTmFtZSIsIm1lc3NhZ2UiLCJfdCIsIndpZGdldFRpdGxlIiwiZ2V0V2lkZ2V0TmFtZSIsInN0eWxlIiwiZXJyb3JNc2ciLCJpc0VuY3J5cHRlZCIsImlzUm9vbUVuY3J5cHRlZCIsIm9uUGVybWlzc2lvbkdyYW50ZWQiLCJncmFudFdpZGdldFBlcm1pc3Npb24iLCJGcmFnbWVudCIsImFsbG93IiwiaWZyYW1lUmVmQ2hhbmdlIiwiYWxsb3dGdWxsU2NyZWVuIiwic2FuZGJveCIsIm92ZXJsYXkiLCJ6SW5kZXhBYm92ZU90aGVyUGVyc2lzdGVudEVsZW1lbnRzIiwiekluZGV4IiwibW92ZVJlZiIsIm1vdmVQZXJzaXN0ZWRFbGVtZW50IiwiYXBwVGlsZUNsYXNzZXMiLCJteF9BcHBUaWxlX21pbmkiLCJmdWxsV2lkdGgiLCJteF9BcHBUaWxlRnVsbFdpZHRoIiwibXhfQXBwVGlsZSIsImNvbnRleHRNZW51IiwiV2lkZ2V0Q29udGV4dE1lbnUiLCJfZXh0ZW5kczIiLCJhYm92ZUxlZnRPZiIsImNvbnRleHRNZW51QnV0dG9uIiwiZ2V0Qm91bmRpbmdDbGllbnRSZWN0Iiwib25GaW5pc2hlZCIsImNsb3NlQ29udGV4dE1lbnUiLCJzaG93VW5waW4iLCJvbkVkaXRDbGljayIsImxheW91dEJ1dHRvbnMiLCJzaG93TGF5b3V0QnV0dG9ucyIsImlzTWF4aW1pc2VkIiwia2V5Iiwib25DbGljayIsIm9uVG9nZ2xlTWF4aW1pc2VkQ2xpY2siLCJJY29uIiwib25NaW5pbWlzZUNsaWNrZWQiLCJzaG93TWVudWJhciIsImhhbmRsZU1pbmltaXNlUG9pbnRlckV2ZW50cyIsInNob3dUaXRsZSIsInNob3dQb3BvdXQiLCJvblBvcG91dFdpZGdldENsaWNrIiwiQ29udGV4dE1lbnVCdXR0b24iLCJsYWJlbCIsImlzRXhwYW5kZWQiLCJvbkNvbnRleHRNZW51Q2xpY2siLCJleHBvcnRzIiwiTWF0cml4Q2xpZW50Q29udGV4dCJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9jb21wb25lbnRzL3ZpZXdzL2VsZW1lbnRzL0FwcFRpbGUudHN4Il0sInNvdXJjZXNDb250ZW50IjpbIi8qXG5Db3B5cmlnaHQgMjAyNCBOZXcgVmVjdG9yIEx0ZC5cbkNvcHlyaWdodCAyMDIwLTIwMjIgVGhlIE1hdHJpeC5vcmcgRm91bmRhdGlvbiBDLkkuQy5cbkNvcHlyaWdodCAyMDE5IE1pY2hhZWwgVGVsYXR5bnNraSA8N3QzY2hndXlAZ21haWwuY29tPlxuQ29weXJpZ2h0IDIwMTggTmV3IFZlY3RvciBMdGRcbkNvcHlyaWdodCAyMDE3IFZlY3RvciBDcmVhdGlvbnMgTHRkXG5cblNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBR1BMLTMuMC1vbmx5IE9SIEdQTC0zLjAtb25seVxuUGxlYXNlIHNlZSBMSUNFTlNFIGZpbGVzIGluIHRoZSByZXBvc2l0b3J5IHJvb3QgZm9yIGZ1bGwgZGV0YWlscy5cbiovXG5cbmltcG9ydCBSZWFjdCwgeyBDb250ZXh0VHlwZSwgY3JlYXRlUmVmLCBDU1NQcm9wZXJ0aWVzLCBNdXRhYmxlUmVmT2JqZWN0LCBSZWFjdE5vZGUgfSBmcm9tIFwicmVhY3RcIjtcbmltcG9ydCBjbGFzc05hbWVzIGZyb20gXCJjbGFzc25hbWVzXCI7XG5pbXBvcnQgeyBJV2lkZ2V0LCBNYXRyaXhDYXBhYmlsaXRpZXMgfSBmcm9tIFwibWF0cml4LXdpZGdldC1hcGlcIjtcbmltcG9ydCB7IFJvb20sIFJvb21FdmVudCB9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9tYXRyaXhcIjtcbmltcG9ydCB7IEtub3duTWVtYmVyc2hpcCB9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy90eXBlc1wiO1xuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL2xvZ2dlclwiO1xuaW1wb3J0IHsgQXBwcm92YWxPcHRzLCBXaWRnZXRMaWZlY3ljbGUgfSBmcm9tIFwiQG1hdHJpeC1vcmcvcmVhY3Qtc2RrLW1vZHVsZS1hcGkvbGliL2xpZmVjeWNsZXMvV2lkZ2V0TGlmZWN5Y2xlXCI7XG5pbXBvcnQgRWxsaXBzaXNJY29uIGZyb20gXCJAdmVjdG9yLWltL2NvbXBvdW5kLWRlc2lnbi10b2tlbnMvYXNzZXRzL3dlYi9pY29ucy9vdmVyZmxvdy1ob3Jpem9udGFsXCI7XG5cbmltcG9ydCBBY2Nlc3NpYmxlQnV0dG9uIGZyb20gXCIuL0FjY2Vzc2libGVCdXR0b25cIjtcbmltcG9ydCB7IF90IH0gZnJvbSBcIi4uLy4uLy4uL2xhbmd1YWdlSGFuZGxlclwiO1xuaW1wb3J0IEFwcFBlcm1pc3Npb24gZnJvbSBcIi4vQXBwUGVybWlzc2lvblwiO1xuaW1wb3J0IEFwcFdhcm5pbmcgZnJvbSBcIi4vQXBwV2FybmluZ1wiO1xuaW1wb3J0IFNwaW5uZXIgZnJvbSBcIi4vU3Bpbm5lclwiO1xuaW1wb3J0IGRpcyBmcm9tIFwiLi4vLi4vLi4vZGlzcGF0Y2hlci9kaXNwYXRjaGVyXCI7XG5pbXBvcnQgQWN0aXZlV2lkZ2V0U3RvcmUgZnJvbSBcIi4uLy4uLy4uL3N0b3Jlcy9BY3RpdmVXaWRnZXRTdG9yZVwiO1xuaW1wb3J0IFNldHRpbmdzU3RvcmUgZnJvbSBcIi4uLy4uLy4uL3NldHRpbmdzL1NldHRpbmdzU3RvcmVcIjtcbmltcG9ydCB7IGFib3ZlTGVmdE9mLCBDb250ZXh0TWVudUJ1dHRvbiB9IGZyb20gXCIuLi8uLi9zdHJ1Y3R1cmVzL0NvbnRleHRNZW51XCI7XG5pbXBvcnQgUGVyc2lzdGVkRWxlbWVudCwgeyBnZXRQZXJzaXN0S2V5IH0gZnJvbSBcIi4vUGVyc2lzdGVkRWxlbWVudFwiO1xuaW1wb3J0IHsgV2lkZ2V0VHlwZSB9IGZyb20gXCIuLi8uLi8uLi93aWRnZXRzL1dpZGdldFR5cGVcIjtcbmltcG9ydCB7IEVsZW1lbnRXaWRnZXQsIFN0b3BHYXBXaWRnZXQgfSBmcm9tIFwiLi4vLi4vLi4vc3RvcmVzL3dpZGdldHMvU3RvcEdhcFdpZGdldFwiO1xuaW1wb3J0IHsgc2hvd0NvbnRleHRNZW51LCBXaWRnZXRDb250ZXh0TWVudSB9IGZyb20gXCIuLi9jb250ZXh0X21lbnVzL1dpZGdldENvbnRleHRNZW51XCI7XG5pbXBvcnQgV2lkZ2V0QXZhdGFyIGZyb20gXCIuLi9hdmF0YXJzL1dpZGdldEF2YXRhclwiO1xuaW1wb3J0IExlZ2FjeUNhbGxIYW5kbGVyIGZyb20gXCIuLi8uLi8uLi9MZWdhY3lDYWxsSGFuZGxlclwiO1xuaW1wb3J0IHsgSUFwcCwgaXNBcHBXaWRnZXQgfSBmcm9tIFwiLi4vLi4vLi4vc3RvcmVzL1dpZGdldFN0b3JlXCI7XG5pbXBvcnQgeyBJY29uIGFzIENvbGxhcHNlSWNvbiB9IGZyb20gXCIuLi8uLi8uLi8uLi9yZXMvaW1nL2VsZW1lbnQtaWNvbnMvbWluaW1pc2UtY29sbGFwc2Uuc3ZnXCI7XG5pbXBvcnQgeyBJY29uIGFzIE1heGltaXNlSWNvbiB9IGZyb20gXCIuLi8uLi8uLi8uLi9yZXMvaW1nL2VsZW1lbnQtaWNvbnMvbWF4aW1pc2UtZXhwYW5kLnN2Z1wiO1xuaW1wb3J0IHsgSWNvbiBhcyBNaW5pbWlzZUljb24gfSBmcm9tIFwiLi4vLi4vLi4vLi4vcmVzL2ltZy9lbGVtZW50LWljb25zL21pbnVzLWJ1dHRvbi5zdmdcIjtcbmltcG9ydCB7IEljb24gYXMgUG9wb3V0SWNvbiB9IGZyb20gXCIuLi8uLi8uLi8uLi9yZXMvaW1nL2ZlYXRoZXItY3VzdG9taXNlZC93aWRnZXQvZXh0ZXJuYWwtbGluay5zdmdcIjtcbmltcG9ydCB7IENvbnRhaW5lciwgV2lkZ2V0TGF5b3V0U3RvcmUgfSBmcm9tIFwiLi4vLi4vLi4vc3RvcmVzL3dpZGdldHMvV2lkZ2V0TGF5b3V0U3RvcmVcIjtcbmltcG9ydCB7IE93blByb2ZpbGVTdG9yZSB9IGZyb20gXCIuLi8uLi8uLi9zdG9yZXMvT3duUHJvZmlsZVN0b3JlXCI7XG5pbXBvcnQgeyBVUERBVEVfRVZFTlQgfSBmcm9tIFwiLi4vLi4vLi4vc3RvcmVzL0FzeW5jU3RvcmVcIjtcbmltcG9ydCBXaWRnZXRVdGlscyBmcm9tIFwiLi4vLi4vLi4vdXRpbHMvV2lkZ2V0VXRpbHNcIjtcbmltcG9ydCBNYXRyaXhDbGllbnRDb250ZXh0IGZyb20gXCIuLi8uLi8uLi9jb250ZXh0cy9NYXRyaXhDbGllbnRDb250ZXh0XCI7XG5pbXBvcnQgeyBBY3Rpb25QYXlsb2FkIH0gZnJvbSBcIi4uLy4uLy4uL2Rpc3BhdGNoZXIvcGF5bG9hZHNcIjtcbmltcG9ydCB7IEFjdGlvbiB9IGZyb20gXCIuLi8uLi8uLi9kaXNwYXRjaGVyL2FjdGlvbnNcIjtcbmltcG9ydCB7IEVsZW1lbnRXaWRnZXRDYXBhYmlsaXRpZXMgfSBmcm9tIFwiLi4vLi4vLi4vc3RvcmVzL3dpZGdldHMvRWxlbWVudFdpZGdldENhcGFiaWxpdGllc1wiO1xuaW1wb3J0IHsgV2lkZ2V0TWVzc2FnaW5nU3RvcmUgfSBmcm9tIFwiLi4vLi4vLi4vc3RvcmVzL3dpZGdldHMvV2lkZ2V0TWVzc2FnaW5nU3RvcmVcIjtcbmltcG9ydCB7IFNka0NvbnRleHRDbGFzcyB9IGZyb20gXCIuLi8uLi8uLi9jb250ZXh0cy9TREtDb250ZXh0XCI7XG5pbXBvcnQgeyBNb2R1bGVSdW5uZXIgfSBmcm9tIFwiLi4vLi4vLi4vbW9kdWxlcy9Nb2R1bGVSdW5uZXJcIjtcbmltcG9ydCB7IHBhcnNlVXJsIH0gZnJvbSBcIi4uLy4uLy4uL3V0aWxzL1VybFV0aWxzXCI7XG5pbXBvcnQgUmlnaHRQYW5lbFN0b3JlIGZyb20gXCIuLi8uLi8uLi9zdG9yZXMvcmlnaHQtcGFuZWwvUmlnaHRQYW5lbFN0b3JlLnRzXCI7XG5pbXBvcnQgeyBSaWdodFBhbmVsUGhhc2VzIH0gZnJvbSBcIi4uLy4uLy4uL3N0b3Jlcy9yaWdodC1wYW5lbC9SaWdodFBhbmVsU3RvcmVQaGFzZXMudHNcIjtcblxuaW50ZXJmYWNlIElQcm9wcyB7XG4gICAgYXBwOiBJV2lkZ2V0IHwgSUFwcDtcbiAgICAvLyBJZiByb29tIGlzIG5vdCBzcGVjaWZpZWQgdGhlbiBpdCBpcyBhbiBhY2NvdW50IGxldmVsIHdpZGdldFxuICAgIC8vIHdoaWNoIGJ5cGFzc2VzIHBlcm1pc3Npb24gcHJvbXB0cyBhcyBpdCB3YXMgYWRkZWQgZXhwbGljaXRseSBieSB0aGF0IHVzZXJcbiAgICByb29tPzogUm9vbTtcbiAgICB0aHJlYWRJZD86IHN0cmluZyB8IG51bGw7XG4gICAgLy8gU3BlY2lmeWluZyAnZnVsbFdpZHRoJyBhcyB0cnVlIHdpbGwgcmVuZGVyIHRoZSBhcHAgdGlsZSB0byBmaWxsIHRoZSB3aWR0aCBvZiB0aGUgYXBwIGRyYXdlciBjb250YWluZXIuXG4gICAgLy8gVGhpcyBzaG91bGQgYmUgc2V0IHRvIHRydWUgd2hlbiB0aGVyZSBpcyBvbmx5IG9uZSB3aWRnZXQgaW4gdGhlIGFwcCBkcmF3ZXIsIG90aGVyd2lzZSBpdCBzaG91bGQgYmUgZmFsc2UuXG4gICAgZnVsbFdpZHRoPzogYm9vbGVhbjtcbiAgICAvLyBPcHRpb25hbC4gSWYgc2V0LCByZW5kZXJzIGEgc21hbGxlciB2aWV3IG9mIHRoZSB3aWRnZXRcbiAgICBtaW5pTW9kZT86IGJvb2xlYW47XG4gICAgLy8gVXNlcklkIG9mIHRoZSBjdXJyZW50IHVzZXJcbiAgICB1c2VySWQ6IHN0cmluZztcbiAgICAvLyBVc2VySWQgb2YgdGhlIGVudGl0eSB0aGF0IGFkZGVkIC8gbW9kaWZpZWQgdGhlIHdpZGdldFxuICAgIGNyZWF0b3JVc2VySWQ6IHN0cmluZztcbiAgICB3YWl0Rm9ySWZyYW1lTG9hZDogYm9vbGVhbjtcbiAgICBzaG93TWVudWJhcj86IGJvb2xlYW47XG4gICAgLy8gT3B0aW9uYWwgb25FZGl0Q2xpY2tIYW5kbGVyIChvdmVycmlkZXMgZGVmYXVsdCBiZWhhdmlvdXIpXG4gICAgb25FZGl0Q2xpY2s/OiAoKSA9PiB2b2lkO1xuICAgIC8vIE9wdGlvbmFsIG9uRGVsZXRlQ2xpY2tIYW5kbGVyIChvdmVycmlkZXMgZGVmYXVsdCBiZWhhdmlvdXIpXG4gICAgb25EZWxldGVDbGljaz86ICgpID0+IHZvaWQ7XG4gICAgLy8gT3B0aW9uYWxseSBoaWRlIHRoZSB0aWxlIHRpdGxlXG4gICAgc2hvd1RpdGxlPzogYm9vbGVhbjtcbiAgICAvLyBPcHRpb25hbGx5IGhhbmRsZSBtaW5pbWlzZSBidXR0b24gcG9pbnRlciBldmVudHMgKGRlZmF1bHQgZmFsc2UpXG4gICAgaGFuZGxlTWluaW1pc2VQb2ludGVyRXZlbnRzPzogYm9vbGVhbjtcbiAgICAvLyBPcHRpb25hbGx5IGhpZGUgdGhlIHBvcG91dCB3aWRnZXQgaWNvblxuICAgIHNob3dQb3BvdXQ/OiBib29sZWFuO1xuICAgIC8vIElzIHRoaXMgYW4gaW5zdGFuY2Ugb2YgYSB1c2VyIHdpZGdldFxuICAgIHVzZXJXaWRnZXQ6IGJvb2xlYW47XG4gICAgLy8gc2V0cyB0aGUgcG9pbnRlci1ldmVudHMgcHJvcGVydHkgb24gdGhlIGlmcmFtZVxuICAgIHBvaW50ZXJFdmVudHM/OiBDU1NQcm9wZXJ0aWVzW1wicG9pbnRlckV2ZW50c1wiXTtcbiAgICB3aWRnZXRQYWdlVGl0bGU/OiBzdHJpbmc7XG4gICAgc2hvd0xheW91dEJ1dHRvbnM/OiBib29sZWFuO1xuICAgIC8vIEhhbmRsZSB0byBtYW51YWxseSBub3RpZnkgdGhlIFBlcnNpc3RlZEVsZW1lbnQgdGhhdCBpdCBuZWVkcyB0byBtb3ZlXG4gICAgbW92ZVBlcnNpc3RlZEVsZW1lbnQ/OiBNdXRhYmxlUmVmT2JqZWN0PCgoKSA9PiB2b2lkKSB8IHVuZGVmaW5lZD47XG4gICAgLy8gQW4gZWxlbWVudCB0byByZW5kZXIgYWZ0ZXIgdGhlIGlmcmFtZSBhcyBhbiBvdmVybGF5XG4gICAgb3ZlcmxheT86IFJlYWN0Tm9kZTtcbiAgICAvLyBJZiBkZWZpbmVkIHRoaXMgYXN5bmMgbWV0aG9kIHdpbGwgYmUgY2FsbGVkIHdoZW4gdGhlIHdpZGdldCByZXF1ZXN0cyB0byBiZWNvbWUgc3RpY2t5LlxuICAgIC8vIEl0IHdpbGwgb25seSBiZWNvbWUgc3RpY2t5IG9uY2UgdGhlIHJldHVybmVkIHByb21pc2UgcmVzb2x2ZXMuXG4gICAgLy8gVGhpcyBpcyB1c2VmdWwgYmVjYXVzZTogV2lkZ2V0IEIgaXMgc3RpY2t5LiBNYWtpbmcgd2lkZ2V0IEEgc3RpY2t5IHdpbGwga2lsbCB3aWRnZXQgQiBpbW1lZGlhdGVseS5cbiAgICAvLyBUaGlzIHByb21pc2UgYWxsb3dzIHRvIGRvIFdpZGdldCBCIHJlbGF0ZWQgY2xlYW51cCBiZWZvcmUgV2lkZ2V0IEEgYmVjb21lcyBzdGlja3kuIChlLmcuIGhhbmd1cCBhIFZvaXAgY2FsbClcbiAgICBzdGlja3lQcm9taXNlPzogKCkgPT4gUHJvbWlzZTx2b2lkPjtcbn1cblxuaW50ZXJmYWNlIElTdGF0ZSB7XG4gICAgaW5pdGlhbGlzaW5nOiBib29sZWFuOyAvLyBUcnVlIHdoaWxlIHdlIGFyZSBtYW5nbGluZyB0aGUgd2lkZ2V0IFVSTFxuICAgIC8vIFRydWUgd2hpbGUgdGhlIGlmcmFtZSBjb250ZW50IGlzIGxvYWRpbmdcbiAgICBsb2FkaW5nOiBib29sZWFuO1xuICAgIC8vIEFzc3VtZSB0aGF0IHdpZGdldCBoYXMgcGVybWlzc2lvbiB0byBsb2FkIGlmIHdlIGFyZSB0aGUgdXNlciB3aG9cbiAgICAvLyBhZGRlZCBpdCB0byB0aGUgcm9vbSwgb3IgaWYgZXhwbGljaXRseSBncmFudGVkIGJ5IHRoZSB1c2VyXG4gICAgaGFzUGVybWlzc2lvblRvTG9hZDogYm9vbGVhbjtcbiAgICAvLyBXYWl0IGZvciB1c2VyIHByb2ZpbGUgbG9hZCB0byBkaXNwbGF5IGNvcnJlY3QgbmFtZVxuICAgIGlzVXNlclByb2ZpbGVSZWFkeTogYm9vbGVhbjtcbiAgICBlcnJvcjogRXJyb3IgfCBudWxsO1xuICAgIG1lbnVEaXNwbGF5ZWQ6IGJvb2xlYW47XG4gICAgcmVxdWlyZXNDbGllbnQ6IGJvb2xlYW47XG4gICAgaGFzQ29udGV4dE1lbnVPcHRpb25zOiBib29sZWFuO1xufVxuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBBcHBUaWxlIGV4dGVuZHMgUmVhY3QuQ29tcG9uZW50PElQcm9wcywgSVN0YXRlPiB7XG4gICAgcHVibGljIHN0YXRpYyBjb250ZXh0VHlwZSA9IE1hdHJpeENsaWVudENvbnRleHQ7XG4gICAgcHVibGljIGRlY2xhcmUgY29udGV4dDogQ29udGV4dFR5cGU8dHlwZW9mIE1hdHJpeENsaWVudENvbnRleHQ+O1xuXG4gICAgcHVibGljIHN0YXRpYyBkZWZhdWx0UHJvcHM6IFBhcnRpYWw8SVByb3BzPiA9IHtcbiAgICAgICAgd2FpdEZvcklmcmFtZUxvYWQ6IHRydWUsXG4gICAgICAgIHNob3dNZW51YmFyOiB0cnVlLFxuICAgICAgICBzaG93VGl0bGU6IHRydWUsXG4gICAgICAgIHNob3dQb3BvdXQ6IHRydWUsXG4gICAgICAgIGhhbmRsZU1pbmltaXNlUG9pbnRlckV2ZW50czogZmFsc2UsXG4gICAgICAgIHVzZXJXaWRnZXQ6IGZhbHNlLFxuICAgICAgICBtaW5pTW9kZTogZmFsc2UsXG4gICAgICAgIHRocmVhZElkOiBudWxsLFxuICAgICAgICBzaG93TGF5b3V0QnV0dG9uczogdHJ1ZSxcbiAgICB9O1xuXG4gICAgcHJpdmF0ZSBjb250ZXh0TWVudUJ1dHRvbiA9IGNyZWF0ZVJlZjxhbnk+KCk7XG4gICAgcHJpdmF0ZSBpZnJhbWU/OiBIVE1MSUZyYW1lRWxlbWVudDsgLy8gcmVmIHRvIHRoZSBpZnJhbWUgKGNhbGxiYWNrIHN0eWxlKVxuICAgIHByaXZhdGUgYWxsb3dlZFdpZGdldHNXYXRjaFJlZj86IHN0cmluZztcbiAgICBwcml2YXRlIHBlcnNpc3RLZXk6IHN0cmluZztcbiAgICBwcml2YXRlIHNnV2lkZ2V0OiBTdG9wR2FwV2lkZ2V0IHwgbnVsbDtcbiAgICBwcml2YXRlIGRpc3BhdGNoZXJSZWY/OiBzdHJpbmc7XG4gICAgcHJpdmF0ZSB1bm1vdW50ZWQgPSBmYWxzZTtcblxuICAgIHB1YmxpYyBjb25zdHJ1Y3Rvcihwcm9wczogSVByb3BzLCBjb250ZXh0OiBDb250ZXh0VHlwZTx0eXBlb2YgTWF0cml4Q2xpZW50Q29udGV4dD4pIHtcbiAgICAgICAgc3VwZXIocHJvcHMsIGNvbnRleHQpO1xuXG4gICAgICAgIC8vIFRpbGVzIGluIG1pbmlNb2RlIGFyZSBmbG9hdGluZywgYW5kIHRoZXJlZm9yZSBub3QgZG9ja2VkXG4gICAgICAgIGlmICghdGhpcy5wcm9wcy5taW5pTW9kZSkge1xuICAgICAgICAgICAgQWN0aXZlV2lkZ2V0U3RvcmUuaW5zdGFuY2UuZG9ja1dpZGdldChcbiAgICAgICAgICAgICAgICB0aGlzLnByb3BzLmFwcC5pZCxcbiAgICAgICAgICAgICAgICBpc0FwcFdpZGdldCh0aGlzLnByb3BzLmFwcCkgPyB0aGlzLnByb3BzLmFwcC5yb29tSWQgOiBudWxsLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFRoZSBrZXkgdXNlZCBmb3IgUGVyc2lzdGVkRWxlbWVudFxuICAgICAgICB0aGlzLnBlcnNpc3RLZXkgPSBnZXRQZXJzaXN0S2V5KFdpZGdldFV0aWxzLmdldFdpZGdldFVpZCh0aGlzLnByb3BzLmFwcCkpO1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgdGhpcy5zZ1dpZGdldCA9IG5ldyBTdG9wR2FwV2lkZ2V0KHRoaXMucHJvcHMpO1xuICAgICAgICAgICAgdGhpcy5zZXR1cFNnTGlzdGVuZXJzKCk7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIGxvZ2dlci5sb2coXCJGYWlsZWQgdG8gY29uc3RydWN0IHdpZGdldFwiLCBlKTtcbiAgICAgICAgICAgIHRoaXMuc2dXaWRnZXQgPSBudWxsO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5zdGF0ZSA9IHRoaXMuZ2V0TmV3U3RhdGUocHJvcHMpO1xuICAgIH1cblxuICAgIHByaXZhdGUgd2F0Y2hVc2VyUmVhZHkgPSAoKTogdm9pZCA9PiB7XG4gICAgICAgIGlmIChPd25Qcm9maWxlU3RvcmUuaW5zdGFuY2UuaXNQcm9maWxlSW5mb0ZldGNoZWQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBPd25Qcm9maWxlU3RvcmUuaW5zdGFuY2Uub25jZShVUERBVEVfRVZFTlQsIHRoaXMub25Vc2VyUmVhZHkpO1xuICAgIH07XG5cbiAgICBwcml2YXRlIG9uVXNlclJlYWR5ID0gKCk6IHZvaWQgPT4ge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHsgaXNVc2VyUHJvZmlsZVJlYWR5OiB0cnVlIH0pO1xuICAgIH07XG5cbiAgICAvLyBU