module Matterhorn.Events.Websocket
( handleWebsocketEvent
, handleWebsocketActionResponse
)
where
import Prelude ()
import Matterhorn.Prelude
import qualified Data.HashMap.Strict as HM
import qualified Data.Sequence as Seq
import qualified Data.Set as Set
import qualified Data.Text as T
import Network.Mattermost.Lenses
import Network.Mattermost.Types
import Network.Mattermost.WebSocket
import Matterhorn.State.ChannelList
import Matterhorn.State.Channels
import Matterhorn.State.Common
import Matterhorn.State.Flagging
import Matterhorn.State.Messages
import Matterhorn.State.Reactions
import Matterhorn.State.Teams
import Matterhorn.State.Users
import Matterhorn.Types
import Matterhorn.Types.Common
foreachTeam :: (TeamId -> MH ()) -> MH ()
foreachTeam :: (TeamId -> MH ()) -> MH ()
foreachTeam TeamId -> MH ()
act = do
HashMap TeamId TeamState
ts <- forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use Lens' ChatState (HashMap TeamId TeamState)
csTeams
let myTIds :: [TeamId]
myTIds = forall k v. HashMap k v -> [k]
HM.keys HashMap TeamId TeamState
ts
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ TeamId -> MH ()
act [TeamId]
myTIds
handleWebsocketEvent :: WebsocketEvent -> MH ()
handleWebsocketEvent :: WebsocketEvent -> MH ()
handleWebsocketEvent WebsocketEvent
we = do
UserId
myId <- forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets ChatState -> UserId
myUserId
HashMap TeamId TeamState
ts <- forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use Lens' ChatState (HashMap TeamId TeamState)
csTeams
let memberOf :: TeamId -> Bool
memberOf TeamId
tId = forall k a. (Eq k, Hashable k) => k -> HashMap k a -> Bool
HM.member TeamId
tId HashMap TeamId TeamState
ts
inMyTeamOrDM :: Maybe TeamId -> Bool
inMyTeamOrDM (Just TeamId
i) = TeamId -> Bool
memberOf TeamId
i
inMyTeamOrDM Maybe TeamId
Nothing = Bool
True
inMyTeam :: Maybe TeamId -> Bool
inMyTeam (Just TeamId
i) = TeamId -> Bool
memberOf TeamId
i
inMyTeam Maybe TeamId
Nothing = Bool
False
case WebsocketEvent -> WebsocketEventType
weEvent WebsocketEvent
we of
WebsocketEventType
WMPosted
| Just Post
p <- WEData -> Maybe Post
wepPost (WebsocketEvent -> WEData
weData WebsocketEvent
we) ->
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Maybe TeamId -> Bool
inMyTeamOrDM (WEData -> Maybe TeamId
wepTeamId (WebsocketEvent -> WEData
weData WebsocketEvent
we))) forall a b. (a -> b) -> a -> b
$ do
let wasMentioned :: Bool
wasMentioned = forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
False (forall a. Ord a => a -> Set a -> Bool
Set.member UserId
myId) forall a b. (a -> b) -> a -> b
$ WEData -> Maybe (Set UserId)
wepMentions (WebsocketEvent -> WEData
weData WebsocketEvent
we)
PostToAdd -> MH ()
addNewPostedMessage forall a b. (a -> b) -> a -> b
$ Post -> Bool -> PostToAdd
RecentPost Post
p Bool
wasMentioned
Maybe TeamId
mtId <- forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use SimpleGetter ChatState (Maybe TeamId)
csCurrentTeamId
Maybe ChannelId
cId <- case Maybe TeamId
mtId of
Maybe TeamId
Nothing -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing
Just TeamId
tId -> forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use (TeamId -> SimpleGetter ChatState (Maybe ChannelId)
csCurrentChannelId TeamId
tId)
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (forall a. a -> Maybe a
Just (Post -> ChannelId
postChannelId Post
p) forall a. Eq a => a -> a -> Bool
/= Maybe ChannelId
cId) forall a b. (a -> b) -> a -> b
$
ChannelId -> Bool -> MH ()
showChannelInSidebar (Post
pforall s a. s -> Getting a s a -> a
^.Lens' Post ChannelId
postChannelIdL) Bool
False
| Bool
otherwise -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
WebsocketEventType
WMPostEdited
| Just Post
p <- WEData -> Maybe Post
wepPost (WebsocketEvent -> WEData
weData WebsocketEvent
we) -> do
Post -> MH ()
editMessage Post
p
Maybe TeamId
currTid <- forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use SimpleGetter ChatState (Maybe TeamId)
csCurrentTeamId
(TeamId -> MH ()) -> MH ()
foreachTeam forall a b. (a -> b) -> a -> b
$ \TeamId
tId -> do
Maybe ChannelId
cId <- forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use (TeamId -> SimpleGetter ChatState (Maybe ChannelId)
csCurrentChannelId TeamId
tId)
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (forall a. a -> Maybe a
Just (Post -> ChannelId
postChannelId Post
p) forall a. Eq a => a -> a -> Bool
== Maybe ChannelId
cId Bool -> Bool -> Bool
&& forall a. a -> Maybe a
Just TeamId
tId forall a. Eq a => a -> a -> Bool
== Maybe TeamId
currTid) forall a b. (a -> b) -> a -> b
$
Bool -> MH ()
updateViewed Bool
False
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (forall a. a -> Maybe a
Just (Post -> ChannelId
postChannelId Post
p) forall a. Eq a => a -> a -> Bool
/= Maybe ChannelId
cId) forall a b. (a -> b) -> a -> b
$
ChannelId -> Bool -> MH ()
showChannelInSidebar (Post
pforall s a. s -> Getting a s a -> a
^.Lens' Post ChannelId
postChannelIdL) Bool
False
| Bool
otherwise -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
WebsocketEventType
WMPostDeleted
| Just Post
p <- WEData -> Maybe Post
wepPost (WebsocketEvent -> WEData
weData WebsocketEvent
we) -> do
Post -> MH ()
deleteMessage Post
p
Maybe TeamId
currTid <- forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use SimpleGetter ChatState (Maybe TeamId)
csCurrentTeamId
(TeamId -> MH ()) -> MH ()
foreachTeam forall a b. (a -> b) -> a -> b
$ \TeamId
tId -> do
Maybe ChannelId
cId <- forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use (TeamId -> SimpleGetter ChatState (Maybe ChannelId)
csCurrentChannelId TeamId
tId)
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (forall a. a -> Maybe a
Just (Post -> ChannelId
postChannelId Post
p) forall a. Eq a => a -> a -> Bool
== Maybe ChannelId
cId Bool -> Bool -> Bool
&& forall a. a -> Maybe a
Just TeamId
tId forall a. Eq a => a -> a -> Bool
== Maybe TeamId
currTid) forall a b. (a -> b) -> a -> b
$
Bool -> MH ()
updateViewed Bool
False
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (forall a. a -> Maybe a
Just (Post -> ChannelId
postChannelId Post
p) forall a. Eq a => a -> a -> Bool
/= Maybe ChannelId
cId) forall a b. (a -> b) -> a -> b
$
ChannelId -> Bool -> MH ()
showChannelInSidebar (Post
pforall s a. s -> Getting a s a -> a
^.Lens' Post ChannelId
postChannelIdL) Bool
False
| Bool
otherwise -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
WebsocketEventType
WMStatusChange
| Just Text
status <- WEData -> Maybe Text
wepStatus (WebsocketEvent -> WEData
weData WebsocketEvent
we)
, Just UserId
uId <- WEData -> Maybe UserId
wepUserId (WebsocketEvent -> WEData
weData WebsocketEvent
we) ->
UserId -> Text -> MH ()
setUserStatus UserId
uId Text
status
| Bool
otherwise -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
WebsocketEventType
WMUserAdded
| Just ChannelId
cId <- WEBroadcast -> Maybe ChannelId
webChannelId (WebsocketEvent -> WEBroadcast
weBroadcast WebsocketEvent
we) ->
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (WEData -> Maybe UserId
wepUserId (WebsocketEvent -> WEData
weData WebsocketEvent
we) forall a. Eq a => a -> a -> Bool
== forall a. a -> Maybe a
Just UserId
myId Bool -> Bool -> Bool
&&
Maybe TeamId -> Bool
inMyTeam (WEData -> Maybe TeamId
wepTeamId (WebsocketEvent -> WEData
weData WebsocketEvent
we))) forall a b. (a -> b) -> a -> b
$
ChannelId -> MH ()
handleChannelInvite ChannelId
cId
| Bool
otherwise -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
WebsocketEventType
WMNewUser
| Just UserId
uId <- WEData -> Maybe UserId
wepUserId forall a b. (a -> b) -> a -> b
$ WebsocketEvent -> WEData
weData WebsocketEvent
we ->
Seq UserId -> MH () -> MH ()
handleNewUsers (forall a. a -> Seq a
Seq.singleton UserId
uId) (forall (m :: * -> *) a. Monad m => a -> m a
return ())
| Bool
otherwise -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
WebsocketEventType
WMUserRemoved
| Just ChannelId
cId <- WEData -> Maybe ChannelId
wepChannelId (WebsocketEvent -> WEData
weData WebsocketEvent
we) ->
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (WEBroadcast -> Maybe UserId
webUserId (WebsocketEvent -> WEBroadcast
weBroadcast WebsocketEvent
we) forall a. Eq a => a -> a -> Bool
== forall a. a -> Maybe a
Just UserId
myId) forall a b. (a -> b) -> a -> b
$
ChannelId -> MH ()
removeChannelFromState ChannelId
cId
| Bool
otherwise -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
WebsocketEventType
WMTyping
| Just UserId
uId <- WEData -> Maybe UserId
wepUserId forall a b. (a -> b) -> a -> b
$ WebsocketEvent -> WEData
weData WebsocketEvent
we
, Just ChannelId
cId <- WEBroadcast -> Maybe ChannelId
webChannelId (WebsocketEvent -> WEBroadcast
weBroadcast WebsocketEvent
we) -> UserId -> ChannelId -> Maybe PostId -> MH ()
handleTypingUser UserId
uId ChannelId
cId (WEData -> Maybe PostId
wepParentId forall a b. (a -> b) -> a -> b
$ WebsocketEvent -> WEData
weData WebsocketEvent
we)
| Bool
otherwise -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
WebsocketEventType
WMChannelDeleted
| Just ChannelId
cId <- WEData -> Maybe ChannelId
wepChannelId (WebsocketEvent -> WEData
weData WebsocketEvent
we) ->
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Maybe TeamId -> Bool
inMyTeamOrDM (WEBroadcast -> Maybe TeamId
webTeamId (WebsocketEvent -> WEBroadcast
weBroadcast WebsocketEvent
we))) forall a b. (a -> b) -> a -> b
$
ChannelId -> MH ()
removeChannelFromState ChannelId
cId
| Bool
otherwise -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
WebsocketEventType
WMDirectAdded
| Just ChannelId
cId <- WEBroadcast -> Maybe ChannelId
webChannelId (WebsocketEvent -> WEBroadcast
weBroadcast WebsocketEvent
we) -> ChannelId -> MH ()
handleChannelInvite ChannelId
cId
| Bool
otherwise -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
WebsocketEventType
WMEphemeralMessage
| Just Post
p <- WEData -> Maybe Post
wepPost forall a b. (a -> b) -> a -> b
$ WebsocketEvent -> WEData
weData WebsocketEvent
we -> Text -> MH ()
postInfoMessage (UserText -> Text
sanitizeUserText forall a b. (a -> b) -> a -> b
$ Post
pforall s a. s -> Getting a s a -> a
^.Lens' Post UserText
postMessageL)
| Bool
otherwise -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
WebsocketEventType
WMPreferenceChanged
| Just Seq Preference
prefs <- WEData -> Maybe (Seq Preference)
wepPreferences (WebsocketEvent -> WEData
weData WebsocketEvent
we) ->
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ Preference -> MH ()
applyPreferenceChange Seq Preference
prefs
| Bool
otherwise -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
WebsocketEventType
WMPreferenceDeleted
| Just Seq Preference
pref <- WEData -> Maybe (Seq Preference)
wepPreferences (WebsocketEvent -> WEData
weData WebsocketEvent
we)
, Just Seq FlaggedPost
fps <- forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM Preference -> Maybe FlaggedPost
preferenceToFlaggedPost Seq Preference
pref ->
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ Seq FlaggedPost
fps forall a b. (a -> b) -> a -> b
$ \FlaggedPost
f ->
PostId -> Bool -> MH ()
updateMessageFlag (FlaggedPost -> PostId
flaggedPostId FlaggedPost
f) Bool
False
| Bool
otherwise -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
WebsocketEventType
WMReactionAdded
| Just Reaction
r <- WEData -> Maybe Reaction
wepReaction (WebsocketEvent -> WEData
weData WebsocketEvent
we)
, Just ChannelId
cId <- WEBroadcast -> Maybe ChannelId
webChannelId (WebsocketEvent -> WEBroadcast
weBroadcast WebsocketEvent
we) -> ChannelId -> [Reaction] -> MH ()
addReactions ChannelId
cId [Reaction
r]
| Bool
otherwise -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
WebsocketEventType
WMReactionRemoved
| Just Reaction
r <- WEData -> Maybe Reaction
wepReaction (WebsocketEvent -> WEData
weData WebsocketEvent
we)
, Just ChannelId
cId <- WEBroadcast -> Maybe ChannelId
webChannelId (WebsocketEvent -> WEBroadcast
weBroadcast WebsocketEvent
we) -> Reaction -> ChannelId -> MH ()
removeReaction Reaction
r ChannelId
cId
| Bool
otherwise -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
WebsocketEventType
WMChannelViewed
| Just ChannelId
cId <- WEData -> Maybe ChannelId
wepChannelId forall a b. (a -> b) -> a -> b
$ WebsocketEvent -> WEData
weData WebsocketEvent
we -> ChannelId -> MH ()
refreshChannelById ChannelId
cId
| Bool
otherwise -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
WebsocketEventType
WMChannelUpdated
| Just ChannelId
cId <- WEBroadcast -> Maybe ChannelId
webChannelId forall a b. (a -> b) -> a -> b
$ WebsocketEvent -> WEBroadcast
weBroadcast WebsocketEvent
we -> do
Maybe ClientChannel
mChan <- forall s (m :: * -> *) a.
MonadState s m =>
Getting (First a) s a -> m (Maybe a)
preuse (ChannelId -> Traversal' ChatState ClientChannel
csChannel(ChannelId
cId))
case Maybe ClientChannel
mChan of
Just ClientChannel
chan -> do
ChannelId -> MH ()
refreshChannelById ChannelId
cId
Maybe TeamId -> MH ()
updateSidebar (ClientChannel
chanforall s a. s -> Getting a s a -> a
^.Lens' ClientChannel ChannelInfo
ccInfoforall b c a. (b -> c) -> (a -> b) -> a -> c
.Lens' ChannelInfo (Maybe TeamId)
cdTeamId)
Maybe ClientChannel
Nothing -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
| Bool
otherwise -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
WebsocketEventType
WMGroupAdded
| Just ChannelId
cId <- WEBroadcast -> Maybe ChannelId
webChannelId (WebsocketEvent -> WEBroadcast
weBroadcast WebsocketEvent
we) -> ChannelId -> MH ()
handleChannelInvite ChannelId
cId
| Bool
otherwise -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
WebsocketEventType
WMChannelMemberUpdated
| Just ChannelMember
channelMember <- WEData -> Maybe ChannelMember
wepChannelMember forall a b. (a -> b) -> a -> b
$ WebsocketEvent -> WEData
weData WebsocketEvent
we ->
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (ChannelMember -> UserId
channelMemberUserId ChannelMember
channelMember forall a. Eq a => a -> a -> Bool
== UserId
myId) forall a b. (a -> b) -> a -> b
$
ChannelId -> ChannelNotifyProps -> MH ()
updateChannelNotifyProps
(ChannelMember -> ChannelId
channelMemberChannelId ChannelMember
channelMember)
(ChannelMember -> ChannelNotifyProps
channelMemberNotifyProps ChannelMember
channelMember)
| Bool
otherwise -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
WebsocketEventType
WMAddedToTeam
| Just TeamId
tId <- WEData -> Maybe TeamId
wepTeamId forall a b. (a -> b) -> a -> b
$ WebsocketEvent -> WEData
weData WebsocketEvent
we
, Just UserId
uId <- WEData -> Maybe UserId
wepUserId forall a b. (a -> b) -> a -> b
$ WebsocketEvent -> WEData
weData WebsocketEvent
we -> do
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (UserId
uId forall a. Eq a => a -> a -> Bool
== UserId
myId Bool -> Bool -> Bool
&& Bool -> Bool
not (TeamId -> Bool
memberOf TeamId
tId)) forall a b. (a -> b) -> a -> b
$ do
TeamId -> MH ()
handleJoinTeam TeamId
tId
| Bool
otherwise -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
WebsocketEventType
WMUpdateTeam
| Just TeamId
tId <- WEBroadcast -> Maybe TeamId
webTeamId forall a b. (a -> b) -> a -> b
$ WebsocketEvent -> WEBroadcast
weBroadcast WebsocketEvent
we -> do
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (TeamId -> Bool
memberOf TeamId
tId) forall a b. (a -> b) -> a -> b
$ do
TeamId -> MH ()
handleUpdateTeam TeamId
tId
| Bool
otherwise -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
WebsocketEventType
WMLeaveTeam
| Just TeamId
tId <- WEData -> Maybe TeamId
wepTeamId forall a b. (a -> b) -> a -> b
$ WebsocketEvent -> WEData
weData WebsocketEvent
we
, Just UserId
uId <- WEData -> Maybe UserId
wepUserId forall a b. (a -> b) -> a -> b
$ WebsocketEvent -> WEData
weData WebsocketEvent
we -> do
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (UserId
uId forall a. Eq a => a -> a -> Bool
== UserId
myId Bool -> Bool -> Bool
&& TeamId -> Bool
memberOf TeamId
tId) forall a b. (a -> b) -> a -> b
$ do
TeamId -> MH ()
handleLeaveTeam TeamId
tId
| Bool
otherwise -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
WebsocketEventType
WMTeamDeleted -> do
LogCategory -> Text -> MH ()
mhLog LogCategory
LogGeneral forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack forall a b. (a -> b) -> a -> b
$
String
"WMTeamDeleted event: " forall a. Semigroup a => a -> a -> a
<> forall a. Show a => a -> String
show WebsocketEvent
we
WebsocketEventType
WMUserUpdated
| Just User
user <- WEData -> Maybe User
wepUser (WebsocketEvent -> WEData
weData WebsocketEvent
we) -> do
User -> MH ()
handleUserUpdated User
user
(TeamId -> MH ()) -> MH ()
withCurrentTeam forall a b. (a -> b) -> a -> b
$ \TeamId
tId ->
TeamId -> (ChannelId -> ClientChannel -> MH ()) -> MH ()
withCurrentChannel TeamId
tId forall a b. (a -> b) -> a -> b
$ \ChannelId
cId ClientChannel
_ -> do
ChannelId -> MH ()
refreshChannelById ChannelId
cId
| Bool
otherwise -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
WebsocketEventType
WMChannelCreated -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
WebsocketEventType
WMEmojiAdded -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
WebsocketEventType
WMWebRTC -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
WebsocketEventType
WMHello -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
WebsocketEventType
WMAuthenticationChallenge -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
WebsocketEventType
WMUserRoleUpdated -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
WebsocketEventType
WMPluginStatusesChanged -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
WebsocketEventType
WMPluginEnabled -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
WebsocketEventType
WMPluginDisabled -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
WMUnknownEvent {} ->
LogCategory -> Text -> MH ()
mhLog LogCategory
LogWebsocket forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack forall a b. (a -> b) -> a -> b
$
String
"Websocket event not handled due to unknown event type: " forall a. Semigroup a => a -> a -> a
<> forall a. Show a => a -> String
show WebsocketEvent
we
handleWebsocketActionResponse :: WebsocketActionResponse -> MH ()
handleWebsocketActionResponse :: WebsocketActionResponse -> MH ()
handleWebsocketActionResponse WebsocketActionResponse
r =
case WebsocketActionResponse -> WebsocketActionStatus
warStatus WebsocketActionResponse
r of
WebsocketActionStatus
WebsocketActionStatusOK -> forall (m :: * -> *) a. Monad m => a -> m a
return ()