From 49982d75180af3ca333ae0ba3c3edf7e6fde0de2 Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Sun, 22 Oct 2023 14:49:27 +0200 Subject: [PATCH 01/11] fixed migrate20230904100000 pointing to the wrong table --- server/backend/migration/20230904100000.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/server/backend/migration/20230904100000.go b/server/backend/migration/20230904100000.go index c744432c..bd62bf8e 100644 --- a/server/backend/migration/20230904100000.go +++ b/server/backend/migration/20230904100000.go @@ -17,6 +17,11 @@ type NewsSource struct { Hook null.String `gorm:"column:hook;type:char;size:12;"` } +// TableName sets the insert table name for this struct type +func (n *NewsSource) TableName() string { + return "newsSource" +} + // migrate20230904100000 // migrates the crontab from kino to movie crontab func (m TumDBMigrator) migrate20230904100000() *gormigrate.Migration { From 138bc7ea2e36cb1c8e7a9067e766d54961e9dcbf Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Sun, 22 Oct 2023 15:27:39 +0200 Subject: [PATCH 02/11] removed an automigration causing migrations to not be applied --- server/backend/migration/20230904100000.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/server/backend/migration/20230904100000.go b/server/backend/migration/20230904100000.go index bd62bf8e..fb412917 100644 --- a/server/backend/migration/20230904100000.go +++ b/server/backend/migration/20230904100000.go @@ -38,9 +38,6 @@ func (m TumDBMigrator) migrate20230904100000() *gormigrate.Migration { if err := SafeEnumAdd(tx, &model.Crontab{}, "type", "movie"); err != nil { return err } - if err := tx.AutoMigrate(&NewsSource{}); err != nil { - return err - } // tu film news source is now inlined if err := tx.Delete(&NewsSource{Source: 2}).Error; err != nil { return err From cf1f22ab46c89c30da0d70bde2ba48c3e5567a32 Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Sun, 22 Oct 2023 16:53:49 +0200 Subject: [PATCH 03/11] removed the studyrooms rpc (#271) --- server/api/tumdev/campus_backend.pb.go | 1309 +++++++---------- server/api/tumdev/campus_backend.pb.gw.go | 69 - server/api/tumdev/campus_backend.proto | 23 - server/api/tumdev/campus_backend.swagger.json | 78 - server/api/tumdev/campus_backend_grpc.pb.go | 37 - 5 files changed, 494 insertions(+), 1022 deletions(-) diff --git a/server/api/tumdev/campus_backend.pb.go b/server/api/tumdev/campus_backend.pb.go index b7fd2369..c22f7b97 100644 --- a/server/api/tumdev/campus_backend.pb.go +++ b/server/api/tumdev/campus_backend.pb.go @@ -117,7 +117,7 @@ func (x CreateFeedbackRequest_Recipient) Number() protoreflect.EnumNumber { // Deprecated: Use CreateFeedbackRequest_Recipient.Descriptor instead. func (CreateFeedbackRequest_Recipient) EnumDescriptor() ([]byte, []int) { - return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{57, 0} + return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{53, 0} } type CreateDeviceRequest struct { @@ -3136,241 +3136,6 @@ func (x *GetUpdateNoteReply) GetVersionName() string { return "" } -type ListStudyRoomsRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *ListStudyRoomsRequest) Reset() { - *x = ListStudyRoomsRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_tumdev_campus_backend_proto_msgTypes[50] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ListStudyRoomsRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ListStudyRoomsRequest) ProtoMessage() {} - -func (x *ListStudyRoomsRequest) ProtoReflect() protoreflect.Message { - mi := &file_tumdev_campus_backend_proto_msgTypes[50] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ListStudyRoomsRequest.ProtoReflect.Descriptor instead. -func (*ListStudyRoomsRequest) Descriptor() ([]byte, []int) { - return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{50} -} - -type ListStudyRoomsReply struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Rooms []*StudyRoomMsgElement `protobuf:"bytes,1,rep,name=rooms,proto3" json:"rooms,omitempty"` -} - -func (x *ListStudyRoomsReply) Reset() { - *x = ListStudyRoomsReply{} - if protoimpl.UnsafeEnabled { - mi := &file_tumdev_campus_backend_proto_msgTypes[51] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ListStudyRoomsReply) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ListStudyRoomsReply) ProtoMessage() {} - -func (x *ListStudyRoomsReply) ProtoReflect() protoreflect.Message { - mi := &file_tumdev_campus_backend_proto_msgTypes[51] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ListStudyRoomsReply.ProtoReflect.Descriptor instead. -func (*ListStudyRoomsReply) Descriptor() ([]byte, []int) { - return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{51} -} - -func (x *ListStudyRoomsReply) GetRooms() []*StudyRoomMsgElement { - if x != nil { - return x.Rooms - } - return nil -} - -type StudyRoomMsgElement struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - Details string `protobuf:"bytes,3,opt,name=details,proto3" json:"details,omitempty"` - Rooms []*StudyRoom `protobuf:"bytes,4,rep,name=rooms,proto3" json:"rooms,omitempty"` -} - -func (x *StudyRoomMsgElement) Reset() { - *x = StudyRoomMsgElement{} - if protoimpl.UnsafeEnabled { - mi := &file_tumdev_campus_backend_proto_msgTypes[52] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *StudyRoomMsgElement) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*StudyRoomMsgElement) ProtoMessage() {} - -func (x *StudyRoomMsgElement) ProtoReflect() protoreflect.Message { - mi := &file_tumdev_campus_backend_proto_msgTypes[52] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use StudyRoomMsgElement.ProtoReflect.Descriptor instead. -func (*StudyRoomMsgElement) Descriptor() ([]byte, []int) { - return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{52} -} - -func (x *StudyRoomMsgElement) GetId() int32 { - if x != nil { - return x.Id - } - return 0 -} - -func (x *StudyRoomMsgElement) GetName() string { - if x != nil { - return x.Name - } - return "" -} - -func (x *StudyRoomMsgElement) GetDetails() string { - if x != nil { - return x.Details - } - return "" -} - -func (x *StudyRoomMsgElement) GetRooms() []*StudyRoom { - if x != nil { - return x.Rooms - } - return nil -} - -type StudyRoom struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - GroupId int32 `protobuf:"varint,1,opt,name=group_id,json=groupId,proto3" json:"group_id,omitempty"` - RoomId int32 `protobuf:"varint,2,opt,name=room_id,json=roomId,proto3" json:"room_id,omitempty"` - RoomCode string `protobuf:"bytes,3,opt,name=room_code,json=roomCode,proto3" json:"room_code,omitempty"` - RoomName string `protobuf:"bytes,4,opt,name=room_name,json=roomName,proto3" json:"room_name,omitempty"` - BuildingName string `protobuf:"bytes,5,opt,name=building_name,json=buildingName,proto3" json:"building_name,omitempty"` -} - -func (x *StudyRoom) Reset() { - *x = StudyRoom{} - if protoimpl.UnsafeEnabled { - mi := &file_tumdev_campus_backend_proto_msgTypes[53] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *StudyRoom) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*StudyRoom) ProtoMessage() {} - -func (x *StudyRoom) ProtoReflect() protoreflect.Message { - mi := &file_tumdev_campus_backend_proto_msgTypes[53] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use StudyRoom.ProtoReflect.Descriptor instead. -func (*StudyRoom) Descriptor() ([]byte, []int) { - return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{53} -} - -func (x *StudyRoom) GetGroupId() int32 { - if x != nil { - return x.GroupId - } - return 0 -} - -func (x *StudyRoom) GetRoomId() int32 { - if x != nil { - return x.RoomId - } - return 0 -} - -func (x *StudyRoom) GetRoomCode() string { - if x != nil { - return x.RoomCode - } - return "" -} - -func (x *StudyRoom) GetRoomName() string { - if x != nil { - return x.RoomName - } - return "" -} - -func (x *StudyRoom) GetBuildingName() string { - if x != nil { - return x.BuildingName - } - return "" -} - type ListMoviesRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -3385,7 +3150,7 @@ type ListMoviesRequest struct { func (x *ListMoviesRequest) Reset() { *x = ListMoviesRequest{} if protoimpl.UnsafeEnabled { - mi := &file_tumdev_campus_backend_proto_msgTypes[54] + mi := &file_tumdev_campus_backend_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3398,7 +3163,7 @@ func (x *ListMoviesRequest) String() string { func (*ListMoviesRequest) ProtoMessage() {} func (x *ListMoviesRequest) ProtoReflect() protoreflect.Message { - mi := &file_tumdev_campus_backend_proto_msgTypes[54] + mi := &file_tumdev_campus_backend_proto_msgTypes[50] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3411,7 +3176,7 @@ func (x *ListMoviesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListMoviesRequest.ProtoReflect.Descriptor instead. func (*ListMoviesRequest) Descriptor() ([]byte, []int) { - return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{54} + return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{50} } func (x *ListMoviesRequest) GetLastId() int32 { @@ -3439,7 +3204,7 @@ type ListMoviesReply struct { func (x *ListMoviesReply) Reset() { *x = ListMoviesReply{} if protoimpl.UnsafeEnabled { - mi := &file_tumdev_campus_backend_proto_msgTypes[55] + mi := &file_tumdev_campus_backend_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3452,7 +3217,7 @@ func (x *ListMoviesReply) String() string { func (*ListMoviesReply) ProtoMessage() {} func (x *ListMoviesReply) ProtoReflect() protoreflect.Message { - mi := &file_tumdev_campus_backend_proto_msgTypes[55] + mi := &file_tumdev_campus_backend_proto_msgTypes[51] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3465,7 +3230,7 @@ func (x *ListMoviesReply) ProtoReflect() protoreflect.Message { // Deprecated: Use ListMoviesReply.ProtoReflect.Descriptor instead. func (*ListMoviesReply) Descriptor() ([]byte, []int) { - return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{55} + return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{51} } func (x *ListMoviesReply) GetMovies() []*Movie { @@ -3503,7 +3268,7 @@ type Movie struct { func (x *Movie) Reset() { *x = Movie{} if protoimpl.UnsafeEnabled { - mi := &file_tumdev_campus_backend_proto_msgTypes[56] + mi := &file_tumdev_campus_backend_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3516,7 +3281,7 @@ func (x *Movie) String() string { func (*Movie) ProtoMessage() {} func (x *Movie) ProtoReflect() protoreflect.Message { - mi := &file_tumdev_campus_backend_proto_msgTypes[56] + mi := &file_tumdev_campus_backend_proto_msgTypes[52] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3529,7 +3294,7 @@ func (x *Movie) ProtoReflect() protoreflect.Message { // Deprecated: Use Movie.ProtoReflect.Descriptor instead. func (*Movie) Descriptor() ([]byte, []int) { - return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{56} + return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{52} } func (x *Movie) GetMovieId() int64 { @@ -3656,7 +3421,7 @@ type CreateFeedbackRequest struct { func (x *CreateFeedbackRequest) Reset() { *x = CreateFeedbackRequest{} if protoimpl.UnsafeEnabled { - mi := &file_tumdev_campus_backend_proto_msgTypes[57] + mi := &file_tumdev_campus_backend_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3669,7 +3434,7 @@ func (x *CreateFeedbackRequest) String() string { func (*CreateFeedbackRequest) ProtoMessage() {} func (x *CreateFeedbackRequest) ProtoReflect() protoreflect.Message { - mi := &file_tumdev_campus_backend_proto_msgTypes[57] + mi := &file_tumdev_campus_backend_proto_msgTypes[53] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3682,7 +3447,7 @@ func (x *CreateFeedbackRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateFeedbackRequest.ProtoReflect.Descriptor instead. func (*CreateFeedbackRequest) Descriptor() ([]byte, []int) { - return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{57} + return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{53} } func (x *CreateFeedbackRequest) GetRecipient() CreateFeedbackRequest_Recipient { @@ -3746,7 +3511,7 @@ type Coordinate struct { func (x *Coordinate) Reset() { *x = Coordinate{} if protoimpl.UnsafeEnabled { - mi := &file_tumdev_campus_backend_proto_msgTypes[58] + mi := &file_tumdev_campus_backend_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3759,7 +3524,7 @@ func (x *Coordinate) String() string { func (*Coordinate) ProtoMessage() {} func (x *Coordinate) ProtoReflect() protoreflect.Message { - mi := &file_tumdev_campus_backend_proto_msgTypes[58] + mi := &file_tumdev_campus_backend_proto_msgTypes[54] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3772,7 +3537,7 @@ func (x *Coordinate) ProtoReflect() protoreflect.Message { // Deprecated: Use Coordinate.ProtoReflect.Descriptor instead. func (*Coordinate) Descriptor() ([]byte, []int) { - return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{58} + return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{54} } func (x *Coordinate) GetLatitude() float64 { @@ -3798,7 +3563,7 @@ type CreateFeedbackReply struct { func (x *CreateFeedbackReply) Reset() { *x = CreateFeedbackReply{} if protoimpl.UnsafeEnabled { - mi := &file_tumdev_campus_backend_proto_msgTypes[59] + mi := &file_tumdev_campus_backend_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3811,7 +3576,7 @@ func (x *CreateFeedbackReply) String() string { func (*CreateFeedbackReply) ProtoMessage() {} func (x *CreateFeedbackReply) ProtoReflect() protoreflect.Message { - mi := &file_tumdev_campus_backend_proto_msgTypes[59] + mi := &file_tumdev_campus_backend_proto_msgTypes[55] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3824,7 +3589,7 @@ func (x *CreateFeedbackReply) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateFeedbackReply.ProtoReflect.Descriptor instead. func (*CreateFeedbackReply) Descriptor() ([]byte, []int) { - return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{59} + return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{55} } type CreateFeedbackImageReply struct { @@ -3838,7 +3603,7 @@ type CreateFeedbackImageReply struct { func (x *CreateFeedbackImageReply) Reset() { *x = CreateFeedbackImageReply{} if protoimpl.UnsafeEnabled { - mi := &file_tumdev_campus_backend_proto_msgTypes[60] + mi := &file_tumdev_campus_backend_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3851,7 +3616,7 @@ func (x *CreateFeedbackImageReply) String() string { func (*CreateFeedbackImageReply) ProtoMessage() {} func (x *CreateFeedbackImageReply) ProtoReflect() protoreflect.Message { - mi := &file_tumdev_campus_backend_proto_msgTypes[60] + mi := &file_tumdev_campus_backend_proto_msgTypes[56] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3864,7 +3629,7 @@ func (x *CreateFeedbackImageReply) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateFeedbackImageReply.ProtoReflect.Descriptor instead. func (*CreateFeedbackImageReply) Descriptor() ([]byte, []int) { - return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{60} + return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{56} } func (x *CreateFeedbackImageReply) GetStatus() string { @@ -3886,7 +3651,7 @@ type CreateFeedbackImageRequest struct { func (x *CreateFeedbackImageRequest) Reset() { *x = CreateFeedbackImageRequest{} if protoimpl.UnsafeEnabled { - mi := &file_tumdev_campus_backend_proto_msgTypes[61] + mi := &file_tumdev_campus_backend_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3899,7 +3664,7 @@ func (x *CreateFeedbackImageRequest) String() string { func (*CreateFeedbackImageRequest) ProtoMessage() {} func (x *CreateFeedbackImageRequest) ProtoReflect() protoreflect.Message { - mi := &file_tumdev_campus_backend_proto_msgTypes[61] + mi := &file_tumdev_campus_backend_proto_msgTypes[57] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3912,7 +3677,7 @@ func (x *CreateFeedbackImageRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateFeedbackImageRequest.ProtoReflect.Descriptor instead. func (*CreateFeedbackImageRequest) Descriptor() ([]byte, []int) { - return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{61} + return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{57} } func (x *CreateFeedbackImageRequest) GetId() int32 { @@ -3940,7 +3705,7 @@ type GetMemberRequest struct { func (x *GetMemberRequest) Reset() { *x = GetMemberRequest{} if protoimpl.UnsafeEnabled { - mi := &file_tumdev_campus_backend_proto_msgTypes[62] + mi := &file_tumdev_campus_backend_proto_msgTypes[58] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3953,7 +3718,7 @@ func (x *GetMemberRequest) String() string { func (*GetMemberRequest) ProtoMessage() {} func (x *GetMemberRequest) ProtoReflect() protoreflect.Message { - mi := &file_tumdev_campus_backend_proto_msgTypes[62] + mi := &file_tumdev_campus_backend_proto_msgTypes[58] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3966,7 +3731,7 @@ func (x *GetMemberRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMemberRequest.ProtoReflect.Descriptor instead. func (*GetMemberRequest) Descriptor() ([]byte, []int) { - return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{62} + return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{58} } func (x *GetMemberRequest) GetLrzId() string { @@ -3989,7 +3754,7 @@ type GetMemberReply struct { func (x *GetMemberReply) Reset() { *x = GetMemberReply{} if protoimpl.UnsafeEnabled { - mi := &file_tumdev_campus_backend_proto_msgTypes[63] + mi := &file_tumdev_campus_backend_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4002,7 +3767,7 @@ func (x *GetMemberReply) String() string { func (*GetMemberReply) ProtoMessage() {} func (x *GetMemberReply) ProtoReflect() protoreflect.Message { - mi := &file_tumdev_campus_backend_proto_msgTypes[63] + mi := &file_tumdev_campus_backend_proto_msgTypes[59] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4015,7 +3780,7 @@ func (x *GetMemberReply) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMemberReply.ProtoReflect.Descriptor instead. func (*GetMemberReply) Descriptor() ([]byte, []int) { - return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{63} + return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{59} } func (x *GetMemberReply) GetLrzId() string { @@ -4050,7 +3815,7 @@ type GetUploadStatusRequest struct { func (x *GetUploadStatusRequest) Reset() { *x = GetUploadStatusRequest{} if protoimpl.UnsafeEnabled { - mi := &file_tumdev_campus_backend_proto_msgTypes[64] + mi := &file_tumdev_campus_backend_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4063,7 +3828,7 @@ func (x *GetUploadStatusRequest) String() string { func (*GetUploadStatusRequest) ProtoMessage() {} func (x *GetUploadStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_tumdev_campus_backend_proto_msgTypes[64] + mi := &file_tumdev_campus_backend_proto_msgTypes[60] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4076,7 +3841,7 @@ func (x *GetUploadStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetUploadStatusRequest.ProtoReflect.Descriptor instead. func (*GetUploadStatusRequest) Descriptor() ([]byte, []int) { - return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{64} + return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{60} } func (x *GetUploadStatusRequest) GetLrzId() string { @@ -4101,7 +3866,7 @@ type GetUploadStatusReply struct { func (x *GetUploadStatusReply) Reset() { *x = GetUploadStatusReply{} if protoimpl.UnsafeEnabled { - mi := &file_tumdev_campus_backend_proto_msgTypes[65] + mi := &file_tumdev_campus_backend_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4114,7 +3879,7 @@ func (x *GetUploadStatusReply) String() string { func (*GetUploadStatusReply) ProtoMessage() {} func (x *GetUploadStatusReply) ProtoReflect() protoreflect.Message { - mi := &file_tumdev_campus_backend_proto_msgTypes[65] + mi := &file_tumdev_campus_backend_proto_msgTypes[61] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4127,7 +3892,7 @@ func (x *GetUploadStatusReply) ProtoReflect() protoreflect.Message { // Deprecated: Use GetUploadStatusReply.ProtoReflect.Descriptor instead. func (*GetUploadStatusReply) Descriptor() ([]byte, []int) { - return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{65} + return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{61} } func (x *GetUploadStatusReply) GetFcmToken() string { @@ -4176,7 +3941,7 @@ type GetNotificationRequest struct { func (x *GetNotificationRequest) Reset() { *x = GetNotificationRequest{} if protoimpl.UnsafeEnabled { - mi := &file_tumdev_campus_backend_proto_msgTypes[66] + mi := &file_tumdev_campus_backend_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4189,7 +3954,7 @@ func (x *GetNotificationRequest) String() string { func (*GetNotificationRequest) ProtoMessage() {} func (x *GetNotificationRequest) ProtoReflect() protoreflect.Message { - mi := &file_tumdev_campus_backend_proto_msgTypes[66] + mi := &file_tumdev_campus_backend_proto_msgTypes[62] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4202,7 +3967,7 @@ func (x *GetNotificationRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetNotificationRequest.ProtoReflect.Descriptor instead. func (*GetNotificationRequest) Descriptor() ([]byte, []int) { - return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{66} + return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{62} } func (x *GetNotificationRequest) GetNotificationId() int32 { @@ -4227,7 +3992,7 @@ type GetNotificationReply struct { func (x *GetNotificationReply) Reset() { *x = GetNotificationReply{} if protoimpl.UnsafeEnabled { - mi := &file_tumdev_campus_backend_proto_msgTypes[67] + mi := &file_tumdev_campus_backend_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4240,7 +4005,7 @@ func (x *GetNotificationReply) String() string { func (*GetNotificationReply) ProtoMessage() {} func (x *GetNotificationReply) ProtoReflect() protoreflect.Message { - mi := &file_tumdev_campus_backend_proto_msgTypes[67] + mi := &file_tumdev_campus_backend_proto_msgTypes[63] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4253,7 +4018,7 @@ func (x *GetNotificationReply) ProtoReflect() protoreflect.Message { // Deprecated: Use GetNotificationReply.ProtoReflect.Descriptor instead. func (*GetNotificationReply) Descriptor() ([]byte, []int) { - return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{67} + return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{63} } func (x *GetNotificationReply) GetNotificationId() int32 { @@ -4302,7 +4067,7 @@ type GetNotificationConfirmRequest struct { func (x *GetNotificationConfirmRequest) Reset() { *x = GetNotificationConfirmRequest{} if protoimpl.UnsafeEnabled { - mi := &file_tumdev_campus_backend_proto_msgTypes[68] + mi := &file_tumdev_campus_backend_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4315,7 +4080,7 @@ func (x *GetNotificationConfirmRequest) String() string { func (*GetNotificationConfirmRequest) ProtoMessage() {} func (x *GetNotificationConfirmRequest) ProtoReflect() protoreflect.Message { - mi := &file_tumdev_campus_backend_proto_msgTypes[68] + mi := &file_tumdev_campus_backend_proto_msgTypes[64] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4328,7 +4093,7 @@ func (x *GetNotificationConfirmRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetNotificationConfirmRequest.ProtoReflect.Descriptor instead. func (*GetNotificationConfirmRequest) Descriptor() ([]byte, []int) { - return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{68} + return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{64} } func (x *GetNotificationConfirmRequest) GetNotificationId() int32 { @@ -4349,7 +4114,7 @@ type GetNotificationConfirmReply struct { func (x *GetNotificationConfirmReply) Reset() { *x = GetNotificationConfirmReply{} if protoimpl.UnsafeEnabled { - mi := &file_tumdev_campus_backend_proto_msgTypes[69] + mi := &file_tumdev_campus_backend_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4362,7 +4127,7 @@ func (x *GetNotificationConfirmReply) String() string { func (*GetNotificationConfirmReply) ProtoMessage() {} func (x *GetNotificationConfirmReply) ProtoReflect() protoreflect.Message { - mi := &file_tumdev_campus_backend_proto_msgTypes[69] + mi := &file_tumdev_campus_backend_proto_msgTypes[65] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4375,7 +4140,7 @@ func (x *GetNotificationConfirmReply) ProtoReflect() protoreflect.Message { // Deprecated: Use GetNotificationConfirmReply.ProtoReflect.Descriptor instead. func (*GetNotificationConfirmReply) Descriptor() ([]byte, []int) { - return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{69} + return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{65} } func (x *GetNotificationConfirmReply) GetStatus() string { @@ -4397,7 +4162,7 @@ type GetCanteenHeadCountRequest struct { func (x *GetCanteenHeadCountRequest) Reset() { *x = GetCanteenHeadCountRequest{} if protoimpl.UnsafeEnabled { - mi := &file_tumdev_campus_backend_proto_msgTypes[70] + mi := &file_tumdev_campus_backend_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4410,7 +4175,7 @@ func (x *GetCanteenHeadCountRequest) String() string { func (*GetCanteenHeadCountRequest) ProtoMessage() {} func (x *GetCanteenHeadCountRequest) ProtoReflect() protoreflect.Message { - mi := &file_tumdev_campus_backend_proto_msgTypes[70] + mi := &file_tumdev_campus_backend_proto_msgTypes[66] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4423,7 +4188,7 @@ func (x *GetCanteenHeadCountRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetCanteenHeadCountRequest.ProtoReflect.Descriptor instead. func (*GetCanteenHeadCountRequest) Descriptor() ([]byte, []int) { - return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{70} + return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{66} } func (x *GetCanteenHeadCountRequest) GetCanteenId() string { @@ -4451,7 +4216,7 @@ type GetCanteenHeadCountReply struct { func (x *GetCanteenHeadCountReply) Reset() { *x = GetCanteenHeadCountReply{} if protoimpl.UnsafeEnabled { - mi := &file_tumdev_campus_backend_proto_msgTypes[71] + mi := &file_tumdev_campus_backend_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4464,7 +4229,7 @@ func (x *GetCanteenHeadCountReply) String() string { func (*GetCanteenHeadCountReply) ProtoMessage() {} func (x *GetCanteenHeadCountReply) ProtoReflect() protoreflect.Message { - mi := &file_tumdev_campus_backend_proto_msgTypes[71] + mi := &file_tumdev_campus_backend_proto_msgTypes[67] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4477,7 +4242,7 @@ func (x *GetCanteenHeadCountReply) ProtoReflect() protoreflect.Message { // Deprecated: Use GetCanteenHeadCountReply.ProtoReflect.Descriptor instead. func (*GetCanteenHeadCountReply) Descriptor() ([]byte, []int) { - return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{71} + return file_tumdev_campus_backend_proto_rawDescGZIP(), []int{67} } func (x *GetCanteenHeadCountReply) GetCount() uint32 { @@ -4521,7 +4286,7 @@ type ListMoreInformationReply_MoreInformation struct { func (x *ListMoreInformationReply_MoreInformation) Reset() { *x = ListMoreInformationReply_MoreInformation{} if protoimpl.UnsafeEnabled { - mi := &file_tumdev_campus_backend_proto_msgTypes[72] + mi := &file_tumdev_campus_backend_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4534,7 +4299,7 @@ func (x *ListMoreInformationReply_MoreInformation) String() string { func (*ListMoreInformationReply_MoreInformation) ProtoMessage() {} func (x *ListMoreInformationReply_MoreInformation) ProtoReflect() protoreflect.Message { - mi := &file_tumdev_campus_backend_proto_msgTypes[72] + mi := &file_tumdev_campus_backend_proto_msgTypes[68] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4914,362 +4679,332 @@ var file_tumdev_campus_backend_proto_rawDesc = []byte{ 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4e, 0x61, - 0x6d, 0x65, 0x22, 0x17, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x74, 0x75, 0x64, 0x79, 0x52, - 0x6f, 0x6f, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x45, 0x0a, 0x13, 0x4c, - 0x69, 0x73, 0x74, 0x53, 0x74, 0x75, 0x64, 0x79, 0x52, 0x6f, 0x6f, 0x6d, 0x73, 0x52, 0x65, 0x70, - 0x6c, 0x79, 0x12, 0x2e, 0x0a, 0x05, 0x72, 0x6f, 0x6f, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x74, 0x75, 0x64, 0x79, 0x52, 0x6f, 0x6f, - 0x6d, 0x4d, 0x73, 0x67, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x05, 0x72, 0x6f, 0x6f, - 0x6d, 0x73, 0x22, 0x79, 0x0a, 0x13, 0x53, 0x74, 0x75, 0x64, 0x79, 0x52, 0x6f, 0x6f, 0x6d, 0x4d, - 0x73, 0x67, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, - 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x24, 0x0a, 0x05, 0x72, 0x6f, 0x6f, 0x6d, 0x73, - 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x74, 0x75, - 0x64, 0x79, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x05, 0x72, 0x6f, 0x6f, 0x6d, 0x73, 0x22, 0x9e, 0x01, - 0x0a, 0x09, 0x53, 0x74, 0x75, 0x64, 0x79, 0x52, 0x6f, 0x6f, 0x6d, 0x12, 0x19, 0x0a, 0x08, 0x67, - 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x67, - 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x69, - 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x72, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x12, - 0x1b, 0x0a, 0x09, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x72, 0x6f, 0x6f, 0x6d, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1b, 0x0a, 0x09, - 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x08, 0x72, 0x6f, 0x6f, 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x62, 0x75, 0x69, - 0x6c, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0c, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x69, 0x6e, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x6e, - 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x76, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x6c, 0x61, 0x73, 0x74, 0x49, 0x64, 0x12, 0x40, 0x0a, 0x0e, - 0x6f, 0x6c, 0x64, 0x65, 0x73, 0x74, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x74, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x52, 0x0c, 0x6f, 0x6c, 0x64, 0x65, 0x73, 0x74, 0x44, 0x61, 0x74, 0x65, 0x41, 0x74, 0x22, 0x35, - 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x76, 0x69, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, - 0x79, 0x12, 0x22, 0x0a, 0x06, 0x6d, 0x6f, 0x76, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x0a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x6f, 0x76, 0x69, 0x65, 0x52, 0x06, 0x6d, - 0x6f, 0x76, 0x69, 0x65, 0x73, 0x22, 0xc6, 0x03, 0x0a, 0x05, 0x4d, 0x6f, 0x76, 0x69, 0x65, 0x12, - 0x19, 0x0a, 0x08, 0x6d, 0x6f, 0x76, 0x69, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x07, 0x6d, 0x6f, 0x76, 0x69, 0x65, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x04, 0x64, 0x61, - 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x6d, 0x65, 0x22, 0x6e, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x76, 0x69, 0x65, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x6c, 0x61, 0x73, 0x74, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x6c, 0x61, 0x73, 0x74, 0x49, 0x64, + 0x12, 0x40, 0x0a, 0x0e, 0x6f, 0x6c, 0x64, 0x65, 0x73, 0x74, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x5f, + 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x64, 0x61, 0x74, 0x65, 0x12, 0x34, 0x0a, 0x07, 0x63, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, - 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, - 0x65, 0x5f, 0x79, 0x65, 0x61, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x72, 0x65, - 0x6c, 0x65, 0x61, 0x73, 0x65, 0x59, 0x65, 0x61, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x75, 0x6e, - 0x74, 0x69, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x75, 0x6e, 0x74, - 0x69, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x67, 0x65, 0x6e, 0x72, 0x65, 0x18, 0x09, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x67, 0x65, 0x6e, 0x72, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x69, 0x72, - 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x69, 0x72, - 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x18, - 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x1f, 0x0a, - 0x0b, 0x69, 0x6d, 0x64, 0x62, 0x5f, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x0c, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6d, 0x64, 0x62, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x20, - 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0d, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x19, 0x0a, 0x08, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x0e, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x07, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6c, - 0x69, 0x6e, 0x6b, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x12, - 0x1b, 0x0a, 0x09, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x11, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x55, 0x72, 0x6c, 0x4a, 0x04, 0x08, 0x01, - 0x10, 0x02, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x4a, 0x04, 0x08, 0x0f, 0x10, 0x10, 0x22, 0xcc, - 0x02, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x64, 0x62, 0x61, 0x63, - 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x42, 0x0a, 0x09, 0x72, 0x65, 0x63, 0x69, - 0x70, 0x69, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x24, 0x2e, 0x61, 0x70, - 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x64, 0x62, 0x61, 0x63, 0x6b, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, - 0x74, 0x52, 0x09, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x1d, 0x0a, 0x0a, - 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x09, 0x66, 0x72, 0x6f, 0x6d, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2b, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f, - 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x6f, 0x73, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x70, 0x70, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x70, 0x70, 0x56, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, - 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, - 0x6e, 0x74, 0x22, 0x29, 0x0a, 0x09, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x12, - 0x0b, 0x0a, 0x07, 0x54, 0x55, 0x4d, 0x5f, 0x44, 0x45, 0x56, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, - 0x54, 0x55, 0x4d, 0x5f, 0x43, 0x4f, 0x4e, 0x54, 0x41, 0x43, 0x54, 0x10, 0x01, 0x22, 0x46, 0x0a, - 0x0a, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6c, - 0x61, 0x74, 0x69, 0x74, 0x75, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x08, 0x6c, - 0x61, 0x74, 0x69, 0x74, 0x75, 0x64, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6c, 0x6f, 0x6e, 0x67, 0x69, - 0x74, 0x75, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x09, 0x6c, 0x6f, 0x6e, 0x67, - 0x69, 0x74, 0x75, 0x64, 0x65, 0x22, 0x15, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, - 0x65, 0x65, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x32, 0x0a, 0x18, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x49, 0x6d, - 0x61, 0x67, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x22, 0x47, 0x0a, 0x1a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x64, 0x62, 0x61, - 0x63, 0x6b, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, - 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x19, - 0x0a, 0x08, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x5f, 0x6e, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x07, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x4e, 0x72, 0x22, 0x29, 0x0a, 0x10, 0x47, 0x65, 0x74, - 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, - 0x06, 0x6c, 0x72, 0x7a, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, - 0x72, 0x7a, 0x49, 0x64, 0x22, 0x58, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, - 0x72, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x15, 0x0a, 0x06, 0x6c, 0x72, 0x7a, 0x5f, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x72, 0x7a, 0x49, 0x64, 0x12, 0x12, 0x0a, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x49, 0x64, 0x22, 0x2f, - 0x0a, 0x16, 0x47, 0x65, 0x74, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x6c, 0x72, 0x7a, 0x5f, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x72, 0x7a, 0x49, 0x64, 0x22, - 0xb3, 0x01, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x63, 0x6d, 0x5f, - 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x63, 0x6d, - 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, - 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, - 0x63, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x5f, - 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x74, 0x75, 0x64, 0x65, 0x6e, - 0x74, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x6d, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x65, 0x5f, - 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x65, 0x6d, 0x70, 0x6c, 0x6f, 0x79, - 0x65, 0x65, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, - 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x72, - 0x6e, 0x61, 0x6c, 0x49, 0x64, 0x22, 0x41, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x27, 0x0a, 0x0f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0xa9, 0x01, 0x0a, 0x14, 0x47, 0x65, 0x74, - 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, - 0x79, 0x12, 0x27, 0x0a, 0x0f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x6e, 0x6f, 0x74, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, - 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, - 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, - 0x69, 0x74, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, - 0x75, 0x72, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, - 0x74, 0x75, 0x72, 0x65, 0x22, 0x48, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, - 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x35, - 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x16, 0x0a, - 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x3b, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x43, 0x61, 0x6e, 0x74, - 0x65, 0x65, 0x6e, 0x48, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x5f, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, - 0x49, 0x64, 0x22, 0xa1, 0x01, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, - 0x6e, 0x48, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, - 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x43, 0x6f, 0x75, - 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x02, 0x52, 0x07, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x12, 0x38, 0x0a, 0x09, - 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x6f, 0x6c, 0x64, 0x65, 0x73, 0x74, 0x44, 0x61, 0x74, 0x65, + 0x41, 0x74, 0x22, 0x35, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x76, 0x69, 0x65, 0x73, + 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x22, 0x0a, 0x06, 0x6d, 0x6f, 0x76, 0x69, 0x65, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x6f, 0x76, 0x69, + 0x65, 0x52, 0x06, 0x6d, 0x6f, 0x76, 0x69, 0x65, 0x73, 0x22, 0xc6, 0x03, 0x0a, 0x05, 0x4d, 0x6f, + 0x76, 0x69, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6d, 0x6f, 0x76, 0x69, 0x65, 0x5f, 0x69, 0x64, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6d, 0x6f, 0x76, 0x69, 0x65, 0x49, 0x64, 0x12, 0x2e, + 0x0a, 0x04, 0x64, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x64, 0x61, 0x74, 0x65, 0x12, 0x34, + 0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2a, 0x2f, 0x0a, 0x0a, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, - 0x54, 0x79, 0x70, 0x65, 0x12, 0x07, 0x0a, 0x03, 0x49, 0x4f, 0x53, 0x10, 0x00, 0x12, 0x0b, 0x0a, - 0x07, 0x41, 0x4e, 0x44, 0x52, 0x4f, 0x49, 0x44, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x57, 0x49, - 0x4e, 0x44, 0x4f, 0x57, 0x53, 0x10, 0x02, 0x32, 0xc3, 0x17, 0x0a, 0x06, 0x43, 0x61, 0x6d, 0x70, - 0x75, 0x73, 0x12, 0x64, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x41, 0x6c, - 0x65, 0x72, 0x74, 0x73, 0x12, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, - 0x65, 0x77, 0x73, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x41, - 0x6c, 0x65, 0x72, 0x74, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x16, 0x62, 0x06, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x73, 0x12, 0x0c, 0x2f, 0x6e, 0x65, 0x77, - 0x73, 0x2f, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x73, 0x12, 0x69, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, - 0x4e, 0x65, 0x77, 0x73, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x1b, 0x2e, 0x61, 0x70, - 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, - 0x69, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, - 0x70, 0x6c, 0x79, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x62, 0x07, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x73, 0x12, 0x0d, 0x2f, 0x6e, 0x65, 0x77, 0x73, 0x2f, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x73, 0x12, 0x49, 0x0a, 0x08, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x12, - 0x14, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, - 0x4e, 0x65, 0x77, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x13, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x0d, 0x62, 0x04, 0x6e, 0x65, 0x77, 0x73, 0x12, 0x05, 0x2f, 0x6e, 0x65, 0x77, 0x73, 0x12, 0x72, - 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x52, 0x61, 0x74, - 0x69, 0x6e, 0x67, 0x73, 0x12, 0x1e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, - 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, - 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x70, + 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x65, + 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x79, 0x65, 0x61, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x59, 0x65, 0x61, 0x72, 0x12, 0x18, 0x0a, + 0x07, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x67, 0x65, 0x6e, 0x72, 0x65, + 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x67, 0x65, 0x6e, 0x72, 0x65, 0x12, 0x1a, 0x0a, + 0x08, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, + 0x6f, 0x72, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x63, 0x74, 0x6f, 0x72, + 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6d, 0x64, 0x62, 0x5f, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, + 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6d, 0x64, 0x62, 0x52, 0x61, 0x74, 0x69, + 0x6e, 0x67, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x69, 0x64, + 0x18, 0x0e, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x49, 0x64, 0x12, + 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, + 0x69, 0x6e, 0x6b, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c, + 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x55, 0x72, 0x6c, + 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x4a, 0x04, 0x08, 0x0f, + 0x10, 0x10, 0x22, 0xcc, 0x02, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, + 0x64, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x42, 0x0a, 0x09, + 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x24, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x64, + 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x52, 0x65, 0x63, 0x69, + 0x70, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x09, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, + 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x66, 0x72, 0x6f, 0x6d, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, + 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2b, 0x0a, 0x08, 0x6c, 0x6f, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x52, 0x08, 0x6c, 0x6f, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x6f, 0x73, 0x5f, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x73, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x70, 0x70, 0x5f, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x70, 0x70, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, + 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x61, + 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x29, 0x0a, 0x09, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, + 0x65, 0x6e, 0x74, 0x12, 0x0b, 0x0a, 0x07, 0x54, 0x55, 0x4d, 0x5f, 0x44, 0x45, 0x56, 0x10, 0x00, + 0x12, 0x0f, 0x0a, 0x0b, 0x54, 0x55, 0x4d, 0x5f, 0x43, 0x4f, 0x4e, 0x54, 0x41, 0x43, 0x54, 0x10, + 0x01, 0x22, 0x46, 0x0a, 0x0a, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x12, + 0x1a, 0x0a, 0x08, 0x6c, 0x61, 0x74, 0x69, 0x74, 0x75, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x01, 0x52, 0x08, 0x6c, 0x61, 0x74, 0x69, 0x74, 0x75, 0x64, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6c, + 0x6f, 0x6e, 0x67, 0x69, 0x74, 0x75, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x09, + 0x6c, 0x6f, 0x6e, 0x67, 0x69, 0x74, 0x75, 0x64, 0x65, 0x22, 0x15, 0x0a, 0x13, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x70, 0x6c, 0x79, + 0x22, 0x32, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x64, 0x62, 0x61, + 0x63, 0x6b, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x16, 0x0a, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x22, 0x47, 0x0a, 0x1a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x65, + 0x65, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, + 0x69, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x5f, 0x6e, 0x72, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x4e, 0x72, 0x22, 0x29, 0x0a, + 0x10, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x15, 0x0a, 0x06, 0x6c, 0x72, 0x7a, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x6c, 0x72, 0x7a, 0x49, 0x64, 0x22, 0x58, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4d, + 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x15, 0x0a, 0x06, 0x6c, 0x72, + 0x7a, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x72, 0x7a, 0x49, + 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x5f, + 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, + 0x49, 0x64, 0x22, 0x2f, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, + 0x6c, 0x72, 0x7a, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x72, + 0x7a, 0x49, 0x64, 0x22, 0xb3, 0x01, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x55, 0x70, 0x6c, 0x6f, 0x61, + 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1b, 0x0a, 0x09, + 0x66, 0x63, 0x6d, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x66, 0x63, 0x6d, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, + 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, + 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x75, 0x64, + 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x74, + 0x75, 0x64, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x6d, 0x70, 0x6c, 0x6f, + 0x79, 0x65, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x65, 0x6d, + 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x65, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x78, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x65, + 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x49, 0x64, 0x22, 0x41, 0x0a, 0x16, 0x47, 0x65, 0x74, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x6e, 0x6f, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0xa9, 0x01, 0x0a, + 0x14, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x27, 0x0a, 0x0f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, + 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x12, + 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, + 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x48, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x4e, + 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x72, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x6e, 0x6f, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x0e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x49, 0x64, 0x22, 0x35, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x52, 0x65, 0x70, 0x6c, + 0x79, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x3b, 0x0a, 0x1a, 0x47, 0x65, 0x74, + 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x48, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x61, 0x6e, 0x74, 0x65, + 0x65, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x61, 0x6e, + 0x74, 0x65, 0x65, 0x6e, 0x49, 0x64, 0x22, 0xa1, 0x01, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x43, 0x61, + 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x48, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, + 0x70, 0x6c, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x78, + 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x6d, 0x61, + 0x78, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, + 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x02, 0x52, 0x07, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, + 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, + 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2a, 0x2f, 0x0a, 0x0a, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x07, 0x0a, 0x03, 0x49, 0x4f, 0x53, 0x10, + 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x41, 0x4e, 0x44, 0x52, 0x4f, 0x49, 0x44, 0x10, 0x01, 0x12, 0x0b, + 0x0a, 0x07, 0x57, 0x49, 0x4e, 0x44, 0x4f, 0x57, 0x53, 0x10, 0x02, 0x32, 0xe6, 0x16, 0x0a, 0x06, + 0x43, 0x61, 0x6d, 0x70, 0x75, 0x73, 0x12, 0x64, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x65, + 0x77, 0x73, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x73, 0x12, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, + 0x65, 0x77, 0x73, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1c, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x62, 0x06, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x73, 0x12, 0x0c, + 0x2f, 0x6e, 0x65, 0x77, 0x73, 0x2f, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x73, 0x12, 0x69, 0x0a, 0x0f, + 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, + 0x1b, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x53, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x53, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x62, + 0x07, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x0d, 0x2f, 0x6e, 0x65, 0x77, 0x73, 0x2f, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x49, 0x0a, 0x08, 0x4c, 0x69, 0x73, 0x74, 0x4e, + 0x65, 0x77, 0x73, 0x12, 0x14, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x65, + 0x77, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x13, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x0d, 0x62, 0x04, 0x6e, 0x65, 0x77, 0x73, 0x12, 0x05, 0x2f, 0x6e, 0x65, + 0x77, 0x73, 0x12, 0x72, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, + 0x6e, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x1e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, + 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x3a, 0x01, + 0x2a, 0x22, 0x13, 0x2f, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x2f, 0x72, 0x61, 0x74, 0x69, + 0x6e, 0x67, 0x2f, 0x67, 0x65, 0x74, 0x12, 0x63, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x44, 0x69, 0x73, + 0x68, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, + 0x65, 0x74, 0x44, 0x69, 0x73, 0x68, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x69, + 0x73, 0x68, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1b, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x3a, 0x01, 0x2a, 0x22, 0x10, 0x2f, 0x64, 0x69, 0x73, 0x68, + 0x2f, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x67, 0x65, 0x74, 0x12, 0x75, 0x0a, 0x13, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x52, 0x61, 0x74, 0x69, + 0x6e, 0x67, 0x12, 0x1f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, + 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x3a, 0x01, 0x2a, 0x22, 0x13, 0x2f, - 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x2f, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x67, - 0x65, 0x74, 0x12, 0x63, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x44, 0x69, 0x73, 0x68, 0x52, 0x61, 0x74, - 0x69, 0x6e, 0x67, 0x73, 0x12, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x69, - 0x73, 0x68, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x69, 0x73, 0x68, 0x52, 0x61, - 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x15, 0x3a, 0x01, 0x2a, 0x22, 0x10, 0x2f, 0x64, 0x69, 0x73, 0x68, 0x2f, 0x72, 0x61, 0x74, - 0x69, 0x6e, 0x67, 0x2f, 0x67, 0x65, 0x74, 0x12, 0x75, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x1f, - 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x61, 0x6e, 0x74, 0x65, - 0x65, 0x6e, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x61, 0x6e, 0x74, - 0x65, 0x65, 0x6e, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1e, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x3a, 0x01, 0x2a, 0x22, 0x13, 0x2f, 0x63, 0x61, 0x6e, 0x74, - 0x65, 0x65, 0x6e, 0x2f, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x6e, 0x65, 0x77, 0x12, 0x69, - 0x0a, 0x10, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x69, 0x73, 0x68, 0x52, 0x61, 0x74, 0x69, - 0x6e, 0x67, 0x12, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, - 0x69, 0x73, 0x68, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x69, 0x73, - 0x68, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1b, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x15, 0x3a, 0x01, 0x2a, 0x22, 0x10, 0x2f, 0x64, 0x69, 0x73, 0x68, 0x2f, 0x72, - 0x61, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x6e, 0x65, 0x77, 0x12, 0x8c, 0x01, 0x0a, 0x15, 0x4c, 0x69, + 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x2f, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x6e, + 0x65, 0x77, 0x12, 0x69, 0x0a, 0x10, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x69, 0x73, 0x68, + 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x44, 0x69, 0x73, 0x68, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x44, 0x69, 0x73, 0x68, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x70, 0x6c, 0x79, + 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x3a, 0x01, 0x2a, 0x22, 0x10, 0x2f, 0x64, 0x69, + 0x73, 0x68, 0x2f, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x6e, 0x65, 0x77, 0x12, 0x8c, 0x01, + 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x44, + 0x69, 0x73, 0x68, 0x54, 0x61, 0x67, 0x73, 0x12, 0x21, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x44, 0x69, 0x73, 0x68, 0x54, - 0x61, 0x67, 0x73, 0x12, 0x21, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x76, - 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x44, 0x69, 0x73, 0x68, 0x54, 0x61, 0x67, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x44, 0x69, 0x73, 0x68, 0x54, 0x61, - 0x67, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x2f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x29, 0x62, - 0x0b, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x12, 0x1a, 0x2f, 0x64, - 0x69, 0x73, 0x68, 0x2f, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x61, 0x6c, 0x6c, 0x52, 0x61, - 0x74, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x73, 0x12, 0x6f, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, - 0x4e, 0x61, 0x6d, 0x65, 0x54, 0x61, 0x67, 0x73, 0x12, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, - 0x69, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x61, 0x6d, - 0x65, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x2d, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x27, 0x62, 0x0b, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x12, - 0x18, 0x2f, 0x64, 0x69, 0x73, 0x68, 0x2f, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x61, 0x6c, - 0x6c, 0x44, 0x69, 0x73, 0x68, 0x54, 0x61, 0x67, 0x73, 0x12, 0x98, 0x01, 0x0a, 0x18, 0x4c, 0x69, - 0x73, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x6e, 0x74, 0x65, - 0x65, 0x6e, 0x54, 0x61, 0x67, 0x73, 0x12, 0x24, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, - 0x6e, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x61, - 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, - 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, - 0x22, 0x32, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2c, 0x62, 0x0b, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, - 0x5f, 0x74, 0x61, 0x67, 0x73, 0x12, 0x1d, 0x2f, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x2f, - 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x61, 0x6c, 0x6c, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, - 0x54, 0x61, 0x67, 0x73, 0x12, 0x67, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x61, 0x6e, 0x74, - 0x65, 0x65, 0x6e, 0x73, 0x12, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, - 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, - 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, - 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x62, 0x07, - 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x12, 0x14, 0x2f, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, - 0x6e, 0x2f, 0x61, 0x6c, 0x6c, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x73, 0x12, 0x59, 0x0a, - 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x69, 0x73, 0x68, 0x65, 0x73, 0x12, 0x16, 0x2e, 0x61, 0x70, - 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x69, 0x73, 0x68, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x69, - 0x73, 0x68, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x17, 0x62, 0x04, 0x64, 0x69, 0x73, 0x68, 0x12, 0x0f, 0x2f, 0x64, 0x69, 0x73, 0x68, 0x2f, 0x61, - 0x6c, 0x6c, 0x44, 0x69, 0x73, 0x68, 0x65, 0x73, 0x12, 0x7a, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, + 0x61, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x61, 0x70, 0x69, + 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x44, 0x69, + 0x73, 0x68, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x2f, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x29, 0x62, 0x0b, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x67, 0x73, + 0x12, 0x1a, 0x2f, 0x64, 0x69, 0x73, 0x68, 0x2f, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x61, + 0x6c, 0x6c, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x73, 0x12, 0x6f, 0x0a, 0x0c, + 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x54, 0x61, 0x67, 0x73, 0x12, 0x18, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x54, 0x61, 0x67, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, + 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x2d, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x27, 0x62, 0x0b, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x74, + 0x61, 0x67, 0x73, 0x12, 0x18, 0x2f, 0x64, 0x69, 0x73, 0x68, 0x2f, 0x72, 0x61, 0x74, 0x69, 0x6e, + 0x67, 0x2f, 0x61, 0x6c, 0x6c, 0x44, 0x69, 0x73, 0x68, 0x54, 0x61, 0x67, 0x73, 0x12, 0x98, 0x01, + 0x0a, 0x18, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x43, + 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x54, 0x61, 0x67, 0x73, 0x12, 0x24, 0x2e, 0x61, 0x70, 0x69, + 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, + 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x22, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, + 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x54, 0x61, 0x67, 0x73, 0x52, + 0x65, 0x70, 0x6c, 0x79, 0x22, 0x32, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2c, 0x62, 0x0b, 0x72, 0x61, + 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x12, 0x1d, 0x2f, 0x63, 0x61, 0x6e, 0x74, + 0x65, 0x65, 0x6e, 0x2f, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x61, 0x6c, 0x6c, 0x52, 0x61, + 0x74, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x73, 0x12, 0x67, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, + 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x73, 0x12, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x61, 0x6e, + 0x74, 0x65, 0x65, 0x6e, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x1f, 0x62, 0x07, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x12, 0x14, 0x2f, 0x63, 0x61, + 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x2f, 0x61, 0x6c, 0x6c, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, + 0x73, 0x12, 0x59, 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x69, 0x73, 0x68, 0x65, 0x73, 0x12, + 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x69, 0x73, 0x68, 0x65, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x44, 0x69, 0x73, 0x68, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1d, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x62, 0x04, 0x64, 0x69, 0x73, 0x68, 0x12, 0x0f, 0x2f, 0x64, 0x69, + 0x73, 0x68, 0x2f, 0x61, 0x6c, 0x6c, 0x44, 0x69, 0x73, 0x68, 0x65, 0x73, 0x12, 0x7a, 0x0a, 0x15, + 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x50, + 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x12, 0x21, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x50, 0x65, 0x72, 0x73, 0x6f, - 0x6e, 0x12, 0x21, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, - 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, 0x2f, - 0x62, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x66, 0x72, 0x65, 0x65, 0x2f, 0x63, 0x6f, 0x6e, 0x74, - 0x61, 0x63, 0x74, 0x73, 0x12, 0x7b, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x72, 0x65, - 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x2e, 0x61, 0x70, - 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x72, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x61, - 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x72, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x72, - 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x24, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x1e, 0x12, 0x1c, 0x2f, 0x62, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x66, 0x72, 0x65, - 0x65, 0x2f, 0x6d, 0x6f, 0x72, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x6e, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x70, 0x65, 0x6e, 0x69, 0x6e, 0x67, - 0x54, 0x69, 0x6d, 0x65, 0x73, 0x12, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, - 0x4f, 0x70, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x70, - 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, - 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x12, 0x18, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6e, - 0x67, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x2f, 0x7b, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, - 0x7d, 0x12, 0x62, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4e, 0x6f, - 0x74, 0x65, 0x12, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x4e, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, - 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x74, - 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, - 0x2f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x6e, 0x6f, 0x74, 0x65, 0x2f, 0x7b, 0x76, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x7d, 0x12, 0x5b, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x74, 0x75, - 0x64, 0x79, 0x52, 0x6f, 0x6f, 0x6d, 0x73, 0x12, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, - 0x73, 0x74, 0x53, 0x74, 0x75, 0x64, 0x79, 0x52, 0x6f, 0x6f, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x74, - 0x75, 0x64, 0x79, 0x52, 0x6f, 0x6f, 0x6d, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x13, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x0d, 0x12, 0x0b, 0x2f, 0x73, 0x74, 0x75, 0x64, 0x79, 0x72, 0x6f, 0x6f, - 0x6d, 0x73, 0x12, 0x55, 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x76, 0x69, 0x65, 0x73, - 0x12, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x76, 0x69, 0x65, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, - 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x76, 0x69, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x19, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x12, 0x11, 0x2f, 0x6d, 0x6f, 0x76, 0x69, 0x65, 0x73, 0x2f, - 0x7b, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x67, 0x0a, 0x0e, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x1a, 0x2e, 0x61, 0x70, - 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x64, 0x62, 0x61, 0x63, 0x6b, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x70, 0x6c, - 0x79, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x3a, 0x0a, 0x61, 0x74, 0x74, 0x61, 0x63, - 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x09, 0x2f, 0x66, 0x65, 0x65, 0x64, 0x62, 0x61, 0x63, 0x6b, - 0x28, 0x01, 0x12, 0x6c, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1b, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x55, - 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x70, 0x6c, 0x6f, - 0x61, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x21, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x12, 0x19, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x75, - 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x2f, 0x7b, 0x6c, 0x72, 0x7a, 0x5f, 0x69, 0x64, 0x7d, - 0x12, 0x73, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x28, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x22, 0x12, 0x20, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x2f, 0x7b, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x90, 0x01, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, - 0x12, 0x22, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x6f, - 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, - 0x6d, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x30, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2a, 0x12, 0x28, - 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x63, - 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x2f, 0x7b, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x52, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x4d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x15, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x4d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x61, - 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x65, 0x70, 0x6c, - 0x79, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x12, 0x11, 0x2f, 0x6d, 0x65, 0x6d, 0x62, - 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x6c, 0x72, 0x7a, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x7e, 0x0a, 0x13, - 0x47, 0x65, 0x74, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x48, 0x65, 0x61, 0x64, 0x43, 0x6f, - 0x75, 0x6e, 0x74, 0x12, 0x1f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x61, 0x6e, - 0x74, 0x65, 0x65, 0x6e, 0x48, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x61, - 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x48, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, - 0x70, 0x6c, 0x79, 0x22, 0x27, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x21, 0x12, 0x1f, 0x2f, 0x63, 0x61, - 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x2f, - 0x7b, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x99, 0x01, 0x0a, - 0x18, 0x49, 0x4f, 0x53, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x24, 0x2e, 0x61, 0x70, 0x69, 0x2e, - 0x49, 0x4f, 0x53, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x22, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x49, 0x4f, 0x53, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x65, - 0x70, 0x6c, 0x79, 0x22, 0x33, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2d, 0x3a, 0x01, 0x2a, 0x22, 0x28, - 0x2f, 0x69, 0x6f, 0x73, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x0c, 0x43, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, - 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x12, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x0c, 0x3a, 0x01, 0x2a, 0x22, 0x07, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5d, - 0x0a, 0x0c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x18, - 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, - 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x2a, 0x13, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, - 0x65, 0x2f, 0x7b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x42, 0x5e, 0x0a, - 0x12, 0x61, 0x70, 0x70, 0x2e, 0x74, 0x75, 0x6d, 0x2e, 0x63, 0x61, 0x6d, 0x70, 0x75, 0x73, 0x2e, - 0x61, 0x70, 0x69, 0x42, 0x0e, 0x43, 0x61, 0x6d, 0x70, 0x75, 0x73, 0x41, 0x70, 0x69, 0x50, 0x72, - 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x54, 0x55, 0x4d, 0x2d, 0x44, 0x65, 0x76, 0x2f, 0x43, 0x61, 0x6d, 0x70, 0x75, 0x73, - 0x2d, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x2f, 0x61, 0x70, 0x69, 0xaa, 0x02, 0x0e, 0x43, - 0x61, 0x6d, 0x70, 0x75, 0x73, 0x41, 0x70, 0x69, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x50, 0x65, + 0x72, 0x73, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x17, 0x12, 0x15, 0x2f, 0x62, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x66, 0x72, 0x65, 0x65, 0x2f, + 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x73, 0x12, 0x7b, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, + 0x4d, 0x6f, 0x72, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x1f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x72, 0x65, 0x49, 0x6e, + 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x72, 0x65, 0x49, + 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, + 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x12, 0x1c, 0x2f, 0x62, 0x61, 0x72, 0x72, 0x69, 0x65, + 0x72, 0x66, 0x72, 0x65, 0x65, 0x2f, 0x6d, 0x6f, 0x72, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x6e, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x70, 0x65, + 0x6e, 0x69, 0x6e, 0x67, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x12, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x70, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x4f, 0x70, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x52, 0x65, + 0x70, 0x6c, 0x79, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x12, 0x18, 0x2f, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x2f, 0x7b, 0x6c, 0x61, 0x6e, 0x67, + 0x75, 0x61, 0x67, 0x65, 0x7d, 0x12, 0x62, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x4e, 0x6f, 0x74, 0x65, 0x12, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x17, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x4e, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x17, 0x12, 0x15, 0x2f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x6e, 0x6f, 0x74, 0x65, 0x2f, + 0x7b, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x7d, 0x12, 0x55, 0x0a, 0x0a, 0x4c, 0x69, 0x73, + 0x74, 0x4d, 0x6f, 0x76, 0x69, 0x65, 0x73, 0x12, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x4d, 0x6f, 0x76, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x14, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x76, 0x69, 0x65, 0x73, + 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x12, 0x11, 0x2f, + 0x6d, 0x6f, 0x76, 0x69, 0x65, 0x73, 0x2f, 0x7b, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x7d, + 0x12, 0x67, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x64, 0x62, 0x61, + 0x63, 0x6b, 0x12, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, + 0x65, 0x65, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x64, 0x62, + 0x61, 0x63, 0x6b, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, + 0x3a, 0x0a, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x09, 0x2f, 0x66, + 0x65, 0x65, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x28, 0x01, 0x12, 0x6c, 0x0a, 0x0f, 0x47, 0x65, 0x74, + 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1b, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x47, 0x65, 0x74, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, + 0x65, 0x70, 0x6c, 0x79, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x12, 0x19, 0x2f, 0x64, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x2f, 0x7b, + 0x6c, 0x72, 0x7a, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x73, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x4e, 0x6f, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x2e, 0x61, 0x70, 0x69, + 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, + 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, + 0x6c, 0x79, 0x22, 0x28, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x22, 0x12, 0x20, 0x2f, 0x6e, 0x6f, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x7b, 0x6e, 0x6f, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x90, 0x01, 0x0a, + 0x16, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x12, 0x22, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, + 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x72, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x30, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x2a, 0x12, 0x28, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x2f, 0x7b, 0x6e, + 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x7d, 0x12, + 0x52, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x15, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, + 0x62, 0x65, 0x72, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, + 0x12, 0x11, 0x2f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x6c, 0x72, 0x7a, 0x5f, + 0x69, 0x64, 0x7d, 0x12, 0x7e, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, + 0x6e, 0x48, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1f, 0x2e, 0x61, 0x70, 0x69, + 0x2e, 0x47, 0x65, 0x74, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x48, 0x65, 0x61, 0x64, 0x43, + 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x48, 0x65, 0x61, 0x64, + 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x27, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x21, 0x12, 0x1f, 0x2f, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x2f, 0x68, 0x65, 0x61, + 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x2f, 0x7b, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x5f, + 0x69, 0x64, 0x7d, 0x12, 0x99, 0x01, 0x0a, 0x18, 0x49, 0x4f, 0x53, 0x44, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x24, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x49, 0x4f, 0x53, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x49, 0x4f, 0x53, + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x33, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x2d, 0x3a, 0x01, 0x2a, 0x22, 0x28, 0x2f, 0x69, 0x6f, 0x73, 0x2f, 0x6e, 0x6f, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x54, 0x0a, 0x0c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, + 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x70, 0x6c, + 0x79, 0x22, 0x12, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0c, 0x3a, 0x01, 0x2a, 0x22, 0x07, 0x2f, 0x64, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5d, 0x0a, 0x0c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x44, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x2a, + 0x13, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x7b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x5f, 0x69, 0x64, 0x7d, 0x42, 0x5e, 0x0a, 0x12, 0x61, 0x70, 0x70, 0x2e, 0x74, 0x75, 0x6d, 0x2e, + 0x63, 0x61, 0x6d, 0x70, 0x75, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x42, 0x0e, 0x43, 0x61, 0x6d, 0x70, + 0x75, 0x73, 0x41, 0x70, 0x69, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x25, 0x67, 0x69, + 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x54, 0x55, 0x4d, 0x2d, 0x44, 0x65, 0x76, + 0x2f, 0x43, 0x61, 0x6d, 0x70, 0x75, 0x73, 0x2d, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x2f, + 0x61, 0x70, 0x69, 0xaa, 0x02, 0x0e, 0x43, 0x61, 0x6d, 0x70, 0x75, 0x73, 0x41, 0x70, 0x69, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -5285,7 +5020,7 @@ func file_tumdev_campus_backend_proto_rawDescGZIP() []byte { } var file_tumdev_campus_backend_proto_enumTypes = make([]protoimpl.EnumInfo, 2) -var file_tumdev_campus_backend_proto_msgTypes = make([]protoimpl.MessageInfo, 73) +var file_tumdev_campus_backend_proto_msgTypes = make([]protoimpl.MessageInfo, 69) var file_tumdev_campus_backend_proto_goTypes = []interface{}{ (DeviceType)(0), // 0: api.DeviceType (CreateFeedbackRequest_Recipient)(0), // 1: api.CreateFeedbackRequest.Recipient @@ -5339,54 +5074,50 @@ var file_tumdev_campus_backend_proto_goTypes = []interface{}{ (*OpeningTimesMsgElement)(nil), // 49: api.OpeningTimesMsgElement (*GetUpdateNoteRequest)(nil), // 50: api.GetUpdateNoteRequest (*GetUpdateNoteReply)(nil), // 51: api.GetUpdateNoteReply - (*ListStudyRoomsRequest)(nil), // 52: api.ListStudyRoomsRequest - (*ListStudyRoomsReply)(nil), // 53: api.ListStudyRoomsReply - (*StudyRoomMsgElement)(nil), // 54: api.StudyRoomMsgElement - (*StudyRoom)(nil), // 55: api.StudyRoom - (*ListMoviesRequest)(nil), // 56: api.ListMoviesRequest - (*ListMoviesReply)(nil), // 57: api.ListMoviesReply - (*Movie)(nil), // 58: api.Movie - (*CreateFeedbackRequest)(nil), // 59: api.CreateFeedbackRequest - (*Coordinate)(nil), // 60: api.Coordinate - (*CreateFeedbackReply)(nil), // 61: api.CreateFeedbackReply - (*CreateFeedbackImageReply)(nil), // 62: api.CreateFeedbackImageReply - (*CreateFeedbackImageRequest)(nil), // 63: api.CreateFeedbackImageRequest - (*GetMemberRequest)(nil), // 64: api.GetMemberRequest - (*GetMemberReply)(nil), // 65: api.GetMemberReply - (*GetUploadStatusRequest)(nil), // 66: api.GetUploadStatusRequest - (*GetUploadStatusReply)(nil), // 67: api.GetUploadStatusReply - (*GetNotificationRequest)(nil), // 68: api.GetNotificationRequest - (*GetNotificationReply)(nil), // 69: api.GetNotificationReply - (*GetNotificationConfirmRequest)(nil), // 70: api.GetNotificationConfirmRequest - (*GetNotificationConfirmReply)(nil), // 71: api.GetNotificationConfirmReply - (*GetCanteenHeadCountRequest)(nil), // 72: api.GetCanteenHeadCountRequest - (*GetCanteenHeadCountReply)(nil), // 73: api.GetCanteenHeadCountReply - (*ListMoreInformationReply_MoreInformation)(nil), // 74: api.ListMoreInformationReply.MoreInformation - (*timestamppb.Timestamp)(nil), // 75: google.protobuf.Timestamp + (*ListMoviesRequest)(nil), // 52: api.ListMoviesRequest + (*ListMoviesReply)(nil), // 53: api.ListMoviesReply + (*Movie)(nil), // 54: api.Movie + (*CreateFeedbackRequest)(nil), // 55: api.CreateFeedbackRequest + (*Coordinate)(nil), // 56: api.Coordinate + (*CreateFeedbackReply)(nil), // 57: api.CreateFeedbackReply + (*CreateFeedbackImageReply)(nil), // 58: api.CreateFeedbackImageReply + (*CreateFeedbackImageRequest)(nil), // 59: api.CreateFeedbackImageRequest + (*GetMemberRequest)(nil), // 60: api.GetMemberRequest + (*GetMemberReply)(nil), // 61: api.GetMemberReply + (*GetUploadStatusRequest)(nil), // 62: api.GetUploadStatusRequest + (*GetUploadStatusReply)(nil), // 63: api.GetUploadStatusReply + (*GetNotificationRequest)(nil), // 64: api.GetNotificationRequest + (*GetNotificationReply)(nil), // 65: api.GetNotificationReply + (*GetNotificationConfirmRequest)(nil), // 66: api.GetNotificationConfirmRequest + (*GetNotificationConfirmReply)(nil), // 67: api.GetNotificationConfirmReply + (*GetCanteenHeadCountRequest)(nil), // 68: api.GetCanteenHeadCountRequest + (*GetCanteenHeadCountReply)(nil), // 69: api.GetCanteenHeadCountReply + (*ListMoreInformationReply_MoreInformation)(nil), // 70: api.ListMoreInformationReply.MoreInformation + (*timestamppb.Timestamp)(nil), // 71: google.protobuf.Timestamp } var file_tumdev_campus_backend_proto_depIdxs = []int32{ 0, // 0: api.CreateDeviceRequest.device_type:type_name -> api.DeviceType 0, // 1: api.DeleteDeviceRequest.device_type:type_name -> api.DeviceType - 75, // 2: api.News.created:type_name -> google.protobuf.Timestamp - 75, // 3: api.News.date:type_name -> google.protobuf.Timestamp + 71, // 2: api.News.created:type_name -> google.protobuf.Timestamp + 71, // 3: api.News.date:type_name -> google.protobuf.Timestamp 8, // 4: api.ListNewsReply.news:type_name -> api.News - 75, // 5: api.ListNewsRequest.oldest_date_at:type_name -> google.protobuf.Timestamp + 71, // 5: api.ListNewsRequest.oldest_date_at:type_name -> google.protobuf.Timestamp 13, // 6: api.ListNewsSourcesReply.sources:type_name -> api.NewsSource 16, // 7: api.ListNewsAlertsReply.alerts:type_name -> api.NewsAlert - 75, // 8: api.NewsAlert.created:type_name -> google.protobuf.Timestamp - 75, // 9: api.NewsAlert.from:type_name -> google.protobuf.Timestamp - 75, // 10: api.NewsAlert.to:type_name -> google.protobuf.Timestamp - 75, // 11: api.ListCanteenRatingsRequest.from:type_name -> google.protobuf.Timestamp - 75, // 12: api.ListCanteenRatingsRequest.to:type_name -> google.protobuf.Timestamp + 71, // 8: api.NewsAlert.created:type_name -> google.protobuf.Timestamp + 71, // 9: api.NewsAlert.from:type_name -> google.protobuf.Timestamp + 71, // 10: api.NewsAlert.to:type_name -> google.protobuf.Timestamp + 71, // 11: api.ListCanteenRatingsRequest.from:type_name -> google.protobuf.Timestamp + 71, // 12: api.ListCanteenRatingsRequest.to:type_name -> google.protobuf.Timestamp 21, // 13: api.ListCanteenRatingsReply.rating:type_name -> api.SingleRatingReply 35, // 14: api.ListCanteenRatingsReply.rating_tags:type_name -> api.RatingTagResult - 75, // 15: api.GetDishRatingsRequest.from:type_name -> google.protobuf.Timestamp - 75, // 16: api.GetDishRatingsRequest.to:type_name -> google.protobuf.Timestamp + 71, // 15: api.GetDishRatingsRequest.from:type_name -> google.protobuf.Timestamp + 71, // 16: api.GetDishRatingsRequest.to:type_name -> google.protobuf.Timestamp 21, // 17: api.GetDishRatingsReply.rating:type_name -> api.SingleRatingReply 35, // 18: api.GetDishRatingsReply.rating_tags:type_name -> api.RatingTagResult 35, // 19: api.GetDishRatingsReply.name_tags:type_name -> api.RatingTagResult 34, // 20: api.SingleRatingReply.rating_tags:type_name -> api.RatingTagNewRequest - 75, // 21: api.SingleRatingReply.visited:type_name -> google.protobuf.Timestamp + 71, // 21: api.SingleRatingReply.visited:type_name -> google.protobuf.Timestamp 33, // 22: api.CreateCanteenRatingRequest.rating_tags:type_name -> api.RatingTag 33, // 23: api.CreateDishRatingRequest.rating_tags:type_name -> api.RatingTag 32, // 24: api.ListAvailableDishTagsReply.rating_tags:type_name -> api.TagsOverview @@ -5394,76 +5125,72 @@ var file_tumdev_campus_backend_proto_depIdxs = []int32{ 32, // 26: api.ListAvailableCanteenTagsReply.rating_tags:type_name -> api.TagsOverview 38, // 27: api.ListCanteensReply.canteen:type_name -> api.Canteen 43, // 28: api.ListResponsiblePersonReply.responsible_person:type_name -> api.ResponsiblePerson - 74, // 29: api.ListMoreInformationReply.infos:type_name -> api.ListMoreInformationReply.MoreInformation + 70, // 29: api.ListMoreInformationReply.infos:type_name -> api.ListMoreInformationReply.MoreInformation 49, // 30: api.ListOpeningTimesReply.facilities:type_name -> api.OpeningTimesMsgElement - 54, // 31: api.ListStudyRoomsReply.rooms:type_name -> api.StudyRoomMsgElement - 55, // 32: api.StudyRoomMsgElement.rooms:type_name -> api.StudyRoom - 75, // 33: api.ListMoviesRequest.oldest_date_at:type_name -> google.protobuf.Timestamp - 58, // 34: api.ListMoviesReply.movies:type_name -> api.Movie - 75, // 35: api.Movie.date:type_name -> google.protobuf.Timestamp - 75, // 36: api.Movie.created:type_name -> google.protobuf.Timestamp - 1, // 37: api.CreateFeedbackRequest.recipient:type_name -> api.CreateFeedbackRequest.Recipient - 60, // 38: api.CreateFeedbackRequest.location:type_name -> api.Coordinate - 75, // 39: api.GetCanteenHeadCountReply.timestamp:type_name -> google.protobuf.Timestamp - 14, // 40: api.Campus.ListNewsAlerts:input_type -> api.ListNewsAlertsRequest - 11, // 41: api.Campus.ListNewsSources:input_type -> api.ListNewsSourcesRequest - 10, // 42: api.Campus.ListNews:input_type -> api.ListNewsRequest - 17, // 43: api.Campus.ListCanteenRatings:input_type -> api.ListCanteenRatingsRequest - 19, // 44: api.Campus.GetDishRatings:input_type -> api.GetDishRatingsRequest - 23, // 45: api.Campus.CreateCanteenRating:input_type -> api.CreateCanteenRatingRequest - 25, // 46: api.Campus.CreateDishRating:input_type -> api.CreateDishRatingRequest - 26, // 47: api.Campus.ListAvailableDishTags:input_type -> api.ListAvailableDishTagsRequest - 28, // 48: api.Campus.ListNameTags:input_type -> api.ListNameTagsRequest - 30, // 49: api.Campus.ListAvailableCanteenTags:input_type -> api.ListAvailableCanteenTagsRequest - 36, // 50: api.Campus.ListCanteens:input_type -> api.ListCanteensRequest - 39, // 51: api.Campus.ListDishes:input_type -> api.ListDishesRequest - 41, // 52: api.Campus.ListResponsiblePerson:input_type -> api.ListResponsiblePersonRequest - 45, // 53: api.Campus.ListMoreInformation:input_type -> api.ListMoreInformationRequest - 47, // 54: api.Campus.ListOpeningTimes:input_type -> api.ListOpeningTimesRequest - 50, // 55: api.Campus.GetUpdateNote:input_type -> api.GetUpdateNoteRequest - 52, // 56: api.Campus.ListStudyRooms:input_type -> api.ListStudyRoomsRequest - 56, // 57: api.Campus.ListMovies:input_type -> api.ListMoviesRequest - 59, // 58: api.Campus.CreateFeedback:input_type -> api.CreateFeedbackRequest - 66, // 59: api.Campus.GetUploadStatus:input_type -> api.GetUploadStatusRequest - 68, // 60: api.Campus.GetNotification:input_type -> api.GetNotificationRequest - 70, // 61: api.Campus.GetNotificationConfirm:input_type -> api.GetNotificationConfirmRequest - 64, // 62: api.Campus.GetMember:input_type -> api.GetMemberRequest - 72, // 63: api.Campus.GetCanteenHeadCount:input_type -> api.GetCanteenHeadCountRequest - 6, // 64: api.Campus.IOSDeviceRequestResponse:input_type -> api.IOSDeviceRequestResponseRequest - 2, // 65: api.Campus.CreateDevice:input_type -> api.CreateDeviceRequest - 4, // 66: api.Campus.DeleteDevice:input_type -> api.DeleteDeviceRequest - 15, // 67: api.Campus.ListNewsAlerts:output_type -> api.ListNewsAlertsReply - 12, // 68: api.Campus.ListNewsSources:output_type -> api.ListNewsSourcesReply - 9, // 69: api.Campus.ListNews:output_type -> api.ListNewsReply - 18, // 70: api.Campus.ListCanteenRatings:output_type -> api.ListCanteenRatingsReply - 20, // 71: api.Campus.GetDishRatings:output_type -> api.GetDishRatingsReply - 22, // 72: api.Campus.CreateCanteenRating:output_type -> api.CreateCanteenRatingReply - 24, // 73: api.Campus.CreateDishRating:output_type -> api.CreateDishRatingReply - 27, // 74: api.Campus.ListAvailableDishTags:output_type -> api.ListAvailableDishTagsReply - 29, // 75: api.Campus.ListNameTags:output_type -> api.ListNameTagsReply - 31, // 76: api.Campus.ListAvailableCanteenTags:output_type -> api.ListAvailableCanteenTagsReply - 37, // 77: api.Campus.ListCanteens:output_type -> api.ListCanteensReply - 40, // 78: api.Campus.ListDishes:output_type -> api.ListDishesReply - 42, // 79: api.Campus.ListResponsiblePerson:output_type -> api.ListResponsiblePersonReply - 46, // 80: api.Campus.ListMoreInformation:output_type -> api.ListMoreInformationReply - 48, // 81: api.Campus.ListOpeningTimes:output_type -> api.ListOpeningTimesReply - 51, // 82: api.Campus.GetUpdateNote:output_type -> api.GetUpdateNoteReply - 53, // 83: api.Campus.ListStudyRooms:output_type -> api.ListStudyRoomsReply - 57, // 84: api.Campus.ListMovies:output_type -> api.ListMoviesReply - 61, // 85: api.Campus.CreateFeedback:output_type -> api.CreateFeedbackReply - 67, // 86: api.Campus.GetUploadStatus:output_type -> api.GetUploadStatusReply - 69, // 87: api.Campus.GetNotification:output_type -> api.GetNotificationReply - 71, // 88: api.Campus.GetNotificationConfirm:output_type -> api.GetNotificationConfirmReply - 65, // 89: api.Campus.GetMember:output_type -> api.GetMemberReply - 73, // 90: api.Campus.GetCanteenHeadCount:output_type -> api.GetCanteenHeadCountReply - 7, // 91: api.Campus.IOSDeviceRequestResponse:output_type -> api.IOSDeviceRequestResponseReply - 3, // 92: api.Campus.CreateDevice:output_type -> api.CreateDeviceReply - 5, // 93: api.Campus.DeleteDevice:output_type -> api.DeleteDeviceReply - 67, // [67:94] is the sub-list for method output_type - 40, // [40:67] is the sub-list for method input_type - 40, // [40:40] is the sub-list for extension type_name - 40, // [40:40] is the sub-list for extension extendee - 0, // [0:40] is the sub-list for field type_name + 71, // 31: api.ListMoviesRequest.oldest_date_at:type_name -> google.protobuf.Timestamp + 54, // 32: api.ListMoviesReply.movies:type_name -> api.Movie + 71, // 33: api.Movie.date:type_name -> google.protobuf.Timestamp + 71, // 34: api.Movie.created:type_name -> google.protobuf.Timestamp + 1, // 35: api.CreateFeedbackRequest.recipient:type_name -> api.CreateFeedbackRequest.Recipient + 56, // 36: api.CreateFeedbackRequest.location:type_name -> api.Coordinate + 71, // 37: api.GetCanteenHeadCountReply.timestamp:type_name -> google.protobuf.Timestamp + 14, // 38: api.Campus.ListNewsAlerts:input_type -> api.ListNewsAlertsRequest + 11, // 39: api.Campus.ListNewsSources:input_type -> api.ListNewsSourcesRequest + 10, // 40: api.Campus.ListNews:input_type -> api.ListNewsRequest + 17, // 41: api.Campus.ListCanteenRatings:input_type -> api.ListCanteenRatingsRequest + 19, // 42: api.Campus.GetDishRatings:input_type -> api.GetDishRatingsRequest + 23, // 43: api.Campus.CreateCanteenRating:input_type -> api.CreateCanteenRatingRequest + 25, // 44: api.Campus.CreateDishRating:input_type -> api.CreateDishRatingRequest + 26, // 45: api.Campus.ListAvailableDishTags:input_type -> api.ListAvailableDishTagsRequest + 28, // 46: api.Campus.ListNameTags:input_type -> api.ListNameTagsRequest + 30, // 47: api.Campus.ListAvailableCanteenTags:input_type -> api.ListAvailableCanteenTagsRequest + 36, // 48: api.Campus.ListCanteens:input_type -> api.ListCanteensRequest + 39, // 49: api.Campus.ListDishes:input_type -> api.ListDishesRequest + 41, // 50: api.Campus.ListResponsiblePerson:input_type -> api.ListResponsiblePersonRequest + 45, // 51: api.Campus.ListMoreInformation:input_type -> api.ListMoreInformationRequest + 47, // 52: api.Campus.ListOpeningTimes:input_type -> api.ListOpeningTimesRequest + 50, // 53: api.Campus.GetUpdateNote:input_type -> api.GetUpdateNoteRequest + 52, // 54: api.Campus.ListMovies:input_type -> api.ListMoviesRequest + 55, // 55: api.Campus.CreateFeedback:input_type -> api.CreateFeedbackRequest + 62, // 56: api.Campus.GetUploadStatus:input_type -> api.GetUploadStatusRequest + 64, // 57: api.Campus.GetNotification:input_type -> api.GetNotificationRequest + 66, // 58: api.Campus.GetNotificationConfirm:input_type -> api.GetNotificationConfirmRequest + 60, // 59: api.Campus.GetMember:input_type -> api.GetMemberRequest + 68, // 60: api.Campus.GetCanteenHeadCount:input_type -> api.GetCanteenHeadCountRequest + 6, // 61: api.Campus.IOSDeviceRequestResponse:input_type -> api.IOSDeviceRequestResponseRequest + 2, // 62: api.Campus.CreateDevice:input_type -> api.CreateDeviceRequest + 4, // 63: api.Campus.DeleteDevice:input_type -> api.DeleteDeviceRequest + 15, // 64: api.Campus.ListNewsAlerts:output_type -> api.ListNewsAlertsReply + 12, // 65: api.Campus.ListNewsSources:output_type -> api.ListNewsSourcesReply + 9, // 66: api.Campus.ListNews:output_type -> api.ListNewsReply + 18, // 67: api.Campus.ListCanteenRatings:output_type -> api.ListCanteenRatingsReply + 20, // 68: api.Campus.GetDishRatings:output_type -> api.GetDishRatingsReply + 22, // 69: api.Campus.CreateCanteenRating:output_type -> api.CreateCanteenRatingReply + 24, // 70: api.Campus.CreateDishRating:output_type -> api.CreateDishRatingReply + 27, // 71: api.Campus.ListAvailableDishTags:output_type -> api.ListAvailableDishTagsReply + 29, // 72: api.Campus.ListNameTags:output_type -> api.ListNameTagsReply + 31, // 73: api.Campus.ListAvailableCanteenTags:output_type -> api.ListAvailableCanteenTagsReply + 37, // 74: api.Campus.ListCanteens:output_type -> api.ListCanteensReply + 40, // 75: api.Campus.ListDishes:output_type -> api.ListDishesReply + 42, // 76: api.Campus.ListResponsiblePerson:output_type -> api.ListResponsiblePersonReply + 46, // 77: api.Campus.ListMoreInformation:output_type -> api.ListMoreInformationReply + 48, // 78: api.Campus.ListOpeningTimes:output_type -> api.ListOpeningTimesReply + 51, // 79: api.Campus.GetUpdateNote:output_type -> api.GetUpdateNoteReply + 53, // 80: api.Campus.ListMovies:output_type -> api.ListMoviesReply + 57, // 81: api.Campus.CreateFeedback:output_type -> api.CreateFeedbackReply + 63, // 82: api.Campus.GetUploadStatus:output_type -> api.GetUploadStatusReply + 65, // 83: api.Campus.GetNotification:output_type -> api.GetNotificationReply + 67, // 84: api.Campus.GetNotificationConfirm:output_type -> api.GetNotificationConfirmReply + 61, // 85: api.Campus.GetMember:output_type -> api.GetMemberReply + 69, // 86: api.Campus.GetCanteenHeadCount:output_type -> api.GetCanteenHeadCountReply + 7, // 87: api.Campus.IOSDeviceRequestResponse:output_type -> api.IOSDeviceRequestResponseReply + 3, // 88: api.Campus.CreateDevice:output_type -> api.CreateDeviceReply + 5, // 89: api.Campus.DeleteDevice:output_type -> api.DeleteDeviceReply + 64, // [64:90] is the sub-list for method output_type + 38, // [38:64] is the sub-list for method input_type + 38, // [38:38] is the sub-list for extension type_name + 38, // [38:38] is the sub-list for extension extendee + 0, // [0:38] is the sub-list for field type_name } func init() { file_tumdev_campus_backend_proto_init() } @@ -6073,54 +5800,6 @@ func file_tumdev_campus_backend_proto_init() { } } file_tumdev_campus_backend_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListStudyRoomsRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tumdev_campus_backend_proto_msgTypes[51].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListStudyRoomsReply); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tumdev_campus_backend_proto_msgTypes[52].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StudyRoomMsgElement); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tumdev_campus_backend_proto_msgTypes[53].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StudyRoom); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tumdev_campus_backend_proto_msgTypes[54].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ListMoviesRequest); i { case 0: return &v.state @@ -6132,7 +5811,7 @@ func file_tumdev_campus_backend_proto_init() { return nil } } - file_tumdev_campus_backend_proto_msgTypes[55].Exporter = func(v interface{}, i int) interface{} { + file_tumdev_campus_backend_proto_msgTypes[51].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ListMoviesReply); i { case 0: return &v.state @@ -6144,7 +5823,7 @@ func file_tumdev_campus_backend_proto_init() { return nil } } - file_tumdev_campus_backend_proto_msgTypes[56].Exporter = func(v interface{}, i int) interface{} { + file_tumdev_campus_backend_proto_msgTypes[52].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Movie); i { case 0: return &v.state @@ -6156,7 +5835,7 @@ func file_tumdev_campus_backend_proto_init() { return nil } } - file_tumdev_campus_backend_proto_msgTypes[57].Exporter = func(v interface{}, i int) interface{} { + file_tumdev_campus_backend_proto_msgTypes[53].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CreateFeedbackRequest); i { case 0: return &v.state @@ -6168,7 +5847,7 @@ func file_tumdev_campus_backend_proto_init() { return nil } } - file_tumdev_campus_backend_proto_msgTypes[58].Exporter = func(v interface{}, i int) interface{} { + file_tumdev_campus_backend_proto_msgTypes[54].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Coordinate); i { case 0: return &v.state @@ -6180,7 +5859,7 @@ func file_tumdev_campus_backend_proto_init() { return nil } } - file_tumdev_campus_backend_proto_msgTypes[59].Exporter = func(v interface{}, i int) interface{} { + file_tumdev_campus_backend_proto_msgTypes[55].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CreateFeedbackReply); i { case 0: return &v.state @@ -6192,7 +5871,7 @@ func file_tumdev_campus_backend_proto_init() { return nil } } - file_tumdev_campus_backend_proto_msgTypes[60].Exporter = func(v interface{}, i int) interface{} { + file_tumdev_campus_backend_proto_msgTypes[56].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CreateFeedbackImageReply); i { case 0: return &v.state @@ -6204,7 +5883,7 @@ func file_tumdev_campus_backend_proto_init() { return nil } } - file_tumdev_campus_backend_proto_msgTypes[61].Exporter = func(v interface{}, i int) interface{} { + file_tumdev_campus_backend_proto_msgTypes[57].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CreateFeedbackImageRequest); i { case 0: return &v.state @@ -6216,7 +5895,7 @@ func file_tumdev_campus_backend_proto_init() { return nil } } - file_tumdev_campus_backend_proto_msgTypes[62].Exporter = func(v interface{}, i int) interface{} { + file_tumdev_campus_backend_proto_msgTypes[58].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetMemberRequest); i { case 0: return &v.state @@ -6228,7 +5907,7 @@ func file_tumdev_campus_backend_proto_init() { return nil } } - file_tumdev_campus_backend_proto_msgTypes[63].Exporter = func(v interface{}, i int) interface{} { + file_tumdev_campus_backend_proto_msgTypes[59].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetMemberReply); i { case 0: return &v.state @@ -6240,7 +5919,7 @@ func file_tumdev_campus_backend_proto_init() { return nil } } - file_tumdev_campus_backend_proto_msgTypes[64].Exporter = func(v interface{}, i int) interface{} { + file_tumdev_campus_backend_proto_msgTypes[60].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetUploadStatusRequest); i { case 0: return &v.state @@ -6252,7 +5931,7 @@ func file_tumdev_campus_backend_proto_init() { return nil } } - file_tumdev_campus_backend_proto_msgTypes[65].Exporter = func(v interface{}, i int) interface{} { + file_tumdev_campus_backend_proto_msgTypes[61].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetUploadStatusReply); i { case 0: return &v.state @@ -6264,7 +5943,7 @@ func file_tumdev_campus_backend_proto_init() { return nil } } - file_tumdev_campus_backend_proto_msgTypes[66].Exporter = func(v interface{}, i int) interface{} { + file_tumdev_campus_backend_proto_msgTypes[62].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetNotificationRequest); i { case 0: return &v.state @@ -6276,7 +5955,7 @@ func file_tumdev_campus_backend_proto_init() { return nil } } - file_tumdev_campus_backend_proto_msgTypes[67].Exporter = func(v interface{}, i int) interface{} { + file_tumdev_campus_backend_proto_msgTypes[63].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetNotificationReply); i { case 0: return &v.state @@ -6288,7 +5967,7 @@ func file_tumdev_campus_backend_proto_init() { return nil } } - file_tumdev_campus_backend_proto_msgTypes[68].Exporter = func(v interface{}, i int) interface{} { + file_tumdev_campus_backend_proto_msgTypes[64].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetNotificationConfirmRequest); i { case 0: return &v.state @@ -6300,7 +5979,7 @@ func file_tumdev_campus_backend_proto_init() { return nil } } - file_tumdev_campus_backend_proto_msgTypes[69].Exporter = func(v interface{}, i int) interface{} { + file_tumdev_campus_backend_proto_msgTypes[65].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetNotificationConfirmReply); i { case 0: return &v.state @@ -6312,7 +5991,7 @@ func file_tumdev_campus_backend_proto_init() { return nil } } - file_tumdev_campus_backend_proto_msgTypes[70].Exporter = func(v interface{}, i int) interface{} { + file_tumdev_campus_backend_proto_msgTypes[66].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetCanteenHeadCountRequest); i { case 0: return &v.state @@ -6324,7 +6003,7 @@ func file_tumdev_campus_backend_proto_init() { return nil } } - file_tumdev_campus_backend_proto_msgTypes[71].Exporter = func(v interface{}, i int) interface{} { + file_tumdev_campus_backend_proto_msgTypes[67].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetCanteenHeadCountReply); i { case 0: return &v.state @@ -6336,7 +6015,7 @@ func file_tumdev_campus_backend_proto_init() { return nil } } - file_tumdev_campus_backend_proto_msgTypes[72].Exporter = func(v interface{}, i int) interface{} { + file_tumdev_campus_backend_proto_msgTypes[68].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ListMoreInformationReply_MoreInformation); i { case 0: return &v.state @@ -6356,7 +6035,7 @@ func file_tumdev_campus_backend_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_tumdev_campus_backend_proto_rawDesc, NumEnums: 2, - NumMessages: 73, + NumMessages: 69, NumExtensions: 0, NumServices: 1, }, diff --git a/server/api/tumdev/campus_backend.pb.gw.go b/server/api/tumdev/campus_backend.pb.gw.go index c55dc7f9..26233dd8 100644 --- a/server/api/tumdev/campus_backend.pb.gw.go +++ b/server/api/tumdev/campus_backend.pb.gw.go @@ -505,24 +505,6 @@ func local_request_Campus_GetUpdateNote_0(ctx context.Context, marshaler runtime } -func request_Campus_ListStudyRooms_0(ctx context.Context, marshaler runtime.Marshaler, client CampusClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq ListStudyRoomsRequest - var metadata runtime.ServerMetadata - - msg, err := client.ListStudyRooms(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_Campus_ListStudyRooms_0(ctx context.Context, marshaler runtime.Marshaler, server CampusServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq ListStudyRoomsRequest - var metadata runtime.ServerMetadata - - msg, err := server.ListStudyRooms(ctx, &protoReq) - return msg, metadata, err - -} - var ( filter_Campus_ListMovies_0 = &utilities.DoubleArray{Encoding: map[string]int{"last_id": 0, "lastId": 1}, Base: []int{1, 1, 2, 0, 0}, Check: []int{0, 1, 1, 2, 3}} ) @@ -1441,31 +1423,6 @@ func RegisterCampusHandlerServer(ctx context.Context, mux *runtime.ServeMux, ser }) - mux.Handle("GET", pattern_Campus_ListStudyRooms_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/api.Campus/ListStudyRooms", runtime.WithHTTPPathPattern("/studyrooms")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_Campus_ListStudyRooms_0(annotatedContext, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - - forward_Campus_ListStudyRooms_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - mux.Handle("GET", pattern_Campus_ListMovies_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -2091,28 +2048,6 @@ func RegisterCampusHandlerClient(ctx context.Context, mux *runtime.ServeMux, cli }) - mux.Handle("GET", pattern_Campus_ListStudyRooms_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/api.Campus/ListStudyRooms", runtime.WithHTTPPathPattern("/studyrooms")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_Campus_ListStudyRooms_0(annotatedContext, inboundMarshaler, client, req, pathParams) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - - forward_Campus_ListStudyRooms_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - mux.Handle("GET", pattern_Campus_ListMovies_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -2441,8 +2376,6 @@ var ( pattern_Campus_GetUpdateNote_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1}, []string{"updatenote", "version"}, "")) - pattern_Campus_ListStudyRooms_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"studyrooms"}, "")) - pattern_Campus_ListMovies_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1}, []string{"movies", "last_id"}, "")) pattern_Campus_CreateFeedback_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"feedback"}, "")) @@ -2497,8 +2430,6 @@ var ( forward_Campus_GetUpdateNote_0 = runtime.ForwardResponseMessage - forward_Campus_ListStudyRooms_0 = runtime.ForwardResponseMessage - forward_Campus_ListMovies_0 = runtime.ForwardResponseMessage forward_Campus_CreateFeedback_0 = runtime.ForwardResponseMessage diff --git a/server/api/tumdev/campus_backend.proto b/server/api/tumdev/campus_backend.proto index b4302c74..5964d632 100644 --- a/server/api/tumdev/campus_backend.proto +++ b/server/api/tumdev/campus_backend.proto @@ -113,10 +113,6 @@ service Campus { option (google.api.http) = {get: "/updatenote/{version}"}; } - rpc ListStudyRooms(ListStudyRoomsRequest) returns (ListStudyRoomsReply) { - option (google.api.http) = {get: "/studyrooms"}; - } - rpc ListMovies(ListMoviesRequest) returns (ListMoviesReply) { option (google.api.http) = {get: "/movies/{last_id}"}; } @@ -479,25 +475,6 @@ message GetUpdateNoteReply { string version_name = 2; } -message ListStudyRoomsRequest {} -message ListStudyRoomsReply { - repeated StudyRoomMsgElement rooms = 1; -} -message StudyRoomMsgElement { - int32 id = 1; - string name = 2; - string details = 3; - repeated StudyRoom rooms = 4; -} - -message StudyRoom { - int32 group_id = 1; - int32 room_id = 2; - string room_code = 3; - string room_name = 4; - string building_name = 5; -} - message ListMoviesRequest { // the last Id you have requested. Use -1 to get all movies int32 last_id = 1; diff --git a/server/api/tumdev/campus_backend.swagger.json b/server/api/tumdev/campus_backend.swagger.json index ba26a3c6..146bc5b7 100644 --- a/server/api/tumdev/campus_backend.swagger.json +++ b/server/api/tumdev/campus_backend.swagger.json @@ -886,28 +886,6 @@ ] } }, - "/studyrooms": { - "get": { - "operationId": "Campus_ListStudyRooms", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/apiListStudyRoomsReply" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "tags": [ - "Campus" - ] - } - }, "/updatenote/{version}": { "get": { "operationId": "Campus_GetUpdateNote", @@ -1500,18 +1478,6 @@ } } }, - "apiListStudyRoomsReply": { - "type": "object", - "properties": { - "rooms": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/apiStudyRoomMsgElement" - } - } - } - }, "apiMovie": { "type": "object", "properties": { @@ -1790,50 +1756,6 @@ } } }, - "apiStudyRoom": { - "type": "object", - "properties": { - "groupId": { - "type": "integer", - "format": "int32" - }, - "roomId": { - "type": "integer", - "format": "int32" - }, - "roomCode": { - "type": "string" - }, - "roomName": { - "type": "string" - }, - "buildingName": { - "type": "string" - } - } - }, - "apiStudyRoomMsgElement": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "name": { - "type": "string" - }, - "details": { - "type": "string" - }, - "rooms": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/apiStudyRoom" - } - } - } - }, "apiTagsOverview": { "type": "object", "properties": { diff --git a/server/api/tumdev/campus_backend_grpc.pb.go b/server/api/tumdev/campus_backend_grpc.pb.go index da650e86..24dabd0c 100644 --- a/server/api/tumdev/campus_backend_grpc.pb.go +++ b/server/api/tumdev/campus_backend_grpc.pb.go @@ -36,7 +36,6 @@ const ( Campus_ListMoreInformation_FullMethodName = "/api.Campus/ListMoreInformation" Campus_ListOpeningTimes_FullMethodName = "/api.Campus/ListOpeningTimes" Campus_GetUpdateNote_FullMethodName = "/api.Campus/GetUpdateNote" - Campus_ListStudyRooms_FullMethodName = "/api.Campus/ListStudyRooms" Campus_ListMovies_FullMethodName = "/api.Campus/ListMovies" Campus_CreateFeedback_FullMethodName = "/api.Campus/CreateFeedback" Campus_GetUploadStatus_FullMethodName = "/api.Campus/GetUploadStatus" @@ -70,7 +69,6 @@ type CampusClient interface { ListMoreInformation(ctx context.Context, in *ListMoreInformationRequest, opts ...grpc.CallOption) (*ListMoreInformationReply, error) ListOpeningTimes(ctx context.Context, in *ListOpeningTimesRequest, opts ...grpc.CallOption) (*ListOpeningTimesReply, error) GetUpdateNote(ctx context.Context, in *GetUpdateNoteRequest, opts ...grpc.CallOption) (*GetUpdateNoteReply, error) - ListStudyRooms(ctx context.Context, in *ListStudyRoomsRequest, opts ...grpc.CallOption) (*ListStudyRoomsReply, error) ListMovies(ctx context.Context, in *ListMoviesRequest, opts ...grpc.CallOption) (*ListMoviesReply, error) CreateFeedback(ctx context.Context, opts ...grpc.CallOption) (Campus_CreateFeedbackClient, error) GetUploadStatus(ctx context.Context, in *GetUploadStatusRequest, opts ...grpc.CallOption) (*GetUploadStatusReply, error) @@ -238,15 +236,6 @@ func (c *campusClient) GetUpdateNote(ctx context.Context, in *GetUpdateNoteReque return out, nil } -func (c *campusClient) ListStudyRooms(ctx context.Context, in *ListStudyRoomsRequest, opts ...grpc.CallOption) (*ListStudyRoomsReply, error) { - out := new(ListStudyRoomsReply) - err := c.cc.Invoke(ctx, Campus_ListStudyRooms_FullMethodName, in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *campusClient) ListMovies(ctx context.Context, in *ListMoviesRequest, opts ...grpc.CallOption) (*ListMoviesReply, error) { out := new(ListMoviesReply) err := c.cc.Invoke(ctx, Campus_ListMovies_FullMethodName, in, out, opts...) @@ -383,7 +372,6 @@ type CampusServer interface { ListMoreInformation(context.Context, *ListMoreInformationRequest) (*ListMoreInformationReply, error) ListOpeningTimes(context.Context, *ListOpeningTimesRequest) (*ListOpeningTimesReply, error) GetUpdateNote(context.Context, *GetUpdateNoteRequest) (*GetUpdateNoteReply, error) - ListStudyRooms(context.Context, *ListStudyRoomsRequest) (*ListStudyRoomsReply, error) ListMovies(context.Context, *ListMoviesRequest) (*ListMoviesReply, error) CreateFeedback(Campus_CreateFeedbackServer) error GetUploadStatus(context.Context, *GetUploadStatusRequest) (*GetUploadStatusReply, error) @@ -452,9 +440,6 @@ func (UnimplementedCampusServer) ListOpeningTimes(context.Context, *ListOpeningT func (UnimplementedCampusServer) GetUpdateNote(context.Context, *GetUpdateNoteRequest) (*GetUpdateNoteReply, error) { return nil, status.Errorf(codes.Unimplemented, "method GetUpdateNote not implemented") } -func (UnimplementedCampusServer) ListStudyRooms(context.Context, *ListStudyRoomsRequest) (*ListStudyRoomsReply, error) { - return nil, status.Errorf(codes.Unimplemented, "method ListStudyRooms not implemented") -} func (UnimplementedCampusServer) ListMovies(context.Context, *ListMoviesRequest) (*ListMoviesReply, error) { return nil, status.Errorf(codes.Unimplemented, "method ListMovies not implemented") } @@ -786,24 +771,6 @@ func _Campus_GetUpdateNote_Handler(srv interface{}, ctx context.Context, dec fun return interceptor(ctx, in, info, handler) } -func _Campus_ListStudyRooms_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(ListStudyRoomsRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CampusServer).ListStudyRooms(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: Campus_ListStudyRooms_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CampusServer).ListStudyRooms(ctx, req.(*ListStudyRoomsRequest)) - } - return interceptor(ctx, in, info, handler) -} - func _Campus_ListMovies_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(ListMoviesRequest) if err := dec(in); err != nil { @@ -1063,10 +1030,6 @@ var Campus_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetUpdateNote", Handler: _Campus_GetUpdateNote_Handler, }, - { - MethodName: "ListStudyRooms", - Handler: _Campus_ListStudyRooms_Handler, - }, { MethodName: "ListMovies", Handler: _Campus_ListMovies_Handler, From b6633d9c836857803d5f5f9749a1011b95e4e578 Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Sun, 22 Oct 2023 17:31:34 +0200 Subject: [PATCH 04/11] removed the roomfinder rooms from the models --- server/backend/migration/20220126230000.go | 97 ++++++++++++++++++++-- server/model/roomfinder_building2area.go | 29 ------- server/model/roomfinder_buildings.go | 35 -------- server/model/roomfinder_buildings2gps.go | 35 -------- server/model/roomfinder_buildings2maps.go | 27 ------ server/model/roomfinder_maps.go | 30 ------- server/model/roomfinder_rooms.go | 39 --------- server/model/roomfinder_rooms2maps.go | 27 ------ 8 files changed, 90 insertions(+), 229 deletions(-) delete mode 100644 server/model/roomfinder_building2area.go delete mode 100644 server/model/roomfinder_buildings.go delete mode 100644 server/model/roomfinder_buildings2gps.go delete mode 100644 server/model/roomfinder_buildings2maps.go delete mode 100644 server/model/roomfinder_maps.go delete mode 100644 server/model/roomfinder_rooms.go delete mode 100644 server/model/roomfinder_rooms2maps.go diff --git a/server/backend/migration/20220126230000.go b/server/backend/migration/20220126230000.go index d6bd0f6f..dd6662fa 100644 --- a/server/backend/migration/20220126230000.go +++ b/server/backend/migration/20220126230000.go @@ -1,11 +1,95 @@ package migration import ( - "github.com/TUM-Dev/Campus-Backend/server/model" "github.com/go-gormigrate/gormigrate/v2" + "github.com/guregu/null" "gorm.io/gorm" ) +// RoomfinderRooms struct is a row record of the roomfinder_rooms table in the tca database +type RoomfinderRooms struct { + RoomID int64 `gorm:"primary_key;column:room_id;type:int;" json:"room_id"` + RoomCode null.String `gorm:"column:room_code;type:varchar(32);" json:"room_code"` + BuildingNr null.String `gorm:"column:building_nr;type:varchar(8);" json:"building_nr"` + ArchID null.String `gorm:"column:arch_id;type:varchar(16);" json:"arch_id"` + Info null.String `gorm:"column:info;type:varchar(64);" json:"info"` + Address null.String `gorm:"column:address;type:varchar(128);" json:"address"` + PurposeID null.Int `gorm:"column:purpose_id;type:int;" json:"purpose_id"` + Purpose null.String `gorm:"column:purpose;type:varchar(64);" json:"purpose"` + Seats null.Int `gorm:"column:seats;type:int;" json:"seats"` + UtmZone null.String `gorm:"column:utm_zone;type:varchar(4);" json:"utm_zone"` + UtmEasting null.String `gorm:"column:utm_easting;type:varchar(32);" json:"utm_easting"` + UtmNorthing null.String `gorm:"column:utm_northing;type:varchar(32);" json:"utm_northing"` + UnitID null.Int `gorm:"column:unit_id;type:int;" json:"unit_id"` + DefaultMapID null.Int `gorm:"column:default_map_id;type:int;" json:"default_map_id"` +} + +// TableName sets the insert table name for this struct type +func (r *RoomfinderRooms) TableName() string { + return "roomfinder_rooms" +} + +// RoomfinderBuilding2area struct is a row record of the roomfinder_building2area table in the tca database +type RoomfinderBuilding2area struct { + BuildingNr string `gorm:"primary_key;column:building_nr;type:varchar(8);" json:"building_nr"` + AreaID int32 `gorm:"column:area_id;type:int;" json:"area_id"` + Campus string `gorm:"column:campus;type:char;size:1;" json:"campus"` + Name string `gorm:"column:name;type:varchar(32);" json:"name"` +} + +// TableName sets the insert table name for this struct type +func (r *RoomfinderBuilding2area) TableName() string { + return "roomfinder_building2area" +} + +// RoomfinderBuildings struct is a row record of the roomfinder_buildings table in the tca database +type RoomfinderBuildings struct { + BuildingNr string `gorm:"primary_key;column:building_nr;type:varchar(8);" json:"building_nr"` + UtmZone null.String `gorm:"column:utm_zone;type:varchar(4);" json:"utm_zone"` + UtmEasting null.String `gorm:"column:utm_easting;type:varchar(32);" json:"utm_easting"` + UtmNorthing null.String `gorm:"column:utm_northing;type:varchar(32);" json:"utm_northing"` + DefaultMapID null.Int `gorm:"column:default_map_id;type:int;" json:"default_map_id"` +} + +// TableName sets the insert table name for this struct type +func (r *RoomfinderBuildings) TableName() string { + return "roomfinder_buildings" +} + +// RoomfinderBuildings2gps struct is a row record of the roomfinder_buildings2gps table in the tca database +type RoomfinderBuildings2gps struct { + ID string `gorm:"primary_key;column:id;type:varchar(8);" json:"id"` + Latitude null.String `gorm:"column:latitude;type:varchar(30);" json:"latitude"` + Longitude null.String `gorm:"column:longitude;type:varchar(30);" json:"longitude"` +} + +// TableName sets the insert table name for this struct type +func (r *RoomfinderBuildings2gps) TableName() string { + return "roomfinder_buildings2gps" +} + +// RoomfinderBuildings2maps struct is a row record of the roomfinder_buildings2maps table in the tca database +type RoomfinderBuildings2maps struct { + BuildingNr string `gorm:"primary_key;column:building_nr;type:varchar(8);" json:"building_nr"` + MapID int64 `gorm:"primary_key;column:map_id;type:int;" json:"map_id"` +} + +// TableName sets the insert table name for this struct type +func (r *RoomfinderBuildings2maps) TableName() string { + return "roomfinder_buildings2maps" +} + +// RoomfinderRooms2maps struct is a row record of the roomfinder_rooms2maps table in the tca database +type RoomfinderRooms2maps struct { + RoomID int64 `gorm:"primary_key;column:room_id;type:int;" json:"room_id"` + MapID int64 `gorm:"primary_key;column:map_id;type:int;" json:"map_id"` +} + +// TableName sets the insert table name for this struct type +func (r *RoomfinderRooms2maps) TableName() string { + return "roomfinder_rooms2maps" +} + // migrate20220126230000 // adds a fulltext index to the roomfinder_rooms table func (m TumDBMigrator) migrate20220126230000() *gormigrate.Migration { @@ -13,12 +97,11 @@ func (m TumDBMigrator) migrate20220126230000() *gormigrate.Migration { ID: "20220126230000", Migrate: func(tx *gorm.DB) error { if err := tx.AutoMigrate( - &model.RoomfinderRooms{}, - &model.RoomfinderBuilding2area{}, - &model.RoomfinderBuildings2gps{}, - &model.RoomfinderBuildings2maps{}, - &model.RoomfinderRooms{}, - &model.RoomfinderRooms2maps{}, + &RoomfinderRooms{}, + &RoomfinderBuilding2area{}, + &RoomfinderBuildings2gps{}, + &RoomfinderBuildings2maps{}, + &RoomfinderRooms2maps{}, ); err != nil { return err } diff --git a/server/model/roomfinder_building2area.go b/server/model/roomfinder_building2area.go deleted file mode 100644 index 4f72cda4..00000000 --- a/server/model/roomfinder_building2area.go +++ /dev/null @@ -1,29 +0,0 @@ -package model - -import ( - "database/sql" - "time" - - "github.com/gofrs/uuid/v5" - "github.com/guregu/null" -) - -var ( - _ = time.Second - _ = sql.LevelDefault - _ = null.Bool{} - _ = uuid.UUID{} -) - -// RoomfinderBuilding2area struct is a row record of the roomfinder_building2area table in the tca database -type RoomfinderBuilding2area struct { - BuildingNr string `gorm:"primary_key;column:building_nr;type:varchar(8);" json:"building_nr"` - AreaID int32 `gorm:"column:area_id;type:int;" json:"area_id"` - Campus string `gorm:"column:campus;type:char;size:1;" json:"campus"` - Name string `gorm:"column:name;type:varchar(32);" json:"name"` -} - -// TableName sets the insert table name for this struct type -func (r *RoomfinderBuilding2area) TableName() string { - return "roomfinder_building2area" -} diff --git a/server/model/roomfinder_buildings.go b/server/model/roomfinder_buildings.go deleted file mode 100644 index 24616e88..00000000 --- a/server/model/roomfinder_buildings.go +++ /dev/null @@ -1,35 +0,0 @@ -package model - -import ( - "database/sql" - "time" - - "github.com/gofrs/uuid/v5" - "github.com/guregu/null" -) - -var ( - _ = time.Second - _ = sql.LevelDefault - _ = null.Bool{} - _ = uuid.UUID{} -) - -// RoomfinderBuildings struct is a row record of the roomfinder_buildings table in the tca database -type RoomfinderBuildings struct { - BuildingNr string `gorm:"primary_key;column:building_nr;type:varchar(8);" json:"building_nr"` - UtmZone null.String `gorm:"column:utm_zone;type:varchar(4);" json:"utm_zone"` - UtmEasting null.String `gorm:"column:utm_easting;type:varchar(32);" json:"utm_easting"` - UtmNorthing null.String `gorm:"column:utm_northing;type:varchar(32);" json:"utm_northing"` - DefaultMapID null.Int `gorm:"column:default_map_id;type:int;" json:"default_map_id"` -} - -// TableName sets the insert table name for this struct type -func (r *RoomfinderBuildings) TableName() string { - return "roomfinder_buildings" -} - -// BeforeSave invoked before saving, return an error if field is not populated. -func (r *RoomfinderBuildings) BeforeSave() error { - return nil -} diff --git a/server/model/roomfinder_buildings2gps.go b/server/model/roomfinder_buildings2gps.go deleted file mode 100644 index ba428520..00000000 --- a/server/model/roomfinder_buildings2gps.go +++ /dev/null @@ -1,35 +0,0 @@ -package model - -import ( - "database/sql" - "time" - - "gorm.io/gorm" - - "github.com/gofrs/uuid/v5" - "github.com/guregu/null" -) - -var ( - _ = time.Second - _ = sql.LevelDefault - _ = null.Bool{} - _ = uuid.UUID{} -) - -// RoomfinderBuildings2gps struct is a row record of the roomfinder_buildings2gps table in the tca database -type RoomfinderBuildings2gps struct { - ID string `gorm:"primary_key;column:id;type:varchar(8);" json:"id"` - Latitude null.String `gorm:"column:latitude;type:varchar(30);" json:"latitude"` - Longitude null.String `gorm:"column:longitude;type:varchar(30);" json:"longitude"` -} - -// TableName sets the insert table name for this struct type -func (r *RoomfinderBuildings2gps) TableName() string { - return "roomfinder_buildings2gps" -} - -// BeforeSave invoked before saving, return an error if field is not populated. -func (r *RoomfinderBuildings2gps) BeforeSave(*gorm.DB) error { - return nil -} diff --git a/server/model/roomfinder_buildings2maps.go b/server/model/roomfinder_buildings2maps.go deleted file mode 100644 index 50b3cecf..00000000 --- a/server/model/roomfinder_buildings2maps.go +++ /dev/null @@ -1,27 +0,0 @@ -package model - -import ( - "database/sql" - "time" - - "github.com/gofrs/uuid/v5" - "github.com/guregu/null" -) - -var ( - _ = time.Second - _ = sql.LevelDefault - _ = null.Bool{} - _ = uuid.UUID{} -) - -// RoomfinderBuildings2maps struct is a row record of the roomfinder_buildings2maps table in the tca database -type RoomfinderBuildings2maps struct { - BuildingNr string `gorm:"primary_key;column:building_nr;type:varchar(8);" json:"building_nr"` - MapID int64 `gorm:"primary_key;column:map_id;type:int;" json:"map_id"` -} - -// TableName sets the insert table name for this struct type -func (r *RoomfinderBuildings2maps) TableName() string { - return "roomfinder_buildings2maps" -} diff --git a/server/model/roomfinder_maps.go b/server/model/roomfinder_maps.go deleted file mode 100644 index e34f6a55..00000000 --- a/server/model/roomfinder_maps.go +++ /dev/null @@ -1,30 +0,0 @@ -package model - -import ( - "database/sql" - "time" - - "github.com/gofrs/uuid/v5" - "github.com/guregu/null" -) - -var ( - _ = time.Second - _ = sql.LevelDefault - _ = null.Bool{} - _ = uuid.UUID{} -) - -// RoomfinderMaps struct is a row record of the roomfinder_maps table in the tca database -type RoomfinderMaps struct { - MapID int64 `gorm:"primary_key;column:map_id;type:int;" json:"map_id"` - Description string `gorm:"column:description;type:varchar(64);" json:"description"` - Scale int32 `gorm:"column:scale;type:int;" json:"scale"` - Width int32 `gorm:"column:width;type:int;" json:"width"` - Height int32 `gorm:"column:height;type:int;" json:"height"` -} - -// TableName sets the insert table name for this struct type -func (r *RoomfinderMaps) TableName() string { - return "roomfinder_maps" -} diff --git a/server/model/roomfinder_rooms.go b/server/model/roomfinder_rooms.go deleted file mode 100644 index 3b81d041..00000000 --- a/server/model/roomfinder_rooms.go +++ /dev/null @@ -1,39 +0,0 @@ -package model - -import ( - "database/sql" - "time" - - "github.com/gofrs/uuid/v5" - "github.com/guregu/null" -) - -var ( - _ = time.Second - _ = sql.LevelDefault - _ = null.Bool{} - _ = uuid.UUID{} -) - -// RoomfinderRooms struct is a row record of the roomfinder_rooms table in the tca database -type RoomfinderRooms struct { - RoomID int64 `gorm:"primary_key;column:room_id;type:int;" json:"room_id"` - RoomCode null.String `gorm:"column:room_code;type:varchar(32);" json:"room_code"` - BuildingNr null.String `gorm:"column:building_nr;type:varchar(8);" json:"building_nr"` - ArchID null.String `gorm:"column:arch_id;type:varchar(16);" json:"arch_id"` - Info null.String `gorm:"column:info;type:varchar(64);" json:"info"` - Address null.String `gorm:"column:address;type:varchar(128);" json:"address"` - PurposeID null.Int `gorm:"column:purpose_id;type:int;" json:"purpose_id"` - Purpose null.String `gorm:"column:purpose;type:varchar(64);" json:"purpose"` - Seats null.Int `gorm:"column:seats;type:int;" json:"seats"` - UtmZone null.String `gorm:"column:utm_zone;type:varchar(4);" json:"utm_zone"` - UtmEasting null.String `gorm:"column:utm_easting;type:varchar(32);" json:"utm_easting"` - UtmNorthing null.String `gorm:"column:utm_northing;type:varchar(32);" json:"utm_northing"` - UnitID null.Int `gorm:"column:unit_id;type:int;" json:"unit_id"` - DefaultMapID null.Int `gorm:"column:default_map_id;type:int;" json:"default_map_id"` -} - -// TableName sets the insert table name for this struct type -func (r *RoomfinderRooms) TableName() string { - return "roomfinder_rooms" -} diff --git a/server/model/roomfinder_rooms2maps.go b/server/model/roomfinder_rooms2maps.go deleted file mode 100644 index a7c7bafc..00000000 --- a/server/model/roomfinder_rooms2maps.go +++ /dev/null @@ -1,27 +0,0 @@ -package model - -import ( - "database/sql" - "time" - - "github.com/gofrs/uuid/v5" - "github.com/guregu/null" -) - -var ( - _ = time.Second - _ = sql.LevelDefault - _ = null.Bool{} - _ = uuid.UUID{} -) - -// RoomfinderRooms2maps struct is a row record of the roomfinder_rooms2maps table in the tca database -type RoomfinderRooms2maps struct { - RoomID int64 `gorm:"primary_key;column:room_id;type:int;" json:"room_id"` - MapID int64 `gorm:"primary_key;column:map_id;type:int;" json:"map_id"` -} - -// TableName sets the insert table name for this struct type -func (r *RoomfinderRooms2maps) TableName() string { - return "roomfinder_rooms2maps" -} From 2f8ed493c283aea3bde851112485641123057c72 Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Sun, 22 Oct 2023 17:54:08 +0200 Subject: [PATCH 05/11] fixed naming issues for the db models --- server/backend/cron/average_rating_computation.go | 4 ++-- server/backend/device.go | 10 +++++----- server/backend/migration/20220713000000.go | 2 +- server/model/cafeteria_rating_tag_average.go | 6 +++--- ...ag_options.go => cafeteria_rating_tag_option.go} | 0 server/model/{devices.go => device.go} | 4 ++-- server/model/ios_device_request_log.go | 6 +++--- ...result_published.go => published_exam_result.go} | 0 server/model/top_news.go | 13 ------------- 9 files changed, 16 insertions(+), 29 deletions(-) rename server/model/{cafeteria_rating_tag_options.go => cafeteria_rating_tag_option.go} (100%) rename server/model/{devices.go => device.go} (94%) rename server/model/{exam_result_published.go => published_exam_result.go} (100%) delete mode 100644 server/model/top_news.go diff --git a/server/backend/cron/average_rating_computation.go b/server/backend/cron/average_rating_computation.go index 8421e0ba..9c3324bb 100644 --- a/server/backend/cron/average_rating_computation.go +++ b/server/backend/cron/average_rating_computation.go @@ -59,7 +59,7 @@ func computeAverageForDishesInCafeteriasTags(c *CronService) { } func computeAverageCafeteriaTags(c *CronService) { - var results []model.CafeteriaRatingTagsAverage + var results []model.CafeteriaRatingTagAverage err := c.db.Raw("SELECT cr.cafeteriaID as cafeteriaID, crt.tagID as tagID, AVG(crt.points) as average, MAX(crt.points) as max, MIN(crt.points) as min, STD(crt.points) as std" + " FROM cafeteria_rating cr" + " JOIN cafeteria_rating_tag crt ON cr.cafeteriaRating = crt.correspondingRating" + @@ -68,7 +68,7 @@ func computeAverageCafeteriaTags(c *CronService) { if err != nil { log.WithError(err).Error("while precomputing average cafeteria tags.") } else if len(results) > 0 { - if err := c.db.Where("1=1").Delete(&model.CafeteriaRatingTagsAverage{}).Error; err != nil { + if err := c.db.Where("1=1").Delete(&model.CafeteriaRatingTagAverage{}).Error; err != nil { log.WithError(err).Error("Error while deleting old averages in the table.") } diff --git a/server/backend/device.go b/server/backend/device.go index b580a4e0..9e2ff94b 100644 --- a/server/backend/device.go +++ b/server/backend/device.go @@ -19,13 +19,13 @@ import ( // deviceBuffer stores all recent device calls in a buffer and flushes them to the database periodically type deviceBuffer struct { lock sync.Mutex - devices map[string]*model.Devices // key is uuid + devices map[string]*model.Device // key is uuid } func newDeviceBuffer() *deviceBuffer { return &deviceBuffer{ lock: sync.Mutex{}, - devices: make(map[string]*model.Devices), + devices: make(map[string]*model.Device), } } @@ -47,7 +47,7 @@ func (b *deviceBuffer) add(deviceID string, method string, osVersion string, app if _, exists := b.devices[deviceID]; exists { b.devices[deviceID].Counter++ } else { - b.devices[deviceID] = &model.Devices{ + b.devices[deviceID] = &model.Device{ UUID: deviceID, LastAccess: time.Now(), LastAPI: method, @@ -62,7 +62,7 @@ func (b *deviceBuffer) add(deviceID string, method string, osVersion string, app func (b *deviceBuffer) flush(tx *gorm.DB) error { b.lock.Lock() defer b.lock.Unlock() - devices := make([]*model.Devices, 0, len(b.devices)) + devices := make([]*model.Device, 0, len(b.devices)) for _, device := range b.devices { devices = append(devices, device) } @@ -86,7 +86,7 @@ func (b *deviceBuffer) flush(tx *gorm.DB) error { if err != nil { log.WithError(err).Error("failed to flush device buffer") } - b.devices = make(map[string]*model.Devices) + b.devices = make(map[string]*model.Device) return nil } diff --git a/server/backend/migration/20220713000000.go b/server/backend/migration/20220713000000.go index 0f3eadf5..09f9ba87 100644 --- a/server/backend/migration/20220713000000.go +++ b/server/backend/migration/20220713000000.go @@ -18,7 +18,7 @@ func (m TumDBMigrator) migrate20220713000000() *gormigrate.Migration { &model.CafeteriaRating{}, &model.CafeteriaRatingAverage{}, &model.CafeteriaRatingTag{}, - &model.CafeteriaRatingTagsAverage{}, + &model.CafeteriaRatingTagAverage{}, &model.CafeteriaRatingTagOption{}, &model.Dish{}, &model.DishesOfTheWeek{}, diff --git a/server/model/cafeteria_rating_tag_average.go b/server/model/cafeteria_rating_tag_average.go index 6c1abeb7..b969ebf7 100644 --- a/server/model/cafeteria_rating_tag_average.go +++ b/server/model/cafeteria_rating_tag_average.go @@ -1,7 +1,7 @@ package model -// CafeteriaRatingTagsAverage stores all precomputed values for the cafeteria ratings -type CafeteriaRatingTagsAverage struct { +// CafeteriaRatingTagAverage stores all precomputed values for the cafeteria ratings +type CafeteriaRatingTagAverage struct { CafeteriaRatingTagsAverage int64 `gorm:"primary_key;AUTO_INCREMENT;column:cafeteriaRatingTagsAverage;type:int;not null;" json:"canteenRatingTagsAverage"` CafeteriaID int64 `gorm:"column:cafeteriaID;foreignKey:cafeteria;type:int;not null;" json:"canteenID"` TagID int64 `gorm:"column:tagID;foreignKey:cafeteriaRatingTagOption;type:int;not null;" json:"tagID"` @@ -12,6 +12,6 @@ type CafeteriaRatingTagsAverage struct { } // TableName sets the insert table name for this struct type -func (n *CafeteriaRatingTagsAverage) TableName() string { +func (n *CafeteriaRatingTagAverage) TableName() string { return "cafeteria_rating_tag_average" } diff --git a/server/model/cafeteria_rating_tag_options.go b/server/model/cafeteria_rating_tag_option.go similarity index 100% rename from server/model/cafeteria_rating_tag_options.go rename to server/model/cafeteria_rating_tag_option.go diff --git a/server/model/devices.go b/server/model/device.go similarity index 94% rename from server/model/devices.go rename to server/model/device.go index 205a5ae9..6542aa24 100755 --- a/server/model/devices.go +++ b/server/model/device.go @@ -6,8 +6,8 @@ import ( "github.com/guregu/null" ) -// Devices struct is a row record of the devices table in the tca database -type Devices struct { +// Device struct is a row record of the devices table in the tca database +type Device struct { Device int64 `gorm:"primary_key;AUTO_INCREMENT;column:device;type:int;" json:"device"` Member null.Int `gorm:"column:member;type:int;" json:"member"` UUID string `gorm:"column:uuid;type:varchar(50);" json:"uuid"` diff --git a/server/model/ios_device_request_log.go b/server/model/ios_device_request_log.go index 5420999d..3a06165b 100644 --- a/server/model/ios_device_request_log.go +++ b/server/model/ios_device_request_log.go @@ -13,8 +13,8 @@ import "time" // containing the RequestID and the data. type IOSDeviceRequestLog struct { RequestID string `gorm:"primary_key;default:UUID()" json:"requestId"` - DeviceID string `json:"deviceId" gorm:"size:200;not null"` - Device IOSDevice `json:"device" gorm:"constraint:OnDelete:CASCADE;"` - RequestType string `json:"requestType" gorm:"not null;type:enum ('CAMPUS_TOKEN_REQUEST');"` + DeviceID string `gorm:"size:200;not null" json:"deviceId"` + Device IOSDevice `gorm:"constraint:OnDelete:CASCADE;" json:"device"` + RequestType string `gorm:"not null;type:enum ('CAMPUS_TOKEN_REQUEST');" json:"requestType"` CreatedAt time.Time `gorm:"autoCreateTime" json:"createdAt"` } diff --git a/server/model/exam_result_published.go b/server/model/published_exam_result.go similarity index 100% rename from server/model/exam_result_published.go rename to server/model/published_exam_result.go diff --git a/server/model/top_news.go b/server/model/top_news.go deleted file mode 100644 index 975a459b..00000000 --- a/server/model/top_news.go +++ /dev/null @@ -1,13 +0,0 @@ -package model - -import ( - "time" -) - -type TopNews struct { - Name string - Link string `protobuf:"bytes,2,opt,name=link,proto3" json:"link,omitempty"` - Created *time.Time - From *time.Time - To *time.Time -} From c2cb0ebbf13f7204ee8fa64a5997040b54d5230b Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Sun, 22 Oct 2023 18:20:33 +0200 Subject: [PATCH 06/11] fixed a typo --- server/backend/migration/migration.go | 1 - 1 file changed, 1 deletion(-) diff --git a/server/backend/migration/migration.go b/server/backend/migration/migration.go index 710c333f..f9682f71 100644 --- a/server/backend/migration/migration.go +++ b/server/backend/migration/migration.go @@ -24,7 +24,6 @@ func (m TumDBMigrator) Migrate() error { if m.shouldAutoMigrate { log.Info("Using automigration") err := m.database.AutoMigrate( - &model.TopNews{}, &model.Crontab{}, &model.File{}, &model.NewsSource{}, From a59f8276cdbefbd757c498e6c177ab5ff79b3eaf Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Sun, 22 Oct 2023 23:30:13 +0200 Subject: [PATCH 07/11] chore: migration smoke testing (#257) * added a rough testcase that assures that migrations don't fail without us noticing * fixed a build error * refactored files around * added the ability to exit after migration * fixed the testcase * made the action sleeps enough that the db gets its shit together * linting fix * tested a different way of communicating with the db * added a request for the docker logs after waiting * more logging * tested a different approach * tested a different approach * more debugging info * tested different config * refactored the wait for db part and source-schema check * migrated the src schema to live in an migation * fixed formatting issue * fixed the migration not being used * linting * tested different way of execing sql * tested even more different way of executing the source shema * fixed executing empty statements * made sure only nessesary things are logged for `migrate20200000000000` * formatting * refactored the migrations to not depend on the TumDBMigrator struct * renamed EXIT_AFTER_MIGRATION -> CI_EXIT_AFTER_MIGRATION * tested a different way of migrating the newsSource table * fixed another typo * removed an automigration * removed now obsolete docs * removed the source schema from the docker-compose file to make running it possible * simplified the migration * added information how long migrations take as debug logs * formatting --- .github/workflows/main.yml | 28 +- README.md | 6 - .../backend/templates/sql-init-config.yaml | 8 - deployment/charts/backend/values.yaml | 1 - docker-compose.yaml | 1 - server/backend/migration/20200000000000.go | 48 + server/backend/migration/20210709193000.go | 2 +- server/backend/migration/20220126230000.go | 2 +- server/backend/migration/20220713000000.go | 2 +- server/backend/migration/20221119131300.go | 2 +- server/backend/migration/20221210000000.go | 2 +- server/backend/migration/20230530000000.go | 2 +- server/backend/migration/20230825000000.go | 2 +- server/backend/migration/20230826000000.go | 2 +- server/backend/migration/20230904000000.go | 2 +- server/backend/migration/20230904100000.go | 2 +- server/backend/migration/20231003000000.go | 2 +- server/backend/migration/migration.go | 80 +- .../migration/static_data}/source-schema.sql | 955 ++++++------------ server/main.go | 105 +- server/utils/db.go | 37 + server/utils/grpc_to_web.go | 50 + server/utils/telemetry.go | 38 + 23 files changed, 577 insertions(+), 802 deletions(-) delete mode 100644 deployment/charts/backend/templates/sql-init-config.yaml create mode 100644 server/backend/migration/20200000000000.go rename {deployment/charts/backend/files => server/backend/migration/static_data}/source-schema.sql (59%) create mode 100644 server/utils/db.go create mode 100644 server/utils/grpc_to_web.go create mode 100644 server/utils/telemetry.go diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 56123e25..c0c6d603 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -17,9 +17,35 @@ jobs: - name: run tests run: go test -v ./... working-directory: ./server + test_migrations: + runs-on: ubuntu-latest + services: + mariadb: + image: bitnami/mariadb:latest + ports: + - 3306:3306 + env: + MARIADB_ROOT_PASSWORD: super_secret_passw0rd + MARIADB_DATABASE: campus_db + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v4 + with: + go-version: '1.21' + cache-dependency-path: | + server/go.sum + - name: wait for db + run: sleep 20 && docker logs $(docker ps -qa) + - name: run migration + run: go run main.go + working-directory: ./server + env: + CI_EXIT_AFTER_MIGRATION: "true" + DB_DSN: root:super_secret_passw0rd@tcp(localhost:3306)/campus_db?charset=utf8mb4&parseTime=True&loc=Local + ENVIRONMENT: dev build: runs-on: ubuntu-latest - needs: [test] + needs: [test, test_migrations] steps: - name: Checkout repository uses: actions/checkout@v4 diff --git a/README.md b/README.md index 350490e2..a1c4d7db 100644 --- a/README.md +++ b/README.md @@ -80,12 +80,6 @@ The docker compose will start the server and a mariadb instance. The server will be available at `localhost:50051` and the mariadb instance at `localhost:3306`. Additionally, docker creates the volume `campus-db-data` to persist the data of the mariadb instances. -### Setting up the Database -The mariadb schema can be installed by executing the following command inside the mariadb container: -```bash -mysql --user=root --password=secret_root_password campus_db < /entrypoint/schema.sql -``` - ### Environment Variables The following environment variables need to be set for the server to work properly: * [REQUIRED] `DB_NAME`: The name of the database to use. diff --git a/deployment/charts/backend/templates/sql-init-config.yaml b/deployment/charts/backend/templates/sql-init-config.yaml deleted file mode 100644 index 5183fe11..00000000 --- a/deployment/charts/backend/templates/sql-init-config.yaml +++ /dev/null @@ -1,8 +0,0 @@ -kind: ConfigMap -apiVersion: v1 -metadata: - name: sql-init - namespace: {{ $.Values.namespace }} -data: - schema.sql: |- -{{ .Files.Get "files/source-schema.sql" | indent 4 }} diff --git a/deployment/charts/backend/values.yaml b/deployment/charts/backend/values.yaml index 1d2fa341..9ac3673b 100644 --- a/deployment/charts/backend/values.yaml +++ b/deployment/charts/backend/values.yaml @@ -38,7 +38,6 @@ mariadb: storageClass: local-path volumePermissions: enabled: true - initdbScriptsConfigMap: sql-init backend: diff --git a/docker-compose.yaml b/docker-compose.yaml index 9bc5cc4a..e876f031 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -39,7 +39,6 @@ services: - MARIADB_DATABASE=${DB_NAME} volumes: - campus-db-data:/bitnami/mariadb - - ./deployment/charts/backend/files/source-schema.sql:/docker-entrypoint-startdb.d/schema.sql healthcheck: test: ['CMD', '/opt/bitnami/scripts/mariadb/healthcheck.sh'] interval: 15s diff --git a/server/backend/migration/20200000000000.go b/server/backend/migration/20200000000000.go new file mode 100644 index 00000000..3ed3e9a6 --- /dev/null +++ b/server/backend/migration/20200000000000.go @@ -0,0 +1,48 @@ +package migration + +import ( + _ "embed" + "regexp" + "strings" + + log "github.com/sirupsen/logrus" + "gorm.io/gorm/logger" + + "github.com/go-gormigrate/gormigrate/v2" + "gorm.io/gorm" +) + +//go:embed static_data/source-schema.sql +var sourceSchema string + +// migrate20200000000000 +// adds the source schema +func migrate20200000000000() *gormigrate.Migration { + return &gormigrate.Migration{ + ID: "20200000000000", + Migrate: func(tx *gorm.DB) error { + tx = tx.Session(&gorm.Session{Logger: logger.Default.LogMode(logger.Silent)}) + for _, line := range strings.Split(sourceSchema, ";") { + line = strings.TrimSpace(line) + if line == "" { + continue + } + if err := tx.Exec(line).Error; err != nil { + log.WithError(err).WithField("line", line).Error("failed to execute line") + return err + } + } + return nil + }, + Rollback: func(tx *gorm.DB) error { + re := regexp.MustCompile(`create table if not exists (?P\S+)`) + tables := re.FindAllStringSubmatch(sourceSchema, -1) + for _, table := range tables { + if err := tx.Migrator().DropTable(table[re.SubexpIndex("table_name")]); err != nil { + return err + } + } + return nil + }, + } +} diff --git a/server/backend/migration/20210709193000.go b/server/backend/migration/20210709193000.go index 4968b74e..d18a3cb5 100644 --- a/server/backend/migration/20210709193000.go +++ b/server/backend/migration/20210709193000.go @@ -20,7 +20,7 @@ type File struct { // adds a "url" column to the database containing the url the file was downloaded from. // adds a "finished" column to the database that indicates, that a files download is finished. // adds a "fileDownload" cron job that runs every 5 minutes. -func (m TumDBMigrator) migrate20210709193000() *gormigrate.Migration { +func migrate20210709193000() *gormigrate.Migration { return &gormigrate.Migration{ ID: "20210709193000", Migrate: func(tx *gorm.DB) error { diff --git a/server/backend/migration/20220126230000.go b/server/backend/migration/20220126230000.go index dd6662fa..bb871570 100644 --- a/server/backend/migration/20220126230000.go +++ b/server/backend/migration/20220126230000.go @@ -92,7 +92,7 @@ func (r *RoomfinderRooms2maps) TableName() string { // migrate20220126230000 // adds a fulltext index to the roomfinder_rooms table -func (m TumDBMigrator) migrate20220126230000() *gormigrate.Migration { +func migrate20220126230000() *gormigrate.Migration { return &gormigrate.Migration{ ID: "20220126230000", Migrate: func(tx *gorm.DB) error { diff --git a/server/backend/migration/20220713000000.go b/server/backend/migration/20220713000000.go index 09f9ba87..82a5da06 100644 --- a/server/backend/migration/20220713000000.go +++ b/server/backend/migration/20220713000000.go @@ -8,7 +8,7 @@ import ( //migrate20210709193000 -func (m TumDBMigrator) migrate20220713000000() *gormigrate.Migration { +func migrate20220713000000() *gormigrate.Migration { return &gormigrate.Migration{ ID: "20220713000000", Migrate: func(tx *gorm.DB) error { diff --git a/server/backend/migration/20221119131300.go b/server/backend/migration/20221119131300.go index 8ea73cea..fd96ba3b 100644 --- a/server/backend/migration/20221119131300.go +++ b/server/backend/migration/20221119131300.go @@ -16,7 +16,7 @@ import ( //go:embed static_data/iosInitialSchedulingPriorities.json var iosInitialPrioritiesFile []byte -func (m TumDBMigrator) migrate20221119131300() *gormigrate.Migration { +func migrate20221119131300() *gormigrate.Migration { return &gormigrate.Migration{ ID: "20221119131300", Migrate: func(tx *gorm.DB) error { diff --git a/server/backend/migration/20221210000000.go b/server/backend/migration/20221210000000.go index 9ec49d3c..45ac4c47 100644 --- a/server/backend/migration/20221210000000.go +++ b/server/backend/migration/20221210000000.go @@ -9,7 +9,7 @@ import ( // migrate20221210000000 // adds a "canteenHeadCount" cron job that runs every 5 minutes. -func (m TumDBMigrator) migrate20221210000000() *gormigrate.Migration { +func migrate20221210000000() *gormigrate.Migration { return &gormigrate.Migration{ ID: "20221210000000", Migrate: func(tx *gorm.DB) error { diff --git a/server/backend/migration/20230530000000.go b/server/backend/migration/20230530000000.go index add100b8..9e044a70 100644 --- a/server/backend/migration/20230530000000.go +++ b/server/backend/migration/20230530000000.go @@ -26,7 +26,7 @@ type NewExamResultsSubscriber struct { LastNotifiedAt null.Time } -func (m TumDBMigrator) migrate20230530000000() *gormigrate.Migration { +func migrate20230530000000() *gormigrate.Migration { return &gormigrate.Migration{ ID: "20230530000000", Migrate: func(tx *gorm.DB) error { diff --git a/server/backend/migration/20230825000000.go b/server/backend/migration/20230825000000.go index db35ca9d..b35630c0 100644 --- a/server/backend/migration/20230825000000.go +++ b/server/backend/migration/20230825000000.go @@ -9,7 +9,7 @@ import ( // migrate20230825000000 // Removes the ability to run chat cronjobs -func (m TumDBMigrator) migrate20230825000000() *gormigrate.Migration { +func migrate20230825000000() *gormigrate.Migration { return &gormigrate.Migration{ ID: "20230825000000", Migrate: func(tx *gorm.DB) error { diff --git a/server/backend/migration/20230826000000.go b/server/backend/migration/20230826000000.go index 3b8fe0dc..92bb8e40 100644 --- a/server/backend/migration/20230826000000.go +++ b/server/backend/migration/20230826000000.go @@ -20,7 +20,7 @@ func (n *Feedback) TableName() string { // migrate20230826000000 // adds a "feedbackEmail" cron job that runs every 30 minutes. -func (m TumDBMigrator) migrate20230826000000() *gormigrate.Migration { +func migrate20230826000000() *gormigrate.Migration { return &gormigrate.Migration{ ID: "20230826000000", Migrate: func(tx *gorm.DB) error { diff --git a/server/backend/migration/20230904000000.go b/server/backend/migration/20230904000000.go index 6c96cba6..aa15f2e6 100644 --- a/server/backend/migration/20230904000000.go +++ b/server/backend/migration/20230904000000.go @@ -9,7 +9,7 @@ import ( // migrate20230904000000 // Removes ticketsales from the db-enums -func (m TumDBMigrator) migrate20230904000000() *gormigrate.Migration { +func migrate20230904000000() *gormigrate.Migration { return &gormigrate.Migration{ ID: "20230904000000", Migrate: func(tx *gorm.DB) error { diff --git a/server/backend/migration/20230904100000.go b/server/backend/migration/20230904100000.go index fb412917..cd785772 100644 --- a/server/backend/migration/20230904100000.go +++ b/server/backend/migration/20230904100000.go @@ -24,7 +24,7 @@ func (n *NewsSource) TableName() string { // migrate20230904100000 // migrates the crontab from kino to movie crontab -func (m TumDBMigrator) migrate20230904100000() *gormigrate.Migration { +func migrate20230904100000() *gormigrate.Migration { return &gormigrate.Migration{ ID: "20230904100000", Migrate: func(tx *gorm.DB) error { diff --git a/server/backend/migration/20231003000000.go b/server/backend/migration/20231003000000.go index b15eea95..1c0b696f 100644 --- a/server/backend/migration/20231003000000.go +++ b/server/backend/migration/20231003000000.go @@ -84,7 +84,7 @@ var staticData embed.FS // migrate20231003000000 // migrates the static data for the canteen rating system and adds the necessary cronjob entries -func (m TumDBMigrator) migrate20231003000000() *gormigrate.Migration { +func migrate20231003000000() *gormigrate.Migration { return &gormigrate.Migration{ ID: "20231003000000", Migrate: func(tx *gorm.DB) error { diff --git a/server/backend/migration/migration.go b/server/backend/migration/migration.go index f9682f71..c13e32d5 100644 --- a/server/backend/migration/migration.go +++ b/server/backend/migration/migration.go @@ -2,38 +2,27 @@ package migration import ( + "time" + "github.com/TUM-Dev/Campus-Backend/server/model" "github.com/go-gormigrate/gormigrate/v2" log "github.com/sirupsen/logrus" "gorm.io/gorm" ) -// TumDBMigrator contains a reference to our database -type TumDBMigrator struct { - database *gorm.DB - shouldAutoMigrate bool -} - -// New creates a new TumDBMigrator with a database -func New(db *gorm.DB, shouldAutoMigrate bool) TumDBMigrator { - return TumDBMigrator{database: db, shouldAutoMigrate: shouldAutoMigrate} +func autoMigrate(db *gorm.DB) error { + err := db.AutoMigrate( + &model.Crontab{}, + &model.File{}, + &model.NewsSource{}, + &model.NewsAlert{}, + &model.News{}, + &model.CanteenHeadCount{}, + ) + return err } -// Migrate starts the migration either by using AutoMigrate in development environments or manually in prod -func (m TumDBMigrator) Migrate() error { - if m.shouldAutoMigrate { - log.Info("Using automigration") - err := m.database.AutoMigrate( - &model.Crontab{}, - &model.File{}, - &model.NewsSource{}, - &model.NewsAlert{}, - &model.News{}, - &model.CanteenHeadCount{}, - ) - return err - } - log.Info("Using manual migration") +func manualMigrate(db *gorm.DB) error { gormigrateOptions := &gormigrate.Options{ TableName: gormigrate.DefaultOptions.TableName, IDColumnName: gormigrate.DefaultOptions.IDColumnName, @@ -41,20 +30,33 @@ func (m TumDBMigrator) Migrate() error { UseTransaction: true, ValidateUnknownMigrations: true, } - mig := gormigrate.New(m.database, gormigrateOptions, []*gormigrate.Migration{ - m.migrate20210709193000(), - m.migrate20220126230000(), - m.migrate20220713000000(), - m.migrate20221119131300(), - m.migrate20221210000000(), - m.migrate20230825000000(), - m.migrate20230904000000(), - m.migrate20230530000000(), - m.migrate20230904100000(), - m.migrate20230826000000(), - m.migrate20231003000000(), - }) - err := mig.Migrate() - return err + migrations := []*gormigrate.Migration{ + migrate20200000000000(), + migrate20210709193000(), + migrate20220126230000(), + migrate20220713000000(), + migrate20221119131300(), + migrate20221210000000(), + migrate20230825000000(), + migrate20230904000000(), + migrate20230530000000(), + migrate20230904100000(), + migrate20230826000000(), + migrate20231003000000(), + } + return gormigrate.New(db, gormigrateOptions, migrations).Migrate() +} +// Migrate starts the migration either by using AutoMigrate in development environments or manually in prod +func Migrate(db *gorm.DB, shouldAutoMigrate bool) error { + log.WithField("shouldAutoMigrate", shouldAutoMigrate).Info("starting migration") + start := time.Now() + var err error + if shouldAutoMigrate { + err = autoMigrate(db) + } else { + err = manualMigrate(db) + } + log.WithField("elapsed", time.Since(start)).Info("migration done") + return err } diff --git a/deployment/charts/backend/files/source-schema.sql b/server/backend/migration/static_data/source-schema.sql similarity index 59% rename from deployment/charts/backend/files/source-schema.sql rename to server/backend/migration/static_data/source-schema.sql index dad3cfc2..f7fea9c7 100644 --- a/deployment/charts/backend/files/source-schema.sql +++ b/server/backend/migration/static_data/source-schema.sql @@ -2,54 +2,44 @@ CREATE USER 'tca-students' IDENTIFIED BY 'strongpassword'; create table if not exists actions ( - action int auto_increment - primary key, + action int auto_increment primary key, name varchar(50) not null, description mediumtext not null, color varchar(6) not null -) - collate = utf8mb4_unicode_ci - auto_increment = 19; +) collate = utf8mb4_unicode_ci + auto_increment = 19; create table if not exists alarm_ban ( - ban int auto_increment - primary key, + ban int auto_increment primary key, created timestamp /* mariadb-5.3 */ default current_timestamp() not null, ip binary(16) not null, - constraint ip - unique (ip) -) - collate = utf8mb4_unicode_ci; + constraint ip unique (ip) +) collate = utf8mb4_unicode_ci; create table if not exists alarm_log ( - alarm int auto_increment - primary key, + alarm int auto_increment primary key, created timestamp /* mariadb-5.3 */ default current_timestamp() not null, message text not null, send int not null, received int not null, test enum ('true', 'false') default 'false' not null, ip binary(16) not null -) - collate = utf8mb4_unicode_ci; +) collate = utf8mb4_unicode_ci; create table if not exists barrierFree_moreInfo ( - id int(11) unsigned auto_increment - primary key, + id int(11) unsigned auto_increment primary key, title varchar(32) null, category varchar(11) null, url varchar(128) null -) - charset = utf8 - auto_increment = 11; +) charset = utf8 + auto_increment = 11; create table if not exists barrierFree_persons ( - id int(11) unsigned auto_increment - primary key, + id int(11) unsigned auto_increment primary key, name varchar(40) null, telephone varchar(32) null, email varchar(32) null, @@ -57,107 +47,81 @@ create table if not exists barrierFree_persons office varchar(16) null, officeHour varchar(16) null, tumID varchar(24) null -) - charset = utf8 - auto_increment = 19; +) charset = utf8 + auto_increment = 19; create table if not exists card_type ( - card_type int auto_increment - primary key, + card_type int auto_increment primary key, title varchar(255) null -) - auto_increment = 2; +) auto_increment = 2; create table if not exists chat_room ( - room int auto_increment - primary key, + room int auto_increment primary key, name varchar(100) not null, semester varchar(3) null, - constraint `Index 2` - unique (semester, name) -) - collate = utf8mb4_unicode_ci - auto_increment = 1724450; + constraint `Index 2` unique (semester, name) +) collate = utf8mb4_unicode_ci + auto_increment = 1724450; create table if not exists crontab ( cron int auto_increment, - `interval` int default 7200 not null, - lastRun int default 0 not null, + `interval` int default 7200 not null, + lastRun int default 0 not null, type enum ('news', 'mensa', 'chat', 'kino', 'roomfinder', 'ticketsale', 'alarm', 'fileDownload', 'canteenHeadCount') null, - id int null, - constraint cron - unique (cron) -) - collate = utf8mb4_unicode_ci - auto_increment = 44; + id int null, + constraint cron unique (cron) +) collate = utf8mb4_unicode_ci + auto_increment = 44; create table if not exists curricula ( - curriculum int auto_increment - primary key, + curriculum int auto_increment primary key, category enum ('bachelor', 'master') default 'bachelor' not null, name mediumtext not null, url mediumtext not null -) - collate = utf8mb4_unicode_ci - auto_increment = 16; +) collate = utf8mb4_unicode_ci + auto_increment = 16; create table if not exists dish ( - dish int auto_increment - primary key, + dish int auto_increment primary key, name varchar(150) not null, type varchar(20) not null -) - collate = utf8mb4_unicode_ci; +) collate = utf8mb4_unicode_ci; create table if not exists dishflags ( - flag int auto_increment - primary key, + flag int auto_increment primary key, short varchar(10) not null, description varchar(50) not null -) - collate = utf8mb4_unicode_ci; +) collate = utf8mb4_unicode_ci; create table if not exists dish2dishflags ( - dish2dishflags int auto_increment - primary key, + dish2dishflags int auto_increment primary key, dish int not null, flag int not null, - constraint dish - unique (dish, flag), - constraint dish2dishflags_ibfk_1 - foreign key (dish) references dish (dish) - on update cascade on delete cascade, - constraint dish2dishflags_ibfk_2 - foreign key (flag) references dishflags (flag) - on update cascade on delete cascade -) - collate = utf8mb4_unicode_ci; - -create or replace index flag - on dish2dishflags (flag); + constraint dish unique (dish, flag), + constraint dish2dishflags_ibfk_1 foreign key (dish) references dish (dish) on update cascade on delete cascade, + constraint dish2dishflags_ibfk_2 foreign key (flag) references dishflags (flag) on update cascade on delete cascade +) collate = utf8mb4_unicode_ci; + +create or replace index flag on dish2dishflags (flag); create table if not exists faculty ( - faculty int auto_increment - primary key, + faculty int auto_increment primary key, name varchar(150) not null, - constraint name - unique (name) -) - charset = utf8mb4 - auto_increment = 18; + constraint name unique (name) +) charset = utf8mb4 + auto_increment = 18; create table if not exists feedback ( - id int auto_increment - primary key, + id int auto_increment primary key, email_id text charset utf8 null, receiver text charset utf8 null, reply_to text charset utf8 null, @@ -166,26 +130,22 @@ create table if not exists feedback latitude decimal(11, 8) null, longitude decimal(11, 8) null, timestamp datetime /* mariadb-5.3 */ default current_timestamp() null -) - auto_increment = 293; +) auto_increment = 293; create table if not exists files ( - file int auto_increment - primary key, + file int auto_increment primary key, name mediumtext not null, path mediumtext not null, downloads int default 0 not null, url varchar(191) null, downloaded tinyint(1) default 1 null -) - collate = utf8mb4_unicode_ci - auto_increment = 34761; +) collate = utf8mb4_unicode_ci + auto_increment = 34761; create table if not exists kino ( - kino int auto_increment - primary key, + kino int auto_increment primary key, date datetime /* mariadb-5.3 */ not null, created timestamp /* mariadb-5.3 */ default current_timestamp() not null, title text not null, @@ -199,41 +159,32 @@ create table if not exists kino cover int null, trailer text null, link varchar(190) not null, - constraint link - unique (link), - constraint kino_ibfk_1 - foreign key (cover) references files (file) - on update cascade on delete set null -) - collate = utf8mb4_unicode_ci - auto_increment = 219; - -create or replace index cover - on kino (cover); + constraint link unique (link), + constraint kino_ibfk_1 foreign key (cover) references files (file) on update cascade on delete set null +) collate = utf8mb4_unicode_ci + auto_increment = 219; + +create or replace index cover on kino (cover); create table if not exists lecture ( - lecture int auto_increment - primary key, + lecture int auto_increment primary key, title varchar(255) null ); create table if not exists location ( - location int auto_increment - primary key, + location int auto_increment primary key, name text not null, lon float(10, 6) not null, lat float(10, 6) not null, radius int default 1000 not null comment 'in meters' -) - charset = utf8 - auto_increment = 2; +) charset = utf8 + auto_increment = 2; create table if not exists member ( - member int auto_increment - primary key, + member int auto_increment primary key, lrz_id varchar(7) not null, name varchar(150) not null, active_day int default 0 null, @@ -241,16 +192,13 @@ create table if not exists member student_id text null, employee_id text null, external_id text null, - constraint lrz_id - unique (lrz_id) -) - collate = utf8mb4_unicode_ci - auto_increment = 104353; + constraint lrz_id unique (lrz_id) +) collate = utf8mb4_unicode_ci + auto_increment = 104353; create table if not exists card ( - card int auto_increment - primary key, + card int auto_increment primary key, member int null, lecture int null, card_type int null, @@ -264,140 +212,94 @@ create table if not exists card updated_at date not null, duplicate_card int null, aggr_rating float default 0 null, - constraint card_ibfk_1 - foreign key (member) references member (member) - on delete set null, - constraint card_ibfk_2 - foreign key (lecture) references lecture (lecture) - on delete set null, - constraint card_ibfk_3 - foreign key (card_type) references card_type (card_type) - on delete set null, - constraint card_ibfk_4 - foreign key (duplicate_card) references card (card) - on delete set null + constraint card_ibfk_1 foreign key (member) references member (member) on delete set null, + constraint card_ibfk_2 foreign key (lecture) references lecture (lecture) on delete set null, + constraint card_ibfk_3 foreign key (card_type) references card_type (card_type) on delete set null, + constraint card_ibfk_4 foreign key (duplicate_card) references card (card) on delete set null ); -create or replace index card_type - on card (card_type); +create or replace index card_type on card (card_type); -create or replace index duplicate_card - on card (duplicate_card); +create or replace index duplicate_card on card (duplicate_card); -create or replace index lecture - on card (lecture); +create or replace index lecture on card (lecture); -create or replace index member - on card (member); +create or replace index member on card (member); create table if not exists card_box ( - card_box int auto_increment - primary key, + card_box int auto_increment primary key, member int null, title varchar(255) null, duration int not null, - constraint card_box_ibfk_1 - foreign key (member) references member (member) - on delete cascade -) - auto_increment = 6; + constraint card_box_ibfk_1 foreign key (member) references member (member) on delete cascade +) auto_increment = 6; -create or replace index member - on card_box (member); +create or replace index member on card_box (member); create table if not exists card_comment ( - card_comment int auto_increment - primary key, + card_comment int auto_increment primary key, member int null, card int not null, rating int default 0 null, created_at date not null, - constraint card_comment_ibfk_1 - foreign key (member) references member (member) - on delete set null, - constraint card_comment_ibfk_2 - foreign key (card) references card (card) - on delete cascade + constraint card_comment_ibfk_1 foreign key (member) references member (member) on delete set null, + constraint card_comment_ibfk_2 foreign key (card) references card (card) on delete cascade ); -create or replace index card - on card_comment (card); +create or replace index card on card_comment (card); -create or replace index member - on card_comment (member); +create or replace index member on card_comment (member); create table if not exists card_option ( - card_option int auto_increment - primary key, + card_option int auto_increment primary key, card int not null, text varchar(2000) default '' null, is_correct_answer tinyint(1) default 0 null, sort_order int default 0 not null, image varchar(2000) null, - constraint card_option_ibfk_1 - foreign key (card) references card (card) - on delete cascade + constraint card_option_ibfk_1 foreign key (card) references card (card) on delete cascade ); -create or replace index card - on card_option (card); +create or replace index card on card_option (card); create table if not exists chat_message ( - message int auto_increment - primary key, + message int auto_increment primary key, member int not null, room int not null, text longtext not null, created datetime /* mariadb-5.3 */ not null, signature longtext not null, - constraint FK_chat_message_chat_room - foreign key (room) references chat_room (room) - on update cascade on delete cascade, - constraint chat_message_ibfk_1 - foreign key (member) references member (member) - on update cascade on delete cascade -) - collate = utf8mb4_unicode_ci - auto_increment = 1977; - -create or replace index chat_message_b3c09425 - on chat_message (member); - -create or replace index chat_message_ca20ebca - on chat_message (room); + constraint FK_chat_message_chat_room foreign key (room) references chat_room (room) on update cascade on delete cascade, + constraint chat_message_ibfk_1 foreign key (member) references member (member) on update cascade on delete cascade +) collate = utf8mb4_unicode_ci + auto_increment = 1977; + +create or replace index chat_message_b3c09425 on chat_message (member); + +create or replace index chat_message_ca20ebca on chat_message (room); create table if not exists chat_room2members ( - room2members int auto_increment - primary key, + room2members int auto_increment primary key, room int not null, member int not null, - constraint chatroom_id - unique (room, member), - constraint FK_chat_room2members_chat_room - foreign key (room) references chat_room (room) - on update cascade on delete cascade, - constraint chat_room2members_ibfk_2 - foreign key (member) references member (member) - on update cascade on delete cascade -) - collate = utf8mb4_unicode_ci - auto_increment = 63377426; - -create or replace index chat_chatroom_members_29801a33 - on chat_room2members (room); - -create or replace index chat_chatroom_members_b3c09425 - on chat_room2members (member); + constraint chatroom_id unique (room, member), + constraint FK_chat_room2members_chat_room foreign key (room) references chat_room (room) on update cascade on delete cascade, + constraint chat_room2members_ibfk_2 foreign key (member) references member (member) on update cascade on delete cascade +) collate = utf8mb4_unicode_ci + auto_increment = 63377426; + +create or replace index chat_chatroom_members_29801a33 on chat_room2members (room); + +create or replace index chat_chatroom_members_b3c09425 on chat_room2members (member); create table if not exists devices ( - device int auto_increment - primary key, + device int auto_increment primary key, member int null, uuid varchar(50) not null, created timestamp /* mariadb-5.3 */ null, @@ -414,19 +316,14 @@ create table if not exists devices confirmationKey varchar(35) null, keyCreated datetime null, keyConfirmed datetime null, - constraint uuid - unique (uuid), - constraint devices_ibfk_1 - foreign key (member) references member (member) - on update cascade on delete cascade -) - collate = utf8mb4_unicode_ci - auto_increment = 144352; + constraint uuid unique (uuid), + constraint devices_ibfk_1 foreign key (member) references member (member) on update cascade on delete cascade +) collate = utf8mb4_unicode_ci + auto_increment = 144352; create table if not exists device2stats ( - device int default 0 not null - primary key, + device int default 0 not null primary key, LecturesPersonalActivity int default 0 not null, CafeteriaActivity int default 0 not null, WizNavStartActivity int default 0 not null, @@ -468,14 +365,10 @@ create table if not exists device2stats NewsCard2 int default 0 not null, NewsCard3 int default 0 not null, NewsCard7 int default 0 not null, - constraint device2stats_ibfk_2 - foreign key (device) references devices (device) - on update cascade on delete cascade -) - collate = utf8mb4_unicode_ci; + constraint device2stats_ibfk_2 foreign key (device) references devices (device) on update cascade on delete cascade +) collate = utf8mb4_unicode_ci; -create or replace index member - on devices (member); +create or replace index member on devices (member); create table if not exists members_card ( @@ -484,144 +377,105 @@ create table if not exists members_card card_box int null, last_answered_active_day int null, primary key (member, card), - constraint members_card_ibfk_1 - foreign key (member) references member (member) - on delete cascade, - constraint members_card_ibfk_2 - foreign key (card) references card (card) - on delete cascade, - constraint members_card_ibfk_3 - foreign key (card_box) references card_box (card_box) - on delete set null + constraint members_card_ibfk_1 foreign key (member) references member (member) on delete cascade, + constraint members_card_ibfk_2 foreign key (card) references card (card) on delete cascade, + constraint members_card_ibfk_3 foreign key (card_box) references card_box (card_box) on delete set null ); -create or replace index card - on members_card (card); +create or replace index card on members_card (card); -create or replace index card_box - on members_card (card_box); +create or replace index card_box on members_card (card_box); create table if not exists members_card_answer_history ( - members_card_answer_history int auto_increment - primary key, + members_card_answer_history int auto_increment primary key, member int not null, card int null, card_box int null, answer varchar(2000) null, answer_score float(10, 2) default 0.00 null, created_at date not null, - constraint members_card_answer_history_ibfk_1 - foreign key (member) references member (member) - on delete cascade, - constraint members_card_answer_history_ibfk_2 - foreign key (card) references card (card) - on delete set null, - constraint members_card_answer_history_ibfk_3 - foreign key (card_box) references card_box (card_box) - on delete set null + constraint members_card_answer_history_ibfk_1 foreign key (member) references member (member) on delete cascade, + constraint members_card_answer_history_ibfk_2 foreign key (card) references card (card) on delete set null, + constraint members_card_answer_history_ibfk_3 foreign key (card_box) references card_box (card_box) on delete set null ); -create or replace index card - on members_card_answer_history (card); +create or replace index card on members_card_answer_history (card); -create or replace index card_box - on members_card_answer_history (card_box); +create or replace index card_box on members_card_answer_history (card_box); -create or replace index member - on members_card_answer_history (member); +create or replace index member on members_card_answer_history (member); create table if not exists mensa ( - mensa int auto_increment - primary key, + mensa int auto_increment primary key, id int null, name mediumtext not null, address mediumtext not null, latitude float(10, 6) default 0.000000 not null, longitude float(10, 6) default 0.000000 not null, - constraint id - unique (id) -) - collate = utf8mb4_unicode_ci - auto_increment = 17; + constraint id unique (id) +) collate = utf8mb4_unicode_ci + auto_increment = 17; create table if not exists dish2mensa ( - dish2mensa int auto_increment - primary key, + dish2mensa int auto_increment primary key, mensa int not null, dish int not null, date date not null, created datetime /* mariadb-5.3 */ not null, modifierd timestamp /* mariadb-5.3 */ default '0000-00-00 00:00:00' not null on update current_timestamp(), - constraint dish2mensa_ibfk_1 - foreign key (mensa) references mensa (mensa) - on update cascade on delete cascade, - constraint dish2mensa_ibfk_2 - foreign key (dish) references dish (dish) - on update cascade on delete cascade -) - collate = utf8mb4_unicode_ci; + constraint dish2mensa_ibfk_1 foreign key (mensa) references mensa (mensa) on update cascade on delete cascade, + constraint dish2mensa_ibfk_2 foreign key (dish) references dish (dish) on update cascade on delete cascade +) collate = utf8mb4_unicode_ci; -create or replace index dish - on dish2mensa (dish); +create or replace index dish on dish2mensa (dish); -create or replace index mensa - on dish2mensa (mensa); +create or replace index mensa on dish2mensa (mensa); create table if not exists mensaplan_mensa ( - id int auto_increment - primary key, + id int auto_increment primary key, name varchar(100) not null, latitude double null, longitude double null, webid int null, category varchar(50) not null -) - engine = MyISAM - collate = utf8mb4_unicode_ci - auto_increment = 30; +) engine = MyISAM + collate = utf8mb4_unicode_ci + auto_increment = 30; create table if not exists mensaprices ( - price int auto_increment - primary key, + price int auto_increment primary key, created timestamp /* mariadb-5.3 */ default current_timestamp() not null, person mediumtext not null, type mediumtext not null, typeLong mediumtext not null, typeNumber int not null, value decimal not null -) - collate = utf8mb4_unicode_ci; +) collate = utf8mb4_unicode_ci; create table if not exists migrations ( - id varchar(255) not null - primary key + id varchar(255) not null primary key ); create table if not exists newsSource ( - source int auto_increment - primary key, + source int auto_increment primary key, title mediumtext not null, url mediumtext null, - icon int null, + icon int not null, hook enum ('newspread', 'impulsivHook') null, - constraint newsSource_ibfk_1 - foreign key (icon) references files (file) - on update cascade on delete set null -) - collate = utf8mb4_unicode_ci - auto_increment = 17; + constraint newsSource_ibfk_1 foreign key (icon) references files (file) on update cascade on delete cascade +) collate = utf8mb4_unicode_ci + auto_increment = 17; create table if not exists news ( - news int auto_increment - primary key, + news int auto_increment primary key, date datetime /* mariadb-5.3 */ not null, created timestamp /* mariadb-5.3 */ default current_timestamp() not null, title tinytext not null, @@ -630,57 +484,42 @@ create table if not exists news link varchar(190) not null, image text null, file int null, - constraint link - unique (link), - constraint news_ibfk_1 - foreign key (src) references newsSource (source) - on update cascade on delete cascade, - constraint news_ibfk_2 - foreign key (file) references files (file) - on update cascade on delete set null -) - collate = utf8mb4_unicode_ci - auto_increment = 770113; - -create or replace index file - on news (file); - -create or replace index src - on news (src); - -create or replace index icon - on newsSource (icon); + constraint link unique (link), + constraint news_ibfk_1 foreign key (src) references newsSource (source) on update cascade on delete cascade, + constraint news_ibfk_2 foreign key (file) references files (file) on update cascade on delete set null +) collate = utf8mb4_unicode_ci + auto_increment = 770113; + +create or replace index file on news (file); + +create or replace index src on news (src); + +create or replace index icon on newsSource (icon); create table if not exists news_alert ( - news_alert int auto_increment - primary key, + news_alert int auto_increment primary key, file int null, name varchar(100) null, link text null, created timestamp /* mariadb-5.3 */ default current_timestamp() not null, `from` datetime /* mariadb-5.3 */ default current_timestamp() not null, `to` datetime /* mariadb-5.3 */ default current_timestamp() not null, - constraint FK_File - unique (file) -) - charset = utf8mb4 - auto_increment = 7; + constraint FK_File unique (file) +) charset = utf8mb4 + auto_increment = 7; create table if not exists notification_type ( - type int auto_increment - primary key, + type int auto_increment primary key, name text not null, confirmation enum ('true', 'false') default 'false' not null -) - charset = utf8 - auto_increment = 4; +) charset = utf8 + auto_increment = 4; create table if not exists notification ( - notification int auto_increment - primary key, + notification int auto_increment primary key, type int not null, location int null, title text not null, @@ -688,21 +527,14 @@ create table if not exists notification created timestamp /* mariadb-5.3 */ default current_timestamp() not null, signature text null, silent tinyint(1) default 0 not null, - constraint notification_ibfk_1 - foreign key (type) references notification_type (type) - on update cascade on delete cascade, - constraint notification_ibfk_2 - foreign key (location) references location (location) - on update cascade on delete set null -) - charset = utf8 - auto_increment = 107; - -create or replace index location - on notification (location); - -create or replace index type - on notification (type); + constraint notification_ibfk_1 foreign key (type) references notification_type (type) on update cascade on delete cascade, + constraint notification_ibfk_2 foreign key (location) references location (location) on update cascade on delete set null +) charset = utf8 + auto_increment = 107; + +create or replace index location on notification (location); + +create or replace index type on notification (type); create table if not exists notification_confirmation ( @@ -712,20 +544,15 @@ create table if not exists notification_confirmation created timestamp /* mariadb-5.3 */ default current_timestamp() not null, received timestamp /* mariadb-5.3 */ null, primary key (notification, device), - constraint notification_confirmation_ibfk_1 - foreign key (notification) references notification (notification), - constraint notification_confirmation_ibfk_2 - foreign key (device) references devices (device) -) - charset = utf8; + constraint notification_confirmation_ibfk_1 foreign key (notification) references notification (notification), + constraint notification_confirmation_ibfk_2 foreign key (device) references devices (device) +) charset = utf8; -create or replace index device - on notification_confirmation (device); +create or replace index device on notification_confirmation (device); create table if not exists openinghours ( - id int auto_increment - primary key, + id int auto_increment primary key, category varchar(20) not null, name varchar(60) not null, address varchar(140) not null, @@ -736,31 +563,26 @@ create table if not exists openinghours url varchar(300) not null, language varchar(2) default 'de' null, reference_id int default -1 null -) - collate = utf8mb4_unicode_ci - auto_increment = 113; +) collate = utf8mb4_unicode_ci + auto_increment = 113; create table if not exists question ( - question int auto_increment - primary key, + question int auto_increment primary key, member int not null, text text not null, created timestamp /* mariadb-5.3 */ default current_timestamp() not null, end timestamp /* mariadb-5.3 */ null -) - auto_increment = 282; +) auto_increment = 282; -create or replace index member - on question (member); +create or replace index member on question (member); create table if not exists question2answer ( question int not null, answer int not null, member int not null, - constraint question - unique (question, member) + constraint question unique (question, member) ); create table if not exists question2faculty @@ -768,29 +590,21 @@ create table if not exists question2faculty question int not null, faculty int not null, primary key (question, faculty), - constraint question2faculty_ibfk_1 - foreign key (question) references question (question) - on update cascade on delete cascade, - constraint question2faculty_ibfk_2 - foreign key (faculty) references faculty (faculty) - on update cascade on delete cascade + constraint question2faculty_ibfk_1 foreign key (question) references question (question) on update cascade on delete cascade, + constraint question2faculty_ibfk_2 foreign key (faculty) references faculty (faculty) on update cascade on delete cascade ); -create or replace index faculty - on question2faculty (faculty); +create or replace index faculty on question2faculty (faculty); create table if not exists questionAnswers ( - answer int auto_increment - primary key, + answer int auto_increment primary key, text text not null -) - auto_increment = 3; +) auto_increment = 3; create table if not exists reports ( - report int auto_increment - primary key, + report int auto_increment primary key, device int null, created timestamp /* mariadb-5.3 */ default current_timestamp() not null, fixed enum ('true', 'false') default 'false' not null, @@ -810,32 +624,24 @@ create table if not exists reports screenHeight varchar(100) not null, screenOrientation varchar(100) not null, screenDpi varchar(100) not null, - constraint reports_ibfk_3 - foreign key (device) references devices (device) - on update cascade on delete set null -) - collate = utf8mb4_unicode_ci; + constraint reports_ibfk_3 foreign key (device) references devices (device) on update cascade on delete set null +) collate = utf8mb4_unicode_ci; -create or replace index device - on reports (device); +create or replace index device on reports (device); create table if not exists rights ( - `right` int auto_increment - primary key, + `right` int auto_increment primary key, name varchar(100) null, description mediumtext not null, category int default 0 not null, - constraint Unquie - unique (name) -) - collate = utf8mb4_unicode_ci - auto_increment = 14; + constraint Unquie unique (name) +) collate = utf8mb4_unicode_ci + auto_increment = 14; create table if not exists menu ( - menu int auto_increment - primary key, + menu int auto_increment primary key, `right` int null, parent int null, name varchar(255) null, @@ -844,126 +650,96 @@ create table if not exists menu icon varchar(200) not null, class varchar(200) not null, position int default 0 not null, - constraint menu_ibfk_1 - foreign key (`right`) references rights (`right`) - on update cascade on delete set null, - constraint menu_ibfk_2 - foreign key (parent) references menu (menu) - on update cascade on delete set null -) - collate = utf8mb4_unicode_ci - auto_increment = 25; - -create or replace index parent - on menu (parent); - -create or replace index `right` - on menu (`right`); + constraint menu_ibfk_1 foreign key (`right`) references rights (`right`) on update cascade on delete set null, + constraint menu_ibfk_2 foreign key (parent) references menu (menu) on update cascade on delete set null +) collate = utf8mb4_unicode_ci + auto_increment = 25; + +create or replace index parent on menu (parent); + +create or replace index `right` on menu (`right`); create table if not exists modules ( - module int auto_increment - primary key, + module int auto_increment primary key, name varchar(255) null, `right` int null, - constraint fkMod2Rights - foreign key (`right`) references rights (`right`) - on update cascade on delete set null -) - collate = utf8mb4_unicode_ci - auto_increment = 31; + constraint fkMod2Rights foreign key (`right`) references rights (`right`) on update cascade on delete set null +) collate = utf8mb4_unicode_ci + auto_increment = 31; -create or replace index module_right - on modules (`right`); +create or replace index module_right on modules (`right`); create table if not exists roles ( - role int auto_increment - primary key, + role int auto_increment primary key, name varchar(50) not null, description mediumtext not null -) - collate = utf8mb4_unicode_ci - auto_increment = 6; +) collate = utf8mb4_unicode_ci + auto_increment = 6; create table if not exists roles2rights ( role int not null, `right` int not null, primary key (role, `right`), - constraint fkRight - foreign key (`right`) references rights (`right`) - on delete cascade, - constraint fkRole - foreign key (role) references roles (role) - on delete cascade -) - collate = utf8mb4_unicode_ci; - -create or replace index fkRight_idx - on roles2rights (`right`); + constraint fkRight foreign key (`right`) references rights (`right`) on delete cascade, + constraint fkRole foreign key (role) references roles (role) on delete cascade +) collate = utf8mb4_unicode_ci; + +create or replace index fkRight_idx on roles2rights (`right`); create table if not exists roomfinder_building2area ( area_id int not null, - building_nr varchar(8) not null - primary key, + building_nr varchar(8) not null primary key, campus char not null, name varchar(32) not null -) - charset = utf8mb4; +) charset = utf8mb4; grant select on table roomfinder_building2area to 'tca-students'; create table if not exists roomfinder_buildings ( - building_nr varchar(8) not null - primary key, + building_nr varchar(8) not null primary key, utm_zone varchar(4) null, utm_easting varchar(32) null, utm_northing varchar(32) null, default_map_id int null -) - charset = utf8mb4; +) charset = utf8mb4; grant select on table roomfinder_buildings to 'tca-students'; create table if not exists roomfinder_buildings2gps ( - id varchar(8) default '' not null - primary key, + id varchar(8) default '' not null primary key, latitude varchar(30) null, longitude varchar(30) null -) - charset = utf8mb4; +) charset = utf8mb4; create table if not exists roomfinder_buildings2maps ( building_nr varchar(8) not null, map_id int not null, primary key (building_nr, map_id) -) - charset = utf8mb4; +) charset = utf8mb4; grant select on table roomfinder_buildings2maps to 'tca-students'; create table if not exists roomfinder_maps ( - map_id int not null - primary key, + map_id int not null primary key, description varchar(64) not null, scale int not null, width int not null, height int not null -) - charset = utf8mb4; +) charset = utf8mb4; grant select on table roomfinder_maps to 'tca-students'; create table if not exists roomfinder_rooms ( - room_id int not null - primary key, + room_id int not null primary key, room_code varchar(32) null, building_nr varchar(8) null, arch_id varchar(16) null, @@ -977,8 +753,7 @@ create table if not exists roomfinder_rooms utm_northing varchar(32) null, unit_id int null, default_map_id int null -) - charset = utf8mb4; +) charset = utf8mb4; grant select on table roomfinder_rooms to 'tca-students'; @@ -987,8 +762,7 @@ create table if not exists roomfinder_rooms2maps room_id int not null, map_id int not null, primary key (room_id, map_id) -) - charset = utf8mb4; +) charset = utf8mb4; create table if not exists roomfinder_schedules ( @@ -998,28 +772,22 @@ create table if not exists roomfinder_schedules title varchar(64) not null, event_id int not null, course_code varchar(32) null, - constraint `unique` - unique (room_id, start, end) -) - charset = utf8mb4; + constraint `unique` unique (room_id, start, end) +) charset = utf8mb4; grant select on table roomfinder_schedules to 'tca-students'; create table if not exists sessions ( - session varchar(255) charset utf8 not null - primary key, + session varchar(255) charset utf8 not null primary key, access int unsigned null, data text null, - constraint session - unique (session) -) - collate = utf8mb4_unicode_ci; + constraint session unique (session) +) collate = utf8mb4_unicode_ci; create table if not exists tag ( - tag int auto_increment - primary key, + tag int auto_increment primary key, title varchar(255) null ); @@ -1028,42 +796,32 @@ create table if not exists card2tag tag int not null, card int not null, primary key (tag, card), - constraint card2tag_ibfk_1 - foreign key (tag) references tag (tag) - on delete cascade, - constraint card2tag_ibfk_2 - foreign key (card) references card (card) - on delete cascade + constraint card2tag_ibfk_1 foreign key (tag) references tag (tag) on delete cascade, + constraint card2tag_ibfk_2 foreign key (card) references card (card) on delete cascade ); -create or replace index card - on card2tag (card); +create or replace index card on card2tag (card); create table if not exists ticket_admin ( - ticket_admin int auto_increment - primary key, + ticket_admin int auto_increment primary key, `key` text not null, created timestamp /* mariadb-5.3 */ default current_timestamp() not null, active tinyint(1) default 0 not null, comment text null -) - charset = utf8 - auto_increment = 48; +) charset = utf8 + auto_increment = 48; create table if not exists ticket_group ( - ticket_group int auto_increment - primary key, + ticket_group int auto_increment primary key, description text not null -) - charset = utf8 - auto_increment = 2; +) charset = utf8 + auto_increment = 2; create table if not exists event ( - event int auto_increment - primary key, + event int auto_increment primary key, news int null, kino int null, file int null, @@ -1074,84 +832,57 @@ create table if not exists event start datetime /* mariadb-5.3 */ null, end datetime /* mariadb-5.3 */ null, ticket_group int default 1 null, - constraint fkEventFile - foreign key (file) references files (file) - on update cascade on delete set null, - constraint fkEventGroup - foreign key (ticket_group) references ticket_group (ticket_group), - constraint fkKino - foreign key (kino) references kino (kino) - on update cascade on delete set null, - constraint fkNews - foreign key (news) references news (news) - on update cascade on delete set null -) - charset = utf8 - auto_increment = 39; - -create or replace index file - on event (file); - -create or replace fulltext index searchTitle - on event (title); + constraint fkEventFile foreign key (file) references files (file) on update cascade on delete set null, + constraint fkEventGroup foreign key (ticket_group) references ticket_group (ticket_group), + constraint fkKino foreign key (kino) references kino (kino) on update cascade on delete set null, + constraint fkNews foreign key (news) references news (news) on update cascade on delete set null +) charset = utf8 + auto_increment = 39; + +create or replace index file on event (file); + +create or replace fulltext index searchTitle on event (title); create table if not exists ticket_admin2group ( - ticket_admin2group int auto_increment - primary key, + ticket_admin2group int auto_increment primary key, ticket_admin int not null, ticket_group int not null, - constraint fkTicketAdmin - foreign key (ticket_admin) references ticket_admin (ticket_admin) - on update cascade on delete cascade, - constraint fkTicketGroup - foreign key (ticket_group) references ticket_group (ticket_group) - on update cascade on delete cascade -) - charset = utf8 - auto_increment = 10; - -create or replace index ticket_admin - on ticket_admin2group (ticket_admin); - -create or replace index ticket_group - on ticket_admin2group (ticket_group); + constraint fkTicketAdmin foreign key (ticket_admin) references ticket_admin (ticket_admin) on update cascade on delete cascade, + constraint fkTicketGroup foreign key (ticket_group) references ticket_group (ticket_group) on update cascade on delete cascade +) charset = utf8 + auto_increment = 10; + +create or replace index ticket_admin on ticket_admin2group (ticket_admin); + +create or replace index ticket_group on ticket_admin2group (ticket_group); create table if not exists ticket_payment ( - ticket_payment int auto_increment - primary key, + ticket_payment int auto_increment primary key, name varchar(50) not null, min_amount int null, max_amount int null, config text not null -) - charset = utf8 - auto_increment = 3; +) charset = utf8 + auto_increment = 3; create table if not exists ticket_type ( - ticket_type int auto_increment - primary key, + ticket_type int auto_increment primary key, event int not null, ticket_payment int not null, price double not null, contingent int not null, description varchar(100) not null, - constraint fkEvent - foreign key (event) references event (event) - on update cascade on delete cascade, - constraint fkPayment - foreign key (ticket_payment) references ticket_payment (ticket_payment) - on update cascade -) - charset = utf8 - auto_increment = 57; + constraint fkEvent foreign key (event) references event (event) on update cascade on delete cascade, + constraint fkPayment foreign key (ticket_payment) references ticket_payment (ticket_payment) on update cascade +) charset = utf8 + auto_increment = 57; create table if not exists ticket_history ( - ticket_history int auto_increment - primary key, + ticket_history int auto_increment primary key, member int not null, ticket_payment int null, ticket_type int not null, @@ -1159,46 +890,32 @@ create table if not exists ticket_history redemption datetime /* mariadb-5.3 */ null, created timestamp /* mariadb-5.3 */ default current_timestamp() not null, code char(128) not null, - constraint fkMember - foreign key (member) references member (member) - on update cascade on delete cascade, - constraint fkTicketPayment - foreign key (ticket_payment) references ticket_payment (ticket_payment) - on update cascade, - constraint fkTicketType - foreign key (ticket_type) references ticket_type (ticket_type) - on update cascade -) - charset = utf8 - auto_increment = 776; - -create or replace index member - on ticket_history (member); - -create or replace index ticket_payment - on ticket_history (ticket_payment); - -create or replace index ticket_type - on ticket_history (ticket_type); - -create or replace index event - on ticket_type (event); - -create or replace index ticket_payment - on ticket_type (ticket_payment); + constraint fkMember foreign key (member) references member (member) on update cascade on delete cascade, + constraint fkTicketPayment foreign key (ticket_payment) references ticket_payment (ticket_payment) on update cascade, + constraint fkTicketType foreign key (ticket_type) references ticket_type (ticket_type) on update cascade +) charset = utf8 + auto_increment = 776; + +create or replace index member on ticket_history (member); + +create or replace index ticket_payment on ticket_history (ticket_payment); + +create or replace index ticket_type on ticket_history (ticket_type); + +create or replace index event on ticket_type (event); + +create or replace index ticket_payment on ticket_type (ticket_payment); create table if not exists update_note ( - version_code int not null - primary key, + version_code int not null primary key, version_name text null, message text null ); create table if not exists users ( - user int auto_increment - primary key, + user int auto_increment primary key, username varchar(7) null, firstname varchar(100) null, surname varchar(100) null, @@ -1211,93 +928,64 @@ create table if not exists users tum_id_employee varchar(50) null comment 'OBFUSCATED_ID_B', tum_id_alumni varchar(50) null comment 'OBFUSCATED_ID_EXT', tum_id_preferred varchar(50) null comment 'OBFUSCATED_ID_BEVORZUGT', - constraint username - unique (username) -) - collate = utf8mb4_unicode_ci - auto_increment = 434; + constraint username unique (username) +) collate = utf8mb4_unicode_ci + auto_increment = 434; create table if not exists log ( - log int auto_increment - primary key, + log int auto_increment primary key, time int not null, user_executed int null, user_affected int null, action int null, comment varchar(255) not null, - constraint fkLog2Actions - foreign key (action) references actions (action) - on update set null on delete set null, - constraint fkLog2UsersAf - foreign key (user_affected) references users (user) - on update set null on delete set null, - constraint fkLog2UsersEx - foreign key (user_executed) references users (user) - on update set null on delete set null -) - collate = utf8mb4_unicode_ci; - -create or replace index action - on log (action); - -create or replace index user - on log (user_executed); - -create or replace index user_affected - on log (user_affected); + constraint fkLog2Actions foreign key (action) references actions (action) on update set null on delete set null, + constraint fkLog2UsersAf foreign key (user_affected) references users (user) on update set null on delete set null, + constraint fkLog2UsersEx foreign key (user_executed) references users (user) on update set null on delete set null +) collate = utf8mb4_unicode_ci; + +create or replace index action on log (action); + +create or replace index user on log (user_executed); + +create or replace index user_affected on log (user_affected); create table if not exists recover ( - recover int auto_increment - primary key, + recover int auto_increment primary key, user int not null, created int not null, hash varchar(190) not null, ip varchar(255) not null, - constraint hash - unique (hash), - constraint fkRecover2User - foreign key (user) references users (user) - on delete cascade -) - collate = utf8mb4_unicode_ci; + constraint hash unique (hash), + constraint fkRecover2User foreign key (user) references users (user) on delete cascade +) collate = utf8mb4_unicode_ci; -create or replace index user - on recover (user); +create or replace index user on recover (user); create table if not exists users2info ( - user int not null - primary key, + user int not null primary key, firstname varchar(255) not null, surname varchar(255) not null, lastPwChange int not null, pager int default 15 null, - constraint fkUsers - foreign key (user) references users (user) - on update cascade on delete cascade -) - collate = utf8mb4_unicode_ci; + constraint fkUsers foreign key (user) references users (user) on update cascade on delete cascade +) collate = utf8mb4_unicode_ci; create table if not exists users2roles ( user int not null, role int not null, primary key (user, role), - constraint fkUser2RolesRole - foreign key (role) references roles (role) - on update cascade on delete cascade, - constraint fkUser2RolesUser - foreign key (user) references users (user) - on update cascade on delete cascade -) - collate = utf8mb4_unicode_ci; + constraint fkUser2RolesRole foreign key (role) references roles (role) on update cascade on delete cascade, + constraint fkUser2RolesUser foreign key (user) references users (user) on update cascade on delete cascade +) collate = utf8mb4_unicode_ci; create table if not exists wifi_measurement ( - id int(20) unsigned auto_increment - primary key, + id int(20) unsigned auto_increment primary key, date date not null, SSID varchar(32) not null, BSSID varchar(64) not null, @@ -1305,5 +993,4 @@ create table if not exists wifi_measurement accuracyInMeters float not null, latitude double not null, longitude double not null -) - collate = utf8mb4_unicode_ci; +) collate = utf8mb4_unicode_ci; diff --git a/server/main.go b/server/main.go index 01b65ca0..516727fd 100644 --- a/server/main.go +++ b/server/main.go @@ -7,34 +7,24 @@ import ( "net" "net/http" "net/textproto" - "os" - "strings" "time" + "github.com/TUM-Dev/Campus-Backend/server/utils" "google.golang.org/grpc/reflection" "github.com/prometheus/client_golang/prometheus/promhttp" - "github.com/TUM-Dev/Campus-Backend/server/env" - "github.com/makasim/sentryhook" - pb "github.com/TUM-Dev/Campus-Backend/server/api/tumdev" "github.com/TUM-Dev/Campus-Backend/server/backend" "github.com/TUM-Dev/Campus-Backend/server/backend/cron" - "github.com/TUM-Dev/Campus-Backend/server/backend/migration" "github.com/getsentry/sentry-go" "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" - "github.com/onrik/gorm-logrus" log "github.com/sirupsen/logrus" "github.com/soheilhy/cmux" "golang.org/x/sync/errgroup" "google.golang.org/grpc" - "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/metadata" - "google.golang.org/grpc/status" - "gorm.io/driver/mysql" - "gorm.io/gorm" ) const httpPort = ":50051" @@ -46,10 +36,10 @@ var Version = "dev" var swagfs embed.FS func main() { - setupTelemetry() + utils.SetupTelemetry(Version) defer sentry.Flush(10 * time.Second) // make sure that sentry handles shutdowns gracefully - db := setupDB() + db := utils.SetupDB() // Create any other background services (these shouldn't do any long-running work here) cronService := cron.New(db) @@ -135,55 +125,6 @@ func StreamRequestLogger(srv any, stream grpc.ServerStream, info *grpc.StreamSer return err } -// setupDB connects to the database and migrates it if necessary -func setupDB() *gorm.DB { - dbHost := os.Getenv("DB_DSN") - if dbHost == "" { - log.Fatal("Failed to start! The 'DB_DSN' environment variable is not defined. Take a look at the README.md for more details.") - } - - log.Info("Connecting to dsn") - db, err := gorm.Open(mysql.Open(dbHost), &gorm.Config{Logger: gorm_logrus.New()}) - if err != nil { - log.WithError(err).Fatal("failed to connect database") - } - - // Migrate the schema - // currently not activated as - if err := migration.New(db, false).Migrate(); err != nil { - log.WithError(err).Fatal("Failed to migrate database") - } - return db -} - -// setupTelemetry initializes our telemetry stack -// - sentry to be connected with log -// - logrus to -func setupTelemetry() { - environment := "development" - log.SetLevel(log.TraceLevel) - if env.IsProd() { - log.SetLevel(log.InfoLevel) - environment = "production" - log.SetFormatter(&log.JSONFormatter{}) // simpler to query but harder to parse in the console - } - - if sentryDSN := os.Getenv("SENTRY_DSN"); sentryDSN != "" { - if err := sentry.Init(sentry.ClientOptions{ - Dsn: sentryDSN, - AttachStacktrace: true, - Release: Version, - Dist: Version, // see https://github.com/getsentry/sentry-react-native/issues/516 why this is equal - Environment: environment, - }); err != nil { - log.WithError(err).Error("Sentry initialization failed") - } - log.AddHook(sentryhook.New([]log.Level{log.PanicLevel, log.FatalLevel, log.ErrorLevel, log.WarnLevel})) - } else { - log.Info("continuing without sentry") - } -} - // addMethodNameInterceptor adds the method name (e.g. "ListNewsSources") to the metadata as x-campus-method for later use (currently logging the devices api usage) func addMethodNameInterceptor(ctx context.Context, method string, req interface{}, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { ctx = metadata.AppendToOutgoingContext(ctx, "x-campus-method", method) @@ -192,49 +133,11 @@ func addMethodNameInterceptor(ctx context.Context, method string, req interface{ // errorHandler translates gRPC raised by the backend into HTTP errors. func errorHandler(_ context.Context, _ *runtime.ServeMux, _ runtime.Marshaler, w http.ResponseWriter, _ *http.Request, err error) { - errorResp := errorResponse{Error: "Internal Server Error", StatusCode: http.StatusInternalServerError} - - if strings.HasPrefix(err.Error(), "no device id") { - errorResp.Error = "Not Authorized" - errorResp.StatusCode = http.StatusForbidden - } - - if s, ok := status.FromError(err); ok { - switch s.Code() { - case codes.NotFound: - errorResp.Error = "Not Found" - errorResp.StatusCode = http.StatusNotFound - case codes.Unimplemented: - errorResp.Error = "Not Implemented" - errorResp.StatusCode = http.StatusNotImplemented - case codes.InvalidArgument: - errorResp.Error = "Invalid Argument" - errorResp.StatusCode = http.StatusBadRequest - case codes.Internal: - errorResp.Error = "Internal Server Error" - errorResp.StatusCode = http.StatusInternalServerError - } - - if s.Message() != "" { - errorResp.Error = s.Message() - } - - if s.Details() != nil && len(s.Details()) > 0 { - errorResp.Details = s.Details() - } - } - + errorResp := utils.GrpcErrorToWebError(err) w.Header().Set("Content-Type", "application/json") w.WriteHeader(errorResp.StatusCode) if err = json.NewEncoder(w).Encode(errorResp); err != nil { log.WithError(err).Error("Marshal error response failed") - return } } - -type errorResponse struct { - Error string `json:"error"` - Details []interface{} `json:"details,omitempty"` - StatusCode int `json:"-"` -} diff --git a/server/utils/db.go b/server/utils/db.go new file mode 100644 index 00000000..59d7bdb4 --- /dev/null +++ b/server/utils/db.go @@ -0,0 +1,37 @@ +package utils + +import ( + "os" + + "github.com/TUM-Dev/Campus-Backend/server/backend/migration" + gormlogrus "github.com/onrik/gorm-logrus" + log "github.com/sirupsen/logrus" + "gorm.io/driver/mysql" + "gorm.io/gorm" +) + +// SetupDB connects to the database and migrates it if necessary +func SetupDB() *gorm.DB { + dbHost := os.Getenv("DB_DSN") + if dbHost == "" { + log.Fatal("Failed to start! The 'DB_DSN' environment variable is not defined. Take a look at the README.md for more details.") + } + + log.Info("Connecting to dsn") + db, err := gorm.Open(mysql.Open(dbHost), &gorm.Config{Logger: gormlogrus.New()}) + if err != nil { + log.WithError(err).Fatal("failed to connect database") + } + + // Migrate the schema + // currently not activated as + if err := migration.Migrate(db, false); err != nil { + log.WithError(err).Fatal("Failed to migrate database") + } + + if os.Getenv("CI_EXIT_AFTER_MIGRATION") == "true" { + log.Info("Exiting after migration") + os.Exit(0) + } + return db +} diff --git a/server/utils/grpc_to_web.go b/server/utils/grpc_to_web.go new file mode 100644 index 00000000..6571369c --- /dev/null +++ b/server/utils/grpc_to_web.go @@ -0,0 +1,50 @@ +package utils + +import ( + "net/http" + "strings" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func GrpcErrorToWebError(err error) ErrorResponse { + errorResp := ErrorResponse{Error: "Internal Server Error", StatusCode: http.StatusInternalServerError} + + if strings.HasPrefix(err.Error(), "no device id") { + errorResp.Error = "Not Authorized" + errorResp.StatusCode = http.StatusForbidden + } + + if s, ok := status.FromError(err); ok { + switch s.Code() { + case codes.NotFound: + errorResp.Error = "Not Found" + errorResp.StatusCode = http.StatusNotFound + case codes.Unimplemented: + errorResp.Error = "Not Implemented" + errorResp.StatusCode = http.StatusNotImplemented + case codes.InvalidArgument: + errorResp.Error = "Invalid Argument" + errorResp.StatusCode = http.StatusBadRequest + case codes.Internal: + errorResp.Error = "Internal Server Error" + errorResp.StatusCode = http.StatusInternalServerError + } + + if s.Message() != "" { + errorResp.Error = s.Message() + } + + if s.Details() != nil && len(s.Details()) > 0 { + errorResp.Details = s.Details() + } + } + return errorResp +} + +type ErrorResponse struct { + Error string `json:"error"` + Details []interface{} `json:"details,omitempty"` + StatusCode int `json:"-"` +} diff --git a/server/utils/telemetry.go b/server/utils/telemetry.go new file mode 100644 index 00000000..fd0ecf66 --- /dev/null +++ b/server/utils/telemetry.go @@ -0,0 +1,38 @@ +package utils + +import ( + "os" + + "github.com/TUM-Dev/Campus-Backend/server/env" + "github.com/getsentry/sentry-go" + "github.com/makasim/sentryhook" + log "github.com/sirupsen/logrus" +) + +// SetupTelemetry initializes our telemetry stack +// - sentry to be connected with log +// - logrus to +func SetupTelemetry(Version string) { + environment := "development" + log.SetLevel(log.TraceLevel) + if env.IsProd() { + log.SetLevel(log.InfoLevel) + environment = "production" + log.SetFormatter(&log.JSONFormatter{}) // simpler to query but harder to parse in the console + } + + if sentryDSN := os.Getenv("SENTRY_DSN"); sentryDSN != "" { + if err := sentry.Init(sentry.ClientOptions{ + Dsn: sentryDSN, + AttachStacktrace: true, + Release: Version, + Dist: Version, // see https://github.com/getsentry/sentry-react-native/issues/516 why this is equal + Environment: environment, + }); err != nil { + log.WithError(err).Error("Sentry initialization failed") + } + log.AddHook(sentryhook.New([]log.Level{log.PanicLevel, log.FatalLevel, log.ErrorLevel, log.WarnLevel})) + } else { + log.Info("continuing without sentry") + } +} From 5e365835a303b83584b1f5a0bf61d332410d28cd Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Mon, 23 Oct 2023 22:23:51 +0200 Subject: [PATCH 08/11] chore:full migrations test (#273) * added a rough testcase that assures that migrations don't fail without us noticing * fixed a build error * refactored files around * added the ability to exit after migration * fixed the testcase * made the action sleeps enough that the db gets its shit together * linting fix * tested a different way of communicating with the db * added a request for the docker logs after waiting * more logging * tested a different approach * tested a different approach * more debugging info * tested different config * refactored the wait for db part and source-schema check * migrated the src schema to live in an migation * fixed formatting issue * fixed the migration not being used * linting * tested different way of execing sql * tested even more different way of executing the source shema * fixed executing empty statements * made sure only nessesary things are logged for `migrate20200000000000` * formatting * refactored the migrations to not depend on the TumDBMigrator struct * renamed EXIT_AFTER_MIGRATION -> CI_EXIT_AFTER_MIGRATION * tested a different way of migrating the newsSource table * fixed another typo * removed an automigration * removed now obsolete docs * removed the source schema from the docker-compose file to make running it possible * added all models to the migration * fixed naming issues for the db models * enabled the auto migration in the workflow * removed model.IOSGrade * tested a different way of defining Device.LastAccess * fixed the type of `Device.Developer` * fixed the type of `Device.PkActive` * fixed the type of `NotificationType.Confirmation` * added an mysqldump configuration * added an mysqldump configuration * tested different connection method * switched to atlas for shema diffing * tested different connection strings * added additional formatting * refactored the action * fixed a linting issue * updated the block * added a concurrency setting * test concurrecny * test if `wait for db` is nessesary * tested a different commenting mechanism * fixed linting issues * fixed the name of the action * tested if the comment is edited * plugged the diff_migrations to the commenting step * added an eof delimiter * tested different delimiter mechanism * tested a different formatting * added a better diff * tested if the formatting works * reformatted the message --- .github/workflows/main.yml | 28 +-------- .github/workflows/test_migration.yml | 91 +++++++++++++++++++++++++++ server/backend/migration/migration.go | 42 ++++++++++++- server/model/device.go | 6 +- server/model/notification_type.go | 2 +- server/utils/db.go | 2 +- 6 files changed, 136 insertions(+), 35 deletions(-) create mode 100644 .github/workflows/test_migration.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c0c6d603..56123e25 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -17,35 +17,9 @@ jobs: - name: run tests run: go test -v ./... working-directory: ./server - test_migrations: - runs-on: ubuntu-latest - services: - mariadb: - image: bitnami/mariadb:latest - ports: - - 3306:3306 - env: - MARIADB_ROOT_PASSWORD: super_secret_passw0rd - MARIADB_DATABASE: campus_db - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-go@v4 - with: - go-version: '1.21' - cache-dependency-path: | - server/go.sum - - name: wait for db - run: sleep 20 && docker logs $(docker ps -qa) - - name: run migration - run: go run main.go - working-directory: ./server - env: - CI_EXIT_AFTER_MIGRATION: "true" - DB_DSN: root:super_secret_passw0rd@tcp(localhost:3306)/campus_db?charset=utf8mb4&parseTime=True&loc=Local - ENVIRONMENT: dev build: runs-on: ubuntu-latest - needs: [test, test_migrations] + needs: [test] steps: - name: Checkout repository uses: actions/checkout@v4 diff --git a/.github/workflows/test_migration.yml b/.github/workflows/test_migration.yml new file mode 100644 index 00000000..a8b9b51b --- /dev/null +++ b/.github/workflows/test_migration.yml @@ -0,0 +1,91 @@ +name: Migration Test +on: + pull_request: + branches: [ main ] +concurrency: + group: ${{ github.head_ref }} + cancel-in-progress: true +jobs: + test_migrations: + runs-on: ubuntu-latest + services: + auto_mariadb: + image: bitnami/mariadb:latest + ports: + - 3306:3306 + env: + MARIADB_ROOT_PASSWORD: super_secret_passw0rd + MARIADB_DATABASE: campus_db + manual_mariadb: + image: bitnami/mariadb:latest + ports: + - 3300:3306 + env: + MARIADB_ROOT_PASSWORD: super_secret_passw0rd + MARIADB_DATABASE: campus_db + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v4 + with: + go-version: '1.21' + cache-dependency-path: | + server/go.sum + - name: run manual migrations + run: go run main.go + working-directory: ./server + env: + CI_EXIT_AFTER_MIGRATION: "true" + CI_AUTO_MIGRATION: "false" + DB_DSN: root:super_secret_passw0rd@tcp(localhost:3306)/campus_db?charset=utf8mb4&parseTime=True&loc=Local + ENVIRONMENT: dev + - name: run auto migrations + run: go run main.go + working-directory: ./server + env: + CI_EXIT_AFTER_MIGRATION: "true" + CI_AUTO_MIGRATION: "true" + DB_DSN: root:super_secret_passw0rd@tcp(localhost:3300)/campus_db?charset=utf8mb4&parseTime=True&loc=Local + ENVIRONMENT: dev + - uses: ariga/setup-atlas@master + - name: export diff the migrations + id: diff_migrations + run: | + EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64) && + echo "local_to_auto<<$EOF" >> $GITHUB_OUTPUT && + atlas schema diff --from "maria://root:super_secret_passw0rd@localhost:3306/campus_db" --to "maria://root:super_secret_passw0rd@localhost:3300/campus_db" --format '{{ sql . " " }}' >> $GITHUB_OUTPUT && + echo "$EOF" >> $GITHUB_OUTPUT + echo "auto_to_local<<$EOF" >> $GITHUB_OUTPUT && + atlas schema diff --from "maria://root:super_secret_passw0rd@localhost:3306/campus_db" --to "maria://root:super_secret_passw0rd@localhost:3300/campus_db" --format '{{ sql . " " }}' >> $GITHUB_OUTPUT && + echo "$EOF" >> $GITHUB_OUTPUT + - name: Find Comment + uses: peter-evans/find-comment@v2 + id: fc + with: + issue-number: "${{ github.event.number }}" + body-includes: Found the following differences in the sql schema + comment-author: github-actions[bot] + - name: Create comment + uses: peter-evans/create-or-update-comment@v3 + with: + issue-number: "${{ github.event.number }}" + comment-id: "${{ steps.fc.outputs.comment-id }}" + body: | + :eyes: Found the following differences in the sql schema: + +
+ Needed get from local to auto migration state + + ```sql + ${{ steps.diff_migrations.outputs.local_to_auto }} + ``` + +
+
+ Needed from auto to local migration state + + ```sql + ${{ steps.diff_migrations.outputs.auto_to_local }} + ``` + +
+ edit-mode: replace diff --git a/server/backend/migration/migration.go b/server/backend/migration/migration.go index c13e32d5..2c477d31 100644 --- a/server/backend/migration/migration.go +++ b/server/backend/migration/migration.go @@ -12,12 +12,48 @@ import ( func autoMigrate(db *gorm.DB) error { err := db.AutoMigrate( + &model.Cafeteria{}, + &model.CafeteriaRating{}, + &model.CafeteriaRatingAverage{}, + &model.CafeteriaRatingTag{}, + &model.CafeteriaRatingTagAverage{}, + &model.CafeteriaRatingTagOption{}, + &model.CanteenHeadCount{}, &model.Crontab{}, + &model.Device{}, + &model.Dish{}, + &model.DishNameTag{}, + &model.DishNameTagAverage{}, + &model.DishNameTagOption{}, + &model.DishNameTagOptionExcluded{}, + &model.DishNameTagOptionIncluded{}, + &model.DishRating{}, + &model.DishRatingAverage{}, + &model.DishRatingTag{}, + &model.DishRatingTagAverage{}, + &model.DishRatingTagOption{}, + &model.DishToDishNameTag{}, + &model.DishesOfTheWeek{}, + &model.PublishedExamResult{}, + &model.Feedback{}, &model.File{}, - &model.NewsSource{}, - &model.NewsAlert{}, + &model.IOSDevice{}, + //&model.IOSDeviceLastUpdated{}, -- not a gorm model + &model.IOSDeviceRequestLog{}, + &model.IOSDevicesActivityReset{}, + //&model.IOSGrade{}, -- not a gorm model + //&model.IOSRemoteNotification...{}, -- wtf??? + &model.IOSScheduledUpdateLog{}, + &model.IOSSchedulingPriority{}, + &model.Kino{}, + &model.NewExamResultsSubscriber{}, &model.News{}, - &model.CanteenHeadCount{}, + &model.NewsAlert{}, + &model.NewsSource{}, + &model.Notification{}, + &model.NotificationConfirmation{}, + &model.NotificationType{}, + &model.UpdateNote{}, ) return err } diff --git a/server/model/device.go b/server/model/device.go index 6542aa24..52ca2707 100755 --- a/server/model/device.go +++ b/server/model/device.go @@ -12,14 +12,14 @@ type Device struct { Member null.Int `gorm:"column:member;type:int;" json:"member"` UUID string `gorm:"column:uuid;type:varchar(50);" json:"uuid"` Created null.Time `gorm:"column:created;type:timestamp;" json:"created"` - LastAccess time.Time `gorm:"column:lastAccess;type:timestamp;default:0000-00-00 00:00:00;" json:"last_access"` + LastAccess time.Time `gorm:"column:lastAccess;type:timestamp;default:'0000-00-00 00:00:00';" json:"last_access"` LastAPI string `gorm:"column:lastApi;type:text;size:16777215;" json:"last_api"` - Developer string `gorm:"column:developer;type:char;size:5;default:false;" json:"developer"` + Developer string `gorm:"column:developer;type:enum('true','false');default:'false';" json:"developer"` OsVersion string `gorm:"column:osVersion;type:text;size:16777215;" json:"os_version"` AppVersion string `gorm:"column:appVersion;type:text;size:16777215;" json:"app_version"` Counter int32 `gorm:"column:counter;type:int;default:0;" json:"counter"` Pk null.String `gorm:"column:pk;type:text;size:4294967295;" json:"pk"` - PkActive string `gorm:"column:pkActive;type:char;size:5;default:false;" json:"pk_active"` + PkActive string `gorm:"column:pkActive;type:enum('true', 'false');default:'false';" json:"pk_active"` GcmToken null.String `gorm:"column:gcmToken;type:text;size:65535;" json:"gcm_token"` GcmStatus null.String `gorm:"column:gcmStatus;type:varchar(200);" json:"gcm_status"` ConfirmationKey null.String `gorm:"column:confirmationKey;type:varchar(35);" json:"confirmation_key"` diff --git a/server/model/notification_type.go b/server/model/notification_type.go index 661383d7..7a53f240 100644 --- a/server/model/notification_type.go +++ b/server/model/notification_type.go @@ -19,5 +19,5 @@ var ( type NotificationType struct { Type int64 `gorm:"primary_key;AUTO_INCREMENT;column:type;type:int;" json:"type"` Name string `gorm:"column:name;type:text;size:65535;" json:"name"` - Confirmation string `gorm:"column:confirmation;type:char;size:5;default:false;" json:"confirmation"` + Confirmation string `gorm:"column:confirmation;type:enum('true', 'false');default:'false';" json:"confirmation"` } diff --git a/server/utils/db.go b/server/utils/db.go index 59d7bdb4..802852ac 100644 --- a/server/utils/db.go +++ b/server/utils/db.go @@ -25,7 +25,7 @@ func SetupDB() *gorm.DB { // Migrate the schema // currently not activated as - if err := migration.Migrate(db, false); err != nil { + if err := migration.Migrate(db, os.Getenv("CI_AUTO_MIGRATION") == "true"); err != nil { log.WithError(err).Fatal("Failed to migrate database") } From 5682ad9b2bafbe1b5ddb21770778fe38570d6285 Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Tue, 24 Oct 2023 00:57:12 +0200 Subject: [PATCH 09/11] Chore:stable migrations (#275) * made sure that migrate20220713000000 is stable against model changes * made sure that migrate20221119131300 is stable against model changes * made sure that migrate20221210000000 is stable against model changes * made migrate20230904100000 stable against model changes * added TableName's to migrate20221119131300 --- server/backend/migration/20220713000000.go | 296 +++++++++++++++++++-- server/backend/migration/20221119131300.go | 111 ++++++-- server/backend/migration/20221210000000.go | 39 ++- server/backend/migration/20230904100000.go | 20 +- 4 files changed, 414 insertions(+), 52 deletions(-) diff --git a/server/backend/migration/20220713000000.go b/server/backend/migration/20220713000000.go index 82a5da06..b40ef531 100644 --- a/server/backend/migration/20220713000000.go +++ b/server/backend/migration/20220713000000.go @@ -1,38 +1,294 @@ package migration import ( + "time" + "github.com/TUM-Dev/Campus-Backend/server/model" "github.com/go-gormigrate/gormigrate/v2" "gorm.io/gorm" ) -//migrate20210709193000 +// InitialCafeteria stores all Available cafeterias in the format of the eat-api +type InitialCafeteria struct { + Cafeteria int64 `gorm:"primary_key;AUTO_INCREMENT;column:cafeteria;type:int;not null;" json:"canteen" ` + Name string `gorm:"column:name;type:mediumtext;not null;" json:"name" ` + Address string `gorm:"column:address;type:text;not null;" json:"address" ` + Latitude float32 `gorm:"column:latitude;type:float;not null;" json:"latitude" ` + Longitude float32 `gorm:"column:longitude;type:float;not null;" json:"longitude"` +} + +// TableName sets the insert table name for this struct type +func (n *InitialCafeteria) TableName() string { + return "cafeteria" +} + +// InitialCafeteriaRating stores all Available cafeterias in the format of the eat-api +type InitialCafeteriaRating struct { + CafeteriaRating int64 `gorm:"primary_key;AUTO_INCREMENT;column:cafeteriaRating;type:int;not null;" json:"canteenrating"` + Points int32 `gorm:"column:points;type:int;not null;" json:"points"` + Comment string `gorm:"column:comment;type:text;" json:"comment" ` + CafeteriaID int64 `gorm:"column:cafeteriaID;foreignKey:cafeteria;type:int;not null;" json:"canteenID"` + Timestamp time.Time `gorm:"column:timestamp;type:timestamp;not null;" json:"timestamp" ` + Image string `gorm:"column:image;type:text;" json:"image"` +} + +// TableName sets the insert table name for this struct type +func (n *InitialCafeteriaRating) TableName() string { + return "cafeteria_rating" +} + +// InitialCafeteriaRatingTag struct is a row record of the either the dish_tag_rating-table or the cafeteria_rating_tags-table in the database +type InitialCafeteriaRatingTag struct { + CafeteriaRatingTag int64 `gorm:"primary_key;AUTO_INCREMENT;column:CafeteriaRatingTag;type:int;not null;" json:"CanteenRatingTag" ` + CorrespondingRating int64 `gorm:"foreignKey:cafeteriaRatingID;column:correspondingRating;type:int;not null;" json:"correspondingRating"` + Points int32 `gorm:"column:points;type:int;not null;" json:"points"` + TagID int64 `gorm:"foreignKey:cafeteriaRatingTagOption;column:tagID;type:int;not null;" json:"tagID"` +} + +// TableName sets the insert table name for this struct type +func (n *InitialCafeteriaRatingTag) TableName() string { + return "cafeteria_rating_tag" +} + +// InitialCafeteriaRatingTagOption stores all available options for tags which can be used to quickly rate cafeterias +type InitialCafeteriaRatingTagOption struct { + CafeteriaRatingsTagOption int64 `gorm:"primary_key;AUTO_INCREMENT;column:cafeteriaRatingTagOption;type:int;not null;" json:"canteenRatingTagOption"` + DE string `gorm:"column:DE;text;default:de;not null;" json:"DE"` + EN string `gorm:"column:EN;text;default:en;not null;" json:"EN"` +} + +// TableName sets the insert table name for this struct type +func (n *InitialCafeteriaRatingTagOption) TableName() string { + return "cafeteria_rating_tag_option" +} + +// InitialDish represents one dish fin a specific cafeteria +type InitialDish struct { + Dish int64 `gorm:"primary_key;AUTO_INCREMENT;column:dish;type:int;not null;" json:"dish"` + Name string `gorm:"column:name;type:text;not null;" json:"name" ` + Type string `gorm:"column:type;type:text;not null;" json:"type" ` + CafeteriaID int64 `gorm:"column:cafeteriaID;foreignKey:cafeteria;type:int;not null;" json:"cafeteriaID"` +} + +// TableName sets the insert table name for this struct type +func (n *InitialDish) TableName() string { + return "dish" +} + +type InitialDishesOfTheWeek struct { + DishesOfTheWeek int64 `gorm:"primary_key;AUTO_INCREMENT;column:dishesOfTheWeek;type:int;not null;" json:"dishesOfTheWeek"` + Year int32 `gorm:"column:year;type:int;not null;" json:"year"` + Week int32 `gorm:"column:week;type:int;not null;" json:"week"` + Day int32 `gorm:"column:day;type:int;not null;" json:"day"` + DishID int64 `gorm:"column:dishID;foreignKey:dish;type:int;not null;" json:"dishID"` +} + +// TableName sets the insert table name for this struct type +func (n *InitialDishesOfTheWeek) TableName() string { + return "dishes_of_the_week" +} + +type InitialDishNameTagOption struct { + DishNameTagOption int64 `gorm:"primary_key;AUTO_INCREMENT;column:dishNameTagOption;type:int;not null;" json:"dishNameTagOption"` + DE string `gorm:"column:DE;type:text;not null;" json:"DE"` + EN string `gorm:"column:EN;type:text;not null;" json:"EN"` +} + +// TableName sets the insert table name for this struct type +func (n *InitialDishNameTagOption) TableName() string { + return "dish_name_tag_option" +} + +type InitialDishRatingTagOption struct { + DishRatingTagOption int64 `gorm:"primary_key;AUTO_INCREMENT;column:dishRatingTagOption;type:int;not null;" json:"dishRatingTagOption"` + DE string `gorm:"column:DE;type:text;default:de;not null;" json:"DE"` + EN string `gorm:"column:EN;type:text;default:en;not null;" json:"EN"` +} + +// TableName sets the insert table name for this struct type +func (n *InitialDishRatingTagOption) TableName() string { + return "dish_rating_tag_option" +} + +type InitialDishNameTag struct { + DishNameTag int64 `gorm:"primary_key;AUTO_INCREMENT;column:DishNameTag;type:int;not null;" json:"DishNameTag"` + CorrespondingRating int64 `gorm:"foreignKey:dish;column:correspondingRating;type:int;not null;" json:"correspondingRating"` + Points int32 `gorm:"column:points;type:int;not null;" json:"points"` + TagNameID int64 `gorm:"foreignKey:tagRatingID;column:tagNameID;type:int;not null;" json:"tagnameID"` +} + +// TableName sets the insert table name for this struct type +func (n *InitialDishNameTag) TableName() string { + return "dish_name_tag" +} + +type InitialDishNameTagOptionExcluded struct { + DishNameTagOptionExcluded int64 `gorm:"primary_key;AUTO_INCREMENT;column:dishNameTagOptionExcluded;type:int;not null;" json:"dishNameTagOptionExcluded"` + NameTagID int64 `gorm:"foreignKey:dishNameTagOption;column:nameTagID;type:int;not null;" json:"nameTagID"` + Expression string `gorm:"column:expression;type:text;" json:"expression"` +} + +// TableName sets the insert table name for this struct type +func (n *InitialDishNameTagOptionExcluded) TableName() string { + return "dish_name_tag_option_excluded" +} + +type InitialDishNameTagOptionIncluded struct { + DishNameTagOptionIncluded int64 `gorm:"primary_key;AUTO_INCREMENT;column:dishNameTagOptionIncluded;type:int;not null;" json:"dishNameTagOptionIncluded"` + NameTagID int64 `gorm:"foreignKey:dishNameTagOption;column:nameTagID;type:int;not null;" json:"nameTagID"` + Expression string `gorm:"column:expression;type:text;" json:"expression"` +} + +// TableName sets the insert table name for this struct type +func (n *InitialDishNameTagOptionIncluded) TableName() string { + return "dish_name_tag_option_included" +} + +type InitialDishRating struct { + DishRating int64 `gorm:"primary_key;AUTO_INCREMENT;column:dishRating;type:int;not null;" json:"dishRating"` + Points int32 `gorm:"column:points;type:int;not null;" json:"points"` + CafeteriaID int64 `gorm:"column:cafeteriaID;foreignKey:cafeteria;type:int;not null;" json:"cafeteriaID"` + DishID int64 `gorm:"column:dishID;foreignKey:dish;type:int;not null;" json:"dishID"` + Comment string `gorm:"column:comment;type:text;" json:"comment"` + Timestamp time.Time `gorm:"column:timestamp;type:timestamp;not null;" json:"timestamp"` + Image string `gorm:"column:image;type:text;" json:"image"` +} + +// TableName sets the insert table name for this struct type +func (n *InitialDishRating) TableName() string { + return "dish_rating" +} + +type InitialDishRatingTag struct { + DishRatingTag int64 `gorm:"primary_key;AUTO_INCREMENT;column:dishRatingTag;type:int;not null;" json:"dishRatingTag"` + CorrespondingRating int64 `gorm:"foreignKey:cafeteriaRating;column:parentRating;type:int;not null;" json:"parentRating"` + Points int32 `gorm:"column:points;type:int;not null;" json:"points"` + TagID int64 `gorm:"foreignKey:dishRatingTagOption;column:tagID;type:int;not null;" json:"tagID"` +} + +// TableName sets the insert table name for this struct type +func (n *InitialDishRatingTag) TableName() string { + return "dish_rating_tag" +} + +type InitialDishToDishNameTag struct { + DishToDishNameTag int64 `gorm:"primary_key;AUTO_INCREMENT;column:dishToDishNameTag;type:int;not null;" json:"dishToDishNameTag"` + DishID int64 `gorm:"column:dishID;foreignKey:dish;type:int;not null;" json:"dishID"` + NameTagID int64 `gorm:"foreignKey:dishNameTagOption;column:nameTagID;type:int;not null;" json:"nameTagID"` +} + +// TableName sets the insert table name for this struct type +func (n *InitialDishToDishNameTag) TableName() string { + return "dish_to_dish_name_tag" +} + +// InitialCafeteriaRatingAverage stores all precomputed values for the cafeteria ratings +type InitialCafeteriaRatingAverage struct { + CafeteriaRatingAverage int64 `gorm:"primary_key;AUTO_INCREMENT;column:cafeteriaRatingAverage;type:int;not null;" json:"canteenRatingAverage" ` + CafeteriaID int64 `gorm:"column:cafeteriaID;foreignKey:cafeteria;type:int;not null;" json:"canteenID"` + Average float64 `gorm:"column:average;type:float;not null;" json:"average" ` + Min int32 `gorm:"column:min;type:int;not null;" json:"min"` + Max int32 `gorm:"column:max;type:int;not null;" json:"max"` + Std float64 `gorm:"column:std;type:float;not null;" json:"std"` +} + +// TableName sets the insert table name for this struct type +func (n *InitialCafeteriaRatingAverage) TableName() string { + return "cafeteria_rating_average" +} + +// InitialCafeteriaRatingTagAverage stores all precomputed values for the cafeteria ratings +type InitialCafeteriaRatingTagAverage struct { + CafeteriaRatingTagsAverage int64 `gorm:"primary_key;AUTO_INCREMENT;column:cafeteriaRatingTagsAverage;type:int;not null;" json:"canteenRatingTagsAverage"` + CafeteriaID int64 `gorm:"column:cafeteriaID;foreignKey:cafeteria;type:int;not null;" json:"canteenID"` + TagID int64 `gorm:"column:tagID;foreignKey:cafeteriaRatingTagOption;type:int;not null;" json:"tagID"` + Average float32 `gorm:"column:average;type:float;not null;" json:"average"` + Min int8 `gorm:"column:min;type:int;not null;" json:"min"` + Max int8 `gorm:"column:max;type:int;not null;" json:"max"` + Std float32 `gorm:"column:std;type:float;not null;" json:"std"` +} + +// TableName sets the insert table name for this struct type +func (n *InitialCafeteriaRatingTagAverage) TableName() string { + return "cafeteria_rating_tag_average" +} + +// InitialDishNameTagAverage stores all precomputed values for the DishName ratings +type InitialDishNameTagAverage struct { + DishNameTagAverage int64 `gorm:"primary_key;AUTO_INCREMENT;column:dishNameTagAverage;type:int;not null;" json:"dishNameTagAverage" ` + CafeteriaID int64 `gorm:"column:cafeteriaID;foreignKey:cafeteria;type:int;not null;" json:"cafeteriaID"` + TagID int64 `gorm:"column:tagID;foreignKey:DishNameTagOption;type:int;not null;" json:"tagID"` + Average float32 `gorm:"column:average;type:float;not null;" json:"average" ` + Min int8 `gorm:"column:min;type:int;not null;" json:"min"` + Max int8 `gorm:"column:max;type:int;not null;" json:"max"` + Std float32 `gorm:"column:std;type:float;not null;" json:"std"` +} + +// TableName sets the insert table name for this struct type +func (n *InitialDishNameTagAverage) TableName() string { + return "dish_name_tag_average" +} + +// InitialDishRatingAverage stores all precomputed values for the cafeteria ratings +type InitialDishRatingAverage struct { + DishRatingAverage int64 `gorm:"primary_key;AUTO_INCREMENT;column:dishRatingAverage;type:int;not null;" json:"dishRatingAverage" ` + CafeteriaID int64 `gorm:"column:cafeteriaID;foreignKey:cafeteria;type:int;not null;" json:"cafeteriaID"` + DishID int64 `gorm:"column:dishID;foreignKey:dish;type:int;not null;" json:"dishID"` + Average float64 `gorm:"column:average;type:float;not null;" json:"average" ` + Min int32 `gorm:"column:min;type:int;not null;" json:"min"` + Max int32 `gorm:"column:max;type:int;not null;" json:"max"` + Std float64 `gorm:"column:std;type:float;not null;" json:"std"` +} + +// TableName sets the insert table name for this struct type +func (n *InitialDishRatingAverage) TableName() string { + return "dish_rating_average" +} + +// InitialDishRatingTagAverage stores all precomputed values for the cafeteria ratings +type InitialDishRatingTagAverage struct { + DishRatingTagsAverage int64 `gorm:"primary_key;AUTO_INCREMENT;column:dishRatingTagsAverage;type:int;not null;" json:"dishRatingTagsAverage" ` + CafeteriaID int64 `gorm:"column:cafeteriaID;foreignKey:cafeteria;type:int;not null;" json:"cafeteriaID"` + TagID int64 `gorm:"column:tagID;foreignKey:tagID;type:int;not null;" json:"tagID"` + DishID int64 `gorm:"column:dishID;foreignKey:dishID;type:int;not null;" json:"dishID"` + Average float32 `gorm:"column:average;type:float;not null;" json:"average" ` + Min int8 `gorm:"column:min;type:int;not null;" json:"min"` + Max int8 `gorm:"column:max;type:int;not null;" json:"max"` + Std float32 `gorm:"column:std;type:float;not null;" json:"std"` +} + +// TableName sets the insert table name for this struct type +func (n *InitialDishRatingTagAverage) TableName() string { + return "dish_rating_tag_average" +} +// migrate20220713000000 +// - adds all canteen related models func migrate20220713000000() *gormigrate.Migration { return &gormigrate.Migration{ ID: "20220713000000", Migrate: func(tx *gorm.DB) error { if err := tx.AutoMigrate( - &model.Cafeteria{}, - &model.CafeteriaRating{}, - &model.CafeteriaRatingAverage{}, - &model.CafeteriaRatingTag{}, - &model.CafeteriaRatingTagAverage{}, - &model.CafeteriaRatingTagOption{}, - &model.Dish{}, - &model.DishesOfTheWeek{}, - &model.DishNameTagOption{}, - &model.DishNameTagOptionIncluded{}, - &model.DishNameTagOptionExcluded{}, - &model.DishNameTag{}, - &model.DishNameTagAverage{}, - &model.DishRating{}, - &model.DishRatingAverage{}, - &model.DishRatingTag{}, - &model.DishRatingTagAverage{}, - &model.DishRatingTagOption{}, - &model.DishToDishNameTag{}, + &InitialCafeteria{}, + &InitialCafeteriaRating{}, + &InitialCafeteriaRatingTag{}, + &InitialCafeteriaRatingTagOption{}, + &InitialDish{}, + &InitialDishesOfTheWeek{}, + &InitialDishNameTagOption{}, + &InitialDishNameTagOptionIncluded{}, + &InitialDishNameTagOptionExcluded{}, + &InitialDishNameTag{}, + &InitialDishRating{}, + &InitialDishRatingTag{}, + &InitialDishRatingTagOption{}, + &InitialDishToDishNameTag{}, + &InitialCafeteriaRatingAverage{}, + &InitialCafeteriaRatingTagAverage{}, + &InitialDishNameTagAverage{}, + &InitialDishRatingAverage{}, + &InitialDishRatingTagAverage{}, ); err != nil { return err } diff --git a/server/backend/migration/20221119131300.go b/server/backend/migration/20221119131300.go index fd96ba3b..5387d508 100644 --- a/server/backend/migration/20221119131300.go +++ b/server/backend/migration/20221119131300.go @@ -3,6 +3,7 @@ package migration import ( _ "embed" "encoding/json" + "time" "github.com/TUM-Dev/Campus-Backend/server/model" "github.com/go-gormigrate/gormigrate/v2" @@ -16,19 +17,99 @@ import ( //go:embed static_data/iosInitialSchedulingPriorities.json var iosInitialPrioritiesFile []byte +type InitialIOSDevice struct { + DeviceID string `gorm:"primary_key" json:"deviceId"` + CreatedAt time.Time `gorm:"autoCreateTime" json:"createdAt"` + PublicKey string `gorm:"not null" json:"publicKey"` + ActivityToday int32 `gorm:"default:0" json:"activityToday"` + ActivityThisWeek int32 `gorm:"default:0" json:"activityThisWeek"` + ActivityThisMonth int32 `gorm:"default:0" json:"activityThisMonth"` + ActivityThisYear int32 `gorm:"default:0" json:"activityThisYear"` +} + +// TableName sets the insert table name for this struct type +func (n *InitialIOSDevice) TableName() string { + return "ios_devices" +} + +type InitialIOSSchedulingPriority struct { + ID int64 `gorm:"primary_key;auto_increment;not_null" json:"id"` + FromDay int `gorm:"not null" json:"from_day"` + ToDay int `gorm:"not null" json:"to_day"` + FromHour int `gorm:"not null" json:"from_hour"` + ToHour int `gorm:"not null" json:"to_hour"` + Priority int `gorm:"not null" json:"priority"` +} + +// TableName sets the insert table name for this struct type +func (p *InitialIOSSchedulingPriority) TableName() string { + return "ios_scheduling_priorities" +} + +// InitialIOSScheduledUpdateLog logs the last time a device was updated. +type InitialIOSScheduledUpdateLog struct { + ID int64 `gorm:"primary_key;auto_increment;not_null" json:"id"` + DeviceID string `gorm:"index:idx_scheduled_update_log_device,unique" json:"deviceId"` + Device InitialIOSDevice `gorm:"constraint:OnDelete:CASCADE;" json:"device"` + Type string `gorm:"type:enum ('grades');" json:"type"` + CreatedAt time.Time `gorm:"index:idx_scheduled_update_log_created,unique;autoCreateTime" json:"createdAt"` +} + +// TableName sets the insert table name for this struct type +func (p *InitialIOSScheduledUpdateLog) TableName() string { + return "ios_scheduled_update_logs" +} + +type InitialIOSDeviceRequestLog struct { + RequestID string `gorm:"primary_key;default:UUID()" json:"requestId"` + DeviceID string `gorm:"size:200;not null" json:"deviceId"` + Device InitialIOSDevice `gorm:"constraint:OnDelete:CASCADE;" json:"device"` + RequestType string `gorm:"not null;type:enum ('CAMPUS_TOKEN_REQUEST');" json:"requestType"` + CreatedAt time.Time `gorm:"autoCreateTime" json:"createdAt"` +} + +// TableName sets the insert table name for this struct type +func (p *InitialIOSDeviceRequestLog) TableName() string { + return "ios_device_request_logs" +} + +type InitialIOSEncryptedGrade struct { + ID int64 `gorm:"primaryKey"` + Device InitialIOSDevice `gorm:"constraint:OnDelete:CASCADE"` + DeviceID string `gorm:"index;not null"` + LectureTitle string `gorm:"not null"` + Grade string `gorm:"not null"` + IsEncrypted bool `gorm:"not null,default:true"` +} + +// TableName sets the insert table name for this struct type +func (p *InitialIOSEncryptedGrade) TableName() string { + return "ios_encrypted_grades" +} + +type InitialIOSDevicesActivityReset struct { + Type string `gorm:"primary_key;type:enum('day', 'week', 'month', 'year')"` + LastReset time.Time `gorm:"autoCreateTime"` +} + +// TableName sets the insert table name for this struct type +func (p *InitialIOSDevicesActivityReset) TableName() string { + return "ios_devices_activity_resets" +} + +// migrate20221119131300 +// - adds the ability to connect to ios devices func migrate20221119131300() *gormigrate.Migration { return &gormigrate.Migration{ ID: "20221119131300", Migrate: func(tx *gorm.DB) error { - if err := tx.AutoMigrate( - &model.IOSDevice{}, - &model.Crontab{}, - &model.IOSSchedulingPriority{}, - &model.IOSScheduledUpdateLog{}, - &model.IOSDeviceRequestLog{}, - &model.IOSEncryptedGrade{}, - &model.IOSDevicesActivityReset{}, + &InitialIOSDevice{}, + &InitialIOSSchedulingPriority{}, + &InitialIOSScheduledUpdateLog{}, + &InitialIOSDeviceRequestLog{}, + &InitialIOSEncryptedGrade{}, + &InitialIOSDevicesActivityReset{}, ); err != nil { return err } @@ -37,7 +118,7 @@ func migrate20221119131300() *gormigrate.Migration { return err } - var priorities []model.IOSSchedulingPriority + var priorities []InitialIOSSchedulingPriority if err := json.Unmarshal(iosInitialPrioritiesFile, &priorities); err != nil { log.WithError(err).Error("could not unmarshal json") @@ -66,22 +147,22 @@ func migrate20221119131300() *gormigrate.Migration { }, Rollback: func(tx *gorm.DB) error { - if err := tx.Migrator().DropTable(&model.IOSDevice{}); err != nil { + if err := tx.Migrator().DropTable(&InitialIOSDevice{}); err != nil { return err } - if err := tx.Migrator().DropTable(&model.IOSSchedulingPriority{}); err != nil { + if err := tx.Migrator().DropTable(&InitialIOSSchedulingPriority{}); err != nil { return err } - if err := tx.Migrator().DropTable(&model.IOSScheduledUpdateLog{}); err != nil { + if err := tx.Migrator().DropTable(&InitialIOSScheduledUpdateLog{}); err != nil { return err } - if err := tx.Migrator().DropTable(&model.IOSDeviceRequestLog{}); err != nil { + if err := tx.Migrator().DropTable(&InitialIOSDeviceRequestLog{}); err != nil { return err } - if err := tx.Migrator().DropTable(&model.IOSEncryptedGrade{}); err != nil { + if err := tx.Migrator().DropTable(&InitialIOSEncryptedGrade{}); err != nil { return err } - if err := tx.Migrator().DropTable(&model.IOSDevicesActivityReset{}); err != nil { + if err := tx.Migrator().DropTable(&InitialIOSDevicesActivityReset{}); err != nil { return err } diff --git a/server/backend/migration/20221210000000.go b/server/backend/migration/20221210000000.go index 45ac4c47..9471b5aa 100644 --- a/server/backend/migration/20221210000000.go +++ b/server/backend/migration/20221210000000.go @@ -1,31 +1,44 @@ package migration import ( + "time" + "github.com/TUM-Dev/Campus-Backend/server/model" "github.com/go-gormigrate/gormigrate/v2" "github.com/guregu/null" "gorm.io/gorm" ) +// InitialCanteenHeadCount stores all available people counts for available canteens. The CanteenId represents the same ID, as for the canteen inside the eat-api. +type InitialCanteenHeadCount struct { + CanteenId string `gorm:"primary_key;column:canteen_id;type:varchar(64);not null;" json:"canteen_id"` + Count uint32 `gorm:"column:count;type:int;not null;" json:"count"` + MaxCount uint32 `gorm:"column:max_count;type:int;not null;" json:"max_count"` + Percent float32 `gorm:"column:percent;type:float;not null;" json:"percent"` + Timestamp time.Time `gorm:"column:timestamp;type:timestamp;not null;" json:"timestamp" ` +} + +// TableName sets the insert table name for this struct type +func (n *InitialCanteenHeadCount) TableName() string { + return "canteen_head_count" +} + // migrate20221210000000 -// adds a "canteenHeadCount" cron job that runs every 5 minutes. +// - adds InitialCanteenHeadCount table +// - adds a "canteenHeadCount" cron job that runs every 5 minutes. func migrate20221210000000() *gormigrate.Migration { return &gormigrate.Migration{ ID: "20221210000000", Migrate: func(tx *gorm.DB) error { - - err := tx.AutoMigrate( - &model.CanteenHeadCount{}, - ) - if err != nil { + // table + if err := tx.AutoMigrate(&InitialCanteenHeadCount{}); err != nil { return err } - // allow "canteenHeadCount" in the enum + // cron if err := SafeEnumAdd(tx, model.Crontab{}, "type", "canteenHeadCount"); err != nil { return err } - return tx.Create(&model.Crontab{ Interval: 60 * 5, // Every 5 minutes Type: null.StringFrom("canteenHeadCount"), @@ -33,11 +46,15 @@ func migrate20221210000000() *gormigrate.Migration { }, Rollback: func(tx *gorm.DB) error { - err := tx.Delete(&model.Crontab{}, "type = 'canteenHeadCount'").Error - if err != nil { + // table + if err := tx.Migrator().DropTable(&InitialCanteenHeadCount{}); err != nil { + return err + } + + // cron + if err := tx.Delete(&model.Crontab{}, "type = 'canteenHeadCount'").Error; err != nil { return err } - // Remove the 'canteenHeadCount' from the enum return SafeEnumRemove(tx, model.Crontab{}, "type", "canteenHeadCount") }, } diff --git a/server/backend/migration/20230904100000.go b/server/backend/migration/20230904100000.go index cd785772..e58b9414 100644 --- a/server/backend/migration/20230904100000.go +++ b/server/backend/migration/20230904100000.go @@ -7,14 +7,22 @@ import ( "gorm.io/gorm" ) +type NewsSourceFile struct { + File int64 `gorm:"primary_key;AUTO_INCREMENT;column:file;type:int;"` +} + +func (n *NewsSourceFile) TableName() string { + return "files" +} + // NewsSource struct is a row record of the newsSource table in the tca database type NewsSource struct { - Source int64 `gorm:"primary_key;AUTO_INCREMENT;column:source;type:int;"` - Title string `gorm:"column:title;type:text;size:16777215;"` - URL null.String `gorm:"column:url;type:text;size:16777215;"` - FileID int64 `gorm:"column:icon;not null;type:int;"` - File model.File `gorm:"foreignKey:FileID;references:file;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"` - Hook null.String `gorm:"column:hook;type:char;size:12;"` + Source int64 `gorm:"primary_key;AUTO_INCREMENT;column:source;type:int;"` + Title string `gorm:"column:title;type:text;size:16777215;"` + URL null.String `gorm:"column:url;type:text;size:16777215;"` + FileID int64 `gorm:"column:icon;not null;type:int;"` + File NewsSourceFile `gorm:"foreignKey:FileID;references:file;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"` + Hook null.String `gorm:"column:hook;type:char;size:12;"` } // TableName sets the insert table name for this struct type From 4d668ae9434c503fe3c3c4647180af267100a1de Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Tue, 24 Oct 2023 20:13:22 +0200 Subject: [PATCH 10/11] chore:less boilerplate heavy ios notifications (#272) * removed a bit of ios boilerplate * removed even more boilerplate * removed another instance of boilerplate * more refactoring * more simplification work * refactored the enum mirator to also be simpler to maintain --- server/api/tumdev/campus_backend.pb.go | 1290 ++++++++--------- server/api/tumdev/campus_backend.proto | 2 +- server/backend/cafeteria.go | 14 +- server/backend/campus_api/campus_api.go | 5 +- server/backend/device.go | 4 +- .../ios_notifications/apns/jwt_token.go | 34 +- .../ios_notifications/apns/repository.go | 53 +- .../backend/ios_notifications/apns/service.go | 22 +- .../crypto/encrypted_string.go | 8 +- .../ios_notifications/device/repository.go | 31 +- .../ios_notifications/device/service.go | 19 +- .../devices_activity_reset/repository.go | 5 +- .../devices_activity_reset/service.go | 5 - .../backend/ios_notifications/interfaces.go | 13 - .../request_response/repository.go | 29 +- .../request_response/service.go | 78 +- .../scheduled_update_log/repository.go | 10 +- .../scheduling/repository.go | 5 +- .../ios_notifications/scheduling/service.go | 15 +- server/backend/migration/safe_enum_migrate.go | 54 +- .../scheduling/repository.go | 1 - .../scheduling/service.go | 8 +- .../subscriber/repository.go | 12 +- .../subscriber/service.go | 6 +- server/backend/validators.go | 10 +- 25 files changed, 773 insertions(+), 960 deletions(-) delete mode 100644 server/backend/ios_notifications/interfaces.go diff --git a/server/api/tumdev/campus_backend.pb.go b/server/api/tumdev/campus_backend.pb.go index c22f7b97..adc7e75e 100644 --- a/server/api/tumdev/campus_backend.pb.go +++ b/server/api/tumdev/campus_backend.pb.go @@ -126,7 +126,7 @@ type CreateDeviceRequest struct { unknownFields protoimpl.UnknownFields DeviceId string `protobuf:"bytes,1,opt,name=device_id,json=deviceId,proto3" json:"device_id,omitempty"` - PublicKey *string `protobuf:"bytes,2,opt,name=public_key,json=publicKey,proto3,oneof" json:"public_key,omitempty"` + PublicKey string `protobuf:"bytes,2,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` DeviceType DeviceType `protobuf:"varint,3,opt,name=device_type,json=deviceType,proto3,enum=api.DeviceType" json:"device_type,omitempty"` } @@ -170,8 +170,8 @@ func (x *CreateDeviceRequest) GetDeviceId() string { } func (x *CreateDeviceRequest) GetPublicKey() string { - if x != nil && x.PublicKey != nil { - return *x.PublicKey + if x != nil { + return x.PublicKey } return "" } @@ -4345,666 +4345,665 @@ var file_tumdev_campus_backend_proto_rawDesc = []byte{ 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x22, 0x97, 0x01, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, + 0x6f, 0x22, 0x83, 0x01, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, - 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, - 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x09, 0x70, 0x75, - 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x88, 0x01, 0x01, 0x12, 0x30, 0x0a, 0x0b, 0x64, 0x65, - 0x76, 0x69, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x0f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, - 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x42, 0x0d, 0x0a, 0x0b, - 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x22, 0x30, 0x0a, 0x11, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, + 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x61, 0x70, 0x69, + 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x22, 0x30, 0x0a, 0x11, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1b, 0x0a, 0x09, + 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x22, 0x64, 0x0a, 0x13, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x22, 0x64, 0x0a, - 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x30, 0x0a, + 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, + 0x79, 0x70, 0x65, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x22, + 0x30, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, + 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, - 0x64, 0x12, 0x30, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x65, 0x76, - 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, - 0x79, 0x70, 0x65, 0x22, 0x30, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x44, 0x65, 0x76, - 0x69, 0x63, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, - 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x76, - 0x69, 0x63, 0x65, 0x49, 0x64, 0x22, 0x5a, 0x0a, 0x1f, 0x49, 0x4f, 0x53, 0x44, 0x65, 0x76, 0x69, - 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, - 0x61, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, - 0x64, 0x22, 0x39, 0x0a, 0x1d, 0x49, 0x4f, 0x53, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x65, 0x70, - 0x6c, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xbf, 0x02, 0x0a, - 0x04, 0x4e, 0x65, 0x77, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, - 0x65, 0x78, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x12, - 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, - 0x69, 0x6e, 0x6b, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x5f, 0x75, 0x72, 0x6c, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x55, 0x72, 0x6c, - 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x26, 0x0a, - 0x0f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x63, 0x6f, 0x6e, 0x5f, 0x75, 0x72, 0x6c, - 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x63, - 0x6f, 0x6e, 0x55, 0x72, 0x6c, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, - 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x34, 0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x64, 0x22, 0x5a, 0x0a, 0x1f, 0x49, 0x4f, 0x53, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x39, 0x0a, + 0x1d, 0x49, 0x4f, 0x53, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x18, + 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xbf, 0x02, 0x0a, 0x04, 0x4e, 0x65, 0x77, + 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, + 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x78, 0x74, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6c, + 0x69, 0x6e, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x12, + 0x1b, 0x0a, 0x09, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x55, 0x72, 0x6c, 0x12, 0x1b, 0x0a, 0x09, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x26, 0x0a, 0x0f, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x5f, 0x69, 0x63, 0x6f, 0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x63, 0x6f, 0x6e, 0x55, 0x72, + 0x6c, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x74, 0x69, 0x74, 0x6c, + 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, + 0x69, 0x74, 0x6c, 0x65, 0x12, 0x34, 0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x52, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x12, 0x2e, 0x0a, 0x04, 0x64, 0x61, + 0x74, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x64, 0x61, 0x74, 0x65, 0x22, 0x2e, 0x0a, 0x0d, 0x4c, 0x69, + 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1d, 0x0a, 0x04, 0x6e, + 0x65, 0x77, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x4e, 0x65, 0x77, 0x73, 0x52, 0x04, 0x6e, 0x65, 0x77, 0x73, 0x22, 0x96, 0x01, 0x0a, 0x0f, 0x4c, + 0x69, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, + 0x0a, 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x6e, 0x65, 0x77, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x6c, 0x61, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x49, 0x64, + 0x12, 0x1f, 0x0a, 0x0b, 0x6e, 0x65, 0x77, 0x73, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x6e, 0x65, 0x77, 0x73, 0x53, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x12, 0x40, 0x0a, 0x0e, 0x6f, 0x6c, 0x64, 0x65, 0x73, 0x74, 0x5f, 0x64, 0x61, 0x74, 0x65, + 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x12, 0x2e, - 0x0a, 0x04, 0x64, 0x61, 0x74, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x6f, 0x6c, 0x64, 0x65, 0x73, 0x74, 0x44, 0x61, 0x74, + 0x65, 0x41, 0x74, 0x22, 0x18, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x53, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x41, 0x0a, + 0x14, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, + 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x29, 0x0a, 0x07, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4e, 0x65, 0x77, + 0x73, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x07, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, + 0x22, 0x55, 0x0a, 0x0a, 0x4e, 0x65, 0x77, 0x73, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x16, + 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x19, 0x0a, 0x08, + 0x69, 0x63, 0x6f, 0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x69, 0x63, 0x6f, 0x6e, 0x55, 0x72, 0x6c, 0x22, 0x44, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x4e, + 0x65, 0x77, 0x73, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x2b, 0x0a, 0x12, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x6e, 0x65, 0x77, 0x73, 0x5f, 0x61, 0x6c, + 0x65, 0x72, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x6c, 0x61, + 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x49, 0x64, 0x22, 0x3d, 0x0a, + 0x13, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x73, 0x52, + 0x65, 0x70, 0x6c, 0x79, 0x12, 0x26, 0x0a, 0x06, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4e, 0x65, 0x77, 0x73, 0x41, + 0x6c, 0x65, 0x72, 0x74, 0x52, 0x06, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x73, 0x22, 0xce, 0x01, 0x0a, + 0x09, 0x4e, 0x65, 0x77, 0x73, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x6d, + 0x61, 0x67, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x69, + 0x6d, 0x61, 0x67, 0x65, 0x55, 0x72, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x34, 0x0a, 0x07, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x64, 0x61, 0x74, 0x65, 0x22, 0x2e, - 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, - 0x1d, 0x0a, 0x04, 0x6e, 0x65, 0x77, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x09, 0x2e, - 0x61, 0x70, 0x69, 0x2e, 0x4e, 0x65, 0x77, 0x73, 0x52, 0x04, 0x6e, 0x65, 0x77, 0x73, 0x22, 0x96, - 0x01, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x6e, 0x65, 0x77, 0x73, 0x5f, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x6c, 0x61, 0x73, 0x74, 0x4e, 0x65, - 0x77, 0x73, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x6e, 0x65, 0x77, 0x73, 0x5f, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x6e, 0x65, 0x77, 0x73, 0x53, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x40, 0x0a, 0x0e, 0x6f, 0x6c, 0x64, 0x65, 0x73, 0x74, 0x5f, - 0x64, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x64, 0x12, 0x2e, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x66, 0x72, 0x6f, + 0x6d, 0x12, 0x2a, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x6f, 0x6c, 0x64, 0x65, 0x73, - 0x74, 0x44, 0x61, 0x74, 0x65, 0x41, 0x74, 0x22, 0x18, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x4e, - 0x65, 0x77, 0x73, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x22, 0x41, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x53, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x29, 0x0a, 0x07, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x61, 0x70, 0x69, - 0x2e, 0x4e, 0x65, 0x77, 0x73, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x07, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x73, 0x22, 0x55, 0x0a, 0x0a, 0x4e, 0x65, 0x77, 0x73, 0x53, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, - 0x74, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, - 0x12, 0x19, 0x0a, 0x08, 0x69, 0x63, 0x6f, 0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x69, 0x63, 0x6f, 0x6e, 0x55, 0x72, 0x6c, 0x22, 0x44, 0x0a, 0x15, 0x4c, - 0x69, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x2b, 0x0a, 0x12, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x6e, 0x65, 0x77, - 0x73, 0x5f, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x0f, 0x6c, 0x61, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x49, - 0x64, 0x22, 0x3d, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x41, 0x6c, 0x65, - 0x72, 0x74, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x26, 0x0a, 0x06, 0x61, 0x6c, 0x65, 0x72, - 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4e, - 0x65, 0x77, 0x73, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x52, 0x06, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x73, - 0x22, 0xce, 0x01, 0x0a, 0x09, 0x4e, 0x65, 0x77, 0x73, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x12, 0x1b, - 0x0a, 0x09, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x55, 0x72, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x6c, - 0x69, 0x6e, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x12, - 0x34, 0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x63, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x64, 0x12, 0x2e, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, - 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x2a, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x02, 0x74, - 0x6f, 0x22, 0xac, 0x01, 0x0a, 0x19, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, - 0x6e, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x1d, 0x0a, 0x0a, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x49, 0x64, 0x12, 0x2e, - 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x2a, - 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, - 0x6d, 0x69, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, - 0x22, 0xc8, 0x01, 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, - 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x2e, 0x0a, 0x06, - 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x61, - 0x70, 0x69, 0x2e, 0x53, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x52, - 0x65, 0x70, 0x6c, 0x79, 0x52, 0x06, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x10, 0x0a, 0x03, - 0x61, 0x76, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x61, 0x76, 0x67, 0x12, 0x10, - 0x0a, 0x03, 0x73, 0x74, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x73, 0x74, 0x64, - 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6d, - 0x69, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x61, 0x78, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, - 0x03, 0x6d, 0x61, 0x78, 0x12, 0x35, 0x0a, 0x0b, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x74, - 0x61, 0x67, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x61, 0x70, 0x69, 0x2e, - 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, - 0x0a, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x73, 0x22, 0xbc, 0x01, 0x0a, 0x15, - 0x47, 0x65, 0x74, 0x44, 0x69, 0x73, 0x68, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, - 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x61, 0x6e, 0x74, 0x65, - 0x65, 0x6e, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x69, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x64, 0x69, 0x73, 0x68, 0x12, 0x2e, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x02, 0x74, 0x6f, 0x22, 0xac, 0x01, + 0x0a, 0x19, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x52, 0x61, 0x74, + 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, + 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x04, 0x66, 0x72, + 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x2a, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x2a, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x52, 0x02, 0x74, 0x6f, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0xf7, 0x01, 0x0a, 0x13, 0x47, - 0x65, 0x74, 0x44, 0x69, 0x73, 0x68, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x70, - 0x6c, 0x79, 0x12, 0x2e, 0x0a, 0x06, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x52, - 0x61, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x52, 0x06, 0x72, 0x61, 0x74, 0x69, - 0x6e, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x76, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, - 0x03, 0x61, 0x76, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x74, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x01, 0x52, 0x03, 0x73, 0x74, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x69, 0x6e, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x03, 0x6d, 0x69, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x61, 0x78, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6d, 0x61, 0x78, 0x12, 0x35, 0x0a, 0x0b, 0x72, 0x61, - 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x14, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x52, - 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x0a, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, - 0x73, 0x12, 0x31, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x18, 0x07, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x61, 0x74, 0x69, 0x6e, - 0x67, 0x54, 0x61, 0x67, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x08, 0x6e, 0x61, 0x6d, 0x65, - 0x54, 0x61, 0x67, 0x73, 0x22, 0xcc, 0x01, 0x0a, 0x11, 0x53, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x52, - 0x61, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6f, + 0x6d, 0x70, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0xc8, 0x01, 0x0a, + 0x17, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x52, 0x61, 0x74, 0x69, + 0x6e, 0x67, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x2e, 0x0a, 0x06, 0x72, 0x61, 0x74, 0x69, + 0x6e, 0x67, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, + 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x70, 0x6c, 0x79, + 0x52, 0x06, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x76, 0x67, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x61, 0x76, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x74, + 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x73, 0x74, 0x64, 0x12, 0x10, 0x0a, 0x03, + 0x6d, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6d, 0x69, 0x6e, 0x12, 0x10, + 0x0a, 0x03, 0x6d, 0x61, 0x78, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6d, 0x61, 0x78, + 0x12, 0x35, 0x0a, 0x0b, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x18, + 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x61, 0x74, 0x69, + 0x6e, 0x67, 0x54, 0x61, 0x67, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x0a, 0x72, 0x61, 0x74, + 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x73, 0x22, 0xbc, 0x01, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x44, + 0x69, 0x73, 0x68, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x49, 0x64, + 0x12, 0x12, 0x0a, 0x04, 0x64, 0x69, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x64, 0x69, 0x73, 0x68, 0x12, 0x2e, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, + 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x2a, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x02, 0x74, 0x6f, + 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0xf7, 0x01, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x44, 0x69, + 0x73, 0x68, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x2e, + 0x0a, 0x06, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x52, 0x61, 0x74, 0x69, 0x6e, + 0x67, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x52, 0x06, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x10, + 0x0a, 0x03, 0x61, 0x76, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x61, 0x76, 0x67, + 0x12, 0x10, 0x0a, 0x03, 0x73, 0x74, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x73, + 0x74, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x03, 0x6d, 0x69, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x61, 0x78, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x03, 0x6d, 0x61, 0x78, 0x12, 0x35, 0x0a, 0x0b, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, + 0x5f, 0x74, 0x61, 0x67, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x52, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x52, 0x0a, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x73, 0x12, 0x31, 0x0a, + 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x14, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, + 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x08, 0x6e, 0x61, 0x6d, 0x65, 0x54, 0x61, 0x67, 0x73, + 0x22, 0xcc, 0x01, 0x0a, 0x11, 0x53, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x52, 0x61, 0x74, 0x69, 0x6e, + 0x67, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x12, 0x14, + 0x0a, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x69, + 0x6d, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x39, + 0x0a, 0x0b, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x18, 0x04, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, + 0x54, 0x61, 0x67, 0x4e, 0x65, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x0a, 0x72, + 0x61, 0x74, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x73, 0x12, 0x34, 0x0a, 0x07, 0x76, 0x69, 0x73, + 0x69, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x76, 0x69, 0x73, 0x69, 0x74, 0x65, 0x64, 0x22, + 0x1a, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, + 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0xb4, 0x01, 0x0a, 0x1a, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x52, 0x61, 0x74, + 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x70, 0x6f, 0x69, 0x6e, - 0x74, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, - 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x65, - 0x6e, 0x74, 0x12, 0x39, 0x0a, 0x0b, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x67, - 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x61, - 0x74, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x4e, 0x65, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x52, 0x0a, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x73, 0x12, 0x34, 0x0a, - 0x07, 0x76, 0x69, 0x73, 0x69, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x76, 0x69, 0x73, 0x69, - 0x74, 0x65, 0x64, 0x22, 0x1a, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x61, 0x6e, - 0x74, 0x65, 0x65, 0x6e, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, - 0xb4, 0x01, 0x0a, 0x1a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, - 0x6e, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, - 0x0a, 0x06, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, - 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, - 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x61, 0x6e, 0x74, - 0x65, 0x65, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x2f, 0x0a, 0x0b, 0x72, - 0x61, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x0e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, - 0x52, 0x0a, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x73, 0x12, 0x18, 0x0a, 0x07, - 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, - 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x17, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x44, 0x69, 0x73, 0x68, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, - 0xc5, 0x01, 0x0a, 0x17, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x69, 0x73, 0x68, 0x52, 0x61, - 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, - 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x70, 0x6f, 0x69, - 0x6e, 0x74, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x5f, 0x69, - 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, - 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x69, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x64, 0x69, 0x73, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x2f, 0x0a, 0x0b, - 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x0e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x54, 0x61, - 0x67, 0x52, 0x0a, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x73, 0x12, 0x18, 0x0a, - 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x1e, 0x0a, 0x1c, 0x4c, 0x69, 0x73, 0x74, 0x41, - 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x44, 0x69, 0x73, 0x68, 0x54, 0x61, 0x67, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x50, 0x0a, 0x1a, 0x4c, 0x69, 0x73, 0x74, 0x41, - 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x44, 0x69, 0x73, 0x68, 0x54, 0x61, 0x67, 0x73, - 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x32, 0x0a, 0x0b, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x5f, - 0x74, 0x61, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x61, 0x70, 0x69, - 0x2e, 0x54, 0x61, 0x67, 0x73, 0x4f, 0x76, 0x65, 0x72, 0x76, 0x69, 0x65, 0x77, 0x52, 0x0a, 0x72, - 0x61, 0x74, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x73, 0x22, 0x15, 0x0a, 0x13, 0x4c, 0x69, 0x73, - 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x22, 0x47, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x54, 0x61, 0x67, 0x73, - 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x32, 0x0a, 0x0b, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x5f, - 0x74, 0x61, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x61, 0x70, 0x69, - 0x2e, 0x54, 0x61, 0x67, 0x73, 0x4f, 0x76, 0x65, 0x72, 0x76, 0x69, 0x65, 0x77, 0x52, 0x0a, 0x72, - 0x61, 0x74, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x73, 0x22, 0x21, 0x0a, 0x1f, 0x4c, 0x69, 0x73, - 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, - 0x6e, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x53, 0x0a, 0x1d, - 0x4c, 0x69, 0x73, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x6e, - 0x74, 0x65, 0x65, 0x6e, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x32, 0x0a, - 0x0b, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, 0x73, 0x4f, 0x76, 0x65, - 0x72, 0x76, 0x69, 0x65, 0x77, 0x52, 0x0a, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, - 0x73, 0x22, 0x45, 0x0a, 0x0c, 0x54, 0x61, 0x67, 0x73, 0x4f, 0x76, 0x65, 0x72, 0x76, 0x69, 0x65, - 0x77, 0x12, 0x15, 0x0a, 0x06, 0x74, 0x61, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x05, 0x74, 0x61, 0x67, 0x49, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x64, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x64, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x65, 0x6e, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x65, 0x6e, 0x22, 0x3a, 0x0a, 0x09, 0x52, 0x61, 0x74, 0x69, - 0x6e, 0x67, 0x54, 0x61, 0x67, 0x12, 0x15, 0x0a, 0x06, 0x74, 0x61, 0x67, 0x5f, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x74, 0x61, 0x67, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, - 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x06, 0x70, 0x6f, - 0x69, 0x6e, 0x74, 0x73, 0x22, 0x44, 0x0a, 0x13, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x54, 0x61, - 0x67, 0x4e, 0x65, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x74, - 0x61, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x74, 0x61, 0x67, - 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x05, 0x52, 0x06, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x22, 0x70, 0x0a, 0x0f, 0x52, 0x61, - 0x74, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x15, 0x0a, + 0x74, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x5f, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x49, + 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x2f, 0x0a, 0x0b, 0x72, 0x61, 0x74, 0x69, 0x6e, + 0x67, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x52, 0x0a, 0x72, 0x61, + 0x74, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, + 0x65, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x65, + 0x6e, 0x74, 0x22, 0x17, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x69, 0x73, 0x68, + 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0xc5, 0x01, 0x0a, 0x17, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x69, 0x73, 0x68, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x12, + 0x1d, 0x0a, 0x0a, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x49, 0x64, 0x12, 0x12, + 0x0a, 0x04, 0x64, 0x69, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x69, + 0x73, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x2f, 0x0a, 0x0b, 0x72, 0x61, 0x74, 0x69, + 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, + 0x61, 0x70, 0x69, 0x2e, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x52, 0x0a, 0x72, + 0x61, 0x74, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, + 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, + 0x65, 0x6e, 0x74, 0x22, 0x1e, 0x0a, 0x1c, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, + 0x61, 0x62, 0x6c, 0x65, 0x44, 0x69, 0x73, 0x68, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x22, 0x50, 0x0a, 0x1a, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, + 0x61, 0x62, 0x6c, 0x65, 0x44, 0x69, 0x73, 0x68, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x70, 0x6c, + 0x79, 0x12, 0x32, 0x0a, 0x0b, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x67, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, + 0x73, 0x4f, 0x76, 0x65, 0x72, 0x76, 0x69, 0x65, 0x77, 0x52, 0x0a, 0x72, 0x61, 0x74, 0x69, 0x6e, + 0x67, 0x54, 0x61, 0x67, 0x73, 0x22, 0x15, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x61, 0x6d, + 0x65, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x47, 0x0a, 0x11, + 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x70, 0x6c, + 0x79, 0x12, 0x32, 0x0a, 0x0b, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x67, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, + 0x73, 0x4f, 0x76, 0x65, 0x72, 0x76, 0x69, 0x65, 0x77, 0x52, 0x0a, 0x72, 0x61, 0x74, 0x69, 0x6e, + 0x67, 0x54, 0x61, 0x67, 0x73, 0x22, 0x21, 0x0a, 0x1f, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x76, 0x61, + 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x54, 0x61, 0x67, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x53, 0x0a, 0x1d, 0x4c, 0x69, 0x73, 0x74, + 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, + 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x32, 0x0a, 0x0b, 0x72, 0x61, 0x74, + 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, 0x73, 0x4f, 0x76, 0x65, 0x72, 0x76, 0x69, 0x65, + 0x77, 0x52, 0x0a, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x73, 0x22, 0x45, 0x0a, + 0x0c, 0x54, 0x61, 0x67, 0x73, 0x4f, 0x76, 0x65, 0x72, 0x76, 0x69, 0x65, 0x77, 0x12, 0x15, 0x0a, 0x06, 0x74, 0x61, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x74, - 0x61, 0x67, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x76, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x01, 0x52, 0x03, 0x61, 0x76, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x74, 0x64, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x01, 0x52, 0x03, 0x73, 0x74, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x69, 0x6e, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6d, 0x69, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x61, - 0x78, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6d, 0x61, 0x78, 0x22, 0x15, 0x0a, 0x13, - 0x4c, 0x69, 0x73, 0x74, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x22, 0x3b, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x61, 0x6e, 0x74, 0x65, - 0x65, 0x6e, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x26, 0x0a, 0x07, 0x63, 0x61, 0x6e, 0x74, - 0x65, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x61, 0x70, 0x69, 0x2e, - 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x52, 0x07, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, - 0x22, 0x6d, 0x0a, 0x07, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x6c, 0x6f, 0x6e, 0x67, 0x69, 0x74, 0x75, - 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x09, 0x6c, 0x6f, 0x6e, 0x67, 0x69, 0x74, - 0x75, 0x64, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x61, 0x74, 0x69, 0x74, 0x75, 0x64, 0x65, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, 0x08, 0x6c, 0x61, 0x74, 0x69, 0x74, 0x75, 0x64, 0x65, 0x22, - 0x6c, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x69, 0x73, 0x68, 0x65, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x5f, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, - 0x6e, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x79, 0x65, 0x61, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x04, 0x79, 0x65, 0x61, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x77, 0x65, 0x65, 0x6b, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x77, 0x65, 0x65, 0x6b, 0x12, 0x10, 0x0a, 0x03, 0x64, - 0x61, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x64, 0x61, 0x79, 0x22, 0x25, 0x0a, - 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x69, 0x73, 0x68, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, - 0x12, 0x12, 0x0a, 0x04, 0x64, 0x69, 0x73, 0x68, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, - 0x64, 0x69, 0x73, 0x68, 0x22, 0x1e, 0x0a, 0x1c, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x22, 0x63, 0x0a, 0x1a, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x52, 0x65, 0x70, - 0x6c, 0x79, 0x12, 0x45, 0x0a, 0x12, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x69, 0x62, 0x6c, - 0x65, 0x5f, 0x70, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, - 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x69, 0x62, 0x6c, 0x65, - 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x52, 0x11, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x69, - 0x62, 0x6c, 0x65, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x22, 0x8c, 0x01, 0x0a, 0x11, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x12, - 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x68, 0x6f, 0x6e, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x68, 0x6f, 0x6e, - 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x61, 0x63, 0x75, 0x6c, - 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x66, 0x61, 0x63, 0x75, 0x6c, 0x74, - 0x79, 0x12, 0x15, 0x0a, 0x06, 0x74, 0x75, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x74, 0x75, 0x6d, 0x49, 0x64, 0x22, 0xfc, 0x01, 0x0a, 0x16, 0x52, 0x6f, 0x6f, - 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6c, 0x65, 0x6d, - 0x65, 0x6e, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x72, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, - 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x08, 0x72, 0x6f, 0x6f, 0x6d, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x62, 0x75, 0x69, - 0x6c, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6e, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, - 0x62, 0x75, 0x69, 0x6c, 0x64, 0x69, 0x6e, 0x67, 0x4e, 0x72, 0x12, 0x17, 0x0a, 0x07, 0x61, 0x72, - 0x63, 0x68, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x72, 0x63, - 0x68, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x18, 0x07, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x70, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x63, - 0x61, 0x6d, 0x70, 0x75, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, 0x61, 0x6d, - 0x70, 0x75, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x1c, 0x0a, 0x1a, 0x4c, 0x69, 0x73, 0x74, 0x4d, - 0x6f, 0x72, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xb6, 0x01, 0x0a, 0x18, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, - 0x72, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, - 0x6c, 0x79, 0x12, 0x43, 0x0a, 0x05, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x2d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x72, 0x65, - 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, - 0x2e, 0x4d, 0x6f, 0x72, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x05, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x1a, 0x55, 0x0a, 0x0f, 0x4d, 0x6f, 0x72, 0x65, 0x49, - 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, - 0x74, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, - 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, - 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x22, 0x35, - 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x70, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x54, 0x69, 0x6d, - 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x61, 0x6e, - 0x67, 0x75, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x61, 0x6e, - 0x67, 0x75, 0x61, 0x67, 0x65, 0x22, 0x54, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x70, 0x65, - 0x6e, 0x69, 0x6e, 0x67, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x3b, - 0x0a, 0x0a, 0x66, 0x61, 0x63, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x69, 0x6e, 0x67, - 0x54, 0x69, 0x6d, 0x65, 0x73, 0x4d, 0x73, 0x67, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, - 0x0a, 0x66, 0x61, 0x63, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x22, 0xbf, 0x02, 0x0a, 0x16, - 0x4f, 0x70, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x4d, 0x73, 0x67, 0x45, - 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, - 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, - 0x72, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x12, 0x12, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x72, 0x6f, 0x6f, 0x6d, 0x12, 0x2b, 0x0a, 0x11, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, - 0x74, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x10, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x74, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x68, 0x6f, 0x75, - 0x72, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6e, - 0x67, 0x48, 0x6f, 0x75, 0x72, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x12, 0x10, 0x0a, 0x03, - 0x75, 0x72, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x1a, - 0x0a, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x65, - 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x0b, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x22, 0x30, 0x0a, - 0x14, 0x47, 0x65, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x74, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, - 0x51, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x74, 0x65, - 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x21, 0x0a, 0x0c, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4e, 0x61, - 0x6d, 0x65, 0x22, 0x6e, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x76, 0x69, 0x65, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x6c, 0x61, 0x73, 0x74, 0x5f, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x6c, 0x61, 0x73, 0x74, 0x49, 0x64, - 0x12, 0x40, 0x0a, 0x0e, 0x6f, 0x6c, 0x64, 0x65, 0x73, 0x74, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x5f, - 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x61, 0x67, 0x49, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x02, 0x64, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x02, 0x65, 0x6e, 0x22, 0x3a, 0x0a, 0x09, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x54, 0x61, + 0x67, 0x12, 0x15, 0x0a, 0x06, 0x74, 0x61, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x05, 0x74, 0x61, 0x67, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6f, 0x69, 0x6e, + 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x06, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, + 0x22, 0x44, 0x0a, 0x13, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x4e, 0x65, 0x77, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x74, 0x61, 0x67, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x74, 0x61, 0x67, 0x49, 0x64, 0x12, 0x16, + 0x0a, 0x06, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, + 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x22, 0x70, 0x0a, 0x0f, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, + 0x54, 0x61, 0x67, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x74, 0x61, 0x67, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x74, 0x61, 0x67, 0x49, 0x64, + 0x12, 0x10, 0x0a, 0x03, 0x61, 0x76, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x61, + 0x76, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x74, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, + 0x03, 0x73, 0x74, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x03, 0x6d, 0x69, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x61, 0x78, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x03, 0x6d, 0x61, 0x78, 0x22, 0x15, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, + 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, + 0x3b, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x73, 0x52, + 0x65, 0x70, 0x6c, 0x79, 0x12, 0x26, 0x0a, 0x07, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x61, 0x6e, 0x74, + 0x65, 0x65, 0x6e, 0x52, 0x07, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x22, 0x6d, 0x0a, 0x07, + 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x6c, 0x6f, 0x6e, 0x67, 0x69, 0x74, 0x75, 0x64, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x01, 0x52, 0x09, 0x6c, 0x6f, 0x6e, 0x67, 0x69, 0x74, 0x75, 0x64, 0x65, 0x12, + 0x1a, 0x0a, 0x08, 0x6c, 0x61, 0x74, 0x69, 0x74, 0x75, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x01, 0x52, 0x08, 0x6c, 0x61, 0x74, 0x69, 0x74, 0x75, 0x64, 0x65, 0x22, 0x6c, 0x0a, 0x11, 0x4c, + 0x69, 0x73, 0x74, 0x44, 0x69, 0x73, 0x68, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x49, 0x64, 0x12, + 0x12, 0x0a, 0x04, 0x79, 0x65, 0x61, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x79, + 0x65, 0x61, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x77, 0x65, 0x65, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x04, 0x77, 0x65, 0x65, 0x6b, 0x12, 0x10, 0x0a, 0x03, 0x64, 0x61, 0x79, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x64, 0x61, 0x79, 0x22, 0x25, 0x0a, 0x0f, 0x4c, 0x69, 0x73, + 0x74, 0x44, 0x69, 0x73, 0x68, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x12, 0x0a, 0x04, + 0x64, 0x69, 0x73, 0x68, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x64, 0x69, 0x73, 0x68, + 0x22, 0x1e, 0x0a, 0x1c, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x69, + 0x62, 0x6c, 0x65, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x22, 0x63, 0x0a, 0x1a, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x69, + 0x62, 0x6c, 0x65, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x45, + 0x0a, 0x12, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x5f, 0x70, 0x65, + 0x72, 0x73, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x61, 0x70, 0x69, + 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x50, 0x65, 0x72, 0x73, + 0x6f, 0x6e, 0x52, 0x11, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x50, + 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x22, 0x8c, 0x01, 0x0a, 0x11, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x69, 0x62, 0x6c, 0x65, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x1c, 0x0a, 0x09, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x12, 0x14, 0x0a, + 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, + 0x61, 0x69, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x61, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x66, 0x61, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x12, 0x15, 0x0a, + 0x06, 0x74, 0x75, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, + 0x75, 0x6d, 0x49, 0x64, 0x22, 0xfc, 0x01, 0x0a, 0x16, 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x6e, 0x66, + 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x12, + 0x17, 0x0a, 0x07, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x06, 0x72, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x6f, 0x6f, 0x6d, + 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x6f, 0x6f, + 0x6d, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x69, 0x6e, + 0x67, 0x5f, 0x6e, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x62, 0x75, 0x69, 0x6c, + 0x64, 0x69, 0x6e, 0x67, 0x4e, 0x72, 0x12, 0x17, 0x0a, 0x07, 0x61, 0x72, 0x63, 0x68, 0x5f, 0x69, + 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x72, 0x63, 0x68, 0x49, 0x64, 0x12, + 0x12, 0x0a, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x69, + 0x6e, 0x66, 0x6f, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, + 0x07, 0x70, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x70, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x61, 0x6d, 0x70, 0x75, + 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, 0x61, 0x6d, 0x70, 0x75, 0x73, 0x12, + 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x22, 0x1c, 0x0a, 0x1a, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x72, 0x65, 0x49, + 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x22, 0xb6, 0x01, 0x0a, 0x18, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x72, 0x65, 0x49, 0x6e, + 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x43, + 0x0a, 0x05, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, + 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x72, 0x65, 0x49, 0x6e, 0x66, 0x6f, + 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x2e, 0x4d, 0x6f, 0x72, + 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x69, 0x6e, + 0x66, 0x6f, 0x73, 0x1a, 0x55, 0x0a, 0x0f, 0x4d, 0x6f, 0x72, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x72, + 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x1a, 0x0a, 0x08, + 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x22, 0x35, 0x0a, 0x17, 0x4c, 0x69, + 0x73, 0x74, 0x4f, 0x70, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, + 0x65, 0x22, 0x54, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x70, 0x65, 0x6e, 0x69, 0x6e, 0x67, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x3b, 0x0a, 0x0a, 0x66, 0x61, + 0x63, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x54, 0x69, 0x6d, 0x65, + 0x73, 0x4d, 0x73, 0x67, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x0a, 0x66, 0x61, 0x63, + 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x22, 0xbf, 0x02, 0x0a, 0x16, 0x4f, 0x70, 0x65, 0x6e, + 0x69, 0x6e, 0x67, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x4d, 0x73, 0x67, 0x45, 0x6c, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, + 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x12, 0x12, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, + 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, + 0x12, 0x2b, 0x0a, 0x11, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x73, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x74, 0x72, 0x61, + 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, + 0x0d, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x68, 0x6f, 0x75, 0x72, 0x73, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x48, 0x6f, 0x75, + 0x72, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, + 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x61, + 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x61, + 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, + 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x72, 0x65, + 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x22, 0x30, 0x0a, 0x14, 0x47, 0x65, 0x74, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x51, 0x0a, 0x12, 0x47, + 0x65, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6c, + 0x79, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x6e, + 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x76, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x6c, 0x61, 0x73, 0x74, 0x49, 0x64, 0x12, 0x40, 0x0a, 0x0e, + 0x6f, 0x6c, 0x64, 0x65, 0x73, 0x74, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x74, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x52, 0x0c, 0x6f, 0x6c, 0x64, 0x65, 0x73, 0x74, 0x44, 0x61, 0x74, 0x65, 0x41, 0x74, 0x22, 0x35, + 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x76, 0x69, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, + 0x79, 0x12, 0x22, 0x0a, 0x06, 0x6d, 0x6f, 0x76, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x0a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x6f, 0x76, 0x69, 0x65, 0x52, 0x06, 0x6d, + 0x6f, 0x76, 0x69, 0x65, 0x73, 0x22, 0xc6, 0x03, 0x0a, 0x05, 0x4d, 0x6f, 0x76, 0x69, 0x65, 0x12, + 0x19, 0x0a, 0x08, 0x6d, 0x6f, 0x76, 0x69, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x07, 0x6d, 0x6f, 0x76, 0x69, 0x65, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x04, 0x64, 0x61, + 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x6f, 0x6c, 0x64, 0x65, 0x73, 0x74, 0x44, 0x61, 0x74, 0x65, - 0x41, 0x74, 0x22, 0x35, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x76, 0x69, 0x65, 0x73, - 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x22, 0x0a, 0x06, 0x6d, 0x6f, 0x76, 0x69, 0x65, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x6f, 0x76, 0x69, - 0x65, 0x52, 0x06, 0x6d, 0x6f, 0x76, 0x69, 0x65, 0x73, 0x22, 0xc6, 0x03, 0x0a, 0x05, 0x4d, 0x6f, - 0x76, 0x69, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6d, 0x6f, 0x76, 0x69, 0x65, 0x5f, 0x69, 0x64, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6d, 0x6f, 0x76, 0x69, 0x65, 0x49, 0x64, 0x12, 0x2e, - 0x0a, 0x04, 0x64, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x64, 0x61, 0x74, 0x65, 0x12, 0x34, - 0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x63, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x65, - 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x79, 0x65, 0x61, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0b, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x59, 0x65, 0x61, 0x72, 0x12, 0x18, 0x0a, - 0x07, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x67, 0x65, 0x6e, 0x72, 0x65, - 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x67, 0x65, 0x6e, 0x72, 0x65, 0x12, 0x1a, 0x0a, - 0x08, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x08, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, - 0x6f, 0x72, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x63, 0x74, 0x6f, 0x72, - 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6d, 0x64, 0x62, 0x5f, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, - 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6d, 0x64, 0x62, 0x52, 0x61, 0x74, 0x69, - 0x6e, 0x67, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x69, 0x64, - 0x18, 0x0e, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x49, 0x64, 0x12, - 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, - 0x69, 0x6e, 0x6b, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c, - 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x55, 0x72, 0x6c, - 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x4a, 0x04, 0x08, 0x0f, - 0x10, 0x10, 0x22, 0xcc, 0x02, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, - 0x64, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x42, 0x0a, 0x09, - 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x24, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x64, - 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x52, 0x65, 0x63, 0x69, - 0x70, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x09, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, - 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x66, 0x72, 0x6f, 0x6d, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, - 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2b, 0x0a, 0x08, 0x6c, 0x6f, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x61, 0x70, - 0x69, 0x2e, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x52, 0x08, 0x6c, 0x6f, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x6f, 0x73, 0x5f, 0x76, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x73, 0x56, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x70, 0x70, 0x5f, 0x76, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x70, 0x70, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, - 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x61, - 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x29, 0x0a, 0x09, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, - 0x65, 0x6e, 0x74, 0x12, 0x0b, 0x0a, 0x07, 0x54, 0x55, 0x4d, 0x5f, 0x44, 0x45, 0x56, 0x10, 0x00, - 0x12, 0x0f, 0x0a, 0x0b, 0x54, 0x55, 0x4d, 0x5f, 0x43, 0x4f, 0x4e, 0x54, 0x41, 0x43, 0x54, 0x10, - 0x01, 0x22, 0x46, 0x0a, 0x0a, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x12, - 0x1a, 0x0a, 0x08, 0x6c, 0x61, 0x74, 0x69, 0x74, 0x75, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x01, 0x52, 0x08, 0x6c, 0x61, 0x74, 0x69, 0x74, 0x75, 0x64, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6c, - 0x6f, 0x6e, 0x67, 0x69, 0x74, 0x75, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x09, - 0x6c, 0x6f, 0x6e, 0x67, 0x69, 0x74, 0x75, 0x64, 0x65, 0x22, 0x15, 0x0a, 0x13, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x70, 0x6c, 0x79, - 0x22, 0x32, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x64, 0x62, 0x61, - 0x63, 0x6b, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x16, 0x0a, 0x06, - 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x22, 0x47, 0x0a, 0x1a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x65, - 0x65, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, - 0x69, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x5f, 0x6e, 0x72, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x4e, 0x72, 0x22, 0x29, 0x0a, - 0x10, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x15, 0x0a, 0x06, 0x6c, 0x72, 0x7a, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x6c, 0x72, 0x7a, 0x49, 0x64, 0x22, 0x58, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x15, 0x0a, 0x06, 0x6c, 0x72, - 0x7a, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x72, 0x7a, 0x49, - 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x5f, - 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x49, 0x64, 0x22, 0x2f, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, - 0x6c, 0x72, 0x7a, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x72, - 0x7a, 0x49, 0x64, 0x22, 0xb3, 0x01, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x55, 0x70, 0x6c, 0x6f, 0x61, - 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1b, 0x0a, 0x09, - 0x66, 0x63, 0x6d, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x08, 0x66, 0x63, 0x6d, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, - 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, - 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x75, 0x64, - 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x74, - 0x75, 0x64, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x6d, 0x70, 0x6c, 0x6f, - 0x79, 0x65, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x65, 0x6d, - 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x65, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x78, 0x74, 0x65, - 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x65, - 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x49, 0x64, 0x22, 0x41, 0x0a, 0x16, 0x47, 0x65, 0x74, - 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x6e, 0x6f, - 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0xa9, 0x01, 0x0a, - 0x14, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x27, 0x0a, 0x0f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x64, 0x61, 0x74, 0x65, 0x12, 0x34, 0x0a, 0x07, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, + 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, + 0x65, 0x5f, 0x79, 0x65, 0x61, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x72, 0x65, + 0x6c, 0x65, 0x61, 0x73, 0x65, 0x59, 0x65, 0x61, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x75, 0x6e, + 0x74, 0x69, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x75, 0x6e, 0x74, + 0x69, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x67, 0x65, 0x6e, 0x72, 0x65, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x67, 0x65, 0x6e, 0x72, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x69, 0x72, + 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x69, 0x72, + 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x18, + 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x1f, 0x0a, + 0x0b, 0x69, 0x6d, 0x64, 0x62, 0x5f, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x0c, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6d, 0x64, 0x62, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x20, + 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0d, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x19, 0x0a, 0x08, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x0e, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x07, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6c, + 0x69, 0x6e, 0x6b, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x12, + 0x1b, 0x0a, 0x09, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x11, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x55, 0x72, 0x6c, 0x4a, 0x04, 0x08, 0x01, + 0x10, 0x02, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x4a, 0x04, 0x08, 0x0f, 0x10, 0x10, 0x22, 0xcc, + 0x02, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x64, 0x62, 0x61, 0x63, + 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x42, 0x0a, 0x09, 0x72, 0x65, 0x63, 0x69, + 0x70, 0x69, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x24, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x64, 0x62, 0x61, 0x63, 0x6b, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, + 0x74, 0x52, 0x09, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x1d, 0x0a, 0x0a, + 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x66, 0x72, 0x6f, 0x6d, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2b, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f, + 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x6f, 0x73, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x70, 0x70, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x70, 0x70, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, + 0x6e, 0x74, 0x22, 0x29, 0x0a, 0x09, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x12, + 0x0b, 0x0a, 0x07, 0x54, 0x55, 0x4d, 0x5f, 0x44, 0x45, 0x56, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, + 0x54, 0x55, 0x4d, 0x5f, 0x43, 0x4f, 0x4e, 0x54, 0x41, 0x43, 0x54, 0x10, 0x01, 0x22, 0x46, 0x0a, + 0x0a, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6c, + 0x61, 0x74, 0x69, 0x74, 0x75, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x08, 0x6c, + 0x61, 0x74, 0x69, 0x74, 0x75, 0x64, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6c, 0x6f, 0x6e, 0x67, 0x69, + 0x74, 0x75, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x09, 0x6c, 0x6f, 0x6e, 0x67, + 0x69, 0x74, 0x75, 0x64, 0x65, 0x22, 0x15, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, + 0x65, 0x65, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x32, 0x0a, 0x18, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x49, 0x6d, + 0x61, 0x67, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x22, 0x47, 0x0a, 0x1a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x64, 0x62, 0x61, + 0x63, 0x6b, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, + 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x19, + 0x0a, 0x08, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x5f, 0x6e, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x07, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x4e, 0x72, 0x22, 0x29, 0x0a, 0x10, 0x47, 0x65, 0x74, + 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, + 0x06, 0x6c, 0x72, 0x7a, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, + 0x72, 0x7a, 0x49, 0x64, 0x22, 0x58, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, + 0x72, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x15, 0x0a, 0x06, 0x6c, 0x72, 0x7a, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x72, 0x7a, 0x49, 0x64, 0x12, 0x12, 0x0a, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x49, 0x64, 0x22, 0x2f, + 0x0a, 0x16, 0x47, 0x65, 0x74, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x6c, 0x72, 0x7a, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x72, 0x7a, 0x49, 0x64, 0x22, + 0xb3, 0x01, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x63, 0x6d, 0x5f, + 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x63, 0x6d, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, + 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x5f, + 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x74, 0x75, 0x64, 0x65, 0x6e, + 0x74, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x6d, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x65, 0x5f, + 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x65, 0x6d, 0x70, 0x6c, 0x6f, 0x79, + 0x65, 0x65, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x49, 0x64, 0x22, 0x41, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x27, 0x0a, 0x0f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0xa9, 0x01, 0x0a, 0x14, 0x47, 0x65, 0x74, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, + 0x79, 0x12, 0x27, 0x0a, 0x0f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x6e, 0x6f, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, + 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, + 0x69, 0x74, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x74, 0x75, 0x72, 0x65, 0x22, 0x48, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, - 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x12, - 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x74, 0x79, - 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, - 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, - 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x48, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x4e, - 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x72, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x6e, 0x6f, 0x74, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x05, 0x52, 0x0e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x49, 0x64, 0x22, 0x35, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x52, 0x65, 0x70, 0x6c, - 0x79, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x3b, 0x0a, 0x1a, 0x47, 0x65, 0x74, - 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x48, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x61, 0x6e, 0x74, 0x65, - 0x65, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x61, 0x6e, - 0x74, 0x65, 0x65, 0x6e, 0x49, 0x64, 0x22, 0xa1, 0x01, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x43, 0x61, - 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x48, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, - 0x70, 0x6c, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x78, - 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x6d, 0x61, - 0x78, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, - 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x02, 0x52, 0x07, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, - 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, - 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2a, 0x2f, 0x0a, 0x0a, 0x44, 0x65, - 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x07, 0x0a, 0x03, 0x49, 0x4f, 0x53, 0x10, - 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x41, 0x4e, 0x44, 0x52, 0x4f, 0x49, 0x44, 0x10, 0x01, 0x12, 0x0b, - 0x0a, 0x07, 0x57, 0x49, 0x4e, 0x44, 0x4f, 0x57, 0x53, 0x10, 0x02, 0x32, 0xe6, 0x16, 0x0a, 0x06, - 0x43, 0x61, 0x6d, 0x70, 0x75, 0x73, 0x12, 0x64, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x65, - 0x77, 0x73, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x73, 0x12, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, - 0x69, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, - 0x65, 0x77, 0x73, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1c, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x62, 0x06, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x73, 0x12, 0x0c, - 0x2f, 0x6e, 0x65, 0x77, 0x73, 0x2f, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x73, 0x12, 0x69, 0x0a, 0x0f, - 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, - 0x1b, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x53, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x61, - 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x53, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x62, - 0x07, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x0d, 0x2f, 0x6e, 0x65, 0x77, 0x73, 0x2f, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x49, 0x0a, 0x08, 0x4c, 0x69, 0x73, 0x74, 0x4e, - 0x65, 0x77, 0x73, 0x12, 0x14, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x65, - 0x77, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x61, 0x70, 0x69, 0x2e, - 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x13, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x0d, 0x62, 0x04, 0x6e, 0x65, 0x77, 0x73, 0x12, 0x05, 0x2f, 0x6e, 0x65, - 0x77, 0x73, 0x12, 0x72, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, - 0x6e, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x1e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, - 0x69, 0x73, 0x74, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, - 0x69, 0x73, 0x74, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, - 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x3a, 0x01, - 0x2a, 0x22, 0x13, 0x2f, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x2f, 0x72, 0x61, 0x74, 0x69, - 0x6e, 0x67, 0x2f, 0x67, 0x65, 0x74, 0x12, 0x63, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x44, 0x69, 0x73, - 0x68, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, - 0x65, 0x74, 0x44, 0x69, 0x73, 0x68, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x69, - 0x73, 0x68, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1b, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x3a, 0x01, 0x2a, 0x22, 0x10, 0x2f, 0x64, 0x69, 0x73, 0x68, - 0x2f, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x67, 0x65, 0x74, 0x12, 0x75, 0x0a, 0x13, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x52, 0x61, 0x74, 0x69, - 0x6e, 0x67, 0x12, 0x1f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, - 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x70, + 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x35, + 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x16, 0x0a, + 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x3b, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x43, 0x61, 0x6e, 0x74, + 0x65, 0x65, 0x6e, 0x48, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, + 0x49, 0x64, 0x22, 0xa1, 0x01, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, + 0x6e, 0x48, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, + 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x43, 0x6f, 0x75, + 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x02, 0x52, 0x07, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x12, 0x38, 0x0a, 0x09, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2a, 0x2f, 0x0a, 0x0a, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x07, 0x0a, 0x03, 0x49, 0x4f, 0x53, 0x10, 0x00, 0x12, 0x0b, 0x0a, + 0x07, 0x41, 0x4e, 0x44, 0x52, 0x4f, 0x49, 0x44, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x57, 0x49, + 0x4e, 0x44, 0x4f, 0x57, 0x53, 0x10, 0x02, 0x32, 0xe6, 0x16, 0x0a, 0x06, 0x43, 0x61, 0x6d, 0x70, + 0x75, 0x73, 0x12, 0x64, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x41, 0x6c, + 0x65, 0x72, 0x74, 0x73, 0x12, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, + 0x65, 0x77, 0x73, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x41, + 0x6c, 0x65, 0x72, 0x74, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x16, 0x62, 0x06, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x73, 0x12, 0x0c, 0x2f, 0x6e, 0x65, 0x77, + 0x73, 0x2f, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x73, 0x12, 0x69, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, + 0x4e, 0x65, 0x77, 0x73, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x1b, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, + 0x70, 0x6c, 0x79, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x62, 0x07, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x73, 0x12, 0x0d, 0x2f, 0x6e, 0x65, 0x77, 0x73, 0x2f, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x73, 0x12, 0x49, 0x0a, 0x08, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x12, + 0x14, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, + 0x4e, 0x65, 0x77, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x13, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x0d, 0x62, 0x04, 0x6e, 0x65, 0x77, 0x73, 0x12, 0x05, 0x2f, 0x6e, 0x65, 0x77, 0x73, 0x12, 0x72, + 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x52, 0x61, 0x74, + 0x69, 0x6e, 0x67, 0x73, 0x12, 0x1e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, + 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, + 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x3a, 0x01, 0x2a, 0x22, 0x13, 0x2f, - 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x2f, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x6e, - 0x65, 0x77, 0x12, 0x69, 0x0a, 0x10, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x69, 0x73, 0x68, - 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x44, 0x69, 0x73, 0x68, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x44, 0x69, 0x73, 0x68, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x70, 0x6c, 0x79, - 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x3a, 0x01, 0x2a, 0x22, 0x10, 0x2f, 0x64, 0x69, - 0x73, 0x68, 0x2f, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x6e, 0x65, 0x77, 0x12, 0x8c, 0x01, - 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x44, - 0x69, 0x73, 0x68, 0x54, 0x61, 0x67, 0x73, 0x12, 0x21, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, + 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x2f, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x67, + 0x65, 0x74, 0x12, 0x63, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x44, 0x69, 0x73, 0x68, 0x52, 0x61, 0x74, + 0x69, 0x6e, 0x67, 0x73, 0x12, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x69, + 0x73, 0x68, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x69, 0x73, 0x68, 0x52, 0x61, + 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x15, 0x3a, 0x01, 0x2a, 0x22, 0x10, 0x2f, 0x64, 0x69, 0x73, 0x68, 0x2f, 0x72, 0x61, 0x74, + 0x69, 0x6e, 0x67, 0x2f, 0x67, 0x65, 0x74, 0x12, 0x75, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x1f, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x61, 0x6e, 0x74, 0x65, + 0x65, 0x6e, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x1d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x61, 0x6e, 0x74, + 0x65, 0x65, 0x6e, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1e, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x3a, 0x01, 0x2a, 0x22, 0x13, 0x2f, 0x63, 0x61, 0x6e, 0x74, + 0x65, 0x65, 0x6e, 0x2f, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x6e, 0x65, 0x77, 0x12, 0x69, + 0x0a, 0x10, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x69, 0x73, 0x68, 0x52, 0x61, 0x74, 0x69, + 0x6e, 0x67, 0x12, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, + 0x69, 0x73, 0x68, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x69, 0x73, + 0x68, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1b, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x15, 0x3a, 0x01, 0x2a, 0x22, 0x10, 0x2f, 0x64, 0x69, 0x73, 0x68, 0x2f, 0x72, + 0x61, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x6e, 0x65, 0x77, 0x12, 0x8c, 0x01, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x44, 0x69, 0x73, 0x68, 0x54, - 0x61, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x61, 0x70, 0x69, - 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x44, 0x69, - 0x73, 0x68, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x2f, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x29, 0x62, 0x0b, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x67, 0x73, - 0x12, 0x1a, 0x2f, 0x64, 0x69, 0x73, 0x68, 0x2f, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x61, - 0x6c, 0x6c, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x73, 0x12, 0x6f, 0x0a, 0x0c, - 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x54, 0x61, 0x67, 0x73, 0x12, 0x18, 0x2e, 0x61, - 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x54, 0x61, 0x67, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x2d, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x27, 0x62, 0x0b, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x74, - 0x61, 0x67, 0x73, 0x12, 0x18, 0x2f, 0x64, 0x69, 0x73, 0x68, 0x2f, 0x72, 0x61, 0x74, 0x69, 0x6e, - 0x67, 0x2f, 0x61, 0x6c, 0x6c, 0x44, 0x69, 0x73, 0x68, 0x54, 0x61, 0x67, 0x73, 0x12, 0x98, 0x01, - 0x0a, 0x18, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x43, - 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x54, 0x61, 0x67, 0x73, 0x12, 0x24, 0x2e, 0x61, 0x70, 0x69, - 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, - 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x22, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, - 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x54, 0x61, 0x67, 0x73, 0x52, - 0x65, 0x70, 0x6c, 0x79, 0x22, 0x32, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2c, 0x62, 0x0b, 0x72, 0x61, - 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x12, 0x1d, 0x2f, 0x63, 0x61, 0x6e, 0x74, - 0x65, 0x65, 0x6e, 0x2f, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x61, 0x6c, 0x6c, 0x52, 0x61, - 0x74, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x73, 0x12, 0x67, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, - 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x73, 0x12, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, - 0x69, 0x73, 0x74, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x61, 0x6e, - 0x74, 0x65, 0x65, 0x6e, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x1f, 0x62, 0x07, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x12, 0x14, 0x2f, 0x63, 0x61, - 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x2f, 0x61, 0x6c, 0x6c, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, - 0x73, 0x12, 0x59, 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x69, 0x73, 0x68, 0x65, 0x73, 0x12, - 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x69, 0x73, 0x68, 0x65, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, - 0x73, 0x74, 0x44, 0x69, 0x73, 0x68, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1d, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x62, 0x04, 0x64, 0x69, 0x73, 0x68, 0x12, 0x0f, 0x2f, 0x64, 0x69, - 0x73, 0x68, 0x2f, 0x61, 0x6c, 0x6c, 0x44, 0x69, 0x73, 0x68, 0x65, 0x73, 0x12, 0x7a, 0x0a, 0x15, - 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x50, - 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x12, 0x21, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, + 0x61, 0x67, 0x73, 0x12, 0x21, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x76, + 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x44, 0x69, 0x73, 0x68, 0x54, 0x61, 0x67, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, + 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x44, 0x69, 0x73, 0x68, 0x54, 0x61, + 0x67, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x2f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x29, 0x62, + 0x0b, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x12, 0x1a, 0x2f, 0x64, + 0x69, 0x73, 0x68, 0x2f, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x61, 0x6c, 0x6c, 0x52, 0x61, + 0x74, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x73, 0x12, 0x6f, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, + 0x4e, 0x61, 0x6d, 0x65, 0x54, 0x61, 0x67, 0x73, 0x12, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x61, 0x6d, + 0x65, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x2d, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x27, 0x62, 0x0b, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x12, + 0x18, 0x2f, 0x64, 0x69, 0x73, 0x68, 0x2f, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x61, 0x6c, + 0x6c, 0x44, 0x69, 0x73, 0x68, 0x54, 0x61, 0x67, 0x73, 0x12, 0x98, 0x01, 0x0a, 0x18, 0x4c, 0x69, + 0x73, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x6e, 0x74, 0x65, + 0x65, 0x6e, 0x54, 0x61, 0x67, 0x73, 0x12, 0x24, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, + 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, + 0x6e, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, + 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, + 0x22, 0x32, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2c, 0x62, 0x0b, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, + 0x5f, 0x74, 0x61, 0x67, 0x73, 0x12, 0x1d, 0x2f, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x2f, + 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x61, 0x6c, 0x6c, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, + 0x54, 0x61, 0x67, 0x73, 0x12, 0x67, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x61, 0x6e, 0x74, + 0x65, 0x65, 0x6e, 0x73, 0x12, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, + 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, + 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x62, 0x07, + 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x12, 0x14, 0x2f, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, + 0x6e, 0x2f, 0x61, 0x6c, 0x6c, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x73, 0x12, 0x59, 0x0a, + 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x69, 0x73, 0x68, 0x65, 0x73, 0x12, 0x16, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x69, 0x73, 0x68, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x69, + 0x73, 0x68, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x17, 0x62, 0x04, 0x64, 0x69, 0x73, 0x68, 0x12, 0x0f, 0x2f, 0x64, 0x69, 0x73, 0x68, 0x2f, 0x61, + 0x6c, 0x6c, 0x44, 0x69, 0x73, 0x68, 0x65, 0x73, 0x12, 0x7a, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x50, 0x65, 0x72, 0x73, 0x6f, - 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, - 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x50, 0x65, - 0x72, 0x73, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x17, 0x12, 0x15, 0x2f, 0x62, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x66, 0x72, 0x65, 0x65, 0x2f, - 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x73, 0x12, 0x7b, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, - 0x4d, 0x6f, 0x72, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x1f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x72, 0x65, 0x49, 0x6e, - 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x1d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x72, 0x65, 0x49, - 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, - 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x12, 0x1c, 0x2f, 0x62, 0x61, 0x72, 0x72, 0x69, 0x65, - 0x72, 0x66, 0x72, 0x65, 0x65, 0x2f, 0x6d, 0x6f, 0x72, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x6e, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x70, 0x65, - 0x6e, 0x69, 0x6e, 0x67, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x12, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e, - 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x70, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x54, 0x69, 0x6d, 0x65, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, - 0x73, 0x74, 0x4f, 0x70, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x52, 0x65, - 0x70, 0x6c, 0x79, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x12, 0x18, 0x2f, 0x6f, 0x70, - 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x2f, 0x7b, 0x6c, 0x61, 0x6e, 0x67, - 0x75, 0x61, 0x67, 0x65, 0x7d, 0x12, 0x62, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x4e, 0x6f, 0x74, 0x65, 0x12, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x17, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x4e, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x17, 0x12, 0x15, 0x2f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x6e, 0x6f, 0x74, 0x65, 0x2f, - 0x7b, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x7d, 0x12, 0x55, 0x0a, 0x0a, 0x4c, 0x69, 0x73, - 0x74, 0x4d, 0x6f, 0x76, 0x69, 0x65, 0x73, 0x12, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, - 0x73, 0x74, 0x4d, 0x6f, 0x76, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x14, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x76, 0x69, 0x65, 0x73, - 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x12, 0x11, 0x2f, - 0x6d, 0x6f, 0x76, 0x69, 0x65, 0x73, 0x2f, 0x7b, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x7d, - 0x12, 0x67, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x64, 0x62, 0x61, - 0x63, 0x6b, 0x12, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, - 0x65, 0x65, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, + 0x6e, 0x12, 0x21, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, + 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, 0x2f, + 0x62, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x66, 0x72, 0x65, 0x65, 0x2f, 0x63, 0x6f, 0x6e, 0x74, + 0x61, 0x63, 0x74, 0x73, 0x12, 0x7b, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x72, 0x65, + 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x72, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x72, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x72, + 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x24, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x1e, 0x12, 0x1c, 0x2f, 0x62, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x66, 0x72, 0x65, + 0x65, 0x2f, 0x6d, 0x6f, 0x72, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x6e, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x70, 0x65, 0x6e, 0x69, 0x6e, 0x67, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x12, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, + 0x4f, 0x70, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x70, + 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, + 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x12, 0x18, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6e, + 0x67, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x2f, 0x7b, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, + 0x7d, 0x12, 0x62, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4e, 0x6f, + 0x74, 0x65, 0x12, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x4e, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, + 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x74, + 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, + 0x2f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x6e, 0x6f, 0x74, 0x65, 0x2f, 0x7b, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x7d, 0x12, 0x55, 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x76, + 0x69, 0x65, 0x73, 0x12, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, + 0x76, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x6f, 0x76, 0x69, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, + 0x79, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x12, 0x11, 0x2f, 0x6d, 0x6f, 0x76, 0x69, + 0x65, 0x73, 0x2f, 0x7b, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x67, 0x0a, 0x0e, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x64, 0x62, - 0x61, 0x63, 0x6b, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, - 0x3a, 0x0a, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x09, 0x2f, 0x66, - 0x65, 0x65, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x28, 0x01, 0x12, 0x6c, 0x0a, 0x0f, 0x47, 0x65, 0x74, - 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1b, 0x2e, 0x61, - 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, - 0x47, 0x65, 0x74, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, - 0x65, 0x70, 0x6c, 0x79, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x12, 0x19, 0x2f, 0x64, - 0x65, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x2f, 0x7b, - 0x6c, 0x72, 0x7a, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x73, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x4e, 0x6f, - 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x2e, 0x61, 0x70, 0x69, - 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, - 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, - 0x6c, 0x79, 0x22, 0x28, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x22, 0x12, 0x20, 0x2f, 0x6e, 0x6f, 0x74, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x7b, 0x6e, 0x6f, 0x74, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x90, 0x01, 0x0a, - 0x16, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x12, 0x22, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, + 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x61, 0x70, 0x69, + 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x52, + 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x3a, 0x0a, 0x61, 0x74, + 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x09, 0x2f, 0x66, 0x65, 0x65, 0x64, 0x62, + 0x61, 0x63, 0x6b, 0x28, 0x01, 0x12, 0x6c, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x55, 0x70, 0x6c, 0x6f, + 0x61, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1b, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, + 0x65, 0x74, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x55, + 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, + 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x12, 0x19, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x2f, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x2f, 0x7b, 0x6c, 0x72, 0x7a, 0x5f, + 0x69, 0x64, 0x7d, 0x12, 0x73, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x28, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x22, 0x12, 0x20, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x7b, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x90, 0x01, 0x0a, 0x16, 0x47, 0x65, 0x74, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x72, 0x6d, 0x12, 0x22, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x72, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x61, 0x70, - 0x69, 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x30, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x2a, 0x12, 0x28, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x2f, 0x7b, 0x6e, - 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x7d, 0x12, - 0x52, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x15, 0x2e, 0x61, - 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, - 0x62, 0x65, 0x72, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, - 0x12, 0x11, 0x2f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x6c, 0x72, 0x7a, 0x5f, - 0x69, 0x64, 0x7d, 0x12, 0x7e, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, - 0x6e, 0x48, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1f, 0x2e, 0x61, 0x70, 0x69, - 0x2e, 0x47, 0x65, 0x74, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x48, 0x65, 0x61, 0x64, 0x43, - 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x61, 0x70, - 0x69, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x48, 0x65, 0x61, 0x64, - 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x27, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x21, 0x12, 0x1f, 0x2f, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x2f, 0x68, 0x65, 0x61, - 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x2f, 0x7b, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x5f, - 0x69, 0x64, 0x7d, 0x12, 0x99, 0x01, 0x0a, 0x18, 0x49, 0x4f, 0x53, 0x44, 0x65, 0x76, 0x69, 0x63, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x24, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x49, 0x4f, 0x53, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x49, 0x4f, 0x53, - 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x33, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x2d, 0x3a, 0x01, 0x2a, 0x22, 0x28, 0x2f, 0x69, 0x6f, 0x73, 0x2f, 0x6e, 0x6f, 0x74, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x54, 0x0a, 0x0c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, - 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, - 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x70, 0x6c, - 0x79, 0x22, 0x12, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0c, 0x3a, 0x01, 0x2a, 0x22, 0x07, 0x2f, 0x64, - 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5d, 0x0a, 0x0c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x44, - 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, - 0x63, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x2a, - 0x13, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x7b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, - 0x5f, 0x69, 0x64, 0x7d, 0x42, 0x5e, 0x0a, 0x12, 0x61, 0x70, 0x70, 0x2e, 0x74, 0x75, 0x6d, 0x2e, - 0x63, 0x61, 0x6d, 0x70, 0x75, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x42, 0x0e, 0x43, 0x61, 0x6d, 0x70, - 0x75, 0x73, 0x41, 0x70, 0x69, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x25, 0x67, 0x69, - 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x54, 0x55, 0x4d, 0x2d, 0x44, 0x65, 0x76, - 0x2f, 0x43, 0x61, 0x6d, 0x70, 0x75, 0x73, 0x2d, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x2f, - 0x61, 0x70, 0x69, 0xaa, 0x02, 0x0e, 0x43, 0x61, 0x6d, 0x70, 0x75, 0x73, 0x41, 0x70, 0x69, 0x50, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x66, 0x69, 0x72, 0x6d, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x30, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x2a, 0x12, 0x28, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x2f, 0x7b, 0x6e, 0x6f, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x52, 0x0a, 0x09, 0x47, + 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x15, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, + 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x13, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, + 0x65, 0x70, 0x6c, 0x79, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x12, 0x11, 0x2f, 0x6d, + 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x6c, 0x72, 0x7a, 0x5f, 0x69, 0x64, 0x7d, 0x12, + 0x7e, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x48, 0x65, 0x61, + 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, + 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x48, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, + 0x74, 0x43, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x48, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, + 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x27, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x21, 0x12, 0x1f, + 0x2f, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, + 0x6e, 0x74, 0x2f, 0x7b, 0x63, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x6e, 0x5f, 0x69, 0x64, 0x7d, 0x12, + 0x99, 0x01, 0x0a, 0x18, 0x49, 0x4f, 0x53, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x24, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x49, 0x4f, 0x53, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x49, 0x4f, 0x53, 0x44, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x33, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2d, 0x3a, 0x01, + 0x2a, 0x22, 0x28, 0x2f, 0x69, 0x6f, 0x73, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x0c, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x18, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x12, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x0c, 0x3a, 0x01, 0x2a, 0x22, 0x07, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x12, 0x5d, 0x0a, 0x0c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x12, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, + 0x70, 0x6c, 0x79, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x2a, 0x13, 0x2f, 0x64, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x2f, 0x7b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, + 0x42, 0x5e, 0x0a, 0x12, 0x61, 0x70, 0x70, 0x2e, 0x74, 0x75, 0x6d, 0x2e, 0x63, 0x61, 0x6d, 0x70, + 0x75, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x42, 0x0e, 0x43, 0x61, 0x6d, 0x70, 0x75, 0x73, 0x41, 0x70, + 0x69, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x54, 0x55, 0x4d, 0x2d, 0x44, 0x65, 0x76, 0x2f, 0x43, 0x61, 0x6d, + 0x70, 0x75, 0x73, 0x2d, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x2f, 0x61, 0x70, 0x69, 0xaa, + 0x02, 0x0e, 0x43, 0x61, 0x6d, 0x70, 0x75, 0x73, 0x41, 0x70, 0x69, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -6028,7 +6027,6 @@ func file_tumdev_campus_backend_proto_init() { } } } - file_tumdev_campus_backend_proto_msgTypes[0].OneofWrappers = []interface{}{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ diff --git a/server/api/tumdev/campus_backend.proto b/server/api/tumdev/campus_backend.proto index 5964d632..56452d89 100644 --- a/server/api/tumdev/campus_backend.proto +++ b/server/api/tumdev/campus_backend.proto @@ -174,7 +174,7 @@ enum DeviceType { message CreateDeviceRequest { string device_id = 1; - optional string public_key = 2; + string public_key = 2; DeviceType device_type = 3; } diff --git a/server/backend/cafeteria.go b/server/backend/cafeteria.go index 6f3e57c7..947873ab 100644 --- a/server/backend/cafeteria.go +++ b/server/backend/cafeteria.go @@ -301,7 +301,7 @@ func queryTags(cafeteriaID int32, dishID int32, ratingType ModelType, tx *gorm.D } if err != nil { - log.WithError(err).Error("while querying the tags for the request.") + log.WithError(err).Error("while querying the tags for the request") } //needed since the gRPC element does not specify column names - cannot be directly queried into the grpc message object. @@ -672,25 +672,25 @@ func (s *CampusServer) GetCafeterias(ctx context.Context, _ *pb.ListCanteensRequ }, requestStatus } -func (s *CampusServer) ListDishes(ctx context.Context, request *pb.ListDishesRequest) (*pb.ListDishesReply, error) { - if request.Year < 2022 { +func (s *CampusServer) ListDishes(ctx context.Context, req *pb.ListDishesRequest) (*pb.ListDishesReply, error) { + if req.Year < 2022 { return &pb.ListDishesReply{}, status.Error(codes.Internal, "Years must be larger or equal to 2022 ") // currently, no previous values have been added } - if request.Week < 1 || request.Week > 53 { + if req.Week < 1 || req.Week > 53 { return &pb.ListDishesReply{}, status.Error(codes.Internal, "Weeks must be in the range 1 - 53") } - if request.Day < 0 || request.Day > 4 { + if req.Day < 0 || req.Day > 4 { return &pb.ListDishesReply{}, status.Error(codes.Internal, "Days must be in the range 1 (Monday) - 4 (Friday)") } var requestStatus error = nil var results []string err := s.db.WithContext(ctx).Table("dishes_of_the_week weekly"). - Where("weekly.day = ? AND weekly.week = ? and weekly.year = ?", request.Day, request.Week, request.Year). + Where("weekly.day = ? AND weekly.week = ? and weekly.year = ?", req.Day, req.Week, req.Year). Select("weekly.dishID"). Joins("JOIN dish d ON d.dish = weekly.dishID"). Joins("JOIN cafeteria c ON c.cafeteria = d.cafeteriaID"). - Where("c.name LIKE ?", request.CanteenId). + Where("c.name LIKE ?", req.CanteenId). Select("d.name"). Find(&results).Error diff --git a/server/backend/campus_api/campus_api.go b/server/backend/campus_api/campus_api.go index 746455e4..003cc646 100644 --- a/server/backend/campus_api/campus_api.go +++ b/server/backend/campus_api/campus_api.go @@ -7,13 +7,16 @@ import ( "fmt" "io" "net/http" + "os" "github.com/TUM-Dev/Campus-Backend/server/model" log "github.com/sirupsen/logrus" ) -func FetchExamResultsPublished(token string) (*model.TUMAPIPublishedExamResults, error) { +// FetchExamResultsPublished fetches all published exam results from the TUM Campus API using CAMPUS_API_TOKEN. +func FetchExamResultsPublished() (*model.TUMAPIPublishedExamResults, error) { var examResultsPublished model.TUMAPIPublishedExamResults + token := os.Getenv("CAMPUS_API_TOKEN") err := RequestCampusApi("/wbservicesbasic.pruefungenErgebnisse", token, &examResultsPublished) if err != nil { return nil, err diff --git a/server/backend/device.go b/server/backend/device.go index 9e2ff94b..d899f159 100644 --- a/server/backend/device.go +++ b/server/backend/device.go @@ -128,7 +128,7 @@ func (s *CampusServer) CreateDevice(_ context.Context, req *pb.CreateDeviceReque return nil, status.Error(codes.InvalidArgument, err.Error()) } - switch req.GetDeviceType() { + switch req.DeviceType { case pb.DeviceType_ANDROID: return nil, status.Error(codes.Unimplemented, "android device creation not implemented") case pb.DeviceType_IOS: @@ -146,7 +146,7 @@ func (s *CampusServer) DeleteDevice(_ context.Context, req *pb.DeleteDeviceReque return nil, status.Error(codes.InvalidArgument, err.Error()) } - switch req.GetDeviceType() { + switch req.DeviceType { case pb.DeviceType_ANDROID: return nil, status.Error(codes.Unimplemented, "android device remove not implemented") case pb.DeviceType_IOS: diff --git a/server/backend/ios_notifications/apns/jwt_token.go b/server/backend/ios_notifications/apns/jwt_token.go index 45d0dfc0..7e4df0c5 100644 --- a/server/backend/ios_notifications/apns/jwt_token.go +++ b/server/backend/ios_notifications/apns/jwt_token.go @@ -15,20 +15,6 @@ import ( log "github.com/sirupsen/logrus" ) -const ( - // TokenTimeout for the token in seconds - TokenTimeout = 3000 -) - -var ( - ErrorAuthKeyNotPem = errors.New("failed to parse token: AuthKey must be a valid .p8 PEM file") - ErrorAuthKeyNotEcdsa = errors.New("failed to parse token: AuthKey must be of type ecdsa.PrivateKey") - ErrorAuthKeyNil = errors.New("failed to parse token: AuthKey was nil") - ApnsKeyId = os.Getenv("APNS_KEY_ID") - ApnsTeamId = os.Getenv("APNS_TEAM_ID") - ApnsP8FilePath = os.Getenv("APNS_P8_FILE_PATH") -) - type JWTToken struct { sync.Mutex EncryptionKey *ecdsa.PrivateKey @@ -39,15 +25,15 @@ type JWTToken struct { } func NewToken() (*JWTToken, error) { - encryptionKey, err := APNsEncryptionKeyFromFile() + encryptionKey, err := EncryptionKeyFromFile() if err != nil { return nil, err } token := JWTToken{ EncryptionKey: encryptionKey, - KeyId: ApnsKeyId, - TeamId: ApnsTeamId, + KeyId: os.Getenv("APNS_KEY_ID"), + TeamId: os.Getenv("APNS_TEAM_ID"), } if err = token.Generate(); err != nil { @@ -57,11 +43,11 @@ func NewToken() (*JWTToken, error) { return &token, nil } -// APNsEncryptionKeyFromFile reads the APNs encryption key from the file system +// EncryptionKeyFromFile reads the APNs encryption key from the file system // and returns it as an ecdsa.PrivateKey // The file location is defined by the APNS_P8_FILE_PATH environment variable -func APNsEncryptionKeyFromFile() (*ecdsa.PrivateKey, error) { - path, err := filepath.Abs(ApnsP8FilePath) +func EncryptionKeyFromFile() (*ecdsa.PrivateKey, error) { + path, err := filepath.Abs(os.Getenv("APNS_P8_FILE_PATH")) if err != nil { log.Error("No valid path to AuthKey") @@ -81,7 +67,7 @@ func APNsEncryptionKeyFromFile() (*ecdsa.PrivateKey, error) { if block == nil { log.Error("Could not decode APNs encryption key from file") - return nil, ErrorAuthKeyNotPem + return nil, errors.New("failed to parse token: AuthKey must be a valid .p8 PEM file") } key, err := x509.ParsePKCS8PrivateKey(block.Bytes) @@ -96,7 +82,7 @@ func APNsEncryptionKeyFromFile() (*ecdsa.PrivateKey, error) { return ecdsaKey, nil } - return nil, ErrorAuthKeyNotEcdsa + return nil, errors.New("failed to parse token: AuthKey must be of type ecdsa.PrivateKey") } func (t *JWTToken) GenerateNewTokenIfExpired() (bearer string) { @@ -114,12 +100,12 @@ func (t *JWTToken) GenerateNewTokenIfExpired() (bearer string) { } func (t *JWTToken) IsExpired() bool { - return currentTimestamp() >= (t.IssuedAt + TokenTimeout) + return currentTimestamp() >= (t.IssuedAt + 3000) } func (t *JWTToken) Generate() error { if t.EncryptionKey == nil { - return ErrorAuthKeyNil + return errors.New("failed to parse token: AuthKey was nil") } issuedAt := currentTimestamp() diff --git a/server/backend/ios_notifications/apns/repository.go b/server/backend/ios_notifications/apns/repository.go index 41d905d6..c3eb29f5 100644 --- a/server/backend/ios_notifications/apns/repository.go +++ b/server/backend/ios_notifications/apns/repository.go @@ -16,25 +16,6 @@ import ( "gorm.io/gorm" ) -const ( - // BundleId from the Apple Developer Portal - BundleId = "de.tum.tca" - // ReadIdleTimeout is the idle time after which the http2 transport will do a health check - ReadIdleTimeout = 15 * time.Second - // HTTPClientTimeout is the timeout for the http client used to send notifications - HTTPClientTimeout = 60 * time.Second -) - -const ( - ApnsDevelopmentURL = "https://api.sandbox.push.apple.com:443" - ApnsProductionURL = "https://api.push.apple.com:443" -) - -var ( - ErrCouldNotSendNotification = errors.New("could not send notification") - ErrCouldNotDecodeAPNsResponse = errors.New("could not decode apns response") -) - type Repository struct { DB gorm.DB Token *JWTToken @@ -43,11 +24,11 @@ type Repository struct { // ApnsUrl uses the environment variable ENVIRONMENT to determine whether // to use the production or development APNs URL. -func (r *Repository) ApnsUrl() string { +func (r *Repository) ApnsUrl(DeviceId string) string { if env.IsProd() { - return ApnsProductionURL + return "https://api.push.apple.com:443/3/device/" + DeviceId } - return ApnsDevelopmentURL + return "https://api.sandbox.push.apple.com:443/3/device/" + DeviceId } // CreateCampusTokenRequest creates a request log in the database that can be referred to @@ -72,26 +53,16 @@ func (r *Repository) CreateRequest(deviceId string, requestType model.IOSBackgro return &request, nil } -func (r *Repository) SendAlertNotification(payload *model.IOSNotificationPayload) (*model.IOSRemoteNotificationResponse, error) { - return r.SendNotification(payload, model.IOSAPNSPushTypeAlert, 10) -} - -func (r *Repository) SendBackgroundNotification(payload *model.IOSNotificationPayload) (*model.IOSRemoteNotificationResponse, error) { - return r.SendNotification(payload, model.IOSAPNSPushTypeBackground, 10) -} - -func (r *Repository) SendNotification(notification *model.IOSNotificationPayload, apnsPushType model.IOSAPNSPushType, priority int) (*model.IOSRemoteNotificationResponse, error) { - - url := r.ApnsUrl() + "/3/device/" + notification.DeviceId +func (r *Repository) SendNotification(notification *model.IOSNotificationPayload, apnsPushType model.IOSAPNSPushType) (*model.IOSRemoteNotificationResponse, error) { body, _ := notification.MarshalJSON() - req, _ := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(body)) + req, _ := http.NewRequest(http.MethodPost, r.ApnsUrl(notification.DeviceId), bytes.NewBuffer(body)) // can be e.g. alert or background req.Header.Set("apns-push-type", apnsPushType.String()) - req.Header.Set("apns-topic", BundleId) + req.Header.Set("apns-topic", "de.tum.tca") // can be a value between 1 and 10 - req.Header.Set("apns-priority", strconv.Itoa(priority)) + req.Header.Set("apns-priority", strconv.Itoa(10)) bearer := r.Token.GenerateNewTokenIfExpired() req.Header.Set("authorization", "bearer "+bearer) @@ -99,7 +70,7 @@ func (r *Repository) SendNotification(notification *model.IOSNotificationPayload resp, err := r.httpClient.Do(req) if err != nil { log.WithError(err).Error("Could not send notification") - return nil, ErrCouldNotSendNotification + return nil, errors.New("could not send notification") } defer func(Body io.ReadCloser) { if err := Body.Close(); err != nil { @@ -108,9 +79,9 @@ func (r *Repository) SendNotification(notification *model.IOSNotificationPayload }(resp.Body) var response model.IOSRemoteNotificationResponse - if err = json.NewDecoder(resp.Body).Decode(&response); err != nil && err != io.EOF { + if err := json.NewDecoder(resp.Body).Decode(&response); err != nil && err != io.EOF { log.WithError(err).Error("Could not decode APNs response") - return nil, ErrCouldNotDecodeAPNsResponse + return nil, errors.New("could not decode apns response") } return &response, nil @@ -118,7 +89,7 @@ func (r *Repository) SendNotification(notification *model.IOSNotificationPayload func NewRepository(db *gorm.DB, token *JWTToken) *Repository { transport := &http2.Transport{ - ReadIdleTimeout: ReadIdleTimeout, + ReadIdleTimeout: 15 * time.Second, } return &Repository{ @@ -126,7 +97,7 @@ func NewRepository(db *gorm.DB, token *JWTToken) *Repository { Token: token, httpClient: &http.Client{ Transport: transport, - Timeout: HTTPClientTimeout, + Timeout: 60 * time.Second, }, } } diff --git a/server/backend/ios_notifications/apns/service.go b/server/backend/ios_notifications/apns/service.go index 8e3f8c65..27700525 100644 --- a/server/backend/ios_notifications/apns/service.go +++ b/server/backend/ios_notifications/apns/service.go @@ -4,6 +4,7 @@ package apns import ( "errors" + "os" "github.com/TUM-Dev/Campus-Backend/server/model" log "github.com/sirupsen/logrus" @@ -32,30 +33,23 @@ func (s *Service) RequestGradeUpdateForDevice(deviceID string) error { notification := model.NewIOSNotificationPayload(deviceID).Background(campusRequestToken.RequestID, model.IOSBackgroundCampusTokenRequest) - if _, err := s.Repository.SendBackgroundNotification(notification); err != nil { + if _, err := s.Repository.SendNotification(notification, model.IOSAPNSPushTypeBackground); err != nil { log.WithError(err).Error("Could not send background notification") - return ErrCouldNotSendNotification + return errors.New("could not send notification") } return nil } func ValidateRequirementsForIOSNotificationsService() error { - if ApnsKeyId == "" { - return errors.New("APNS_KEY_ID env variable is not set") + for _, envVar := range []string{"APNS_KEY_ID", "APNS_TEAM_ID", "APNS_P8_FILE_PATH"} { + if os.Getenv(envVar) == "" { + return errors.New(envVar + " env variable is not set") + } } - if ApnsTeamId == "" { - return errors.New("APNS_TEAM_ID env variable is not set") - } - - if ApnsP8FilePath == "" { - return errors.New("APNS_P8_FILE_PATH env variable is not set") - } - - if _, err := APNsEncryptionKeyFromFile(); err != nil { + if _, err := EncryptionKeyFromFile(); err != nil { return errors.New("APNS P8 token is not valid or not set") } - return nil } diff --git a/server/backend/ios_notifications/crypto/encrypted_string.go b/server/backend/ios_notifications/crypto/encrypted_string.go index 3ee6fd7c..01654a7b 100644 --- a/server/backend/ios_notifications/crypto/encrypted_string.go +++ b/server/backend/ios_notifications/crypto/encrypted_string.go @@ -47,21 +47,19 @@ func AsymmetricEncrypt(plaintext string, publicKey string) (*EncryptedString, er func StringToPublicKey(pub string) (*rsa.PublicKey, error) { block, _ := pem.Decode([]byte(pub)) - if block == nil { return nil, errors.New("failed to parse PEM block containing the public key") } key, err := x509.ParsePKIXPublicKey(block.Bytes) - if err != nil { return nil, errors.New("failed to parse DER encoded public key: " + err.Error()) } - if pubKey, ok := key.(*rsa.PublicKey); ok { - return pubKey, nil - } else { + if pubKey, ok := key.(*rsa.PublicKey); !ok { return nil, errors.New("failed to parse DER encoded public key: " + err.Error()) + } else { + return pubKey, nil } } diff --git a/server/backend/ios_notifications/device/repository.go b/server/backend/ios_notifications/device/repository.go index 13fe053c..6c740ab6 100644 --- a/server/backend/ios_notifications/device/repository.go +++ b/server/backend/ios_notifications/device/repository.go @@ -12,11 +12,9 @@ type Repository struct { } func (repository *Repository) CreateDevice(device *model.IOSDevice) error { - return repository.DB.Transaction(func(tx *gorm.DB) error { var foundDevice model.IOSDevice - res := tx.First(&foundDevice, "device_id = ?", device.DeviceID) if errors.Is(res.Error, gorm.ErrRecordNotFound) { @@ -41,11 +39,7 @@ func (repository *Repository) CreateDevice(device *model.IOSDevice) error { } func (repository *Repository) DeleteDevice(deviceId string) error { - if err := repository.DB.Delete(&model.IOSDevice{DeviceID: deviceId}).Error; err != nil { - return err - } - - return nil + return repository.DB.Delete(&model.IOSDevice{DeviceID: deviceId}).Error } func (repository *Repository) GetDevices() ([]model.IOSDevice, error) { @@ -72,8 +66,14 @@ func (repository *Repository) GetDevice(id string) (*model.IOSDevice, error) { func (repository *Repository) GetDevicesThatShouldUpdateGrades() ([]model.IOSDeviceLastUpdated, error) { var devices []model.IOSDeviceLastUpdated - tx := repository.DB.Raw( - buildDevicesThatShouldUpdateGradesQuery(), + tx := repository.DB.Raw(`select d.device_id, ul.created_at as last_updated, d.public_key + from ios_devices d + left join ios_scheduled_update_logs ul on d.device_id = ul.device_id + where ul.created_at is null + or (ul.type = ? + and ul.created_at < date_sub(now(), interval ? minute)) + group by d.device_id, ul.created_at + order by ul.created_at`, model.IOSUpdateTypeGrades, model.IOSMinimumUpdateInterval, ).Scan(&devices) @@ -85,19 +85,6 @@ func (repository *Repository) GetDevicesThatShouldUpdateGrades() ([]model.IOSDev return devices, nil } -func buildDevicesThatShouldUpdateGradesQuery() string { - return ` - select d.device_id, ul.created_at as last_updated, d.public_key - from ios_devices d - left join ios_scheduled_update_logs ul on d.device_id = ul.device_id - where ul.created_at is null - or (ul.type = ? - and ul.created_at < date_sub(now(), interval ? minute)) - group by d.device_id, ul.created_at - order by ul.created_at; - ` -} - func (repository *Repository) ResetDevicesDailyActivity() error { return repository.DB.Model(model.IOSDevice{}).Where("activity_today != ?", 0).Update("activity_today", 0).Error } diff --git a/server/backend/ios_notifications/device/service.go b/server/backend/ios_notifications/device/service.go index 80cc264d..46d5ef70 100644 --- a/server/backend/ios_notifications/device/service.go +++ b/server/backend/ios_notifications/device/service.go @@ -16,9 +16,6 @@ type Service struct { } var ( - ErrCouldNotCreateDevice = status.Error(codes.Internal, "Could not create device") - ErrCouldNotDeleteDevice = status.Error(codes.Internal, "Could not delete device") - iosRegisteredDevices = promauto.NewGauge(prometheus.GaugeOpts{ Subsystem: "ios", Name: "ios_created_devices", @@ -26,14 +23,14 @@ var ( }) ) -func (service *Service) CreateDevice(request *pb.CreateDeviceRequest) (*pb.CreateDeviceReply, error) { +func (service *Service) CreateDevice(req *pb.CreateDeviceRequest) (*pb.CreateDeviceReply, error) { device := model.IOSDevice{ - DeviceID: request.GetDeviceId(), - PublicKey: request.GetPublicKey(), + DeviceID: req.DeviceId, + PublicKey: req.PublicKey, } if err := service.Repository.CreateDevice(&device); err != nil { - return nil, ErrCouldNotCreateDevice + return nil, status.Error(codes.Internal, "Could not create device") } iosRegisteredDevices.Inc() @@ -42,14 +39,14 @@ func (service *Service) CreateDevice(request *pb.CreateDeviceRequest) (*pb.Creat }, nil } -func (service *Service) DeleteDevice(request *pb.DeleteDeviceRequest) (*pb.DeleteDeviceReply, error) { - if err := service.Repository.DeleteDevice(request.GetDeviceId()); err != nil { - return nil, ErrCouldNotDeleteDevice +func (service *Service) DeleteDevice(req *pb.DeleteDeviceRequest) (*pb.DeleteDeviceReply, error) { + if err := service.Repository.DeleteDevice(req.DeviceId); err != nil { + return nil, status.Error(codes.Internal, "Could not delete device") } iosRegisteredDevices.Dec() return &pb.DeleteDeviceReply{ - DeviceId: request.GetDeviceId(), + DeviceId: req.DeviceId, }, nil } diff --git a/server/backend/ios_notifications/devices_activity_reset/repository.go b/server/backend/ios_notifications/devices_activity_reset/repository.go index 251187c6..9e8cf609 100644 --- a/server/backend/ios_notifications/devices_activity_reset/repository.go +++ b/server/backend/ios_notifications/devices_activity_reset/repository.go @@ -15,10 +15,7 @@ type Repository struct { func (repo *Repository) GetDevicesActivityResets() ([]model.IOSDevicesActivityReset, error) { var resets []model.IOSDevicesActivityReset - - err := repo.DB.Find(&resets).Error - - if err != nil { + if err := repo.DB.Find(&resets).Error; err != nil { return nil, err } diff --git a/server/backend/ios_notifications/devices_activity_reset/service.go b/server/backend/ios_notifications/devices_activity_reset/service.go index f808a983..33bf89d9 100644 --- a/server/backend/ios_notifications/devices_activity_reset/service.go +++ b/server/backend/ios_notifications/devices_activity_reset/service.go @@ -14,27 +14,22 @@ type Service struct { func (service *Service) HandleScheduledActivityReset() error { daily, err := service.Repository.GetDevicesActivityResetDaily() - if err != nil { service.Repository.CreateInitialRecords() - return nil } weekly, err := service.Repository.GetDevicesActivityResetWeekly() - if err != nil { return err } monthly, err := service.Repository.GetDevicesActivityResetMonthly() - if err != nil { return err } yearly, err := service.Repository.GetDevicesActivityResetYearly() - if err != nil { return err } diff --git a/server/backend/ios_notifications/interfaces.go b/server/backend/ios_notifications/interfaces.go deleted file mode 100644 index 32532e15..00000000 --- a/server/backend/ios_notifications/interfaces.go +++ /dev/null @@ -1,13 +0,0 @@ -package ios_notifications - -import ( - "gorm.io/gorm" -) - -type BaseRepository interface { - NewRepository(db *gorm.DB) *BaseRepository -} - -type BaseService interface { - NewService(repository *BaseRepository) *BaseService -} diff --git a/server/backend/ios_notifications/request_response/repository.go b/server/backend/ios_notifications/request_response/repository.go index 9e2b39cc..45fb44ae 100644 --- a/server/backend/ios_notifications/request_response/repository.go +++ b/server/backend/ios_notifications/request_response/repository.go @@ -12,11 +12,7 @@ type Repository struct { } func (r *Repository) SaveEncryptedGrade(grade *model.IOSEncryptedGrade) error { - if err := r.DB.Create(grade).Error; err != nil { - return err - } - - return nil + return r.DB.Create(grade).Error } func (r *Repository) GetIOSDeviceRequest(requestId string) (*model.IOSDeviceRequestLog, error) { @@ -38,36 +34,21 @@ func (r *Repository) GetIOSEncryptedGrades(deviceId string) ([]model.IOSEncrypte } func (r *Repository) DeleteEncryptedGrades(deviceId string) error { - if err := r.DB.Delete(&model.IOSEncryptedGrade{}, "device_id = ?", deviceId).Error; err != nil { - return err - } - - return nil + return r.DB.Delete(&model.IOSEncryptedGrade{}, "device_id = ?", deviceId).Error } func (r *Repository) DeleteRequestLog(requestId string) error { - if err := r.DB.Delete(&model.IOSDeviceRequestLog{}, "request_id = ?", requestId).Error; err != nil { - return err - } - - return nil + return r.DB.Delete(&model.IOSDeviceRequestLog{}, "request_id = ?", requestId).Error } func (r *Repository) DeleteAllRequestLogsForThisDeviceWithType(requestLog *model.IOSDeviceRequestLog) error { - - res := r.DB. + return r.DB. Delete( &model.IOSDeviceRequestLog{}, "device_id = ? and request_type = ?", requestLog.DeviceID, requestLog.RequestType, - ) - - if err := res.Error; err != nil { - return err - } - - return nil + ).Error } func NewRepository(db *gorm.DB, token *apns.JWTToken) *Repository { diff --git a/server/backend/ios_notifications/request_response/service.go b/server/backend/ios_notifications/request_response/service.go index 85f58a72..7a79372d 100644 --- a/server/backend/ios_notifications/request_response/service.go +++ b/server/backend/ios_notifications/request_response/service.go @@ -23,97 +23,82 @@ type Service struct { Repository *Repository } -var ( - ErrOutdatedRequest = status.Error(codes.Internal, "Could not get request, probably request is already outdated") - ErrEmptyPayload = status.Error(codes.InvalidArgument, "Payload is empty") - ErrUnknownRequestType = status.Error(codes.InvalidArgument, "Unknown request type") - ErrInternalHandleGrades = status.Error(codes.Internal, "Could not handle grades request") - ErrCouldNotGetDevice = status.Error(codes.Internal, "Could not get device") - ErrAPNSNotActive = status.Error(codes.Internal, "APNS is not active") - - collectedNewGrades = promauto.NewHistogram(prometheus.HistogramOpts{ - Name: "ios_new_grades", - Help: "The total number of processed events", - Buckets: prometheus.LinearBuckets(0, 5, 5), - }) -) - -func (service *Service) HandleDeviceRequestResponse(request *pb.IOSDeviceRequestResponseRequest, apnsIsActive bool) (*pb.IOSDeviceRequestResponseReply, error) { - // requestId refers to the request id that was sent to the device and stored in the Database - requestId := request.GetRequestId() - - log.WithField("requestId", requestId).Info("Handling request") +var collectedNewGrades = promauto.NewHistogram(prometheus.HistogramOpts{ + Name: "ios_new_grades", + Help: "The total number of processed events", + Buckets: prometheus.LinearBuckets(0, 5, 5), +}) - requestLog, err := service.Repository.GetIOSDeviceRequest(requestId) +func (service *Service) HandleDeviceRequestResponse(req *pb.IOSDeviceRequestResponseRequest, apnsIsActive bool) (*pb.IOSDeviceRequestResponseReply, error) { + log.WithField("requestId", req.RequestId).Trace("Handling request") + requestLog, err := service.Repository.GetIOSDeviceRequest(req.RequestId) if err != nil { log.WithError(err).Error("Could not get request") - return nil, ErrOutdatedRequest + return nil, status.Error(codes.Internal, "Could not get request, probably request is already outdated") } switch requestLog.RequestType { case model.IOSBackgroundCampusTokenRequest.String(): - campusToken := request.GetPayload() - - if campusToken == "" { - return nil, ErrEmptyPayload + if req.Payload == "" { + return nil, status.Error(codes.InvalidArgument, "Payload is empty") } if !apnsIsActive { - return nil, ErrAPNSNotActive + return nil, status.Error(codes.Internal, "APNS is not active") } - return service.handleDeviceCampusTokenRequest(requestLog, campusToken) + return service.handleDeviceCampusTokenRequest(requestLog, req.Payload) default: - return nil, ErrUnknownRequestType + return nil, status.Error(codes.InvalidArgument, "Unknown request type") } } func (service *Service) handleDeviceCampusTokenRequest(requestLog *model.IOSDeviceRequestLog, campusToken string) (*pb.IOSDeviceRequestResponseReply, error) { - log.WithField("DeviceID", requestLog.DeviceID).Info("Handling campus token request") + log.WithField("DeviceID", requestLog.DeviceID).Trace("Handling campus token request") userRepo := device.NewRepository(service.Repository.DB) device, err := userRepo.GetDevice(requestLog.DeviceID) - if err != nil { log.WithError(err).Error("Could not get device") - return nil, ErrCouldNotGetDevice + return nil, status.Error(codes.Internal, "Could not get device") } apiGrades, err := campus_api.FetchGrades(campusToken) if err != nil { log.WithError(err).Error("Could not fetch grades") - return nil, ErrInternalHandleGrades + return nil, status.Error(codes.Internal, "Could not handle grades request") } oldEncryptedGrades, err := service.Repository.GetIOSEncryptedGrades(requestLog.DeviceID) if err != nil { log.WithError(err).Error("Could not get old grades") - return nil, ErrInternalHandleGrades + return nil, status.Error(codes.Internal, "Could not handle grades request") } oldGrades, err := decryptGrades(oldEncryptedGrades, campusToken) if err != nil { log.WithError(err).Error("Could not decrypt old grades") - return nil, ErrInternalHandleGrades + return nil, status.Error(codes.Internal, "Could not handle grades request") } newGrades := compareAndFindNewGrades(apiGrades.Grades, oldGrades) collectedNewGrades.Observe(float64(len(newGrades))) if len(newGrades) == 0 { log.Info("No new grades found") - service.deleteRequestLog(requestLog) + if err := service.Repository.DeleteAllRequestLogsForThisDeviceWithType(requestLog); err != nil { + log.WithError(err).Error("Could not delete request logs") + } return &pb.IOSDeviceRequestResponseReply{ Message: "Successfully handled request", }, nil } err = service.Repository.DeleteEncryptedGrades(requestLog.DeviceID) - if err != nil { log.WithError(err).Error("Could not delete old grades") - return nil, ErrInternalHandleGrades + return nil, status.Error(codes.Internal, "Could not handle grades request") } service.encryptGradesAndStoreInDatabase(apiGrades.Grades, requestLog.DeviceID, campusToken) @@ -125,26 +110,19 @@ func (service *Service) handleDeviceCampusTokenRequest(requestLog *model.IOSDevi sendGradesToDevice(device, newGrades, apnsRepository) } - service.deleteRequestLog(requestLog) + if err := service.Repository.DeleteAllRequestLogsForThisDeviceWithType(requestLog); err != nil { + log.WithError(err).Error("Could not delete request logs") + } return &pb.IOSDeviceRequestResponseReply{ Message: "Successfully handled request", }, nil } -func (service *Service) deleteRequestLog(requestLog *model.IOSDeviceRequestLog) { - err := service.Repository.DeleteAllRequestLogsForThisDeviceWithType(requestLog) - - if err != nil { - log.WithError(err).Error("Could not delete request logs") - } -} - func decryptGrades(grades []model.IOSEncryptedGrade, campusToken string) ([]model.IOSEncryptedGrade, error) { oldGrades := make([]model.IOSEncryptedGrade, len(grades)) for i, encryptedGrade := range grades { err := encryptedGrade.Decrypt(campusToken) - if err != nil { log.WithError(err).Error("Could not decrypt grade") return nil, status.Error(codes.Internal, "Could not decrypt grade") @@ -197,7 +175,6 @@ func (service *Service) encryptGradesAndStoreInDatabase(grades []model.IOSGrade, func sendGradesToDevice(device *model.IOSDevice, grades []model.IOSGrade, apns *apns.Repository) { alertTitle := fmt.Sprintf("%d New Grades Available", len(grades)) - if len(grades) == 1 { alertTitle = "New Grade Available" } @@ -217,8 +194,7 @@ func sendGradesToDevice(device *model.IOSDevice, grades []model.IOSGrade, apns * log.WithField("DeviceID", device.DeviceID).Info("Sending push notification") - _, err := apns.SendAlertNotification(notificationPayload) - if err != nil { + if _, err := apns.SendNotification(notificationPayload, model.IOSAPNSPushTypeAlert); err != nil { log.WithField("DeviceID", device.DeviceID).WithError(err).Error("Could not send notification") } } diff --git a/server/backend/ios_notifications/scheduled_update_log/repository.go b/server/backend/ios_notifications/scheduled_update_log/repository.go index e85ae0af..48057f0e 100644 --- a/server/backend/ios_notifications/scheduled_update_log/repository.go +++ b/server/backend/ios_notifications/scheduled_update_log/repository.go @@ -13,18 +13,12 @@ type Repository struct { } func (service *Repository) LogScheduledUpdate(log *model.IOSScheduledUpdateLog) error { - tx := service.DB.Clauses(clause.OnConflict{ + return service.DB.Clauses(clause.OnConflict{ Columns: []clause.Column{{Name: "device_id"}}, DoUpdates: clause.AssignmentColumns([]string{ "created_at", }), - }).Create(log) - - if err := tx.Error; err != nil { - return err - } - - return nil + }).Create(log).Error } func NewRepository(db *gorm.DB) *Repository { diff --git a/server/backend/ios_notifications/scheduling/repository.go b/server/backend/ios_notifications/scheduling/repository.go index 01c9ac2d..fb78f528 100644 --- a/server/backend/ios_notifications/scheduling/repository.go +++ b/server/backend/ios_notifications/scheduling/repository.go @@ -10,11 +10,8 @@ type Repository struct { } func (repository *Repository) FindSchedulingPriorities() ([]model.IOSSchedulingPriority, error) { - db := repository.DB - var priorities []model.IOSSchedulingPriority - - err := db.Find(&priorities).Error + err := repository.DB.Find(&priorities).Error return priorities, err } diff --git a/server/backend/ios_notifications/scheduling/service.go b/server/backend/ios_notifications/scheduling/service.go index 4c7aa2cb..bec9256b 100644 --- a/server/backend/ios_notifications/scheduling/service.go +++ b/server/backend/ios_notifications/scheduling/service.go @@ -15,11 +15,6 @@ import ( log "github.com/sirupsen/logrus" ) -const ( - DevicesToCheckPerCronBase = 10 - MaxRoutineCount = 10 -) - var devicesToUpdate = promauto.NewGauge(prometheus.GaugeOpts{ Name: "ios_scheduling_devices_to_update", Help: "The numer of devices that should be updated for a given priority", @@ -35,7 +30,6 @@ type Service struct { func (service *Service) HandleScheduledCron() error { priorities, err := service.Repository.FindSchedulingPriorities() - if err != nil { return err } @@ -43,11 +37,11 @@ func (service *Service) HandleScheduledCron() error { currentPriority := findIOSSchedulingPriorityForNow(priorities) devices, err := service.DevicesRepository.GetDevicesThatShouldUpdateGrades() - if err != nil { log.WithError(err).Error("can't get devices") return err } + devicesToUpdate.Set(float64(len(devices))) if len(devices) == 0 { @@ -65,7 +59,7 @@ func (service *Service) HandleScheduledCron() error { } func (service *Service) handleDevices(devices []model.IOSDeviceLastUpdated) { - routinesCount := min(len(devices), MaxRoutineCount) + routinesCount := min(len(devices), 10) chunkSize := len(devices) / routinesCount perfectlyChunkable := (len(devices) % routinesCount) == 0 @@ -118,10 +112,9 @@ func (service *Service) LogScheduledUpdate(deviceID string) error { return service.SchedulerLogRepository.LogScheduledUpdate(&scheduleLog) } -// selectDevicesToUpdate selects max DevicesToCheckPerCronBase devices to update -// based on the priority. +// selectDevicesToUpdate selects the first DevicesToCheckPerCronBase * priority devices func (service *Service) selectDevicesToUpdate(devices []model.IOSDeviceLastUpdated, priority int) []model.IOSDeviceLastUpdated { - maxDevicesToCheck := DevicesToCheckPerCronBase * priority + maxDevicesToCheck := 10 * priority if len(devices) < maxDevicesToCheck { return devices diff --git a/server/backend/migration/safe_enum_migrate.go b/server/backend/migration/safe_enum_migrate.go index c034f861..a5f91a6e 100644 --- a/server/backend/migration/safe_enum_migrate.go +++ b/server/backend/migration/safe_enum_migrate.go @@ -5,32 +5,27 @@ import ( "fmt" "strings" + log "github.com/sirupsen/logrus" + "gorm.io/gorm" ) func SafeEnumAdd(tx *gorm.DB, table interface{}, column string, additionalTypes ...string) error { enumTypes, err := getEnumTypesFromDB(tx, table, column) - if err != nil { return err } - enumTypes = append(enumTypes, additionalTypes...) - enumTypes = ensureUnique(enumTypes) - - return alterEnumColumn(tx, table, column, enumTypes) + return alterEnumColumn(tx, table, column, ensureUnique(append(enumTypes, additionalTypes...))) } func SafeEnumRemove(tx *gorm.DB, table interface{}, column string, rollbackTypes ...string) error { enumTypes, err := getEnumTypesFromDB(tx, table, column) - if err != nil { return err } - enumTypes = RemoveTypes(enumTypes, rollbackTypes...) - - return alterEnumColumn(tx, table, column, enumTypes) + return alterEnumColumn(tx, table, column, RemoveTypes(enumTypes, rollbackTypes...)) } func ensureUnique(types []string) []string { @@ -46,44 +41,34 @@ func ensureUnique(types []string) []string { } func alterEnumColumn(tx *gorm.DB, table interface{}, column string, types []string) error { - enum := BuildEnum(types) - stmt := &gorm.Statement{DB: tx} err := stmt.Parse(&table) if err != nil { return errors.New("could not parse enum table") } - tableName := stmt.Schema.Table - rawQuery := fmt.Sprintf( + if err := tx.Exec(fmt.Sprintf( "ALTER TABLE %s MODIFY %s %s;", - tableName, + stmt.Schema.Table, column, - enum, - ) - - tx = tx.Exec(rawQuery) - - if tx.Error != nil { + BuildEnum(types), + )).Error; err != nil { + log.WithError(err).Error("Error altering enum table") return errors.New("could not alter enum table") } - return nil } func getEnumTypesFromDB(tx *gorm.DB, table interface{}, column string) ([]string, error) { columnType, err := tx.Migrator().ColumnTypes(&table) - if err != nil { return nil, errors.New("could not get enum column types") } enumTypes, err := getEnumTypes(columnType, column) - if err != nil { return nil, err } - return enumTypes, nil } @@ -100,20 +85,16 @@ func RemoveTypes(types []string, rollbackTypes ...string) []string { } func getEnumTypes(columTypes []gorm.ColumnType, column string) ([]string, error) { - var cType string - for _, t := range columTypes { if t.Name() == column { if t, ok := t.ColumnType(); ok { - cType = t - break + return EnumTypesFromString(t) } else { return nil, errors.New("could not get column type") } } } - - return EnumTypesFromString(cType) + return nil, errors.New("column does not exist") } func EnumTypesFromString(enum string) ([]string, error) { @@ -138,15 +119,6 @@ func EnumTypesFromString(enum string) ([]string, error) { } func BuildEnum(types []string) string { - str := "enum(" - - for _, t := range types { - str += fmt.Sprintf("'%s',", t) - } - - str = strings.TrimRight(str, ",") - - str += ")" - - return str + enums := strings.Join(types, "','") + return fmt.Sprintf("enum('%s')", enums) } diff --git a/server/backend/new_exam_results_hook/scheduling/repository.go b/server/backend/new_exam_results_hook/scheduling/repository.go index 558cb6c6..aaff769a 100644 --- a/server/backend/new_exam_results_hook/scheduling/repository.go +++ b/server/backend/new_exam_results_hook/scheduling/repository.go @@ -15,7 +15,6 @@ func (repository *Repository) StoreExamResultsPublished(examResultsPublished []m return db.Transaction(func(tx *gorm.DB) error { err := tx.Where("1 = 1").Delete(&model.PublishedExamResult{}).Error - if err != nil { return err } diff --git a/server/backend/new_exam_results_hook/scheduling/service.go b/server/backend/new_exam_results_hook/scheduling/service.go index e1b68c13..917f3dad 100644 --- a/server/backend/new_exam_results_hook/scheduling/service.go +++ b/server/backend/new_exam_results_hook/scheduling/service.go @@ -1,8 +1,6 @@ package scheduling import ( - "os" - "github.com/TUM-Dev/Campus-Backend/server/backend/campus_api" "github.com/TUM-Dev/Campus-Backend/server/backend/ios_notifications/apns" "github.com/TUM-Dev/Campus-Backend/server/backend/ios_notifications/device" @@ -11,10 +9,6 @@ import ( log "github.com/sirupsen/logrus" ) -var ( - CampusApiToken = os.Getenv("CAMPUS_API_TOKEN") -) - type Service struct { Repository *Repository DevicesRepository *device.Repository @@ -25,7 +19,7 @@ type Service struct { func (service *Service) HandleScheduledCron() error { log.Info("Fetching published exam results") - apiResult, err := campus_api.FetchExamResultsPublished(CampusApiToken) + apiResult, err := campus_api.FetchExamResultsPublished() if err != nil { return err } diff --git a/server/backend/new_exam_results_hook/subscriber/repository.go b/server/backend/new_exam_results_hook/subscriber/repository.go index a8059293..27667410 100644 --- a/server/backend/new_exam_results_hook/subscriber/repository.go +++ b/server/backend/new_exam_results_hook/subscriber/repository.go @@ -15,29 +15,25 @@ type Repository struct { } func (repository *Repository) FindAllSubscribers() (*[]model.NewExamResultsSubscriber, error) { - db := repository.DB - var subscribers []model.NewExamResultsSubscriber - - err := db.Find(&subscribers).Error + err := repository.DB.Find(&subscribers).Error return &subscribers, err } func (repository *Repository) NotifySubscriber(subscriber *model.NewExamResultsSubscriber, newGrades *[]model.PublishedExamResult) error { - url := subscriber.CallbackUrl - body, err := json.Marshal(newGrades) if err != nil { log.WithError(err).Error("Error while marshalling newGrades") return err } - req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(body)) + req, err := http.NewRequest(http.MethodPost, subscriber.CallbackUrl, bytes.NewBuffer(body)) if err != nil { log.WithError(err).Error("Error while creating request") return err } + req.Header.Set("Content-Type", "application/json") if subscriber.ApiKey.Valid { req.Header.Set("Authorization", subscriber.ApiKey.String) @@ -45,7 +41,7 @@ func (repository *Repository) NotifySubscriber(subscriber *model.NewExamResultsS _, err = http.DefaultClient.Do(req) if err != nil { - log.WithField("url", url).WithError(err).Error("Error while fetching url") + log.WithField("url", subscriber.CallbackUrl).WithError(err).Error("Error while fetching url") return err } diff --git a/server/backend/new_exam_results_hook/subscriber/service.go b/server/backend/new_exam_results_hook/subscriber/service.go index ef8509f6..55c6747f 100644 --- a/server/backend/new_exam_results_hook/subscriber/service.go +++ b/server/backend/new_exam_results_hook/subscriber/service.go @@ -10,15 +10,13 @@ type Service struct { } func (service *Service) NotifySubscribers(newGrades *[]model.PublishedExamResult) error { - repository := service.Repository - - subscribers, err := repository.FindAllSubscribers() + subscribers, err := service.Repository.FindAllSubscribers() if err != nil { return err } for _, subscriber := range *subscribers { - if err := repository.NotifySubscriber(&subscriber, newGrades); err != nil { + if err := service.Repository.NotifySubscriber(&subscriber, newGrades); err != nil { log.WithError(err).Error("Failed to notify subscriber") continue } diff --git a/server/backend/validators.go b/server/backend/validators.go index 234216bb..ddc047f1 100644 --- a/server/backend/validators.go +++ b/server/backend/validators.go @@ -6,20 +6,20 @@ import ( pb "github.com/TUM-Dev/Campus-Backend/server/api/tumdev" ) -func ValidateCreateDevice(request *pb.CreateDeviceRequest) error { - if request.GetDeviceId() == "" { +func ValidateCreateDevice(req *pb.CreateDeviceRequest) error { + if req.DeviceId == "" { return errors.New("deviceId is empty") } - if request.GetDeviceType() == pb.DeviceType_IOS && request.GetPublicKey() == "" { + if req.DeviceType == pb.DeviceType_IOS && req.PublicKey == "" { return errors.New("publicKey is needed for IOS") } return nil } -func ValidateDeleteDevice(request *pb.DeleteDeviceRequest) error { - if request.GetDeviceId() == "" { +func ValidateDeleteDevice(req *pb.DeleteDeviceRequest) error { + if req.DeviceId == "" { return errors.New("deviceId is empty") } From e2fa378112ab7bdf431a7e8e0fba8f2aa14d1740 Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Wed, 25 Oct 2023 13:14:09 +0200 Subject: [PATCH 11/11] modified the request logger to log more useful things --- server/main.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/server/main.go b/server/main.go index 516727fd..6fd3c114 100644 --- a/server/main.go +++ b/server/main.go @@ -7,6 +7,7 @@ import ( "net" "net/http" "net/textproto" + "strings" "time" "github.com/TUM-Dev/Campus-Backend/server/utils" @@ -114,14 +115,23 @@ func main() { func UnaryRequestLogger(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { start := time.Now() resp, err := handler(ctx, req) - fields := log.Fields{"elapsed": time.Since(start)} - log.WithContext(ctx).WithFields(fields).WithError(err).Info(info.FullMethod) + fields := log.Fields{"elapsed": time.Since(start), "method": strings.TrimPrefix(info.FullMethod, "/api.Campus/")} + if err != nil { + log.WithFields(fields).Info("request") + } else { + log.WithFields(fields).WithError(err).Warn("request") + } return resp, err } func StreamRequestLogger(srv any, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { start := time.Now() err := handler(srv, stream) - log.WithField("elapsed", time.Since(start)).WithError(err).Info(info.FullMethod) + fields := log.Fields{"elapsed": time.Since(start), "method": strings.TrimPrefix(info.FullMethod, "/api.Campus/")} + if err != nil { + log.WithFields(fields).Info("request") + } else { + log.WithFields(fields).WithError(err).Warn("request") + } return err }