UNPKG

matrix-react-sdk

Version:
695 lines (603 loc) 92.7 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _react = _interopRequireWildcard(require("react")); var _dispatcher = _interopRequireDefault(require("../../../dispatcher/dispatcher")); var _CallHandler = _interopRequireDefault(require("../../../CallHandler")); var _MatrixClientPeg = require("../../../MatrixClientPeg"); var _languageHandler = require("../../../languageHandler"); var _VideoFeed = _interopRequireDefault(require("./VideoFeed")); var _RoomAvatar = _interopRequireDefault(require("../avatars/RoomAvatar")); var _call = require("matrix-js-sdk/src/webrtc/call"); var _classnames = _interopRequireDefault(require("classnames")); var _AccessibleButton = _interopRequireDefault(require("../elements/AccessibleButton")); var _Keyboard = require("../../../Keyboard"); var _ContextMenu = require("../../structures/ContextMenu"); var _CallContextMenu = _interopRequireDefault(require("../context_menus/CallContextMenu")); var _Avatar = require("../../../Avatar"); var _DialpadContextMenu = _interopRequireDefault(require("../context_menus/DialpadContextMenu")); var _replaceableComponent = require("../../../utils/replaceableComponent"); var _dec, _class, _temp; function getFullScreenElement() { return document.fullscreenElement || // moz omitted because firefox supports this unprefixed now (webkit here for safari) document.webkitFullscreenElement || document.msFullscreenElement; } function requestFullscreen(element /*: Element*/ ) { const method = element.requestFullscreen || // moz omitted since firefox supports unprefixed now element.webkitRequestFullScreen || element.msRequestFullscreen; if (method) method.call(element); } function exitFullscreen() { const exitMethod = document.exitFullscreen || document.webkitExitFullscreen || document.msExitFullscreen; if (exitMethod) exitMethod.call(document); } const CONTROLS_HIDE_DELAY = 1000; // Height of the header duplicated from CSS because we need to subtract it from our max // height to get the max height of the video const CONTEXT_MENU_VPADDING = 8; // How far the context menu sits above the button (px) let CallView = (_dec = (0, _replaceableComponent.replaceableComponent)("views.voip.CallView"), _dec(_class = (_temp = class CallView extends _react.default.Component /*:: <IProps, IState>*/ { constructor(props /*: IProps*/ ) { super(props); (0, _defineProperty2.default)(this, "dispatcherRef", void 0); (0, _defineProperty2.default)(this, "contentRef", /*#__PURE__*/(0, _react.createRef)()); (0, _defineProperty2.default)(this, "controlsHideTimer", null); (0, _defineProperty2.default)(this, "dialpadButton", /*#__PURE__*/(0, _react.createRef)()); (0, _defineProperty2.default)(this, "contextMenuButton", /*#__PURE__*/(0, _react.createRef)()); (0, _defineProperty2.default)(this, "onAction", payload => { switch (payload.action) { case 'video_fullscreen': { if (!this.contentRef.current) { return; } if (payload.fullscreen) { requestFullscreen(this.contentRef.current); } else if (getFullScreenElement()) { exitFullscreen(); } break; } } }); (0, _defineProperty2.default)(this, "onCallState", state => { this.setState({ callState: state }); }); (0, _defineProperty2.default)(this, "onFeedsChanged", (newFeeds /*: Array<CallFeed>*/ ) => { this.setState({ feeds: newFeeds }); }); (0, _defineProperty2.default)(this, "onCallLocalHoldUnhold", () => { this.setState({ isLocalOnHold: this.props.call.isLocalOnHold() }); }); (0, _defineProperty2.default)(this, "onCallRemoteHoldUnhold", () => { this.setState({ isRemoteOnHold: this.props.call.isRemoteOnHold(), // update both here because isLocalOnHold changes when we hold the call too isLocalOnHold: this.props.call.isLocalOnHold() }); }); (0, _defineProperty2.default)(this, "onFullscreenClick", () => { _dispatcher.default.dispatch({ action: 'video_fullscreen', fullscreen: true }); }); (0, _defineProperty2.default)(this, "onExpandClick", () => { const userFacingRoomId = _CallHandler.default.sharedInstance().roomIdForCall(this.props.call); _dispatcher.default.dispatch({ action: 'view_room', room_id: userFacingRoomId }); }); (0, _defineProperty2.default)(this, "onControlsHideTimer", () => { this.controlsHideTimer = null; this.setState({ controlsVisible: false }); }); (0, _defineProperty2.default)(this, "onMouseMove", () => { this.showControls(); }); (0, _defineProperty2.default)(this, "onDialpadClick", () => { if (!this.state.showDialpad) { if (this.controlsHideTimer) { clearTimeout(this.controlsHideTimer); this.controlsHideTimer = null; } this.setState({ showDialpad: true, controlsVisible: true }); } else { if (this.controlsHideTimer !== null) { clearTimeout(this.controlsHideTimer); } this.controlsHideTimer = window.setTimeout(this.onControlsHideTimer, CONTROLS_HIDE_DELAY); this.setState({ showDialpad: false }); } }); (0, _defineProperty2.default)(this, "onMicMuteClick", () => { const newVal = !this.state.micMuted; this.props.call.setMicrophoneMuted(newVal); this.setState({ micMuted: newVal }); }); (0, _defineProperty2.default)(this, "onVidMuteClick", () => { const newVal = !this.state.vidMuted; this.props.call.setLocalVideoMuted(newVal); this.setState({ vidMuted: newVal }); }); (0, _defineProperty2.default)(this, "onMoreClick", () => { if (this.controlsHideTimer) { clearTimeout(this.controlsHideTimer); this.controlsHideTimer = null; } this.setState({ showMoreMenu: true, controlsVisible: true }); }); (0, _defineProperty2.default)(this, "closeDialpad", () => { this.setState({ showDialpad: false }); this.controlsHideTimer = window.setTimeout(this.onControlsHideTimer, CONTROLS_HIDE_DELAY); }); (0, _defineProperty2.default)(this, "closeContextMenu", () => { this.setState({ showMoreMenu: false }); this.controlsHideTimer = window.setTimeout(this.onControlsHideTimer, CONTROLS_HIDE_DELAY); }); (0, _defineProperty2.default)(this, "onNativeKeyDown", ev => { let handled = false; const ctrlCmdOnly = (0, _Keyboard.isOnlyCtrlOrCmdKeyEvent)(ev); switch (ev.key) { case _Keyboard.Key.D: if (ctrlCmdOnly) { this.onMicMuteClick(); // show the controls to give feedback this.showControls(); handled = true; } break; case _Keyboard.Key.E: if (ctrlCmdOnly) { this.onVidMuteClick(); // show the controls to give feedback this.showControls(); handled = true; } break; } if (handled) { ev.stopPropagation(); ev.preventDefault(); } }); (0, _defineProperty2.default)(this, "onRoomAvatarClick", () => { const userFacingRoomId = _CallHandler.default.sharedInstance().roomIdForCall(this.props.call); _dispatcher.default.dispatch({ action: 'view_room', room_id: userFacingRoomId }); }); (0, _defineProperty2.default)(this, "onSecondaryRoomAvatarClick", () => { const userFacingRoomId = _CallHandler.default.sharedInstance().roomIdForCall(this.props.secondaryCall); _dispatcher.default.dispatch({ action: 'view_room', room_id: userFacingRoomId }); }); (0, _defineProperty2.default)(this, "onCallResumeClick", () => { const userFacingRoomId = _CallHandler.default.sharedInstance().roomIdForCall(this.props.call); _CallHandler.default.sharedInstance().setActiveCallRoomId(userFacingRoomId); }); (0, _defineProperty2.default)(this, "onTransferClick", () => { const transfereeCall = _CallHandler.default.sharedInstance().getTransfereeForCallId(this.props.call.callId); this.props.call.transferToCall(transfereeCall); }); this.state = { isLocalOnHold: this.props.call.isLocalOnHold(), isRemoteOnHold: this.props.call.isRemoteOnHold(), micMuted: this.props.call.isMicrophoneMuted(), vidMuted: this.props.call.isLocalVideoMuted(), callState: this.props.call.state, controlsVisible: true, showMoreMenu: false, showDialpad: false, feeds: this.props.call.getFeeds() }; this.updateCallListeners(null, this.props.call); } componentDidMount() { this.dispatcherRef = _dispatcher.default.register(this.onAction); document.addEventListener('keydown', this.onNativeKeyDown); } componentWillUnmount() { if (getFullScreenElement()) { exitFullscreen(); } document.removeEventListener("keydown", this.onNativeKeyDown); this.updateCallListeners(this.props.call, null); _dispatcher.default.unregister(this.dispatcherRef); } componentDidUpdate(prevProps) { if (this.props.call === prevProps.call) return; this.setState({ isLocalOnHold: this.props.call.isLocalOnHold(), isRemoteOnHold: this.props.call.isRemoteOnHold(), micMuted: this.props.call.isMicrophoneMuted(), vidMuted: this.props.call.isLocalVideoMuted(), callState: this.props.call.state }); this.updateCallListeners(null, this.props.call); } updateCallListeners(oldCall /*: MatrixCall*/ , newCall /*: MatrixCall*/ ) { if (oldCall === newCall) return; if (oldCall) { oldCall.removeListener(_call.CallEvent.State, this.onCallState); oldCall.removeListener(_call.CallEvent.LocalHoldUnhold, this.onCallLocalHoldUnhold); oldCall.removeListener(_call.CallEvent.RemoteHoldUnhold, this.onCallRemoteHoldUnhold); oldCall.removeListener(_call.CallEvent.FeedsChanged, this.onFeedsChanged); } if (newCall) { newCall.on(_call.CallEvent.State, this.onCallState); newCall.on(_call.CallEvent.LocalHoldUnhold, this.onCallLocalHoldUnhold); newCall.on(_call.CallEvent.RemoteHoldUnhold, this.onCallRemoteHoldUnhold); newCall.on(_call.CallEvent.FeedsChanged, this.onFeedsChanged); } } showControls() { if (this.state.showMoreMenu || this.state.showDialpad) return; if (!this.state.controlsVisible) { this.setState({ controlsVisible: true }); } if (this.controlsHideTimer !== null) { clearTimeout(this.controlsHideTimer); } this.controlsHideTimer = window.setTimeout(this.onControlsHideTimer, CONTROLS_HIDE_DELAY); } render() { const client = _MatrixClientPeg.MatrixClientPeg.get(); const callRoomId = _CallHandler.default.sharedInstance().roomIdForCall(this.props.call); const secondaryCallRoomId = _CallHandler.default.sharedInstance().roomIdForCall(this.props.secondaryCall); const callRoom = client.getRoom(callRoomId); const secCallRoom = this.props.secondaryCall ? client.getRoom(secondaryCallRoomId) : null; let dialPad; let contextMenu; if (this.state.showDialpad) { dialPad = /*#__PURE__*/_react.default.createElement(_DialpadContextMenu.default, (0, _extends2.default)({}, (0, _ContextMenu.alwaysAboveRightOf)(this.dialpadButton.current.getBoundingClientRect(), _ContextMenu.ChevronFace.None, CONTEXT_MENU_VPADDING), { onFinished: this.closeDialpad, call: this.props.call })); } if (this.state.showMoreMenu) { contextMenu = /*#__PURE__*/_react.default.createElement(_CallContextMenu.default, (0, _extends2.default)({}, (0, _ContextMenu.alwaysAboveLeftOf)(this.contextMenuButton.current.getBoundingClientRect(), _ContextMenu.ChevronFace.None, CONTEXT_MENU_VPADDING), { onFinished: this.closeContextMenu, call: this.props.call })); } const micClasses = (0, _classnames.default)({ mx_CallView_callControls_button: true, mx_CallView_callControls_button_micOn: !this.state.micMuted, mx_CallView_callControls_button_micOff: this.state.micMuted }); const vidClasses = (0, _classnames.default)({ mx_CallView_callControls_button: true, mx_CallView_callControls_button_vidOn: !this.state.vidMuted, mx_CallView_callControls_button_vidOff: this.state.vidMuted }); // Put the other states of the mic/video icons in the document to make sure they're cached // (otherwise the icon disappears briefly when toggled) const micCacheClasses = (0, _classnames.default)({ mx_CallView_callControls_button: true, mx_CallView_callControls_button_micOn: this.state.micMuted, mx_CallView_callControls_button_micOff: !this.state.micMuted, mx_CallView_callControls_button_invisible: true }); const vidCacheClasses = (0, _classnames.default)({ mx_CallView_callControls_button: true, mx_CallView_callControls_button_vidOn: this.state.micMuted, mx_CallView_callControls_button_vidOff: !this.state.micMuted, mx_CallView_callControls_button_invisible: true }); const callControlsClasses = (0, _classnames.default)({ mx_CallView_callControls: true, mx_CallView_callControls_hidden: !this.state.controlsVisible }); const vidMuteButton = this.props.call.type === _call.CallType.Video ? /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, { className: vidClasses, onClick: this.onVidMuteClick }) : null; // The dial pad & 'more' button actions are only relevant in a connected call // When not connected, we have to put something there to make the flexbox alignment correct const dialpadButton = this.state.callState === _call.CallState.Connected ? /*#__PURE__*/_react.default.createElement(_ContextMenu.ContextMenuButton, { className: "mx_CallView_callControls_button mx_CallView_callControls_dialpad", inputRef: this.dialpadButton, onClick: this.onDialpadClick, isExpanded: this.state.showDialpad }) : /*#__PURE__*/_react.default.createElement("div", { className: "mx_CallView_callControls_button mx_CallView_callControls_button_dialpad_hidden" }); const contextMenuButton = this.state.callState === _call.CallState.Connected ? /*#__PURE__*/_react.default.createElement(_ContextMenu.ContextMenuButton, { className: "mx_CallView_callControls_button mx_CallView_callControls_button_more", onClick: this.onMoreClick, inputRef: this.contextMenuButton, isExpanded: this.state.showMoreMenu }) : /*#__PURE__*/_react.default.createElement("div", { className: "mx_CallView_callControls_button mx_CallView_callControls_button_more_hidden" }); // in the near future, the dial pad button will go on the left. For now, it's the nothing button // because something needs to have margin-right: auto to make the alignment correct. const callControls = /*#__PURE__*/_react.default.createElement("div", { className: callControlsClasses }, dialpadButton, /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, { className: micClasses, onClick: this.onMicMuteClick }), /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, { className: "mx_CallView_callControls_button mx_CallView_callControls_button_hangup", onClick: () => { _dispatcher.default.dispatch({ action: 'hangup', room_id: callRoomId }); } }), vidMuteButton, /*#__PURE__*/_react.default.createElement("div", { className: micCacheClasses }), /*#__PURE__*/_react.default.createElement("div", { className: vidCacheClasses }), contextMenuButton); const avatarSize = this.props.pipMode ? 76 : 160; // The 'content' for the call, ie. the videos for a video call and profile picture // for voice calls (fills the bg) let contentView /*: React.ReactNode*/ ; const transfereeCall = _CallHandler.default.sharedInstance().getTransfereeForCallId(this.props.call.callId); const isOnHold = this.state.isLocalOnHold || this.state.isRemoteOnHold; let holdTransferContent; if (transfereeCall) { const transferTargetRoom = _MatrixClientPeg.MatrixClientPeg.get().getRoom(_CallHandler.default.sharedInstance().roomIdForCall(this.props.call)); const transferTargetName = transferTargetRoom ? transferTargetRoom.name : (0, _languageHandler._t)("unknown person"); const transfereeRoom = _MatrixClientPeg.MatrixClientPeg.get().getRoom(_CallHandler.default.sharedInstance().roomIdForCall(transfereeCall)); const transfereeName = transfereeRoom ? transfereeRoom.name : (0, _languageHandler._t)("unknown person"); holdTransferContent = /*#__PURE__*/_react.default.createElement("div", { className: "mx_CallView_holdTransferContent" }, (0, _languageHandler._t)("Consulting with %(transferTarget)s. <a>Transfer to %(transferee)s</a>", { transferTarget: transferTargetName, transferee: transfereeName }, { a: sub => /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, { kind: "link", onClick: this.onTransferClick }, sub) })); } else if (isOnHold) { let onHoldText = null; if (this.state.isRemoteOnHold) { const holdString = _CallHandler.default.sharedInstance().hasAnyUnheldCall() ? (0, _languageHandler._td)("You held the call <a>Switch</a>") : (0, _languageHandler._td)("You held the call <a>Resume</a>"); onHoldText = (0, _languageHandler._t)(holdString, {}, { a: sub => /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, { kind: "link", onClick: this.onCallResumeClick }, sub) }); } else if (this.state.isLocalOnHold) { onHoldText = (0, _languageHandler._t)("%(peerName)s held the call", { peerName: this.props.call.getOpponentMember().name }); } holdTransferContent = /*#__PURE__*/_react.default.createElement("div", { className: "mx_CallView_holdTransferContent" }, onHoldText); } // This is a bit messy. I can't see a reason to have two onHold/transfer screens if (isOnHold || transfereeCall) { if (this.props.call.type === _call.CallType.Video) { const containerClasses = (0, _classnames.default)({ mx_CallView_content: true, mx_CallView_video: true, mx_CallView_video_hold: isOnHold }); let onHoldBackground = null; const backgroundStyle /*: CSSProperties*/ = {}; const backgroundAvatarUrl = (0, _Avatar.avatarUrlForMember)( // is it worth getting the size of the div to pass here? this.props.call.getOpponentMember(), 1024, 1024, 'crop'); backgroundStyle.backgroundImage = 'url(' + backgroundAvatarUrl + ')'; onHoldBackground = /*#__PURE__*/_react.default.createElement("div", { className: "mx_CallView_video_holdBackground", style: backgroundStyle }); contentView = /*#__PURE__*/_react.default.createElement("div", { className: containerClasses, ref: this.contentRef, onMouseMove: this.onMouseMove }, onHoldBackground, holdTransferContent, callControls); } else { const classes = (0, _classnames.default)({ mx_CallView_content: true, mx_CallView_voice: true, mx_CallView_voice_hold: isOnHold }); contentView = /*#__PURE__*/_react.default.createElement("div", { className: classes, onMouseMove: this.onMouseMove }, /*#__PURE__*/_react.default.createElement("div", { className: "mx_CallView_voice_avatarsContainer" }, /*#__PURE__*/_react.default.createElement("div", { className: "mx_CallView_voice_avatarContainer", style: { width: avatarSize, height: avatarSize } }, /*#__PURE__*/_react.default.createElement(_RoomAvatar.default, { room: callRoom, height: avatarSize, width: avatarSize }))), holdTransferContent, callControls); } } else if (this.props.call.noIncomingFeeds()) { // Here we're reusing the css classes from voice on hold, because // I am lazy. If this gets merged, the CallView might be subject // to change anyway - I might take an axe to this file in order to // try to get other things working const classes = (0, _classnames.default)({ mx_CallView_content: true, mx_CallView_voice: true }); const feeds = this.props.call.getLocalFeeds().map((feed, i) => { // Here we check to hide local audio feeds to achieve the same UI/UX // as before. But once again this might be subject to change if (feed.isVideoMuted()) return; return /*#__PURE__*/_react.default.createElement(_VideoFeed.default, { key: i, feed: feed, call: this.props.call, pipMode: this.props.pipMode, onResize: this.props.onResize }); }); // Saying "Connecting" here isn't really true, but the best thing // I can come up with, but this might be subject to change as well contentView = /*#__PURE__*/_react.default.createElement("div", { className: classes, onMouseMove: this.onMouseMove }, feeds, /*#__PURE__*/_react.default.createElement("div", { className: "mx_CallView_voice_avatarsContainer" }, /*#__PURE__*/_react.default.createElement("div", { className: "mx_CallView_voice_avatarContainer", style: { width: avatarSize, height: avatarSize } }, /*#__PURE__*/_react.default.createElement(_RoomAvatar.default, { room: callRoom, height: avatarSize, width: avatarSize }))), /*#__PURE__*/_react.default.createElement("div", { className: "mx_CallView_holdTransferContent" }, (0, _languageHandler._t)("Connecting")), callControls); } else { const containerClasses = (0, _classnames.default)({ mx_CallView_content: true, mx_CallView_video: true }); // TODO: Later the CallView should probably be reworked to support // any number of feeds but now we can always expect there to be two // feeds. This is because the js-sdk ignores any new incoming streams const feeds = this.state.feeds.map((feed, i) => { // Here we check to hide local audio feeds to achieve the same UI/UX // as before. But once again this might be subject to change if (feed.isVideoMuted() && feed.isLocal()) return; return /*#__PURE__*/_react.default.createElement(_VideoFeed.default, { key: i, feed: feed, call: this.props.call, pipMode: this.props.pipMode, onResize: this.props.onResize }); }); contentView = /*#__PURE__*/_react.default.createElement("div", { className: containerClasses, ref: this.contentRef, onMouseMove: this.onMouseMove }, feeds, callControls); } const callTypeText = this.props.call.type === _call.CallType.Video ? (0, _languageHandler._t)("Video Call") : (0, _languageHandler._t)("Voice Call"); let myClassName; let fullScreenButton; if (this.props.call.type === _call.CallType.Video && !this.props.pipMode) { fullScreenButton = /*#__PURE__*/_react.default.createElement("div", { className: "mx_CallView_header_button mx_CallView_header_button_fullscreen", onClick: this.onFullscreenClick, title: (0, _languageHandler._t)("Fill Screen") }); } let expandButton; if (this.props.pipMode) { expandButton = /*#__PURE__*/_react.default.createElement("div", { className: "mx_CallView_header_button mx_CallView_header_button_expand", onClick: this.onExpandClick, title: (0, _languageHandler._t)("Return to call") }); } const headerControls = /*#__PURE__*/_react.default.createElement("div", { className: "mx_CallView_header_controls" }, fullScreenButton, expandButton); let header /*: React.ReactNode*/ ; if (!this.props.pipMode) { header = /*#__PURE__*/_react.default.createElement("div", { className: "mx_CallView_header" }, /*#__PURE__*/_react.default.createElement("div", { className: "mx_CallView_header_phoneIcon" }), /*#__PURE__*/_react.default.createElement("span", { className: "mx_CallView_header_callType" }, callTypeText), headerControls); myClassName = 'mx_CallView_large'; } else { let secondaryCallInfo; if (this.props.secondaryCall) { secondaryCallInfo = /*#__PURE__*/_react.default.createElement("span", { className: "mx_CallView_header_secondaryCallInfo" }, /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, { element: "span", onClick: this.onSecondaryRoomAvatarClick }, /*#__PURE__*/_react.default.createElement(_RoomAvatar.default, { room: secCallRoom, height: 16, width: 16 }), /*#__PURE__*/_react.default.createElement("span", { className: "mx_CallView_secondaryCall_roomName" }, (0, _languageHandler._t)("%(name)s on hold", { name: secCallRoom.name })))); } header = /*#__PURE__*/_react.default.createElement("div", { className: "mx_CallView_header" }, /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, { onClick: this.onRoomAvatarClick }, /*#__PURE__*/_react.default.createElement(_RoomAvatar.default, { room: callRoom, height: 32, width: 32 })), /*#__PURE__*/_react.default.createElement("div", { className: "mx_CallView_header_callInfo" }, /*#__PURE__*/_react.default.createElement("div", { className: "mx_CallView_header_roomName" }, callRoom.name), /*#__PURE__*/_react.default.createElement("div", { className: "mx_CallView_header_callTypeSmall" }, callTypeText, secondaryCallInfo)), headerControls); myClassName = 'mx_CallView_pip'; } return /*#__PURE__*/_react.default.createElement("div", { className: "mx_CallView " + myClassName }, header, contentView, dialPad, contextMenu); } }, _temp)) || _class); exports.default = CallView; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9jb21wb25lbnRzL3ZpZXdzL3ZvaXAvQ2FsbFZpZXcudHN4Il0sIm5hbWVzIjpbImdldEZ1bGxTY3JlZW5FbGVtZW50IiwiZG9jdW1lbnQiLCJmdWxsc2NyZWVuRWxlbWVudCIsIndlYmtpdEZ1bGxzY3JlZW5FbGVtZW50IiwibXNGdWxsc2NyZWVuRWxlbWVudCIsInJlcXVlc3RGdWxsc2NyZWVuIiwiZWxlbWVudCIsIm1ldGhvZCIsIndlYmtpdFJlcXVlc3RGdWxsU2NyZWVuIiwibXNSZXF1ZXN0RnVsbHNjcmVlbiIsImNhbGwiLCJleGl0RnVsbHNjcmVlbiIsImV4aXRNZXRob2QiLCJ3ZWJraXRFeGl0RnVsbHNjcmVlbiIsIm1zRXhpdEZ1bGxzY3JlZW4iLCJDT05UUk9MU19ISURFX0RFTEFZIiwiQ09OVEVYVF9NRU5VX1ZQQURESU5HIiwiQ2FsbFZpZXciLCJSZWFjdCIsIkNvbXBvbmVudCIsImNvbnN0cnVjdG9yIiwicHJvcHMiLCJwYXlsb2FkIiwiYWN0aW9uIiwiY29udGVudFJlZiIsImN1cnJlbnQiLCJmdWxsc2NyZWVuIiwic3RhdGUiLCJzZXRTdGF0ZSIsImNhbGxTdGF0ZSIsIm5ld0ZlZWRzIiwiZmVlZHMiLCJpc0xvY2FsT25Ib2xkIiwiaXNSZW1vdGVPbkhvbGQiLCJkaXMiLCJkaXNwYXRjaCIsInVzZXJGYWNpbmdSb29tSWQiLCJDYWxsSGFuZGxlciIsInNoYXJlZEluc3RhbmNlIiwicm9vbUlkRm9yQ2FsbCIsInJvb21faWQiLCJjb250cm9sc0hpZGVUaW1lciIsImNvbnRyb2xzVmlzaWJsZSIsInNob3dDb250cm9scyIsInNob3dEaWFscGFkIiwiY2xlYXJUaW1lb3V0Iiwid2luZG93Iiwic2V0VGltZW91dCIsIm9uQ29udHJvbHNIaWRlVGltZXIiLCJuZXdWYWwiLCJtaWNNdXRlZCIsInNldE1pY3JvcGhvbmVNdXRlZCIsInZpZE11dGVkIiwic2V0TG9jYWxWaWRlb011dGVkIiwic2hvd01vcmVNZW51IiwiZXYiLCJoYW5kbGVkIiwiY3RybENtZE9ubHkiLCJrZXkiLCJLZXkiLCJEIiwib25NaWNNdXRlQ2xpY2siLCJFIiwib25WaWRNdXRlQ2xpY2siLCJzdG9wUHJvcGFnYXRpb24iLCJwcmV2ZW50RGVmYXVsdCIsInNlY29uZGFyeUNhbGwiLCJzZXRBY3RpdmVDYWxsUm9vbUlkIiwidHJhbnNmZXJlZUNhbGwiLCJnZXRUcmFuc2ZlcmVlRm9yQ2FsbElkIiwiY2FsbElkIiwidHJhbnNmZXJUb0NhbGwiLCJpc01pY3JvcGhvbmVNdXRlZCIsImlzTG9jYWxWaWRlb011dGVkIiwiZ2V0RmVlZHMiLCJ1cGRhdGVDYWxsTGlzdGVuZXJzIiwiY29tcG9uZW50RGlkTW91bnQiLCJkaXNwYXRjaGVyUmVmIiwicmVnaXN0ZXIiLCJvbkFjdGlvbiIsImFkZEV2ZW50TGlzdGVuZXIiLCJvbk5hdGl2ZUtleURvd24iLCJjb21wb25lbnRXaWxsVW5tb3VudCIsInJlbW92ZUV2ZW50TGlzdGVuZXIiLCJ1bnJlZ2lzdGVyIiwiY29tcG9uZW50RGlkVXBkYXRlIiwicHJldlByb3BzIiwib2xkQ2FsbCIsIm5ld0NhbGwiLCJyZW1vdmVMaXN0ZW5lciIsIkNhbGxFdmVudCIsIlN0YXRlIiwib25DYWxsU3RhdGUiLCJMb2NhbEhvbGRVbmhvbGQiLCJvbkNhbGxMb2NhbEhvbGRVbmhvbGQiLCJSZW1vdGVIb2xkVW5ob2xkIiwib25DYWxsUmVtb3RlSG9sZFVuaG9sZCIsIkZlZWRzQ2hhbmdlZCIsIm9uRmVlZHNDaGFuZ2VkIiwib24iLCJyZW5kZXIiLCJjbGllbnQiLCJNYXRyaXhDbGllbnRQZWciLCJnZXQiLCJjYWxsUm9vbUlkIiwic2Vjb25kYXJ5Q2FsbFJvb21JZCIsImNhbGxSb29tIiwiZ2V0Um9vbSIsInNlY0NhbGxSb29tIiwiZGlhbFBhZCIsImNvbnRleHRNZW51IiwiZGlhbHBhZEJ1dHRvbiIsImdldEJvdW5kaW5nQ2xpZW50UmVjdCIsIkNoZXZyb25GYWNlIiwiTm9uZSIsImNsb3NlRGlhbHBhZCIsImNvbnRleHRNZW51QnV0dG9uIiwiY2xvc2VDb250ZXh0TWVudSIsIm1pY0NsYXNzZXMiLCJteF9DYWxsVmlld19jYWxsQ29udHJvbHNfYnV0dG9uIiwibXhfQ2FsbFZpZXdfY2FsbENvbnRyb2xzX2J1dHRvbl9taWNPbiIsIm14X0NhbGxWaWV3X2NhbGxDb250cm9sc19idXR0b25fbWljT2ZmIiwidmlkQ2xhc3NlcyIsIm14X0NhbGxWaWV3X2NhbGxDb250cm9sc19idXR0b25fdmlkT24iLCJteF9DYWxsVmlld19jYWxsQ29udHJvbHNfYnV0dG9uX3ZpZE9mZiIsIm1pY0NhY2hlQ2xhc3NlcyIsIm14X0NhbGxWaWV3X2NhbGxDb250cm9sc19idXR0b25faW52aXNpYmxlIiwidmlkQ2FjaGVDbGFzc2VzIiwiY2FsbENvbnRyb2xzQ2xhc3NlcyIsIm14X0NhbGxWaWV3X2NhbGxDb250cm9scyIsIm14X0NhbGxWaWV3X2NhbGxDb250cm9sc19oaWRkZW4iLCJ2aWRNdXRlQnV0dG9uIiwidHlwZSIsIkNhbGxUeXBlIiwiVmlkZW8iLCJDYWxsU3RhdGUiLCJDb25uZWN0ZWQiLCJvbkRpYWxwYWRDbGljayIsIm9uTW9yZUNsaWNrIiwiY2FsbENvbnRyb2xzIiwiYXZhdGFyU2l6ZSIsInBpcE1vZGUiLCJjb250ZW50VmlldyIsImlzT25Ib2xkIiwiaG9sZFRyYW5zZmVyQ29udGVudCIsInRyYW5zZmVyVGFyZ2V0Um9vbSIsInRyYW5zZmVyVGFyZ2V0TmFtZSIsIm5hbWUiLCJ0cmFuc2ZlcmVlUm9vbSIsInRyYW5zZmVyZWVOYW1lIiwidHJhbnNmZXJUYXJnZXQiLCJ0cmFuc2ZlcmVlIiwiYSIsInN1YiIsIm9uVHJhbnNmZXJDbGljayIsIm9uSG9sZFRleHQiLCJob2xkU3RyaW5nIiwiaGFzQW55VW5oZWxkQ2FsbCIsIm9uQ2FsbFJlc3VtZUNsaWNrIiwicGVlck5hbWUiLCJnZXRPcHBvbmVudE1lbWJlciIsImNvbnRhaW5lckNsYXNzZXMiLCJteF9DYWxsVmlld19jb250ZW50IiwibXhfQ2FsbFZpZXdfdmlkZW8iLCJteF9DYWxsVmlld192aWRlb19ob2xkIiwib25Ib2xkQmFja2dyb3VuZCIsImJhY2tncm91bmRTdHlsZSIsImJhY2tncm91bmRBdmF0YXJVcmwiLCJiYWNrZ3JvdW5kSW1hZ2UiLCJvbk1vdXNlTW92ZSIsImNsYXNzZXMiLCJteF9DYWxsVmlld192b2ljZSIsIm14X0NhbGxWaWV3X3ZvaWNlX2hvbGQiLCJ3aWR0aCIsImhlaWdodCIsIm5vSW5jb21pbmdGZWVkcyIsImdldExvY2FsRmVlZHMiLCJtYXAiLCJmZWVkIiwiaSIsImlzVmlkZW9NdXRlZCIsIm9uUmVzaXplIiwiaXNMb2NhbCIsImNhbGxUeXBlVGV4dCIsIm15Q2xhc3NOYW1lIiwiZnVsbFNjcmVlbkJ1dHRvbiIsIm9uRnVsbHNjcmVlbkNsaWNrIiwiZXhwYW5kQnV0dG9uIiwib25FeHBhbmRDbGljayIsImhlYWRlckNvbnRyb2xzIiwiaGVhZGVyIiwic2Vjb25kYXJ5Q2FsbEluZm8iLCJvblNlY29uZGFyeVJvb21BdmF0YXJDbGljayIsIm9uUm9vbUF2YXRhckNsaWNrIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7QUFpQkE7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBRUE7Ozs7QUFnQ0EsU0FBU0Esb0JBQVQsR0FBZ0M7QUFDNUIsU0FDSUMsUUFBUSxDQUFDQyxpQkFBVCxJQUNBO0FBQ0FELEVBQUFBLFFBQVEsQ0FBQ0UsdUJBRlQsSUFHQUYsUUFBUSxDQUFDRyxtQkFKYjtBQU1IOztBQUVELFNBQVNDLGlCQUFULENBQTJCQztBQUEzQjtBQUFBLEVBQTZDO0FBQ3pDLFFBQU1DLE1BQU0sR0FDUkQsT0FBTyxDQUFDRCxpQkFBUixJQUNBO0FBQ0FDLEVBQUFBLE9BQU8sQ0FBQ0UsdUJBRlIsSUFHQUYsT0FBTyxDQUFDRyxtQkFKWjtBQU1BLE1BQUlGLE1BQUosRUFBWUEsTUFBTSxDQUFDRyxJQUFQLENBQVlKLE9BQVo7QUFDZjs7QUFF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