diff --git a/internal/common/notification/c.go b/internal/common/notification/c.go index 32f1bef7a..237ee425d 100644 --- a/internal/common/notification/c.go +++ b/internal/common/notification/c.go @@ -1,9 +1,12 @@ package notification import ( + "Open_IM/pkg/common/config" "Open_IM/pkg/common/constant" - pbChat "Open_IM/pkg/proto/msg" - "strings" + "Open_IM/pkg/proto/msg" + "Open_IM/pkg/proto/sdkws" + "context" + utils "github.com/OpenIMSDK/open_utils" ) type NotificationMsg struct { @@ -19,13 +22,12 @@ type NotificationMsg struct { } func Notification(n *NotificationMsg) { - var req pbChat.SendMsgReq + var req msg.SendMsgReq var msg sdkws.MsgData var offlineInfo sdkws.OfflinePushInfo var title, desc, ex string var pushSwitch, unReadCount bool var reliabilityLevel int - req.OperationID = n.OperationID msg.SendID = n.SendID msg.RecvID = n.RecvID msg.Content = n.Content @@ -272,18 +274,10 @@ func Notification(n *NotificationMsg) { offlineInfo.Ex = ex msg.OfflinePushInfo = &offlineInfo req.MsgData = &msg - etcdConn := rpc.GetDefaultConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImMsgName, req.OperationID) - if etcdConn == nil { - errMsg := req.OperationID + "getcdv3.GetDefaultConn == nil" - log.NewError(req.OperationID, errMsg) - return - } - client := pbChat.NewMsgClient(etcdConn) - reply, err := client.SendMsg(context.Background(), &req) - if err != nil { - log.NewError(req.OperationID, "SendMsg rpc failed, ", req.String(), err.Error()) - } else if reply.ErrCode != 0 { - log.NewError(req.OperationID, "SendMsg rpc failed, ", req.String(), reply.ErrCode, reply.ErrMsg) - } + _, err := sendMsg(context.Background(), &req) +} + +func sendMsg(ctx context.Context, req *msg.SendMsgReq) (msg.SendMsgResp, error) { + } diff --git a/internal/common/notification/conversation.go b/internal/common/notification/conversation.go index 88d56f10a..1f87b3263 100644 --- a/internal/common/notification/conversation.go +++ b/internal/common/notification/conversation.go @@ -1,9 +1,10 @@ -package msg +package notification import ( "Open_IM/pkg/common/config" "Open_IM/pkg/common/constant" "Open_IM/pkg/common/log" + "Open_IM/pkg/common/tracelog" sdkws "Open_IM/pkg/proto/sdkws" "Open_IM/pkg/utils" "context" @@ -42,7 +43,6 @@ func SetConversationNotification(operationID, sendID, recvID string, contentType // SetPrivate调用 func ConversationSetPrivateNotification(ctx context.Context, sendID, recvID string, isPrivateChat bool) { - log.NewInfo(operationID, utils.GetSelfFuncName()) conversationSetPrivateTips := &sdkws.ConversationSetPrivateTips{ RecvID: recvID, SendID: sendID, @@ -56,23 +56,23 @@ func ConversationSetPrivateNotification(ctx context.Context, sendID, recvID stri tipsMsg = config.Config.Notification.ConversationSetPrivate.DefaultTips.CloseTips } tips.DefaultTips = tipsMsg - SetConversationNotification(operationID, sendID, recvID, constant.ConversationPrivateChatNotification, conversationSetPrivateTips, tips) + SetConversationNotification(tracelog.GetOperationID(ctx), sendID, recvID, constant.ConversationPrivateChatNotification, conversationSetPrivateTips, tips) } // 会话改变 func ConversationChangeNotification(ctx context.Context, userID string) { - log.NewInfo(operationID, utils.GetSelfFuncName()) + ConversationChangedTips := &sdkws.ConversationUpdateTips{ UserID: userID, } var tips sdkws.TipsComm tips.DefaultTips = config.Config.Notification.ConversationOptUpdate.DefaultTips.Tips - SetConversationNotification(operationID, userID, userID, constant.ConversationOptChangeNotification, ConversationChangedTips, tips) + SetConversationNotification(tracelog.GetOperationID(ctx), userID, userID, constant.ConversationOptChangeNotification, ConversationChangedTips, tips) } -//会话未读数同步 -func ConversationUnreadChangeNotification(context context.Context, userID, conversationID string, updateUnreadCountTime int64) { - log.NewInfo(operationID, utils.GetSelfFuncName()) +// 会话未读数同步 +func ConversationUnreadChangeNotification(ctx context.Context, userID, conversationID string, updateUnreadCountTime int64) { + ConversationChangedTips := &sdkws.ConversationUpdateTips{ UserID: userID, ConversationIDList: []string{conversationID}, @@ -80,5 +80,5 @@ func ConversationUnreadChangeNotification(context context.Context, userID, conve } var tips sdkws.TipsComm tips.DefaultTips = config.Config.Notification.ConversationOptUpdate.DefaultTips.Tips - SetConversationNotification(operationID, userID, userID, constant.ConversationUnreadNotification, ConversationChangedTips, tips) + SetConversationNotification(tracelog.GetOperationID(ctx), userID, userID, constant.ConversationUnreadNotification, ConversationChangedTips, tips) } diff --git a/internal/common/notification/friend.go b/internal/common/notification/friend.go index 2ade47709..9af20a095 100644 --- a/internal/common/notification/friend.go +++ b/internal/common/notification/friend.go @@ -2,13 +2,12 @@ package notification import ( "Open_IM/internal/common/check" - "Open_IM/internal/rpc/msg" "Open_IM/pkg/common/config" "Open_IM/pkg/common/constant" "Open_IM/pkg/common/log" "Open_IM/pkg/common/tracelog" pbFriend "Open_IM/pkg/proto/friend" - sdkws "Open_IM/pkg/proto/sdkws" + "Open_IM/pkg/proto/sdkws" "Open_IM/pkg/utils" "context" "github.com/golang/protobuf/jsonpb" @@ -16,15 +15,11 @@ import ( ) func getFromToUserNickname(fromUserID, toUserID string) (string, string, error) { - users, err := check.GetUsersInfo(context.Background(), fromUserID, toUserID) + users, err := check.NewUserCheck().GetUsersInfoMap(context.Background(), []string{fromUserID, toUserID}, true) if err != nil { return "", "", nil } - if users[0].UserID == fromUserID { - return users[0].Nickname, users[1].Nickname, nil - } - return users[1].Nickname, users[0].Nickname, nil - + return users[fromUserID].Nickname, users[toUserID].Nickname, nil } func friendNotification(operationID, fromUserID, toUserID string, contentType int32, m proto.Message) { @@ -77,7 +72,7 @@ func friendNotification(operationID, fromUserID, toUserID string, contentType in return } - var n msg.NotificationMsg + var n NotificationMsg n.SendID = fromUserID n.RecvID = toUserID n.ContentType = contentType @@ -89,10 +84,10 @@ func friendNotification(operationID, fromUserID, toUserID string, contentType in log.Error(operationID, "Marshal failed ", err.Error(), tips.String()) return } - msg.Notification(&n) + Notification(&n) } -func FriendApplicationAddNotification(ctx context.Context, req *pbFriend.AddFriendReq) { +func FriendApplicationAddNotification(ctx context.Context, req *pbFriend.ApplyToAddFriendReq) { FriendApplicationTips := sdkws.FriendApplicationTips{FromToUserID: &sdkws.FromToUserID{}} FriendApplicationTips.FromToUserID.FromUserID = req.FromUserID FriendApplicationTips.FromToUserID.ToUserID = req.ToUserID @@ -117,7 +112,7 @@ func FriendApplicationRefusedNotification(ctx context.Context, req *pbFriend.Res func FriendAddedNotification(ctx context.Context, operationID, opUserID, fromUserID, toUserID string) { friendAddedTips := sdkws.FriendAddedTips{Friend: &sdkws.FriendInfo{}, OpUser: &sdkws.PublicUserInfo{}} - user, err := check.GetUsersInfo(context.Background(), opUserID) + user, err := check.NewUserCheck().GetUsersInfos(context.Background(), []string{opUserID}, true) if err != nil { return } diff --git a/internal/common/notification/group.go b/internal/common/notification/group.go index c3982ed6d..e51b08732 100644 --- a/internal/common/notification/group.go +++ b/internal/common/notification/group.go @@ -1,13 +1,10 @@ package notification import ( - "Open_IM/internal/rpc/msg" "Open_IM/pkg/common/config" "Open_IM/pkg/common/constant" - imdb "Open_IM/pkg/common/db/mysql_model/im_mysql_model" "Open_IM/pkg/common/log" "Open_IM/pkg/common/tokenverify" - utils2 "Open_IM/pkg/common/utils" pbGroup "Open_IM/pkg/proto/group" "Open_IM/pkg/proto/sdkws" "Open_IM/pkg/utils" @@ -17,13 +14,6 @@ import ( "google.golang.org/protobuf/types/known/wrapperspb" ) -//message GroupCreatedTips{ -// GroupInfo Group = 1; -// GroupMemberFullInfo Creator = 2; -// repeated GroupMemberFullInfo MemberList = 3; -// uint64 OperationTime = 4; -//} creator->group - func setOpUserInfo(opUserID, groupID string, groupMemberInfo *sdkws.GroupMemberFullInfo) error { if tokenverify.IsManagerUserID(opUserID) { u, err := imdb.GetUserByUserID(opUserID) @@ -182,7 +172,7 @@ func groupNotification(contentType int32, m proto.Message, sendID, groupID, recv return } - var n msg.NotificationMsg + var n NotificationMsg n.SendID = sendID if groupID != "" { n.RecvID = groupID @@ -207,7 +197,7 @@ func groupNotification(contentType int32, m proto.Message, sendID, groupID, recv log.Error(operationID, "Marshal failed ", err.Error(), tips.String()) return } - msg.Notification(&n) + Notification(&n) } // 创建群后调用 @@ -574,26 +564,6 @@ func MemberInvitedNotification(operationID, groupID, opUserID, reason string, in groupNotification(constant.MemberInvitedNotification, &MemberInvitedTips, opUserID, groupID, "", operationID) } -//message GroupInfoChangedTips{ -// int32 ChangedType = 1; //bitwise operators: 1:groupName; 10:Notification 100:Introduction; 1000:FaceUrl -// GroupInfo Group = 2; -// GroupMemberFullInfo OpUser = 3; -//} - -//message MemberLeaveTips{ -// GroupInfo Group = 1; -// GroupMemberFullInfo LeaverUser = 2; -// uint64 OperationTime = 3; -//} - -//群成员退群后调用 - -// message MemberEnterTips{ -// GroupInfo Group = 1; -// GroupMemberFullInfo EntrantUser = 2; -// uint64 OperationTime = 3; -// } -// // 群成员主动申请进群,管理员同意后调用, func MemberEnterNotification(ctx context.Context, req *pbGroup.GroupApplicationResponseReq) { MemberEnterTips := sdkws.MemberEnterTips{Group: &sdkws.GroupInfo{}, EntrantUser: &sdkws.GroupMemberFullInfo{}} diff --git a/internal/common/notification/msg.go b/internal/common/notification/msg.go index a846ce738..23a78c135 100644 --- a/internal/common/notification/msg.go +++ b/internal/common/notification/msg.go @@ -1,7 +1,6 @@ package notification import ( - "Open_IM/internal/rpc/msg" "Open_IM/pkg/common/constant" "Open_IM/pkg/common/log" sdkws "Open_IM/pkg/proto/sdkws" @@ -32,7 +31,7 @@ func MessageNotification(operationID, sendID, recvID string, contentType int32, } tips.JsonDetail, _ = marshaler.MarshalToString(m) - var n msg.NotificationMsg + var n NotificationMsg n.SendID = sendID n.RecvID = recvID n.ContentType = contentType @@ -44,5 +43,5 @@ func MessageNotification(operationID, sendID, recvID string, contentType int32, log.Error(operationID, "Marshal failed ", err.Error(), tips.String()) return } - msg.Notification(&n) + Notification(&n) } diff --git a/internal/common/notification/super_group.go b/internal/common/notification/super_group.go index 19d08dd98..61130a290 100644 --- a/internal/common/notification/super_group.go +++ b/internal/common/notification/super_group.go @@ -1,7 +1,6 @@ package notification import ( - "Open_IM/internal/rpc/msg" "Open_IM/pkg/common/constant" "Open_IM/pkg/common/log" //sdk "Open_IM/pkg/proto/sdkws" @@ -11,7 +10,7 @@ import ( ) func SuperGroupNotification(operationID, sendID, recvID string) { - n := &msg.NotificationMsg{ + n := &NotificationMsg{ SendID: sendID, RecvID: recvID, MsgFrom: constant.SysMsgType, @@ -20,5 +19,5 @@ func SuperGroupNotification(operationID, sendID, recvID string) { OperationID: operationID, } log.NewInfo(operationID, utils.GetSelfFuncName(), string(n.Content)) - msg.Notification(n) + Notification(n) } diff --git a/internal/rpc/friend/friend.go b/internal/rpc/friend/friend.go index 28b146281..3b99ede9d 100644 --- a/internal/rpc/friend/friend.go +++ b/internal/rpc/friend/friend.go @@ -128,7 +128,7 @@ func (s *friendServer) ImportFriends(ctx context.Context, req *pbFriend.ImportFr if err := tokenverify.CheckAdmin(ctx); err != nil { return nil, err } - if _, err := check.GetUsersInfo(ctx, req.OwnerUserID, req.FriendUserIDs); err != nil { + if _, err := check.NewUserCheck().GetUsersInfos(ctx, append([]string{req.OwnerUserID}, req.FriendUserIDs...), true); err != nil { return nil, err } diff --git a/internal/rpc/group/group.go b/internal/rpc/group/group.go index 85119fd82..4adb96647 100644 --- a/internal/rpc/group/group.go +++ b/internal/rpc/group/group.go @@ -2,7 +2,7 @@ package group import ( "Open_IM/internal/common/check" - chat "Open_IM/internal/rpc/msg" + "Open_IM/internal/common/notification" "Open_IM/pkg/common/constant" "Open_IM/pkg/common/db/cache" "Open_IM/pkg/common/db/controller" @@ -281,11 +281,11 @@ func (s *groupServer) CreateGroup(ctx context.Context, req *pbGroup.CreateGroupR if req.GroupInfo.GroupType == constant.SuperGroup { go func() { for _, userID := range userIDs { - chat.SuperGroupNotification(tracelog.GetOperationID(ctx), userID, userID) + notification.SuperGroupNotification(tracelog.GetOperationID(ctx), userID, userID) } }() } else { - chat.GroupCreatedNotification(tracelog.GetOperationID(ctx), tracelog.GetOpUserID(ctx), group.GroupID, userIDs) + notification.GroupCreatedNotification(tracelog.GetOperationID(ctx), tracelog.GetOpUserID(ctx), group.GroupID, userIDs) } return resp, nil } @@ -379,7 +379,7 @@ func (s *groupServer) InviteUserToGroup(ctx context.Context, req *pbGroup.Invite return nil, err } for _, request := range requests { - chat.JoinGroupApplicationNotification(ctx, &pbGroup.JoinGroupReq{ + notification.JoinGroupApplicationNotification(ctx, &pbGroup.JoinGroupReq{ GroupID: request.GroupID, ReqMessage: request.ReqMsg, JoinSource: request.JoinSource, @@ -395,7 +395,7 @@ func (s *groupServer) InviteUserToGroup(ctx context.Context, req *pbGroup.Invite return nil, err } for _, userID := range req.InvitedUserIDs { - chat.SuperGroupNotification(tracelog.GetOperationID(ctx), userID, userID) + notification.SuperGroupNotification(tracelog.GetOperationID(ctx), userID, userID) } } else { opUserID := tracelog.GetOpUserID(ctx) @@ -416,7 +416,7 @@ func (s *groupServer) InviteUserToGroup(ctx context.Context, req *pbGroup.Invite if err := s.GroupInterface.CreateGroup(ctx, nil, groupMembers); err != nil { return nil, err } - chat.MemberInvitedNotification(tracelog.GetOperationID(ctx), req.GroupID, tracelog.GetOpUserID(ctx), req.Reason, req.InvitedUserIDs) + notification.MemberInvitedNotification(tracelog.GetOperationID(ctx), req.GroupID, tracelog.GetOpUserID(ctx), req.Reason, req.InvitedUserIDs) } return resp, nil } @@ -493,7 +493,7 @@ func (s *groupServer) KickGroupMember(ctx context.Context, req *pbGroup.KickGrou } go func() { for _, userID := range req.KickedUserIDs { - chat.SuperGroupNotification(tracelog.GetOperationID(ctx), userID, userID) + notification.SuperGroupNotification(tracelog.GetOperationID(ctx), userID, userID) } }() } else { @@ -533,7 +533,7 @@ func (s *groupServer) KickGroupMember(ctx context.Context, req *pbGroup.KickGrou if err := s.GroupInterface.DeleteGroupMember(ctx, group.GroupID, req.KickedUserIDs); err != nil { return nil, err } - chat.MemberKickedNotification(req, req.KickedUserIDs) + notification.MemberKickedNotification(req, req.KickedUserIDs) } return resp, nil } @@ -700,10 +700,10 @@ func (s *groupServer) GroupApplicationResponse(ctx context.Context, req *pbGroup } if !join { if req.HandleResult == constant.GroupResponseAgree { - chat.GroupApplicationAcceptedNotification(req) - chat.MemberEnterNotification(ctx, req) + notification.GroupApplicationAcceptedNotification(req) + notification.MemberEnterNotification(ctx, req) } else if req.HandleResult == constant.GroupResponseRefuse { - chat.GroupApplicationRejectedNotification(req) + notification.GroupApplicationRejectedNotification(req) } } return resp, nil @@ -741,7 +741,7 @@ func (s *groupServer) JoinGroup(ctx context.Context, req *pbGroup.JoinGroupReq) if err := s.GroupInterface.CreateGroup(ctx, nil, []*relationTb.GroupMemberModel{groupMember}); err != nil { return nil, err } - chat.MemberEnterDirectlyNotification(req.GroupID, tracelog.GetOpUserID(ctx), tracelog.GetOperationID(ctx)) + notification.MemberEnterDirectlyNotification(req.GroupID, tracelog.GetOpUserID(ctx), tracelog.GetOperationID(ctx)) return resp, nil } groupRequest := relationTb.GroupRequestModel{ @@ -754,7 +754,7 @@ func (s *groupServer) JoinGroup(ctx context.Context, req *pbGroup.JoinGroupReq) if err := s.GroupInterface.CreateGroupRequest(ctx, []*relationTb.GroupRequestModel{&groupRequest}); err != nil { return nil, err } - chat.JoinGroupApplicationNotification(ctx, req) + notification.JoinGroupApplicationNotification(ctx, req) return resp, nil } @@ -768,13 +768,13 @@ func (s *groupServer) QuitGroup(ctx context.Context, req *pbGroup.QuitGroupReq) if err := s.GroupInterface.DeleteSuperGroupMember(ctx, req.GroupID, []string{tracelog.GetOpUserID(ctx)}); err != nil { return nil, err } - chat.SuperGroupNotification(tracelog.GetOperationID(ctx), tracelog.GetOpUserID(ctx), tracelog.GetOpUserID(ctx)) + notification.SuperGroupNotification(tracelog.GetOperationID(ctx), tracelog.GetOpUserID(ctx), tracelog.GetOpUserID(ctx)) } else { _, err := s.GroupInterface.TakeGroupMember(ctx, req.GroupID, tracelog.GetOpUserID(ctx)) if err != nil { return nil, err } - chat.MemberQuitNotification(req) + notification.MemberQuitNotification(req) } return resp, nil } @@ -808,7 +808,7 @@ func (s *groupServer) SetGroupInfo(ctx context.Context, req *pbGroup.SetGroupInf if err != nil { return nil, err } - chat.GroupInfoSetNotification(tracelog.GetOperationID(ctx), tracelog.GetOpUserID(ctx), req.GroupInfoForSet.GroupID, group.GroupName, group.Notification, group.Introduction, group.FaceURL, req.GroupInfoForSet.NeedVerification) + notification.GroupInfoSetNotification(tracelog.GetOperationID(ctx), tracelog.GetOpUserID(ctx), req.GroupInfoForSet.GroupID, group.GroupName, group.Notification, group.Introduction, group.FaceURL, req.GroupInfoForSet.NeedVerification) if req.GroupInfoForSet.Notification != "" { s.GroupNotification(ctx, group.GroupID) } @@ -858,7 +858,7 @@ func (s *groupServer) TransferGroupOwner(ctx context.Context, req *pbGroup.Trans if err := s.GroupInterface.TransferGroupOwner(ctx, req.GroupID, req.OldOwnerUserID, req.NewOwnerUserID, newOwner.RoleLevel); err != nil { return nil, err } - chat.GroupOwnerTransferredNotification(req) + notification.GroupOwnerTransferredNotification(req) return resp, nil } @@ -990,7 +990,7 @@ func (s *groupServer) DismissGroup(ctx context.Context, req *pbGroup.DismissGrou return nil, err } } else { - chat.GroupDismissedNotification(req) + notification.GroupDismissedNotification(req) } return resp, nil } @@ -1014,7 +1014,7 @@ func (s *groupServer) MuteGroupMember(ctx context.Context, req *pbGroup.MuteGrou if err := s.GroupInterface.UpdateGroupMember(ctx, member.GroupID, member.UserID, data); err != nil { return nil, err } - chat.GroupMemberMutedNotification(tracelog.GetOperationID(ctx), tracelog.GetOpUserID(ctx), req.GroupID, req.UserID, req.MutedSeconds) + notification.GroupMemberMutedNotification(tracelog.GetOperationID(ctx), tracelog.GetOpUserID(ctx), req.GroupID, req.UserID, req.MutedSeconds) return resp, nil } @@ -1037,7 +1037,7 @@ func (s *groupServer) CancelMuteGroupMember(ctx context.Context, req *pbGroup.Ca if err := s.GroupInterface.UpdateGroupMember(ctx, member.GroupID, member.UserID, data); err != nil { return nil, err } - chat.GroupMemberCancelMutedNotification(tracelog.GetOperationID(ctx), tracelog.GetOpUserID(ctx), req.GroupID, req.UserID) + notification.GroupMemberCancelMutedNotification(tracelog.GetOperationID(ctx), tracelog.GetOpUserID(ctx), req.GroupID, req.UserID) return resp, nil } @@ -1049,7 +1049,7 @@ func (s *groupServer) MuteGroup(ctx context.Context, req *pbGroup.MuteGroupReq) if err := s.GroupInterface.UpdateGroup(ctx, req.GroupID, UpdateGroupStatusMap(constant.GroupStatusMuted)); err != nil { return nil, err } - chat.GroupMutedNotification(tracelog.GetOperationID(ctx), tracelog.GetOpUserID(ctx), req.GroupID) + notification.GroupMutedNotification(tracelog.GetOperationID(ctx), tracelog.GetOpUserID(ctx), req.GroupID) return resp, nil } @@ -1061,7 +1061,7 @@ func (s *groupServer) CancelMuteGroup(ctx context.Context, req *pbGroup.CancelMu if err := s.GroupInterface.UpdateGroup(ctx, req.GroupID, UpdateGroupStatusMap(constant.GroupOk)); err != nil { return nil, err } - chat.GroupCancelMutedNotification(tracelog.GetOperationID(ctx), tracelog.GetOpUserID(ctx), req.GroupID) + notification.GroupCancelMutedNotification(tracelog.GetOperationID(ctx), tracelog.GetOpUserID(ctx), req.GroupID) return resp, nil } @@ -1138,7 +1138,7 @@ func (s *groupServer) SetGroupMemberInfo(ctx context.Context, req *pbGroup.SetGr return nil, err } for _, member := range req.Members { - chat.GroupMemberInfoSetNotification(tracelog.GetOperationID(ctx), tracelog.GetOpUserID(ctx), member.GroupID, member.UserID) + notification.GroupMemberInfoSetNotification(tracelog.GetOperationID(ctx), tracelog.GetOpUserID(ctx), member.GroupID, member.UserID) } return resp, nil } diff --git a/internal/rpc/msg/send_msg.go b/internal/rpc/msg/send_msg.go index f2c0ee3a4..e94b1b9dd 100644 --- a/internal/rpc/msg/send_msg.go +++ b/internal/rpc/msg/send_msg.go @@ -95,6 +95,7 @@ func GetGroupInfo(ctx context.Context, groupID string) (sdkws.GroupInfo, error) func GetGroupMemberInfo(ctx context.Context, groupID string, userID string) (*sdkws.GroupMemberFullInfo, error) { } + func GetSuperGroupMsg(ctx context.Context, groupID string, seq uint32) (*sdkws.MsgData, error) { }