diff --git a/CHANGELOG.md b/CHANGELOG.md index 62d2b88fb..492551aba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,23 @@ and Yorkie adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) ## [Unreleased] +## [0.5.0] - 2024-09-05 + +### Added + +- Add Concurrency Tests between Array Operations by @cloneot in https://github.com/yorkie-team/yorkie/pull/985 +- Add metric for WatchDocument streams by @emplam27 in https://github.com/yorkie-team/yorkie/pull/998 +- Add Account Deletion and Change Password to CLI by @sigmaith in https://github.com/yorkie-team/yorkie/pull/983 + +### Changed + +- Optimize FindChangeInfosBetweenServerSeqs to prevent unnecessary Query by @kokodak in https://github.com/yorkie-team/yorkie/pull/974 +- Rename SetByIndex to ArraySet by @hackerwins in https://github.com/yorkie-team/yorkie/pull/995 + +### Fixed + +- Set `updated_at` with `created_at` when creating Document by @window9u in https://github.com/yorkie-team/yorkie/pull/977 + ## [0.4.31] - 2024-08-21 ### Added diff --git a/Makefile b/Makefile index a4ae4862c..b0ec6bc58 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -YORKIE_VERSION := 0.4.31 +YORKIE_VERSION := 0.5.0 GO_PROJECT = github.com/yorkie-team/yorkie diff --git a/admin/client.go b/admin/client.go index fddf21044..1883d032b 100644 --- a/admin/client.go +++ b/admin/client.go @@ -377,3 +377,30 @@ func withShardKey[T any](conn *connect.Request[T], keys ...string) *connect.Requ return conn } + +// DeleteAccount deletes the user's account. +func (c *Client) DeleteAccount(ctx context.Context, username, password string) error { + _, err := c.client.DeleteAccount(ctx, connect.NewRequest(&api.DeleteAccountRequest{ + Username: username, + Password: password, + })) + if err != nil { + return err + } + + return nil +} + +// ChangePassword changes the user's password. +func (c *Client) ChangePassword(ctx context.Context, username, password, newPassword string) error { + _, err := c.client.ChangePassword(ctx, connect.NewRequest(&api.ChangePasswordRequest{ + Username: username, + CurrentPassword: password, + NewPassword: newPassword, + })) + if err != nil { + return err + } + + return nil +} diff --git a/api/converter/from_pb.go b/api/converter/from_pb.go index 450403a42..4200da4d7 100644 --- a/api/converter/from_pb.go +++ b/api/converter/from_pb.go @@ -208,6 +208,8 @@ func FromOperations(pbOps []*api.Operation) ([]operations.Operation, error) { op, err = fromTreeEdit(decoded.TreeEdit) case *api.Operation_TreeStyle_: op, err = fromTreeStyle(decoded.TreeStyle) + case *api.Operation_ArraySet_: + op, err = fromArraySet(decoded.ArraySet) default: return nil, ErrUnsupportedOperation } @@ -539,6 +541,31 @@ func fromTreeStyle(pbTreeStyle *api.Operation_TreeStyle) (*operations.TreeStyle, ), nil } +func fromArraySet(pbSetByIndex *api.Operation_ArraySet) (*operations.ArraySet, error) { + parentCreatedAt, err := fromTimeTicket(pbSetByIndex.ParentCreatedAt) + if err != nil { + return nil, err + } + createdAt, err := fromTimeTicket(pbSetByIndex.CreatedAt) + if err != nil { + return nil, err + } + elem, err := fromElement(pbSetByIndex.Value) + if err != nil { + return nil, err + } + executedAt, err := fromTimeTicket(pbSetByIndex.ExecutedAt) + if err != nil { + return nil, err + } + return operations.NewArraySet( + parentCreatedAt, + createdAt, + elem, + executedAt, + ), nil +} + func fromCreatedAtMapByActor( pbCreatedAtMapByActor map[string]*api.TimeTicket, ) (map[string]*time.Ticket, error) { diff --git a/api/converter/to_pb.go b/api/converter/to_pb.go index 24d90b093..601db864d 100644 --- a/api/converter/to_pb.go +++ b/api/converter/to_pb.go @@ -206,6 +206,8 @@ func ToOperations(ops []operations.Operation) ([]*api.Operation, error) { pbOperation.Body, err = toTreeEdit(op) case *operations.TreeStyle: pbOperation.Body, err = toTreeStyle(op) + case *operations.ArraySet: + pbOperation.Body, err = toArraySet(op) default: return nil, ErrUnsupportedOperation } @@ -375,6 +377,22 @@ func toTreeStyle(style *operations.TreeStyle) (*api.Operation_TreeStyle_, error) }, nil } +func toArraySet(setByIndex *operations.ArraySet) (*api.Operation_ArraySet_, error) { + pbElem, err := toJSONElementSimple(setByIndex.Value()) + if err != nil { + return nil, err + } + + return &api.Operation_ArraySet_{ + ArraySet: &api.Operation_ArraySet{ + ParentCreatedAt: ToTimeTicket(setByIndex.ParentCreatedAt()), + CreatedAt: ToTimeTicket(setByIndex.CreatedAt()), + Value: pbElem, + ExecutedAt: ToTimeTicket(setByIndex.ExecutedAt()), + }, + }, nil +} + func toJSONElementSimple(elem crdt.Element) (*api.JSONElementSimple, error) { switch elem := elem.(type) { case *crdt.Object: diff --git a/api/docs/yorkie.base.yaml b/api/docs/yorkie.base.yaml index 43e17e27d..cc22f1f9f 100644 --- a/api/docs/yorkie.base.yaml +++ b/api/docs/yorkie.base.yaml @@ -2,7 +2,7 @@ openapi: 3.1.0 info: title: Yorkie description: "Yorkie is an open source document store for building collaborative editing applications." - version: v0.4.31 + version: v0.5.0 servers: - url: https://api.yorkie.dev description: Production server diff --git a/api/docs/yorkie/v1/admin.openapi.yaml b/api/docs/yorkie/v1/admin.openapi.yaml index bee1b82fb..f7918424a 100644 --- a/api/docs/yorkie/v1/admin.openapi.yaml +++ b/api/docs/yorkie/v1/admin.openapi.yaml @@ -3,7 +3,7 @@ info: description: Yorkie is an open source document store for building collaborative editing applications. title: Yorkie - version: v0.4.31 + version: v0.5.0 servers: - description: Production server url: https://api.yorkie.dev @@ -1171,6 +1171,12 @@ components: description: "" title: add type: object + arraySet: + $ref: '#/components/schemas/yorkie.v1.Operation.ArraySet' + additionalProperties: false + description: "" + title: array_set + type: object edit: $ref: '#/components/schemas/yorkie.v1.Operation.Edit' additionalProperties: false @@ -1257,6 +1263,36 @@ components: type: object title: Add type: object + yorkie.v1.Operation.ArraySet: + additionalProperties: false + description: "" + properties: + createdAt: + $ref: '#/components/schemas/yorkie.v1.TimeTicket' + additionalProperties: false + description: "" + title: created_at + type: object + executedAt: + $ref: '#/components/schemas/yorkie.v1.TimeTicket' + additionalProperties: false + description: "" + title: executed_at + type: object + parentCreatedAt: + $ref: '#/components/schemas/yorkie.v1.TimeTicket' + additionalProperties: false + description: "" + title: parent_created_at + type: object + value: + $ref: '#/components/schemas/yorkie.v1.JSONElementSimple' + additionalProperties: false + description: "" + title: value + type: object + title: ArraySet + type: object yorkie.v1.Operation.Edit: additionalProperties: false description: "" diff --git a/api/docs/yorkie/v1/resources.openapi.yaml b/api/docs/yorkie/v1/resources.openapi.yaml index 32854957d..d893c2398 100644 --- a/api/docs/yorkie/v1/resources.openapi.yaml +++ b/api/docs/yorkie/v1/resources.openapi.yaml @@ -3,7 +3,7 @@ info: description: Yorkie is an open source document store for building collaborative editing applications. title: Yorkie - version: v0.4.31 + version: v0.5.0 servers: - description: Production server url: https://api.yorkie.dev @@ -680,6 +680,12 @@ components: description: "" title: add type: object + arraySet: + $ref: '#/components/schemas/yorkie.v1.Operation.ArraySet' + additionalProperties: false + description: "" + title: array_set + type: object edit: $ref: '#/components/schemas/yorkie.v1.Operation.Edit' additionalProperties: false @@ -766,6 +772,36 @@ components: type: object title: Add type: object + yorkie.v1.Operation.ArraySet: + additionalProperties: false + description: "" + properties: + createdAt: + $ref: '#/components/schemas/yorkie.v1.TimeTicket' + additionalProperties: false + description: "" + title: created_at + type: object + executedAt: + $ref: '#/components/schemas/yorkie.v1.TimeTicket' + additionalProperties: false + description: "" + title: executed_at + type: object + parentCreatedAt: + $ref: '#/components/schemas/yorkie.v1.TimeTicket' + additionalProperties: false + description: "" + title: parent_created_at + type: object + value: + $ref: '#/components/schemas/yorkie.v1.JSONElementSimple' + additionalProperties: false + description: "" + title: value + type: object + title: ArraySet + type: object yorkie.v1.Operation.Edit: additionalProperties: false description: "" diff --git a/api/docs/yorkie/v1/yorkie.openapi.yaml b/api/docs/yorkie/v1/yorkie.openapi.yaml index 6e2ca097c..1f29856aa 100644 --- a/api/docs/yorkie/v1/yorkie.openapi.yaml +++ b/api/docs/yorkie/v1/yorkie.openapi.yaml @@ -3,7 +3,7 @@ info: description: Yorkie is an open source document store for building collaborative editing applications. title: Yorkie - version: v0.4.31 + version: v0.5.0 servers: - description: Production server url: https://api.yorkie.dev @@ -664,6 +664,12 @@ components: description: "" title: add type: object + arraySet: + $ref: '#/components/schemas/yorkie.v1.Operation.ArraySet' + additionalProperties: false + description: "" + title: array_set + type: object edit: $ref: '#/components/schemas/yorkie.v1.Operation.Edit' additionalProperties: false @@ -750,6 +756,36 @@ components: type: object title: Add type: object + yorkie.v1.Operation.ArraySet: + additionalProperties: false + description: "" + properties: + createdAt: + $ref: '#/components/schemas/yorkie.v1.TimeTicket' + additionalProperties: false + description: "" + title: created_at + type: object + executedAt: + $ref: '#/components/schemas/yorkie.v1.TimeTicket' + additionalProperties: false + description: "" + title: executed_at + type: object + parentCreatedAt: + $ref: '#/components/schemas/yorkie.v1.TimeTicket' + additionalProperties: false + description: "" + title: parent_created_at + type: object + value: + $ref: '#/components/schemas/yorkie.v1.JSONElementSimple' + additionalProperties: false + description: "" + title: value + type: object + title: ArraySet + type: object yorkie.v1.Operation.Edit: additionalProperties: false description: "" diff --git a/api/yorkie/v1/resources.pb.go b/api/yorkie/v1/resources.pb.go index ad76f5ca0..24899754d 100644 --- a/api/yorkie/v1/resources.pb.go +++ b/api/yorkie/v1/resources.pb.go @@ -529,6 +529,7 @@ type Operation struct { // *Operation_Increase_ // *Operation_TreeEdit_ // *Operation_TreeStyle_ + // *Operation_ArraySet_ Body isOperation_Body `protobuf_oneof:"body"` } @@ -641,6 +642,13 @@ func (x *Operation) GetTreeStyle() *Operation_TreeStyle { return nil } +func (x *Operation) GetArraySet() *Operation_ArraySet { + if x, ok := x.GetBody().(*Operation_ArraySet_); ok { + return x.ArraySet + } + return nil +} + type isOperation_Body interface { isOperation_Body() } @@ -685,6 +693,10 @@ type Operation_TreeStyle_ struct { TreeStyle *Operation_TreeStyle `protobuf:"bytes,10,opt,name=tree_style,json=treeStyle,proto3,oneof"` } +type Operation_ArraySet_ struct { + ArraySet *Operation_ArraySet `protobuf:"bytes,11,opt,name=array_set,json=arraySet,proto3,oneof"` +} + func (*Operation_Set_) isOperation_Body() {} func (*Operation_Add_) isOperation_Body() {} @@ -705,6 +717,8 @@ func (*Operation_TreeEdit_) isOperation_Body() {} func (*Operation_TreeStyle_) isOperation_Body() {} +func (*Operation_ArraySet_) isOperation_Body() {} + type JSONElementSimple struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -3007,6 +3021,77 @@ func (x *Operation_TreeStyle) GetCreatedAtMapByActor() map[string]*TimeTicket { return nil } +type Operation_ArraySet struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ParentCreatedAt *TimeTicket `protobuf:"bytes,1,opt,name=parent_created_at,json=parentCreatedAt,proto3" json:"parent_created_at,omitempty"` + CreatedAt *TimeTicket `protobuf:"bytes,2,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + Value *JSONElementSimple `protobuf:"bytes,3,opt,name=value,proto3" json:"value,omitempty"` + ExecutedAt *TimeTicket `protobuf:"bytes,4,opt,name=executed_at,json=executedAt,proto3" json:"executed_at,omitempty"` +} + +func (x *Operation_ArraySet) Reset() { + *x = Operation_ArraySet{} + if protoimpl.UnsafeEnabled { + mi := &file_yorkie_v1_resources_proto_msgTypes[38] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Operation_ArraySet) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Operation_ArraySet) ProtoMessage() {} + +func (x *Operation_ArraySet) ProtoReflect() protoreflect.Message { + mi := &file_yorkie_v1_resources_proto_msgTypes[38] + 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 Operation_ArraySet.ProtoReflect.Descriptor instead. +func (*Operation_ArraySet) Descriptor() ([]byte, []int) { + return file_yorkie_v1_resources_proto_rawDescGZIP(), []int{4, 10} +} + +func (x *Operation_ArraySet) GetParentCreatedAt() *TimeTicket { + if x != nil { + return x.ParentCreatedAt + } + return nil +} + +func (x *Operation_ArraySet) GetCreatedAt() *TimeTicket { + if x != nil { + return x.CreatedAt + } + return nil +} + +func (x *Operation_ArraySet) GetValue() *JSONElementSimple { + if x != nil { + return x.Value + } + return nil +} + +func (x *Operation_ArraySet) GetExecutedAt() *TimeTicket { + if x != nil { + return x.ExecutedAt + } + return nil +} + type JSONElement_JSONObject struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -3021,7 +3106,7 @@ type JSONElement_JSONObject struct { func (x *JSONElement_JSONObject) Reset() { *x = JSONElement_JSONObject{} if protoimpl.UnsafeEnabled { - mi := &file_yorkie_v1_resources_proto_msgTypes[45] + mi := &file_yorkie_v1_resources_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3034,7 +3119,7 @@ func (x *JSONElement_JSONObject) String() string { func (*JSONElement_JSONObject) ProtoMessage() {} func (x *JSONElement_JSONObject) ProtoReflect() protoreflect.Message { - mi := &file_yorkie_v1_resources_proto_msgTypes[45] + mi := &file_yorkie_v1_resources_proto_msgTypes[46] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3092,7 +3177,7 @@ type JSONElement_JSONArray struct { func (x *JSONElement_JSONArray) Reset() { *x = JSONElement_JSONArray{} if protoimpl.UnsafeEnabled { - mi := &file_yorkie_v1_resources_proto_msgTypes[46] + mi := &file_yorkie_v1_resources_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3105,7 +3190,7 @@ func (x *JSONElement_JSONArray) String() string { func (*JSONElement_JSONArray) ProtoMessage() {} func (x *JSONElement_JSONArray) ProtoReflect() protoreflect.Message { - mi := &file_yorkie_v1_resources_proto_msgTypes[46] + mi := &file_yorkie_v1_resources_proto_msgTypes[47] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3164,7 +3249,7 @@ type JSONElement_Primitive struct { func (x *JSONElement_Primitive) Reset() { *x = JSONElement_Primitive{} if protoimpl.UnsafeEnabled { - mi := &file_yorkie_v1_resources_proto_msgTypes[47] + mi := &file_yorkie_v1_resources_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3177,7 +3262,7 @@ func (x *JSONElement_Primitive) String() string { func (*JSONElement_Primitive) ProtoMessage() {} func (x *JSONElement_Primitive) ProtoReflect() protoreflect.Message { - mi := &file_yorkie_v1_resources_proto_msgTypes[47] + mi := &file_yorkie_v1_resources_proto_msgTypes[48] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3242,7 +3327,7 @@ type JSONElement_Text struct { func (x *JSONElement_Text) Reset() { *x = JSONElement_Text{} if protoimpl.UnsafeEnabled { - mi := &file_yorkie_v1_resources_proto_msgTypes[48] + mi := &file_yorkie_v1_resources_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3255,7 +3340,7 @@ func (x *JSONElement_Text) String() string { func (*JSONElement_Text) ProtoMessage() {} func (x *JSONElement_Text) ProtoReflect() protoreflect.Message { - mi := &file_yorkie_v1_resources_proto_msgTypes[48] + mi := &file_yorkie_v1_resources_proto_msgTypes[49] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3314,7 +3399,7 @@ type JSONElement_Counter struct { func (x *JSONElement_Counter) Reset() { *x = JSONElement_Counter{} if protoimpl.UnsafeEnabled { - mi := &file_yorkie_v1_resources_proto_msgTypes[49] + mi := &file_yorkie_v1_resources_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3327,7 +3412,7 @@ func (x *JSONElement_Counter) String() string { func (*JSONElement_Counter) ProtoMessage() {} func (x *JSONElement_Counter) ProtoReflect() protoreflect.Message { - mi := &file_yorkie_v1_resources_proto_msgTypes[49] + mi := &file_yorkie_v1_resources_proto_msgTypes[50] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3392,7 +3477,7 @@ type JSONElement_Tree struct { func (x *JSONElement_Tree) Reset() { *x = JSONElement_Tree{} if protoimpl.UnsafeEnabled { - mi := &file_yorkie_v1_resources_proto_msgTypes[50] + mi := &file_yorkie_v1_resources_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3405,7 +3490,7 @@ func (x *JSONElement_Tree) String() string { func (*JSONElement_Tree) ProtoMessage() {} func (x *JSONElement_Tree) ProtoReflect() protoreflect.Message { - mi := &file_yorkie_v1_resources_proto_msgTypes[50] + mi := &file_yorkie_v1_resources_proto_msgTypes[51] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3460,7 +3545,7 @@ type UpdatableProjectFields_AuthWebhookMethods struct { func (x *UpdatableProjectFields_AuthWebhookMethods) Reset() { *x = UpdatableProjectFields_AuthWebhookMethods{} if protoimpl.UnsafeEnabled { - mi := &file_yorkie_v1_resources_proto_msgTypes[53] + mi := &file_yorkie_v1_resources_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3473,7 +3558,7 @@ func (x *UpdatableProjectFields_AuthWebhookMethods) String() string { func (*UpdatableProjectFields_AuthWebhookMethods) ProtoMessage() {} func (x *UpdatableProjectFields_AuthWebhookMethods) ProtoReflect() protoreflect.Message { - mi := &file_yorkie_v1_resources_proto_msgTypes[53] + mi := &file_yorkie_v1_resources_proto_msgTypes[54] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3556,7 +3641,7 @@ var file_yorkie_v1_resources_proto_rawDesc = []byte{ 0x6c, 0x61, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x42, 0x02, 0x30, 0x01, 0x52, 0x07, 0x6c, 0x61, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x63, - 0x74, 0x6f, 0x72, 0x49, 0x64, 0x22, 0x84, 0x20, 0x0a, 0x09, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, + 0x74, 0x6f, 0x72, 0x49, 0x64, 0x22, 0xb4, 0x22, 0x0a, 0x09, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2c, 0x0a, 0x03, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x74, 0x48, 0x00, 0x52, 0x03, 0x73, 0x65, @@ -3590,229 +3675,248 @@ var file_yorkie_v1_resources_proto_rawDesc = []byte{ 0x0a, 0x0a, 0x74, 0x72, 0x65, 0x65, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x53, 0x74, 0x79, - 0x6c, 0x65, 0x48, 0x00, 0x52, 0x09, 0x74, 0x72, 0x65, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x1a, - 0xc6, 0x01, 0x0a, 0x03, 0x53, 0x65, 0x74, 0x12, 0x41, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x6c, 0x65, 0x48, 0x00, 0x52, 0x09, 0x74, 0x72, 0x65, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x12, + 0x3c, 0x0a, 0x09, 0x61, 0x72, 0x72, 0x61, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x18, 0x0b, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, + 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x41, 0x72, 0x72, 0x61, 0x79, 0x53, 0x65, + 0x74, 0x48, 0x00, 0x52, 0x08, 0x61, 0x72, 0x72, 0x61, 0x79, 0x53, 0x65, 0x74, 0x1a, 0xc6, 0x01, + 0x0a, 0x03, 0x53, 0x65, 0x74, 0x12, 0x41, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, + 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x32, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x79, 0x6f, 0x72, 0x6b, + 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x36, + 0x0a, 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, + 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x65, 0x63, + 0x75, 0x74, 0x65, 0x64, 0x41, 0x74, 0x1a, 0xf3, 0x01, 0x0a, 0x03, 0x41, 0x64, 0x64, 0x12, 0x41, + 0x0a, 0x11, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, + 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, + 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, + 0x52, 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, + 0x74, 0x12, 0x3d, 0x0a, 0x0f, 0x70, 0x72, 0x65, 0x76, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x64, 0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, + 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, + 0x74, 0x52, 0x0d, 0x70, 0x72, 0x65, 0x76, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, + 0x12, 0x32, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1c, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, + 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x52, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x12, 0x36, 0x0a, 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, + 0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, + 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, + 0x52, 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x41, 0x74, 0x1a, 0xf6, 0x01, 0x0a, + 0x04, 0x4d, 0x6f, 0x76, 0x65, 0x12, 0x41, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, + 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x3d, 0x0a, 0x0f, 0x70, 0x72, 0x65, 0x76, + 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, + 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0d, 0x70, 0x72, 0x65, 0x76, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x34, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, + 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, + 0x65, 0x74, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x36, 0x0a, + 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, - 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, - 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x32, 0x0a, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x79, 0x6f, - 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, 0x45, 0x6c, 0x65, 0x6d, - 0x65, 0x6e, 0x74, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x12, 0x36, 0x0a, 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0a, 0x65, 0x78, - 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x41, 0x74, 0x1a, 0xf3, 0x01, 0x0a, 0x03, 0x41, 0x64, 0x64, + 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, + 0x74, 0x65, 0x64, 0x41, 0x74, 0x1a, 0xb9, 0x01, 0x0a, 0x06, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x12, 0x41, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x64, 0x41, 0x74, 0x12, 0x3d, 0x0a, 0x0f, 0x70, 0x72, 0x65, 0x76, 0x5f, 0x63, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, + 0x64, 0x41, 0x74, 0x12, 0x34, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x09, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x36, 0x0a, 0x0b, 0x65, 0x78, 0x65, + 0x63, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, + 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, + 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x41, + 0x74, 0x1a, 0xc2, 0x04, 0x0a, 0x04, 0x45, 0x64, 0x69, 0x74, 0x12, 0x41, 0x0a, 0x11, 0x70, 0x61, + 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0f, 0x70, 0x61, + 0x72, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x2a, 0x0a, + 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x79, 0x6f, + 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x78, 0x74, 0x4e, 0x6f, 0x64, 0x65, + 0x50, 0x6f, 0x73, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x26, 0x0a, 0x02, 0x74, 0x6f, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x54, 0x65, 0x78, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x73, 0x52, 0x02, 0x74, + 0x6f, 0x12, 0x68, 0x0a, 0x17, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, + 0x6d, 0x61, 0x70, 0x5f, 0x62, 0x79, 0x5f, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, + 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x45, 0x64, 0x69, 0x74, 0x2e, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x61, 0x70, 0x42, 0x79, 0x41, 0x63, 0x74, 0x6f, + 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x13, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, + 0x74, 0x4d, 0x61, 0x70, 0x42, 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x36, 0x0a, 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, + 0x64, 0x5f, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, + 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, + 0x74, 0x52, 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x49, 0x0a, + 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x29, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x45, 0x64, 0x69, 0x74, 0x2e, 0x41, 0x74, 0x74, + 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x61, 0x74, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x1a, 0x5d, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x61, 0x70, 0x42, 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2b, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, + 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0xd7, 0x01, 0x0a, 0x06, 0x53, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x12, 0x41, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, - 0x6b, 0x65, 0x74, 0x52, 0x0d, 0x70, 0x72, 0x65, 0x76, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, - 0x41, 0x74, 0x12, 0x32, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1c, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x53, - 0x4f, 0x4e, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x52, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x36, 0x0a, 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, - 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, - 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, - 0x65, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x41, 0x74, 0x1a, 0xf6, - 0x01, 0x0a, 0x04, 0x4d, 0x6f, 0x76, 0x65, 0x12, 0x41, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x65, 0x6e, + 0x6b, 0x65, 0x74, 0x52, 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x64, 0x41, 0x74, 0x12, 0x2a, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, + 0x65, 0x78, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x73, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, + 0x12, 0x26, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x79, + 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x78, 0x74, 0x4e, 0x6f, 0x64, + 0x65, 0x50, 0x6f, 0x73, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x36, 0x0a, 0x0b, 0x65, 0x78, 0x65, 0x63, + 0x75, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, + 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, + 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x41, 0x74, + 0x1a, 0xab, 0x04, 0x0a, 0x05, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x12, 0x41, 0x0a, 0x11, 0x70, 0x61, + 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0f, 0x70, 0x61, + 0x72, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x2a, 0x0a, + 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x79, 0x6f, + 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x78, 0x74, 0x4e, 0x6f, 0x64, 0x65, + 0x50, 0x6f, 0x73, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x26, 0x0a, 0x02, 0x74, 0x6f, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x54, 0x65, 0x78, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x73, 0x52, 0x02, 0x74, + 0x6f, 0x12, 0x4a, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, + 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x79, 0x6c, + 0x65, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x36, 0x0a, + 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, + 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, + 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x69, 0x0a, 0x17, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, + 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x61, 0x70, 0x5f, 0x62, 0x79, 0x5f, 0x61, 0x63, 0x74, 0x6f, 0x72, + 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x79, + 0x6c, 0x65, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x61, 0x70, 0x42, + 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x13, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x61, 0x70, 0x42, 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, + 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, + 0x5d, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x61, 0x70, 0x42, + 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2b, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, + 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, + 0x6b, 0x65, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0xb9, + 0x01, 0x0a, 0x08, 0x49, 0x6e, 0x63, 0x72, 0x65, 0x61, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x11, 0x70, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0f, 0x70, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x32, + 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, + 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, 0x45, 0x6c, + 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x12, 0x36, 0x0a, 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x61, + 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0a, + 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x41, 0x74, 0x1a, 0xf1, 0x03, 0x0a, 0x08, 0x54, + 0x72, 0x65, 0x65, 0x45, 0x64, 0x69, 0x74, 0x12, 0x41, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x3d, 0x0a, 0x0f, 0x70, 0x72, - 0x65, 0x76, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0d, 0x70, 0x72, 0x65, 0x76, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x34, 0x0a, 0x0a, 0x63, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, - 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, - 0x63, 0x6b, 0x65, 0x74, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, - 0x36, 0x0a, 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x65, - 0x63, 0x75, 0x74, 0x65, 0x64, 0x41, 0x74, 0x1a, 0xb9, 0x01, 0x0a, 0x06, 0x52, 0x65, 0x6d, 0x6f, - 0x76, 0x65, 0x12, 0x41, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, - 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, - 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x34, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, - 0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, - 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, - 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x36, 0x0a, 0x0b, 0x65, - 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, - 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, - 0x64, 0x41, 0x74, 0x1a, 0xc2, 0x04, 0x0a, 0x04, 0x45, 0x64, 0x69, 0x74, 0x12, 0x41, 0x0a, 0x11, - 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, - 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0f, - 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, - 0x2a, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, - 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x78, 0x74, 0x4e, 0x6f, - 0x64, 0x65, 0x50, 0x6f, 0x73, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x26, 0x0a, 0x02, 0x74, - 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x78, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x73, 0x52, - 0x02, 0x74, 0x6f, 0x12, 0x68, 0x0a, 0x17, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, - 0x74, 0x5f, 0x6d, 0x61, 0x70, 0x5f, 0x62, 0x79, 0x5f, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x04, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x45, 0x64, 0x69, 0x74, 0x2e, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x61, 0x70, 0x42, 0x79, 0x41, 0x63, - 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x13, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x64, 0x41, 0x74, 0x4d, 0x61, 0x70, 0x42, 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x18, 0x0a, - 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x36, 0x0a, 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, + 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x26, 0x0a, 0x04, 0x66, 0x72, + 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, + 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x50, 0x6f, 0x73, 0x52, 0x04, 0x66, 0x72, + 0x6f, 0x6d, 0x12, 0x22, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, + 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x50, + 0x6f, 0x73, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x6c, 0x0a, 0x17, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x61, 0x70, 0x5f, 0x62, 0x79, 0x5f, 0x61, 0x63, 0x74, 0x6f, + 0x72, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x54, 0x72, + 0x65, 0x65, 0x45, 0x64, 0x69, 0x74, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, + 0x4d, 0x61, 0x70, 0x42, 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x13, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x61, 0x70, 0x42, 0x79, 0x41, + 0x63, 0x74, 0x6f, 0x72, 0x12, 0x30, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, + 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x52, 0x08, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x5f, + 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x73, 0x70, 0x6c, + 0x69, 0x74, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x36, 0x0a, 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, - 0x6b, 0x65, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, - 0x49, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x07, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x45, 0x64, 0x69, 0x74, 0x2e, 0x41, - 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, - 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x1a, 0x5d, 0x0a, 0x18, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x61, 0x70, 0x42, 0x79, 0x41, 0x63, 0x74, 0x6f, - 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2b, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, - 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, - 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, - 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0xd7, 0x01, 0x0a, 0x06, 0x53, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x12, 0x41, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, - 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, - 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x2a, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x54, 0x65, 0x78, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x73, 0x52, 0x04, 0x66, 0x72, - 0x6f, 0x6d, 0x12, 0x26, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, - 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x78, 0x74, 0x4e, - 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x73, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x36, 0x0a, 0x0b, 0x65, 0x78, - 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, - 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, - 0x41, 0x74, 0x1a, 0xab, 0x04, 0x0a, 0x05, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x12, 0x41, 0x0a, 0x11, + 0x6b, 0x65, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x41, 0x74, 0x1a, + 0x5d, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x61, 0x70, 0x42, + 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2b, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, + 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, + 0x6b, 0x65, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0xe1, + 0x04, 0x0a, 0x09, 0x54, 0x72, 0x65, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x12, 0x41, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, - 0x2a, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, - 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x78, 0x74, 0x4e, 0x6f, - 0x64, 0x65, 0x50, 0x6f, 0x73, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x26, 0x0a, 0x02, 0x74, - 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x78, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x73, 0x52, - 0x02, 0x74, 0x6f, 0x12, 0x4a, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, - 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x53, 0x74, - 0x79, 0x6c, 0x65, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, - 0x36, 0x0a, 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x65, - 0x63, 0x75, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x69, 0x0a, 0x17, 0x63, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x61, 0x70, 0x5f, 0x62, 0x79, 0x5f, 0x61, 0x63, 0x74, - 0x6f, 0x72, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x53, - 0x74, 0x79, 0x6c, 0x65, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x61, - 0x70, 0x42, 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x13, 0x63, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x61, 0x70, 0x42, 0x79, 0x41, 0x63, 0x74, - 0x6f, 0x72, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, - 0x01, 0x1a, 0x5d, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x61, - 0x70, 0x42, 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, - 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, - 0x2b, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, - 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, - 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, - 0x1a, 0xb9, 0x01, 0x0a, 0x08, 0x49, 0x6e, 0x63, 0x72, 0x65, 0x61, 0x73, 0x65, 0x12, 0x41, 0x0a, - 0x11, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, - 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, - 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, - 0x12, 0x32, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1c, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, - 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x52, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x12, 0x36, 0x0a, 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, - 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, - 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, - 0x52, 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x41, 0x74, 0x1a, 0xf1, 0x03, 0x0a, - 0x08, 0x54, 0x72, 0x65, 0x65, 0x45, 0x64, 0x69, 0x74, 0x12, 0x41, 0x0a, 0x11, 0x70, 0x61, 0x72, - 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0f, 0x70, 0x61, 0x72, - 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x26, 0x0a, 0x04, - 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x79, 0x6f, 0x72, - 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x50, 0x6f, 0x73, 0x52, 0x04, - 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x22, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x12, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x65, - 0x65, 0x50, 0x6f, 0x73, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x6c, 0x0a, 0x17, 0x63, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x61, 0x70, 0x5f, 0x62, 0x79, 0x5f, 0x61, 0x63, - 0x74, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x79, 0x6f, 0x72, 0x6b, - 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, - 0x54, 0x72, 0x65, 0x65, 0x45, 0x64, 0x69, 0x74, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, - 0x41, 0x74, 0x4d, 0x61, 0x70, 0x42, 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x52, 0x13, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x61, 0x70, 0x42, - 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x30, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x52, 0x08, - 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x70, 0x6c, 0x69, - 0x74, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x73, - 0x70, 0x6c, 0x69, 0x74, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x36, 0x0a, 0x0b, 0x65, 0x78, 0x65, - 0x63, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, - 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, - 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x41, - 0x74, 0x1a, 0x5d, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x61, - 0x70, 0x42, 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, - 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, - 0x2b, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, - 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, - 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, - 0x1a, 0xe1, 0x04, 0x0a, 0x09, 0x54, 0x72, 0x65, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x12, 0x41, - 0x0a, 0x11, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, - 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, - 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, - 0x52, 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, - 0x74, 0x12, 0x26, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x12, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x65, 0x65, - 0x50, 0x6f, 0x73, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x22, 0x0a, 0x02, 0x74, 0x6f, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x50, 0x6f, 0x73, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x4e, 0x0a, - 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x2e, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, - 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x53, 0x74, 0x79, 0x6c, - 0x65, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x36, 0x0a, - 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, - 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, - 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x30, 0x0a, 0x14, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, - 0x74, 0x65, 0x73, 0x5f, 0x74, 0x6f, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x18, 0x06, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x12, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x54, - 0x6f, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x12, 0x6d, 0x0a, 0x17, 0x63, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x61, 0x70, 0x5f, 0x62, 0x79, 0x5f, 0x61, 0x63, 0x74, - 0x6f, 0x72, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x54, - 0x72, 0x65, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, - 0x41, 0x74, 0x4d, 0x61, 0x70, 0x42, 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x52, 0x13, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x61, 0x70, 0x42, - 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, - 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x5d, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, - 0x41, 0x74, 0x4d, 0x61, 0x70, 0x42, 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x6b, 0x65, 0x79, 0x12, 0x2b, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, - 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x3a, 0x02, 0x38, 0x01, 0x42, 0x06, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x22, 0xf1, 0x01, 0x0a, + 0x26, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, + 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x50, 0x6f, + 0x73, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x22, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, + 0x54, 0x72, 0x65, 0x65, 0x50, 0x6f, 0x73, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x4e, 0x0a, 0x0a, 0x61, + 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x2e, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x2e, + 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x36, 0x0a, 0x0b, 0x65, + 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, + 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, + 0x64, 0x41, 0x74, 0x12, 0x30, 0x0a, 0x14, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, + 0x73, 0x5f, 0x74, 0x6f, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x18, 0x06, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x12, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x54, 0x6f, 0x52, + 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x12, 0x6d, 0x0a, 0x17, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, + 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x61, 0x70, 0x5f, 0x62, 0x79, 0x5f, 0x61, 0x63, 0x74, 0x6f, 0x72, + 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x54, 0x72, 0x65, + 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, + 0x4d, 0x61, 0x70, 0x42, 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x13, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x61, 0x70, 0x42, 0x79, 0x41, + 0x63, 0x74, 0x6f, 0x72, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, + 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, + 0x02, 0x38, 0x01, 0x1a, 0x5d, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, + 0x4d, 0x61, 0x70, 0x42, 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x12, 0x2b, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, + 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, + 0x38, 0x01, 0x1a, 0xef, 0x01, 0x0a, 0x08, 0x41, 0x72, 0x72, 0x61, 0x79, 0x53, 0x65, 0x74, 0x12, + 0x41, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x64, 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, + 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, + 0x74, 0x52, 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, + 0x41, 0x74, 0x12, 0x34, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x09, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x32, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x53, + 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x36, 0x0a, 0x0b, + 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, + 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, + 0x65, 0x64, 0x41, 0x74, 0x42, 0x06, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x22, 0xf1, 0x01, 0x0a, 0x11, 0x4a, 0x53, 0x4f, 0x4e, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x12, 0x34, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, @@ -4203,7 +4307,7 @@ func file_yorkie_v1_resources_proto_rawDescGZIP() []byte { } var file_yorkie_v1_resources_proto_enumTypes = make([]protoimpl.EnumInfo, 3) -var file_yorkie_v1_resources_proto_msgTypes = make([]protoimpl.MessageInfo, 55) +var file_yorkie_v1_resources_proto_msgTypes = make([]protoimpl.MessageInfo, 56) var file_yorkie_v1_resources_proto_goTypes = []interface{}{ (ValueType)(0), // 0: yorkie.v1.ValueType (DocEventType)(0), // 1: yorkie.v1.DocEventType @@ -4246,25 +4350,26 @@ var file_yorkie_v1_resources_proto_goTypes = []interface{}{ (*Operation_Increase)(nil), // 38: yorkie.v1.Operation.Increase (*Operation_TreeEdit)(nil), // 39: yorkie.v1.Operation.TreeEdit (*Operation_TreeStyle)(nil), // 40: yorkie.v1.Operation.TreeStyle - nil, // 41: yorkie.v1.Operation.Edit.CreatedAtMapByActorEntry - nil, // 42: yorkie.v1.Operation.Edit.AttributesEntry - nil, // 43: yorkie.v1.Operation.Style.AttributesEntry - nil, // 44: yorkie.v1.Operation.Style.CreatedAtMapByActorEntry - nil, // 45: yorkie.v1.Operation.TreeEdit.CreatedAtMapByActorEntry - nil, // 46: yorkie.v1.Operation.TreeStyle.AttributesEntry - nil, // 47: yorkie.v1.Operation.TreeStyle.CreatedAtMapByActorEntry - (*JSONElement_JSONObject)(nil), // 48: yorkie.v1.JSONElement.JSONObject - (*JSONElement_JSONArray)(nil), // 49: yorkie.v1.JSONElement.JSONArray - (*JSONElement_Primitive)(nil), // 50: yorkie.v1.JSONElement.Primitive - (*JSONElement_Text)(nil), // 51: yorkie.v1.JSONElement.Text - (*JSONElement_Counter)(nil), // 52: yorkie.v1.JSONElement.Counter - (*JSONElement_Tree)(nil), // 53: yorkie.v1.JSONElement.Tree - nil, // 54: yorkie.v1.TextNode.AttributesEntry - nil, // 55: yorkie.v1.TreeNode.AttributesEntry - (*UpdatableProjectFields_AuthWebhookMethods)(nil), // 56: yorkie.v1.UpdatableProjectFields.AuthWebhookMethods - nil, // 57: yorkie.v1.Presence.DataEntry - (*timestamppb.Timestamp)(nil), // 58: google.protobuf.Timestamp - (*wrapperspb.StringValue)(nil), // 59: google.protobuf.StringValue + (*Operation_ArraySet)(nil), // 41: yorkie.v1.Operation.ArraySet + nil, // 42: yorkie.v1.Operation.Edit.CreatedAtMapByActorEntry + nil, // 43: yorkie.v1.Operation.Edit.AttributesEntry + nil, // 44: yorkie.v1.Operation.Style.AttributesEntry + nil, // 45: yorkie.v1.Operation.Style.CreatedAtMapByActorEntry + nil, // 46: yorkie.v1.Operation.TreeEdit.CreatedAtMapByActorEntry + nil, // 47: yorkie.v1.Operation.TreeStyle.AttributesEntry + nil, // 48: yorkie.v1.Operation.TreeStyle.CreatedAtMapByActorEntry + (*JSONElement_JSONObject)(nil), // 49: yorkie.v1.JSONElement.JSONObject + (*JSONElement_JSONArray)(nil), // 50: yorkie.v1.JSONElement.JSONArray + (*JSONElement_Primitive)(nil), // 51: yorkie.v1.JSONElement.Primitive + (*JSONElement_Text)(nil), // 52: yorkie.v1.JSONElement.Text + (*JSONElement_Counter)(nil), // 53: yorkie.v1.JSONElement.Counter + (*JSONElement_Tree)(nil), // 54: yorkie.v1.JSONElement.Tree + nil, // 55: yorkie.v1.TextNode.AttributesEntry + nil, // 56: yorkie.v1.TreeNode.AttributesEntry + (*UpdatableProjectFields_AuthWebhookMethods)(nil), // 57: yorkie.v1.UpdatableProjectFields.AuthWebhookMethods + nil, // 58: yorkie.v1.Presence.DataEntry + (*timestamppb.Timestamp)(nil), // 59: google.protobuf.Timestamp + (*wrapperspb.StringValue)(nil), // 60: google.protobuf.StringValue } var file_yorkie_v1_resources_proto_depIdxs = []int32{ 9, // 0: yorkie.v1.Snapshot.root:type_name -> yorkie.v1.JSONElement @@ -4285,131 +4390,136 @@ var file_yorkie_v1_resources_proto_depIdxs = []int32{ 38, // 15: yorkie.v1.Operation.increase:type_name -> yorkie.v1.Operation.Increase 39, // 16: yorkie.v1.Operation.tree_edit:type_name -> yorkie.v1.Operation.TreeEdit 40, // 17: yorkie.v1.Operation.tree_style:type_name -> yorkie.v1.Operation.TreeStyle - 27, // 18: yorkie.v1.JSONElementSimple.created_at:type_name -> yorkie.v1.TimeTicket - 27, // 19: yorkie.v1.JSONElementSimple.moved_at:type_name -> yorkie.v1.TimeTicket - 27, // 20: yorkie.v1.JSONElementSimple.removed_at:type_name -> yorkie.v1.TimeTicket - 0, // 21: yorkie.v1.JSONElementSimple.type:type_name -> yorkie.v1.ValueType - 48, // 22: yorkie.v1.JSONElement.json_object:type_name -> yorkie.v1.JSONElement.JSONObject - 49, // 23: yorkie.v1.JSONElement.json_array:type_name -> yorkie.v1.JSONElement.JSONArray - 50, // 24: yorkie.v1.JSONElement.primitive:type_name -> yorkie.v1.JSONElement.Primitive - 51, // 25: yorkie.v1.JSONElement.text:type_name -> yorkie.v1.JSONElement.Text - 52, // 26: yorkie.v1.JSONElement.counter:type_name -> yorkie.v1.JSONElement.Counter - 53, // 27: yorkie.v1.JSONElement.tree:type_name -> yorkie.v1.JSONElement.Tree - 9, // 28: yorkie.v1.RHTNode.element:type_name -> yorkie.v1.JSONElement - 11, // 29: yorkie.v1.RGANode.next:type_name -> yorkie.v1.RGANode - 9, // 30: yorkie.v1.RGANode.element:type_name -> yorkie.v1.JSONElement - 27, // 31: yorkie.v1.NodeAttr.updated_at:type_name -> yorkie.v1.TimeTicket - 14, // 32: yorkie.v1.TextNode.id:type_name -> yorkie.v1.TextNodeID - 27, // 33: yorkie.v1.TextNode.removed_at:type_name -> yorkie.v1.TimeTicket - 14, // 34: yorkie.v1.TextNode.ins_prev_id:type_name -> yorkie.v1.TextNodeID - 54, // 35: yorkie.v1.TextNode.attributes:type_name -> yorkie.v1.TextNode.AttributesEntry - 27, // 36: yorkie.v1.TextNodeID.created_at:type_name -> yorkie.v1.TimeTicket - 17, // 37: yorkie.v1.TreeNode.id:type_name -> yorkie.v1.TreeNodeID - 27, // 38: yorkie.v1.TreeNode.removed_at:type_name -> yorkie.v1.TimeTicket - 17, // 39: yorkie.v1.TreeNode.ins_prev_id:type_name -> yorkie.v1.TreeNodeID - 17, // 40: yorkie.v1.TreeNode.ins_next_id:type_name -> yorkie.v1.TreeNodeID - 55, // 41: yorkie.v1.TreeNode.attributes:type_name -> yorkie.v1.TreeNode.AttributesEntry - 15, // 42: yorkie.v1.TreeNodes.content:type_name -> yorkie.v1.TreeNode - 27, // 43: yorkie.v1.TreeNodeID.created_at:type_name -> yorkie.v1.TimeTicket - 17, // 44: yorkie.v1.TreePos.parent_id:type_name -> yorkie.v1.TreeNodeID - 17, // 45: yorkie.v1.TreePos.left_sibling_id:type_name -> yorkie.v1.TreeNodeID - 58, // 46: yorkie.v1.User.created_at:type_name -> google.protobuf.Timestamp - 58, // 47: yorkie.v1.Project.created_at:type_name -> google.protobuf.Timestamp - 58, // 48: yorkie.v1.Project.updated_at:type_name -> google.protobuf.Timestamp - 59, // 49: yorkie.v1.UpdatableProjectFields.name:type_name -> google.protobuf.StringValue - 59, // 50: yorkie.v1.UpdatableProjectFields.auth_webhook_url:type_name -> google.protobuf.StringValue - 56, // 51: yorkie.v1.UpdatableProjectFields.auth_webhook_methods:type_name -> yorkie.v1.UpdatableProjectFields.AuthWebhookMethods - 59, // 52: yorkie.v1.UpdatableProjectFields.client_deactivate_threshold:type_name -> google.protobuf.StringValue - 58, // 53: yorkie.v1.DocumentSummary.created_at:type_name -> google.protobuf.Timestamp - 58, // 54: yorkie.v1.DocumentSummary.accessed_at:type_name -> google.protobuf.Timestamp - 58, // 55: yorkie.v1.DocumentSummary.updated_at:type_name -> google.protobuf.Timestamp - 2, // 56: yorkie.v1.PresenceChange.type:type_name -> yorkie.v1.PresenceChange.ChangeType - 24, // 57: yorkie.v1.PresenceChange.presence:type_name -> yorkie.v1.Presence - 57, // 58: yorkie.v1.Presence.data:type_name -> yorkie.v1.Presence.DataEntry - 27, // 59: yorkie.v1.TextNodePos.created_at:type_name -> yorkie.v1.TimeTicket - 1, // 60: yorkie.v1.DocEvent.type:type_name -> yorkie.v1.DocEventType - 28, // 61: yorkie.v1.DocEvent.body:type_name -> yorkie.v1.DocEventBody - 24, // 62: yorkie.v1.Snapshot.PresencesEntry.value:type_name -> yorkie.v1.Presence - 27, // 63: yorkie.v1.Operation.Set.parent_created_at:type_name -> yorkie.v1.TimeTicket - 8, // 64: yorkie.v1.Operation.Set.value:type_name -> yorkie.v1.JSONElementSimple - 27, // 65: yorkie.v1.Operation.Set.executed_at:type_name -> yorkie.v1.TimeTicket - 27, // 66: yorkie.v1.Operation.Add.parent_created_at:type_name -> yorkie.v1.TimeTicket - 27, // 67: yorkie.v1.Operation.Add.prev_created_at:type_name -> yorkie.v1.TimeTicket - 8, // 68: yorkie.v1.Operation.Add.value:type_name -> yorkie.v1.JSONElementSimple - 27, // 69: yorkie.v1.Operation.Add.executed_at:type_name -> yorkie.v1.TimeTicket - 27, // 70: yorkie.v1.Operation.Move.parent_created_at:type_name -> yorkie.v1.TimeTicket - 27, // 71: yorkie.v1.Operation.Move.prev_created_at:type_name -> yorkie.v1.TimeTicket - 27, // 72: yorkie.v1.Operation.Move.created_at:type_name -> yorkie.v1.TimeTicket - 27, // 73: yorkie.v1.Operation.Move.executed_at:type_name -> yorkie.v1.TimeTicket - 27, // 74: yorkie.v1.Operation.Remove.parent_created_at:type_name -> yorkie.v1.TimeTicket - 27, // 75: yorkie.v1.Operation.Remove.created_at:type_name -> yorkie.v1.TimeTicket - 27, // 76: yorkie.v1.Operation.Remove.executed_at:type_name -> yorkie.v1.TimeTicket - 27, // 77: yorkie.v1.Operation.Edit.parent_created_at:type_name -> yorkie.v1.TimeTicket - 26, // 78: yorkie.v1.Operation.Edit.from:type_name -> yorkie.v1.TextNodePos - 26, // 79: yorkie.v1.Operation.Edit.to:type_name -> yorkie.v1.TextNodePos - 41, // 80: yorkie.v1.Operation.Edit.created_at_map_by_actor:type_name -> yorkie.v1.Operation.Edit.CreatedAtMapByActorEntry - 27, // 81: yorkie.v1.Operation.Edit.executed_at:type_name -> yorkie.v1.TimeTicket - 42, // 82: yorkie.v1.Operation.Edit.attributes:type_name -> yorkie.v1.Operation.Edit.AttributesEntry - 27, // 83: yorkie.v1.Operation.Select.parent_created_at:type_name -> yorkie.v1.TimeTicket - 26, // 84: yorkie.v1.Operation.Select.from:type_name -> yorkie.v1.TextNodePos - 26, // 85: yorkie.v1.Operation.Select.to:type_name -> yorkie.v1.TextNodePos - 27, // 86: yorkie.v1.Operation.Select.executed_at:type_name -> yorkie.v1.TimeTicket - 27, // 87: yorkie.v1.Operation.Style.parent_created_at:type_name -> yorkie.v1.TimeTicket - 26, // 88: yorkie.v1.Operation.Style.from:type_name -> yorkie.v1.TextNodePos - 26, // 89: yorkie.v1.Operation.Style.to:type_name -> yorkie.v1.TextNodePos - 43, // 90: yorkie.v1.Operation.Style.attributes:type_name -> yorkie.v1.Operation.Style.AttributesEntry - 27, // 91: yorkie.v1.Operation.Style.executed_at:type_name -> yorkie.v1.TimeTicket - 44, // 92: yorkie.v1.Operation.Style.created_at_map_by_actor:type_name -> yorkie.v1.Operation.Style.CreatedAtMapByActorEntry - 27, // 93: yorkie.v1.Operation.Increase.parent_created_at:type_name -> yorkie.v1.TimeTicket - 8, // 94: yorkie.v1.Operation.Increase.value:type_name -> yorkie.v1.JSONElementSimple - 27, // 95: yorkie.v1.Operation.Increase.executed_at:type_name -> yorkie.v1.TimeTicket - 27, // 96: yorkie.v1.Operation.TreeEdit.parent_created_at:type_name -> yorkie.v1.TimeTicket - 18, // 97: yorkie.v1.Operation.TreeEdit.from:type_name -> yorkie.v1.TreePos - 18, // 98: yorkie.v1.Operation.TreeEdit.to:type_name -> yorkie.v1.TreePos - 45, // 99: yorkie.v1.Operation.TreeEdit.created_at_map_by_actor:type_name -> yorkie.v1.Operation.TreeEdit.CreatedAtMapByActorEntry - 16, // 100: yorkie.v1.Operation.TreeEdit.contents:type_name -> yorkie.v1.TreeNodes - 27, // 101: yorkie.v1.Operation.TreeEdit.executed_at:type_name -> yorkie.v1.TimeTicket - 27, // 102: yorkie.v1.Operation.TreeStyle.parent_created_at:type_name -> yorkie.v1.TimeTicket - 18, // 103: yorkie.v1.Operation.TreeStyle.from:type_name -> yorkie.v1.TreePos - 18, // 104: yorkie.v1.Operation.TreeStyle.to:type_name -> yorkie.v1.TreePos - 46, // 105: yorkie.v1.Operation.TreeStyle.attributes:type_name -> yorkie.v1.Operation.TreeStyle.AttributesEntry - 27, // 106: yorkie.v1.Operation.TreeStyle.executed_at:type_name -> yorkie.v1.TimeTicket - 47, // 107: yorkie.v1.Operation.TreeStyle.created_at_map_by_actor:type_name -> yorkie.v1.Operation.TreeStyle.CreatedAtMapByActorEntry - 27, // 108: yorkie.v1.Operation.Edit.CreatedAtMapByActorEntry.value:type_name -> yorkie.v1.TimeTicket - 27, // 109: yorkie.v1.Operation.Style.CreatedAtMapByActorEntry.value:type_name -> yorkie.v1.TimeTicket - 27, // 110: yorkie.v1.Operation.TreeEdit.CreatedAtMapByActorEntry.value:type_name -> yorkie.v1.TimeTicket - 27, // 111: yorkie.v1.Operation.TreeStyle.CreatedAtMapByActorEntry.value:type_name -> yorkie.v1.TimeTicket - 10, // 112: yorkie.v1.JSONElement.JSONObject.nodes:type_name -> yorkie.v1.RHTNode - 27, // 113: yorkie.v1.JSONElement.JSONObject.created_at:type_name -> yorkie.v1.TimeTicket - 27, // 114: yorkie.v1.JSONElement.JSONObject.moved_at:type_name -> yorkie.v1.TimeTicket - 27, // 115: yorkie.v1.JSONElement.JSONObject.removed_at:type_name -> yorkie.v1.TimeTicket - 11, // 116: yorkie.v1.JSONElement.JSONArray.nodes:type_name -> yorkie.v1.RGANode - 27, // 117: yorkie.v1.JSONElement.JSONArray.created_at:type_name -> yorkie.v1.TimeTicket - 27, // 118: yorkie.v1.JSONElement.JSONArray.moved_at:type_name -> yorkie.v1.TimeTicket - 27, // 119: yorkie.v1.JSONElement.JSONArray.removed_at:type_name -> yorkie.v1.TimeTicket - 0, // 120: yorkie.v1.JSONElement.Primitive.type:type_name -> yorkie.v1.ValueType - 27, // 121: yorkie.v1.JSONElement.Primitive.created_at:type_name -> yorkie.v1.TimeTicket - 27, // 122: yorkie.v1.JSONElement.Primitive.moved_at:type_name -> yorkie.v1.TimeTicket - 27, // 123: yorkie.v1.JSONElement.Primitive.removed_at:type_name -> yorkie.v1.TimeTicket - 13, // 124: yorkie.v1.JSONElement.Text.nodes:type_name -> yorkie.v1.TextNode - 27, // 125: yorkie.v1.JSONElement.Text.created_at:type_name -> yorkie.v1.TimeTicket - 27, // 126: yorkie.v1.JSONElement.Text.moved_at:type_name -> yorkie.v1.TimeTicket - 27, // 127: yorkie.v1.JSONElement.Text.removed_at:type_name -> yorkie.v1.TimeTicket - 0, // 128: yorkie.v1.JSONElement.Counter.type:type_name -> yorkie.v1.ValueType - 27, // 129: yorkie.v1.JSONElement.Counter.created_at:type_name -> yorkie.v1.TimeTicket - 27, // 130: yorkie.v1.JSONElement.Counter.moved_at:type_name -> yorkie.v1.TimeTicket - 27, // 131: yorkie.v1.JSONElement.Counter.removed_at:type_name -> yorkie.v1.TimeTicket - 15, // 132: yorkie.v1.JSONElement.Tree.nodes:type_name -> yorkie.v1.TreeNode - 27, // 133: yorkie.v1.JSONElement.Tree.created_at:type_name -> yorkie.v1.TimeTicket - 27, // 134: yorkie.v1.JSONElement.Tree.moved_at:type_name -> yorkie.v1.TimeTicket - 27, // 135: yorkie.v1.JSONElement.Tree.removed_at:type_name -> yorkie.v1.TimeTicket - 12, // 136: yorkie.v1.TextNode.AttributesEntry.value:type_name -> yorkie.v1.NodeAttr - 12, // 137: yorkie.v1.TreeNode.AttributesEntry.value:type_name -> yorkie.v1.NodeAttr - 138, // [138:138] is the sub-list for method output_type - 138, // [138:138] is the sub-list for method input_type - 138, // [138:138] is the sub-list for extension type_name - 138, // [138:138] is the sub-list for extension extendee - 0, // [0:138] is the sub-list for field type_name + 41, // 18: yorkie.v1.Operation.array_set:type_name -> yorkie.v1.Operation.ArraySet + 27, // 19: yorkie.v1.JSONElementSimple.created_at:type_name -> yorkie.v1.TimeTicket + 27, // 20: yorkie.v1.JSONElementSimple.moved_at:type_name -> yorkie.v1.TimeTicket + 27, // 21: yorkie.v1.JSONElementSimple.removed_at:type_name -> yorkie.v1.TimeTicket + 0, // 22: yorkie.v1.JSONElementSimple.type:type_name -> yorkie.v1.ValueType + 49, // 23: yorkie.v1.JSONElement.json_object:type_name -> yorkie.v1.JSONElement.JSONObject + 50, // 24: yorkie.v1.JSONElement.json_array:type_name -> yorkie.v1.JSONElement.JSONArray + 51, // 25: yorkie.v1.JSONElement.primitive:type_name -> yorkie.v1.JSONElement.Primitive + 52, // 26: yorkie.v1.JSONElement.text:type_name -> yorkie.v1.JSONElement.Text + 53, // 27: yorkie.v1.JSONElement.counter:type_name -> yorkie.v1.JSONElement.Counter + 54, // 28: yorkie.v1.JSONElement.tree:type_name -> yorkie.v1.JSONElement.Tree + 9, // 29: yorkie.v1.RHTNode.element:type_name -> yorkie.v1.JSONElement + 11, // 30: yorkie.v1.RGANode.next:type_name -> yorkie.v1.RGANode + 9, // 31: yorkie.v1.RGANode.element:type_name -> yorkie.v1.JSONElement + 27, // 32: yorkie.v1.NodeAttr.updated_at:type_name -> yorkie.v1.TimeTicket + 14, // 33: yorkie.v1.TextNode.id:type_name -> yorkie.v1.TextNodeID + 27, // 34: yorkie.v1.TextNode.removed_at:type_name -> yorkie.v1.TimeTicket + 14, // 35: yorkie.v1.TextNode.ins_prev_id:type_name -> yorkie.v1.TextNodeID + 55, // 36: yorkie.v1.TextNode.attributes:type_name -> yorkie.v1.TextNode.AttributesEntry + 27, // 37: yorkie.v1.TextNodeID.created_at:type_name -> yorkie.v1.TimeTicket + 17, // 38: yorkie.v1.TreeNode.id:type_name -> yorkie.v1.TreeNodeID + 27, // 39: yorkie.v1.TreeNode.removed_at:type_name -> yorkie.v1.TimeTicket + 17, // 40: yorkie.v1.TreeNode.ins_prev_id:type_name -> yorkie.v1.TreeNodeID + 17, // 41: yorkie.v1.TreeNode.ins_next_id:type_name -> yorkie.v1.TreeNodeID + 56, // 42: yorkie.v1.TreeNode.attributes:type_name -> yorkie.v1.TreeNode.AttributesEntry + 15, // 43: yorkie.v1.TreeNodes.content:type_name -> yorkie.v1.TreeNode + 27, // 44: yorkie.v1.TreeNodeID.created_at:type_name -> yorkie.v1.TimeTicket + 17, // 45: yorkie.v1.TreePos.parent_id:type_name -> yorkie.v1.TreeNodeID + 17, // 46: yorkie.v1.TreePos.left_sibling_id:type_name -> yorkie.v1.TreeNodeID + 59, // 47: yorkie.v1.User.created_at:type_name -> google.protobuf.Timestamp + 59, // 48: yorkie.v1.Project.created_at:type_name -> google.protobuf.Timestamp + 59, // 49: yorkie.v1.Project.updated_at:type_name -> google.protobuf.Timestamp + 60, // 50: yorkie.v1.UpdatableProjectFields.name:type_name -> google.protobuf.StringValue + 60, // 51: yorkie.v1.UpdatableProjectFields.auth_webhook_url:type_name -> google.protobuf.StringValue + 57, // 52: yorkie.v1.UpdatableProjectFields.auth_webhook_methods:type_name -> yorkie.v1.UpdatableProjectFields.AuthWebhookMethods + 60, // 53: yorkie.v1.UpdatableProjectFields.client_deactivate_threshold:type_name -> google.protobuf.StringValue + 59, // 54: yorkie.v1.DocumentSummary.created_at:type_name -> google.protobuf.Timestamp + 59, // 55: yorkie.v1.DocumentSummary.accessed_at:type_name -> google.protobuf.Timestamp + 59, // 56: yorkie.v1.DocumentSummary.updated_at:type_name -> google.protobuf.Timestamp + 2, // 57: yorkie.v1.PresenceChange.type:type_name -> yorkie.v1.PresenceChange.ChangeType + 24, // 58: yorkie.v1.PresenceChange.presence:type_name -> yorkie.v1.Presence + 58, // 59: yorkie.v1.Presence.data:type_name -> yorkie.v1.Presence.DataEntry + 27, // 60: yorkie.v1.TextNodePos.created_at:type_name -> yorkie.v1.TimeTicket + 1, // 61: yorkie.v1.DocEvent.type:type_name -> yorkie.v1.DocEventType + 28, // 62: yorkie.v1.DocEvent.body:type_name -> yorkie.v1.DocEventBody + 24, // 63: yorkie.v1.Snapshot.PresencesEntry.value:type_name -> yorkie.v1.Presence + 27, // 64: yorkie.v1.Operation.Set.parent_created_at:type_name -> yorkie.v1.TimeTicket + 8, // 65: yorkie.v1.Operation.Set.value:type_name -> yorkie.v1.JSONElementSimple + 27, // 66: yorkie.v1.Operation.Set.executed_at:type_name -> yorkie.v1.TimeTicket + 27, // 67: yorkie.v1.Operation.Add.parent_created_at:type_name -> yorkie.v1.TimeTicket + 27, // 68: yorkie.v1.Operation.Add.prev_created_at:type_name -> yorkie.v1.TimeTicket + 8, // 69: yorkie.v1.Operation.Add.value:type_name -> yorkie.v1.JSONElementSimple + 27, // 70: yorkie.v1.Operation.Add.executed_at:type_name -> yorkie.v1.TimeTicket + 27, // 71: yorkie.v1.Operation.Move.parent_created_at:type_name -> yorkie.v1.TimeTicket + 27, // 72: yorkie.v1.Operation.Move.prev_created_at:type_name -> yorkie.v1.TimeTicket + 27, // 73: yorkie.v1.Operation.Move.created_at:type_name -> yorkie.v1.TimeTicket + 27, // 74: yorkie.v1.Operation.Move.executed_at:type_name -> yorkie.v1.TimeTicket + 27, // 75: yorkie.v1.Operation.Remove.parent_created_at:type_name -> yorkie.v1.TimeTicket + 27, // 76: yorkie.v1.Operation.Remove.created_at:type_name -> yorkie.v1.TimeTicket + 27, // 77: yorkie.v1.Operation.Remove.executed_at:type_name -> yorkie.v1.TimeTicket + 27, // 78: yorkie.v1.Operation.Edit.parent_created_at:type_name -> yorkie.v1.TimeTicket + 26, // 79: yorkie.v1.Operation.Edit.from:type_name -> yorkie.v1.TextNodePos + 26, // 80: yorkie.v1.Operation.Edit.to:type_name -> yorkie.v1.TextNodePos + 42, // 81: yorkie.v1.Operation.Edit.created_at_map_by_actor:type_name -> yorkie.v1.Operation.Edit.CreatedAtMapByActorEntry + 27, // 82: yorkie.v1.Operation.Edit.executed_at:type_name -> yorkie.v1.TimeTicket + 43, // 83: yorkie.v1.Operation.Edit.attributes:type_name -> yorkie.v1.Operation.Edit.AttributesEntry + 27, // 84: yorkie.v1.Operation.Select.parent_created_at:type_name -> yorkie.v1.TimeTicket + 26, // 85: yorkie.v1.Operation.Select.from:type_name -> yorkie.v1.TextNodePos + 26, // 86: yorkie.v1.Operation.Select.to:type_name -> yorkie.v1.TextNodePos + 27, // 87: yorkie.v1.Operation.Select.executed_at:type_name -> yorkie.v1.TimeTicket + 27, // 88: yorkie.v1.Operation.Style.parent_created_at:type_name -> yorkie.v1.TimeTicket + 26, // 89: yorkie.v1.Operation.Style.from:type_name -> yorkie.v1.TextNodePos + 26, // 90: yorkie.v1.Operation.Style.to:type_name -> yorkie.v1.TextNodePos + 44, // 91: yorkie.v1.Operation.Style.attributes:type_name -> yorkie.v1.Operation.Style.AttributesEntry + 27, // 92: yorkie.v1.Operation.Style.executed_at:type_name -> yorkie.v1.TimeTicket + 45, // 93: yorkie.v1.Operation.Style.created_at_map_by_actor:type_name -> yorkie.v1.Operation.Style.CreatedAtMapByActorEntry + 27, // 94: yorkie.v1.Operation.Increase.parent_created_at:type_name -> yorkie.v1.TimeTicket + 8, // 95: yorkie.v1.Operation.Increase.value:type_name -> yorkie.v1.JSONElementSimple + 27, // 96: yorkie.v1.Operation.Increase.executed_at:type_name -> yorkie.v1.TimeTicket + 27, // 97: yorkie.v1.Operation.TreeEdit.parent_created_at:type_name -> yorkie.v1.TimeTicket + 18, // 98: yorkie.v1.Operation.TreeEdit.from:type_name -> yorkie.v1.TreePos + 18, // 99: yorkie.v1.Operation.TreeEdit.to:type_name -> yorkie.v1.TreePos + 46, // 100: yorkie.v1.Operation.TreeEdit.created_at_map_by_actor:type_name -> yorkie.v1.Operation.TreeEdit.CreatedAtMapByActorEntry + 16, // 101: yorkie.v1.Operation.TreeEdit.contents:type_name -> yorkie.v1.TreeNodes + 27, // 102: yorkie.v1.Operation.TreeEdit.executed_at:type_name -> yorkie.v1.TimeTicket + 27, // 103: yorkie.v1.Operation.TreeStyle.parent_created_at:type_name -> yorkie.v1.TimeTicket + 18, // 104: yorkie.v1.Operation.TreeStyle.from:type_name -> yorkie.v1.TreePos + 18, // 105: yorkie.v1.Operation.TreeStyle.to:type_name -> yorkie.v1.TreePos + 47, // 106: yorkie.v1.Operation.TreeStyle.attributes:type_name -> yorkie.v1.Operation.TreeStyle.AttributesEntry + 27, // 107: yorkie.v1.Operation.TreeStyle.executed_at:type_name -> yorkie.v1.TimeTicket + 48, // 108: yorkie.v1.Operation.TreeStyle.created_at_map_by_actor:type_name -> yorkie.v1.Operation.TreeStyle.CreatedAtMapByActorEntry + 27, // 109: yorkie.v1.Operation.ArraySet.parent_created_at:type_name -> yorkie.v1.TimeTicket + 27, // 110: yorkie.v1.Operation.ArraySet.created_at:type_name -> yorkie.v1.TimeTicket + 8, // 111: yorkie.v1.Operation.ArraySet.value:type_name -> yorkie.v1.JSONElementSimple + 27, // 112: yorkie.v1.Operation.ArraySet.executed_at:type_name -> yorkie.v1.TimeTicket + 27, // 113: yorkie.v1.Operation.Edit.CreatedAtMapByActorEntry.value:type_name -> yorkie.v1.TimeTicket + 27, // 114: yorkie.v1.Operation.Style.CreatedAtMapByActorEntry.value:type_name -> yorkie.v1.TimeTicket + 27, // 115: yorkie.v1.Operation.TreeEdit.CreatedAtMapByActorEntry.value:type_name -> yorkie.v1.TimeTicket + 27, // 116: yorkie.v1.Operation.TreeStyle.CreatedAtMapByActorEntry.value:type_name -> yorkie.v1.TimeTicket + 10, // 117: yorkie.v1.JSONElement.JSONObject.nodes:type_name -> yorkie.v1.RHTNode + 27, // 118: yorkie.v1.JSONElement.JSONObject.created_at:type_name -> yorkie.v1.TimeTicket + 27, // 119: yorkie.v1.JSONElement.JSONObject.moved_at:type_name -> yorkie.v1.TimeTicket + 27, // 120: yorkie.v1.JSONElement.JSONObject.removed_at:type_name -> yorkie.v1.TimeTicket + 11, // 121: yorkie.v1.JSONElement.JSONArray.nodes:type_name -> yorkie.v1.RGANode + 27, // 122: yorkie.v1.JSONElement.JSONArray.created_at:type_name -> yorkie.v1.TimeTicket + 27, // 123: yorkie.v1.JSONElement.JSONArray.moved_at:type_name -> yorkie.v1.TimeTicket + 27, // 124: yorkie.v1.JSONElement.JSONArray.removed_at:type_name -> yorkie.v1.TimeTicket + 0, // 125: yorkie.v1.JSONElement.Primitive.type:type_name -> yorkie.v1.ValueType + 27, // 126: yorkie.v1.JSONElement.Primitive.created_at:type_name -> yorkie.v1.TimeTicket + 27, // 127: yorkie.v1.JSONElement.Primitive.moved_at:type_name -> yorkie.v1.TimeTicket + 27, // 128: yorkie.v1.JSONElement.Primitive.removed_at:type_name -> yorkie.v1.TimeTicket + 13, // 129: yorkie.v1.JSONElement.Text.nodes:type_name -> yorkie.v1.TextNode + 27, // 130: yorkie.v1.JSONElement.Text.created_at:type_name -> yorkie.v1.TimeTicket + 27, // 131: yorkie.v1.JSONElement.Text.moved_at:type_name -> yorkie.v1.TimeTicket + 27, // 132: yorkie.v1.JSONElement.Text.removed_at:type_name -> yorkie.v1.TimeTicket + 0, // 133: yorkie.v1.JSONElement.Counter.type:type_name -> yorkie.v1.ValueType + 27, // 134: yorkie.v1.JSONElement.Counter.created_at:type_name -> yorkie.v1.TimeTicket + 27, // 135: yorkie.v1.JSONElement.Counter.moved_at:type_name -> yorkie.v1.TimeTicket + 27, // 136: yorkie.v1.JSONElement.Counter.removed_at:type_name -> yorkie.v1.TimeTicket + 15, // 137: yorkie.v1.JSONElement.Tree.nodes:type_name -> yorkie.v1.TreeNode + 27, // 138: yorkie.v1.JSONElement.Tree.created_at:type_name -> yorkie.v1.TimeTicket + 27, // 139: yorkie.v1.JSONElement.Tree.moved_at:type_name -> yorkie.v1.TimeTicket + 27, // 140: yorkie.v1.JSONElement.Tree.removed_at:type_name -> yorkie.v1.TimeTicket + 12, // 141: yorkie.v1.TextNode.AttributesEntry.value:type_name -> yorkie.v1.NodeAttr + 12, // 142: yorkie.v1.TreeNode.AttributesEntry.value:type_name -> yorkie.v1.NodeAttr + 143, // [143:143] is the sub-list for method output_type + 143, // [143:143] is the sub-list for method input_type + 143, // [143:143] is the sub-list for extension type_name + 143, // [143:143] is the sub-list for extension extendee + 0, // [0:143] is the sub-list for field type_name } func init() { file_yorkie_v1_resources_proto_init() } @@ -4862,8 +4972,8 @@ func file_yorkie_v1_resources_proto_init() { return nil } } - file_yorkie_v1_resources_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JSONElement_JSONObject); i { + file_yorkie_v1_resources_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Operation_ArraySet); i { case 0: return &v.state case 1: @@ -4875,7 +4985,7 @@ func file_yorkie_v1_resources_proto_init() { } } file_yorkie_v1_resources_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JSONElement_JSONArray); i { + switch v := v.(*JSONElement_JSONObject); i { case 0: return &v.state case 1: @@ -4887,7 +4997,7 @@ func file_yorkie_v1_resources_proto_init() { } } file_yorkie_v1_resources_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JSONElement_Primitive); i { + switch v := v.(*JSONElement_JSONArray); i { case 0: return &v.state case 1: @@ -4899,7 +5009,7 @@ func file_yorkie_v1_resources_proto_init() { } } file_yorkie_v1_resources_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JSONElement_Text); i { + switch v := v.(*JSONElement_Primitive); i { case 0: return &v.state case 1: @@ -4911,7 +5021,7 @@ func file_yorkie_v1_resources_proto_init() { } } file_yorkie_v1_resources_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JSONElement_Counter); i { + switch v := v.(*JSONElement_Text); i { case 0: return &v.state case 1: @@ -4923,6 +5033,18 @@ func file_yorkie_v1_resources_proto_init() { } } file_yorkie_v1_resources_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*JSONElement_Counter); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_yorkie_v1_resources_proto_msgTypes[51].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*JSONElement_Tree); i { case 0: return &v.state @@ -4934,7 +5056,7 @@ func file_yorkie_v1_resources_proto_init() { return nil } } - file_yorkie_v1_resources_proto_msgTypes[53].Exporter = func(v interface{}, i int) interface{} { + file_yorkie_v1_resources_proto_msgTypes[54].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*UpdatableProjectFields_AuthWebhookMethods); i { case 0: return &v.state @@ -4958,6 +5080,7 @@ func file_yorkie_v1_resources_proto_init() { (*Operation_Increase_)(nil), (*Operation_TreeEdit_)(nil), (*Operation_TreeStyle_)(nil), + (*Operation_ArraySet_)(nil), } file_yorkie_v1_resources_proto_msgTypes[6].OneofWrappers = []interface{}{ (*JSONElement_JsonObject)(nil), @@ -4973,7 +5096,7 @@ func file_yorkie_v1_resources_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_yorkie_v1_resources_proto_rawDesc, NumEnums: 3, - NumMessages: 55, + NumMessages: 56, NumExtensions: 0, NumServices: 0, }, diff --git a/api/yorkie/v1/resources.proto b/api/yorkie/v1/resources.proto index d1a8c3776..825cd8622 100644 --- a/api/yorkie/v1/resources.proto +++ b/api/yorkie/v1/resources.proto @@ -136,6 +136,12 @@ message Operation { repeated string attributes_to_remove = 6; map created_at_map_by_actor = 7; } + message ArraySet { + TimeTicket parent_created_at = 1; + TimeTicket created_at = 2; + JSONElementSimple value = 3; + TimeTicket executed_at = 4; + } oneof body { Set set = 1; @@ -148,6 +154,7 @@ message Operation { Increase increase = 8; TreeEdit tree_edit = 9; TreeStyle tree_style = 10; + ArraySet array_set = 11; } } diff --git a/build/docker/README.md b/build/docker/README.md index ef18072f2..28820835c 100644 --- a/build/docker/README.md +++ b/build/docker/README.md @@ -18,5 +18,5 @@ docker compose -f docker/docker-compose.yml down The docker-compose files we use are as follows: - `docker-compose.yml`: This file is used to run Yorkie's integration tests. It runs MongoDB. -- `docker-compose-full.yml`: This file launches all the applications needed to - develop Yorkie. It also runs monitoring tools such as Prometheus and Grafana. +- `docker-compose-full.yml`: This file builds Yorkie and launches it. It also runs + MongoDB and monitoring tools such as Prometheus and Grafana. diff --git a/build/docker/docker-compose-full.yml b/build/docker/docker-compose-full.yml index c6739062d..b49563f24 100644 --- a/build/docker/docker-compose-full.yml +++ b/build/docker/docker-compose-full.yml @@ -5,16 +5,21 @@ services: image: prom/prometheus:latest container_name: prometheus ports: - - '9090:9090' + - '9090:9090' command: - - --config.file=/etc/prometheus/prometheus.yml + - --config.file=/etc/prometheus/prometheus.yml volumes: - - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro + - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml:ro grafana: image: grafana/grafana:latest container_name: grafana ports: - '3000:3000' + command: + - --config=/etc/grafana/grafana.ini + volumes: + - ./monitoring/grafana.ini:/etc/grafana/grafana.ini:ro + - ./monitoring/datasources.yml:/etc/grafana/provisioning/datasources/datasources.yml:ro depends_on: - prometheus mongo: @@ -23,3 +28,21 @@ services: restart: always ports: - '27017:27017' + yorkie: + build: + context: ../../ + dockerfile: Dockerfile + container_name: 'yorkie' + command: + [ + 'server', + '--mongo-connection-uri', + 'mongodb://mongo:27017', + '--enable-pprof', + ] + restart: always + ports: + - '8080:8080' + - '8081:8081' + depends_on: + - mongo diff --git a/build/docker/monitoring/README.md b/build/docker/monitoring/README.md new file mode 100644 index 000000000..d49d5c0a4 --- /dev/null +++ b/build/docker/monitoring/README.md @@ -0,0 +1,12 @@ +# Grafana Setup Guide + +## Importing Dashboards + +To import dashboards into Grafana, follow these steps: + +1. Open Grafana in your browser ([http://localhost:3000](http://localhost:3000)). +2. Log in with the default credentials (admin/admin). +3. Click "Dashboards" in the left sidebar. +4. Click "New" and then "Import". +5. Use the Yorkie dashboard ID `18560` to import the dashboard. +6. Click "Load" and "Import" and the dashboard will be made. diff --git a/build/docker/monitoring/datasources.yml b/build/docker/monitoring/datasources.yml new file mode 100644 index 000000000..86fd3465e --- /dev/null +++ b/build/docker/monitoring/datasources.yml @@ -0,0 +1,8 @@ +apiVersion: 1 + +datasources: + - name: Prometheus + type: prometheus + access: proxy + url: http://prometheus:9090 + isDefault: true diff --git a/build/docker/monitoring/grafana.ini b/build/docker/monitoring/grafana.ini new file mode 100644 index 000000000..6145316b9 --- /dev/null +++ b/build/docker/monitoring/grafana.ini @@ -0,0 +1,21 @@ +[paths] +provisioning = /etc/grafana/provisioning + +[server] +http_port = 3000 + +[security] +admin_user = admin +admin_password = admin + +[users] +allow_sign_up = true + +[auth.anonymous] +enabled = false + +[dashboards] +versions_to_keep = 20 + +[unified_alerting] +enabled = true diff --git a/build/docker/monitoring/prometheus.yml b/build/docker/monitoring/prometheus.yml new file mode 100644 index 000000000..9cd0205d6 --- /dev/null +++ b/build/docker/monitoring/prometheus.yml @@ -0,0 +1,7 @@ +scrape_configs: +- job_name: yorkie + metrics_path: /metrics + scrape_interval: 5s + static_configs: + - targets: + - yorkie:8081 diff --git a/build/docker/prometheus.yml b/build/docker/prometheus.yml deleted file mode 100644 index 8f9792960..000000000 --- a/build/docker/prometheus.yml +++ /dev/null @@ -1,8 +0,0 @@ -scrape_configs: -- job_name: yorkie - metrics_path: /metrics - scrape_interval: 5s - static_configs: - - targets: - # win/mac hosts: Use address: host.docker.internal instead of address: localhost in the line below - - host.docker.internal:8081 diff --git a/client/client.go b/client/client.go index 7edc20dba..3f2f082b0 100644 --- a/client/client.go +++ b/client/client.go @@ -792,11 +792,11 @@ func (c *Client) broadcast(ctx context.Context, doc *document.Document, topic st func newTLSConfigFromFile(certFile, serverNameOverride string) (*tls.Config, error) { b, err := os.ReadFile(filepath.Clean(certFile)) if err != nil { - return nil, fmt.Errorf("credentials: failed to read TLS config file %q: %w", certFile, err) + return nil, fmt.Errorf("read TLS config file %q: %w", certFile, err) } cp := x509.NewCertPool() if !cp.AppendCertsFromPEM(b) { - return nil, fmt.Errorf("credentials: failed to append certificates") + return nil, fmt.Errorf("failure to append certs from PEM") } return &tls.Config{ServerName: serverNameOverride, RootCAs: cp, MinVersion: tls.VersionTLS12}, nil diff --git a/cmd/yorkie/config/config.go b/cmd/yorkie/config/config.go index f60cee070..687763fa9 100644 --- a/cmd/yorkie/config/config.go +++ b/cmd/yorkie/config/config.go @@ -170,7 +170,7 @@ func Preload(_ *cobra.Command, _ []string) error { } if err := viper.ReadInConfig(); err != nil { - return fmt.Errorf("failed to read in config: %w", err) + return fmt.Errorf("read in config: %w", err) } return nil } diff --git a/cmd/yorkie/delete_account.go b/cmd/yorkie/delete_account.go new file mode 100644 index 000000000..6e1f61273 --- /dev/null +++ b/cmd/yorkie/delete_account.go @@ -0,0 +1,136 @@ +/* + * Copyright 2024 The Yorkie Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package main + +import ( + "context" + "fmt" + "time" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/yorkie-team/yorkie/admin" + "github.com/yorkie-team/yorkie/cmd/yorkie/config" +) + +func deleteAccountCmd() *cobra.Command { + return &cobra.Command{ + Use: "delete-account", + Short: "Delete account", + PreRunE: config.Preload, + RunE: func(_ *cobra.Command, args []string) error { + rpcAddr := viper.GetString("rpcAddr") + auth, err := config.LoadAuth(rpcAddr) + if err != nil { + return err + } + + if err := readPassword(); err != nil { + return err + } + + if confirmation, err := makeConfirmation(); !confirmation || err != nil { + if err != nil { + return err + } + return nil + } + + conf, err := config.Load() + if err != nil { + return err + } + + if rpcAddr == "" { + rpcAddr = viper.GetString("rpcAddr") + } + + if err := deleteAccount(conf, auth, rpcAddr, username, password); err != nil { + fmt.Println("Failed to delete account: ", err) + } + + return nil + }, + } +} + +func makeConfirmation() (bool, error) { + fmt.Println("Warning: This action cannot be undone. Type 'DELETE' to confirm: ") + var confirmation string + if _, err := fmt.Scanln(&confirmation); err != nil { + return false, fmt.Errorf("read confirmation from user: %w", err) + } + + if confirmation != "DELETE" { + return false, fmt.Errorf("account deletion aborted") + } + + return true, nil +} + +func deleteAccount(conf *config.Config, auth config.Auth, rpcAddr, username, password string) error { + cli, err := admin.Dial(rpcAddr, admin.WithToken(auth.Token), admin.WithInsecure(auth.Insecure)) + if err != nil { + return err + } + defer func() { + cli.Close() + }() + + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + if err := cli.DeleteAccount(ctx, username, password); err != nil { + return fmt.Errorf("delete account: %w", err) + } + + delete(conf.Auths, rpcAddr) + if conf.RPCAddr == rpcAddr { + for addr := range conf.Auths { + conf.RPCAddr = addr + break + } + } + + if err := config.Save(conf); err != nil { + return err + } + + return nil +} + +func init() { + cmd := deleteAccountCmd() + cmd.Flags().StringVarP( + &username, + "username", + "u", + "", + "Username", + ) + cmd.Flags().StringVarP( + &password, + "password", + "p", + "", + "Password (optional)", + ) + + _ = cmd.MarkFlagRequired("username") + rootCmd.AddCommand(cmd) +} diff --git a/cmd/yorkie/login.go b/cmd/yorkie/login.go index da636f0c8..d2626bd15 100644 --- a/cmd/yorkie/login.go +++ b/cmd/yorkie/login.go @@ -18,8 +18,11 @@ package main import ( "context" + "fmt" + "os" "github.com/spf13/cobra" + "golang.org/x/term" "github.com/yorkie-team/yorkie/admin" "github.com/yorkie-team/yorkie/cmd/yorkie/config" @@ -35,9 +38,13 @@ var ( func newLoginCmd() *cobra.Command { return &cobra.Command{ Use: "login", - Short: "Log in to Yorkie server", + Short: "Log in to the Yorkie server", PreRunE: config.Preload, RunE: func(cmd *cobra.Command, args []string) error { + if err := readPassword(); err != nil { + return err + } + cli, err := admin.Dial(rpcAddr, admin.WithInsecure(insecure)) if err != nil { return err @@ -74,6 +81,20 @@ func newLoginCmd() *cobra.Command { } } +// readPassword reads the password from the user. +func readPassword() error { + if password == "" { + fmt.Print("Enter Password: ") + bytePassword, err := term.ReadPassword(int(os.Stdin.Fd())) + if err != nil { + return fmt.Errorf("read password: %w", err) + } + password = string(bytePassword) + fmt.Println() + } + return nil +} + func init() { cmd := newLoginCmd() cmd.Flags().StringVarP( @@ -81,14 +102,14 @@ func init() { "username", "u", "", - "Username (required if password is set)", + "Username", ) cmd.Flags().StringVarP( &password, "password", "p", "", - "Password (required if username is set)", + "Password (optional)", ) cmd.Flags().StringVar( &rpcAddr, @@ -102,6 +123,6 @@ func init() { false, "Skip the TLS connection of the client", ) - cmd.MarkFlagsRequiredTogether("username", "password") + _ = cmd.MarkFlagRequired("username") rootCmd.AddCommand(cmd) } diff --git a/cmd/yorkie/passwd.go b/cmd/yorkie/passwd.go new file mode 100644 index 000000000..0c1200317 --- /dev/null +++ b/cmd/yorkie/passwd.go @@ -0,0 +1,116 @@ +/* + * Copyright 2024 The Yorkie Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package main + +import ( + "context" + "fmt" + "os" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + "golang.org/x/term" + + "github.com/yorkie-team/yorkie/admin" + "github.com/yorkie-team/yorkie/cmd/yorkie/config" +) + +func passwdCmd() *cobra.Command { + return &cobra.Command{ + Use: "passwd", + Short: "Change password", + PreRunE: config.Preload, + RunE: func(cmd *cobra.Command, args []string) error { + rpcAddr := viper.GetString("rpcAddr") + auth, err := config.LoadAuth(rpcAddr) + if err != nil { + return err + } + + password, newPassword, err := readPasswords() + if err != nil { + return err + } + + cli, err := admin.Dial(rpcAddr, admin.WithToken(auth.Token), admin.WithInsecure(auth.Insecure)) + if err != nil { + return err + } + defer func() { + cli.Close() + }() + + ctx := context.Background() + if err := cli.ChangePassword(ctx, username, password, newPassword); err != nil { + return err + } + + if err := deleteAuthSession(rpcAddr); err != nil { + return err + } + + return nil + }, + } +} + +func readPasswords() (string, string, error) { + fmt.Print("Enter Password: ") + bytePassword, err := term.ReadPassword(int(os.Stdin.Fd())) + if err != nil { + return "", "", fmt.Errorf("read password: %w", err) + } + password := string(bytePassword) + fmt.Println() + + fmt.Print("Enter New Password: ") + bytePassword, err = term.ReadPassword(int(os.Stdin.Fd())) + if err != nil { + return "", "", fmt.Errorf("read new password: %w", err) + } + newPassword := string(bytePassword) + fmt.Println() + + return password, newPassword, nil +} + +func deleteAuthSession(rpcAddr string) error { + conf, err := config.Load() + if err != nil { + return err + } + + delete(conf.Auths, rpcAddr) + if err := config.Save(conf); err != nil { + return err + } + + return nil +} + +func init() { + cmd := passwdCmd() + cmd.Flags().StringVarP( + &username, + "username", + "u", + "", + "Username", + ) + _ = cmd.MarkFlagRequired("username") + rootCmd.AddCommand(cmd) +} diff --git a/cmd/yorkie/version.go b/cmd/yorkie/version.go index 3255a25ad..7207f76db 100644 --- a/cmd/yorkie/version.go +++ b/cmd/yorkie/version.go @@ -131,13 +131,13 @@ func printVersionInfo(cmd *cobra.Command, output string, versionInfo *types.Vers case "yaml": marshalled, err := yaml.Marshal(versionInfo) if err != nil { - return errors.New("failed to marshal YAML") + return errors.New("marshal YAML") } cmd.Println(string(marshalled)) case "json": marshalled, err := json.MarshalIndent(versionInfo, "", " ") if err != nil { - return errors.New("failed to marshal JSON") + return errors.New("marshal JSON") } cmd.Println(string(marshalled)) default: diff --git a/go.mod b/go.mod index 3174eb884..ec2fce562 100644 --- a/go.mod +++ b/go.mod @@ -27,6 +27,7 @@ require ( google.golang.org/grpc v1.58.3 google.golang.org/protobuf v1.31.0 gopkg.in/yaml.v2 v2.4.0 + gopkg.in/yaml.v3 v3.0.1 ) require ( @@ -72,10 +73,10 @@ require ( go.uber.org/multierr v1.9.0 // indirect golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.15.0 // indirect + golang.org/x/sys v0.23.0 // indirect + golang.org/x/term v0.23.0 golang.org/x/text v0.14.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect ) replace github.com/hashicorp/go-memdb => github.com/hackerwins/go-memdb v1.3.3-0.20211225080334-513a74641622 diff --git a/go.sum b/go.sum index daf71193d..10b9cb034 100644 --- a/go.sum +++ b/go.sum @@ -524,10 +524,12 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= +golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= +golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/pkg/document/crdt/array.go b/pkg/document/crdt/array.go index 1a5dcd7a3..f0dcb07db 100644 --- a/pkg/document/crdt/array.go +++ b/pkg/document/crdt/array.go @@ -178,6 +178,18 @@ func (a *Array) DeleteByCreatedAt(createdAt *time.Ticket, deletedAt *time.Ticket return node.elem, nil } +// Set sets the given element at the given position of the creation time. +func (a *Array) Set(createdAt *time.Ticket, element Element, executedAt *time.Ticket) (Element, error) { + node, err := a.elements.Set(createdAt, element, executedAt) + if err != nil { + return nil, err + } + if node != nil { + return node.elem, nil + } + return nil, nil +} + // Len returns length of this Array. func (a *Array) Len() int { return a.elements.Len() diff --git a/pkg/document/crdt/rga_tree_list.go b/pkg/document/crdt/rga_tree_list.go index c2e71baac..eae582817 100644 --- a/pkg/document/crdt/rga_tree_list.go +++ b/pkg/document/crdt/rga_tree_list.go @@ -345,3 +345,27 @@ func (a *RGATreeList) insertAfter( a.nodeMapByCreatedAt[value.CreatedAt().Key()] = newNode return nil } + +// Set sets the given element at the given creation time. +func (a *RGATreeList) Set( + createdAt *time.Ticket, + element Element, + executedAt *time.Ticket, +) (*RGATreeListNode, error) { + node, ok := a.nodeMapByCreatedAt[createdAt.Key()] + if !ok { + return nil, fmt.Errorf("set %s: %w", createdAt.Key(), ErrChildNotFound) + } + + var removed *RGATreeListNode + // TODO(junseo): Replace `MovedAt()` with `UpdatedAt()` + // because `movedAt` is related to convergence of positional operations (Insert, Move). + // In the current implementation, concurrent Set and Insert operations do not converge. + if node.elem.MovedAt() == nil || executedAt.After(node.elem.MovedAt()) { + removed = newRGATreeListNode(node.elem) + + node.elem = element + node.elem.SetMovedAt(executedAt) + } + return removed, nil +} diff --git a/pkg/document/json/array.go b/pkg/document/json/array.go index 954615ea6..8b024e706 100644 --- a/pkg/document/json/array.go +++ b/pkg/document/json/array.go @@ -167,10 +167,24 @@ func (p *Array) MoveBefore(nextCreatedAt, createdAt *time.Ticket) { p.moveBeforeInternal(nextCreatedAt, createdAt) } +// MoveAfterByIndex moves the given element to its new position after the given previous element. +func (p *Array) MoveAfterByIndex(prevIndex, targetIndex int) { + prev := p.Get(prevIndex) + target := p.Get(targetIndex) + if prev == nil || target == nil { + panic("index out of bound") + } + p.moveAfterInternal(prev.CreatedAt(), target.CreatedAt()) +} + // InsertIntegerAfter inserts the given integer after the given previous // element. func (p *Array) InsertIntegerAfter(index int, v int) *Array { - p.insertAfterInternal(p.Get(index).CreatedAt(), func(ticket *time.Ticket) crdt.Element { + prev := p.Get(index) + if prev == nil { + panic("index out of bound") + } + p.insertAfterInternal(prev.CreatedAt(), func(ticket *time.Ticket) crdt.Element { primitive, err := crdt.NewPrimitive(v, ticket) if err != nil { panic(err) @@ -183,7 +197,7 @@ func (p *Array) InsertIntegerAfter(index int, v int) *Array { // Get element of the given index. func (p *Array) Get(idx int) crdt.Element { - if p.Len() <= idx { + if idx < 0 || p.Len() <= idx { return nil } @@ -197,15 +211,11 @@ func (p *Array) Get(idx int) crdt.Element { // GetObject returns Object of the given index. func (p *Array) GetObject(idx int) *Object { - if p.Len() <= idx { + element := p.Get(idx) + if element == nil { return nil } - element, err := p.Array.Get(idx) - if err != nil { - panic(err) - } - switch elem := element.(type) { case *crdt.Object: return NewObject(p.context, elem) @@ -218,15 +228,11 @@ func (p *Array) GetObject(idx int) *Object { // GetArray returns Array of the given index. func (p *Array) GetArray(idx int) *Array { - if p.Len() <= idx { + element := p.Get(idx) + if element == nil { return nil } - element, err := p.Array.Get(idx) - if err != nil { - panic(err) - } - switch elem := element.(type) { case *crdt.Array: return NewArray(p.context, elem) @@ -239,15 +245,11 @@ func (p *Array) GetArray(idx int) *Array { // GetText returns Text of the given index. func (p *Array) GetText(idx int) *Text { - if p.Len() <= idx { + element := p.Get(idx) + if element == nil { return nil } - element, err := p.Array.Get(idx) - if err != nil { - panic(err) - } - switch elem := element.(type) { case *crdt.Text: text := NewText() @@ -261,15 +263,11 @@ func (p *Array) GetText(idx int) *Text { // GetCounter returns Counter of the given index. func (p *Array) GetCounter(idx int) *Counter { - if p.Len() <= idx { + element := p.Get(idx) + if element == nil { return nil } - element, err := p.Array.Get(idx) - if err != nil { - panic(err) - } - switch elem := element.(type) { case *crdt.Counter: counter := NewCounter(elem.Value(), elem.ValueType()) @@ -283,15 +281,11 @@ func (p *Array) GetCounter(idx int) *Counter { // GetTree returns Tree of the given index. func (p *Array) GetTree(idx int) *Tree { - if p.Len() <= idx { + element := p.Get(idx) + if element == nil { return nil } - element, err := p.Array.Get(idx) - if err != nil { - panic(err) - } - switch elem := element.(type) { case *crdt.Tree: tree := NewTree() @@ -303,9 +297,26 @@ func (p *Array) GetTree(idx int) *Tree { } } +// SetInteger sets element of the given index. +func (p *Array) SetInteger(idx int, value int) *Array { + target := p.Get(idx) + if target == nil { + panic("index out of bound") + } + + p.setByIndexInternal(target.CreatedAt(), func(ticket *time.Ticket) crdt.Element { + primitive, err := crdt.NewPrimitive(value, ticket) + if err != nil { + panic(err) + } + return primitive + }) + return p +} + // Delete deletes the element of the given index. func (p *Array) Delete(idx int) crdt.Element { - if p.Len() <= idx { + if idx < 0 || p.Len() <= idx { return nil } @@ -381,6 +392,52 @@ func (p *Array) moveBeforeInternal(nextCreatedAt, createdAt *time.Ticket) { } } +func (p *Array) moveAfterInternal(prevCreatedAt, createdAt *time.Ticket) { + ticket := p.context.IssueTimeTicket() + + p.context.Push(operations.NewMove( + p.Array.CreatedAt(), + prevCreatedAt, + createdAt, + ticket, + )) + + if err := p.MoveAfter(prevCreatedAt, createdAt, ticket); err != nil { + panic(err) + } +} + +func (p *Array) setByIndexInternal( + createdAt *time.Ticket, + creator func(ticket *time.Ticket) crdt.Element, +) crdt.Element { + ticket := p.context.IssueTimeTicket() + // NOTE(junseo): It uses `creator(createdAt)` instead of `creator(ticket)` + // because the new element must have the same `createdAt` as the old element. + elem := creator(createdAt) + value := toOriginal(elem) + + copiedValue, err := value.DeepCopy() + if err != nil { + panic(err) + } + p.context.Push(operations.NewArraySet( + p.Array.CreatedAt(), + createdAt, + copiedValue, + ticket, + )) + + _, err = p.Set(createdAt, value, ticket) + if err != nil { + panic(err) + } + // TODO(junseo): GC logic is not implemented here + // because there is no way to distinguish between old and new element with same `createdAt`. + p.context.RegisterElement(value) + return elem +} + // buildArrayElements return the element slice of the given array. // Because the type of the given array is `any`, it is necessary to type assertion. func buildArrayElements( diff --git a/pkg/document/operations/array_set.go b/pkg/document/operations/array_set.go new file mode 100644 index 000000000..11842a435 --- /dev/null +++ b/pkg/document/operations/array_set.go @@ -0,0 +1,102 @@ +/* + * Copyright 2024 The Yorkie Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package operations + +import ( + "github.com/yorkie-team/yorkie/pkg/document/crdt" + "github.com/yorkie-team/yorkie/pkg/document/time" +) + +// ArraySet is an operation representing setting an element in Array. +type ArraySet struct { + // parentCreatedAt is the creation time of the Array that executes ArraySet. + parentCreatedAt *time.Ticket + + // createdAt is the creation time of the target element to set. + createdAt *time.Ticket + + // value is an element set by the set_by_index operations. + value crdt.Element + + // executedAt is the time the operation was executed. + executedAt *time.Ticket +} + +// NewArraySet creates a new instance of ArraySet. +func NewArraySet( + parentCreatedAt *time.Ticket, + createdAt *time.Ticket, + value crdt.Element, + executedAt *time.Ticket, +) *ArraySet { + return &ArraySet{ + parentCreatedAt: parentCreatedAt, + createdAt: createdAt, + value: value, + executedAt: executedAt, + } +} + +// Execute executes this operation on the given document(`root`). +func (o *ArraySet) Execute(root *crdt.Root) error { + parent := root.FindByCreatedAt(o.parentCreatedAt) + + obj, ok := parent.(*crdt.Array) + if !ok { + return ErrNotApplicableDataType + } + + value, err := o.value.DeepCopy() + if err != nil { + return err + } + + _, err = obj.Set(o.createdAt, value, o.executedAt) + if err != nil { + return err + } + + // TODO(junseo): GC logic is not implemented here + // because there is no way to distinguish between old and new element with same `createdAt`. + root.RegisterElement(value) + return nil +} + +// Value returns the value of this operation. +func (o *ArraySet) Value() crdt.Element { + return o.value +} + +// ParentCreatedAt returns the creation time of the Array. +func (o *ArraySet) ParentCreatedAt() *time.Ticket { + return o.parentCreatedAt +} + +// ExecutedAt returns execution time of this operation. +func (o *ArraySet) ExecutedAt() *time.Ticket { + return o.executedAt +} + +// SetActor sets the given actor to this operation. +func (o *ArraySet) SetActor(actorID *time.ActorID) { + o.executedAt = o.executedAt.SetActorID(actorID) +} + +// CreatedAt returns the creation time of the target element. +func (o *ArraySet) CreatedAt() *time.Ticket { + return o.createdAt +} diff --git a/server/backend/database/memory/database.go b/server/backend/database/memory/database.go index 08b2b1364..13a04789c 100644 --- a/server/backend/database/memory/database.go +++ b/server/backend/database/memory/database.go @@ -746,6 +746,7 @@ func (d *DB) FindDocInfoByKeyAndOwner( Owner: clientRefKey.ClientID, ServerSeq: 0, CreatedAt: now, + UpdatedAt: now, AccessedAt: now, } if err := txn.Insert(tblDocuments, info); err != nil { @@ -1051,6 +1052,9 @@ func (d *DB) FindChangeInfosBetweenServerSeqs( txn := d.db.Txn(false) defer txn.Abort() + if from > to { + return nil, nil + } var infos []*database.ChangeInfo iterator, err := txn.LowerBound( diff --git a/server/backend/database/memory/database_test.go b/server/backend/database/memory/database_test.go index 5ee6ad0a1..d308940a7 100644 --- a/server/backend/database/memory/database_test.go +++ b/server/backend/database/memory/database_test.go @@ -60,6 +60,10 @@ func TestDB(t *testing.T) { testcases.RunFindChangesBetweenServerSeqsTest(t, db, projectID) }) + t.Run("RunFindChangeInfosBetweenServerSeqsTest test", func(t *testing.T) { + testcases.RunFindChangeInfosBetweenServerSeqsTest(t, db, projectID) + }) + t.Run("RunFindClosestSnapshotInfo test", func(t *testing.T) { testcases.RunFindClosestSnapshotInfoTest(t, db, projectID) }) diff --git a/server/backend/database/mongo/client.go b/server/backend/database/mongo/client.go index 3d65ff029..16ec85b63 100644 --- a/server/backend/database/mongo/client.go +++ b/server/backend/database/mongo/client.go @@ -739,8 +739,9 @@ func (c *Client) FindDocInfoByKeyAndOwner( "owner": clientRefKey.ClientID, "server_seq": 0, "created_at": now, + "updated_at": now, }, - }) + }, options.FindOneAndUpdate().SetReturnDocument(options.After)) } else { result = c.collection(ColDocuments).FindOne(ctx, filter) if result.Err() == mongo.ErrNoDocuments { @@ -1030,6 +1031,9 @@ func (c *Client) FindChangeInfosBetweenServerSeqs( from int64, to int64, ) ([]*database.ChangeInfo, error) { + if from > to { + return nil, nil + } cursor, err := c.collection(ColChanges).Find(ctx, bson.M{ "project_id": docRefKey.ProjectID, "doc_id": docRefKey.DocID, diff --git a/server/backend/database/mongo/client_test.go b/server/backend/database/mongo/client_test.go index 03e596840..6e0803b5d 100644 --- a/server/backend/database/mongo/client_test.go +++ b/server/backend/database/mongo/client_test.go @@ -76,6 +76,10 @@ func TestClient(t *testing.T) { testcases.RunFindChangesBetweenServerSeqsTest(t, cli, dummyProjectID) }) + t.Run("RunFindChangeInfosBetweenServerSeqsTest test", func(t *testing.T) { + testcases.RunFindChangeInfosBetweenServerSeqsTest(t, cli, dummyProjectID) + }) + t.Run("RunFindClosestSnapshotInfo test", func(t *testing.T) { testcases.RunFindClosestSnapshotInfoTest(t, cli, dummyProjectID) }) diff --git a/server/backend/database/testcases/testcases.go b/server/backend/database/testcases/testcases.go index 06a54bd20..2108f8c83 100644 --- a/server/backend/database/testcases/testcases.go +++ b/server/backend/database/testcases/testcases.go @@ -343,6 +343,185 @@ func RunFindChangesBetweenServerSeqsTest( }) } +// RunFindChangeInfosBetweenServerSeqsTest runs the FindChangeInfosBetweenServerSeqs test for the given db. +func RunFindChangeInfosBetweenServerSeqsTest( + t *testing.T, + db database.Database, + projectID types.ID, +) { + t.Run("continues editing without any interference from other users test", func(t *testing.T) { + ctx := context.Background() + + docKey := key.Key(fmt.Sprintf("tests$%s", t.Name())) + + clientInfo, _ := db.ActivateClient(ctx, projectID, t.Name()) + docInfo, _ := db.FindDocInfoByKeyAndOwner(ctx, clientInfo.RefKey(), docKey, true) + assert.NoError(t, clientInfo.AttachDocument(docInfo.ID, false)) + assert.NoError(t, db.UpdateClientInfoAfterPushPull(ctx, clientInfo, docInfo)) + + updatedClientInfo, _ := db.FindClientInfoByRefKey(ctx, clientInfo.RefKey()) + + // Record the serverSeq value at the time the PushPull request came in. + initialServerSeq := docInfo.ServerSeq + + // The serverSeq of the checkpoint that the server has should always be the same as + // the serverSeq of the user's checkpoint that came in as a request, if no other user interfered. + reqPackCheckpointServerSeq := updatedClientInfo.Checkpoint(docInfo.ID).ServerSeq + + changeInfos, err := db.FindChangeInfosBetweenServerSeqs( + ctx, + docInfo.RefKey(), + reqPackCheckpointServerSeq+1, + initialServerSeq, + ) + + assert.NoError(t, err) + assert.Len(t, changeInfos, 0) + }) + + t.Run("retrieving a document with snapshot that reflect the latest doc info test", func(t *testing.T) { + ctx := context.Background() + + docKey := key.Key(fmt.Sprintf("tests$%s", t.Name())) + + clientInfo, _ := db.ActivateClient(ctx, projectID, t.Name()) + docInfo, _ := db.FindDocInfoByKeyAndOwner(ctx, clientInfo.RefKey(), docKey, true) + docRefKey := docInfo.RefKey() + assert.NoError(t, clientInfo.AttachDocument(docInfo.ID, false)) + assert.NoError(t, db.UpdateClientInfoAfterPushPull(ctx, clientInfo, docInfo)) + + initialServerSeq := docInfo.ServerSeq + + // 01. Create a document and store changes + bytesID, _ := clientInfo.ID.Bytes() + actorID, _ := time.ActorIDFromBytes(bytesID) + doc := document.New(key.Key(t.Name())) + doc.SetActor(actorID) + assert.NoError(t, doc.Update(func(root *json.Object, p *presence.Presence) error { + root.SetNewArray("array") + return nil + })) + for idx := 0; idx < 5; idx++ { + assert.NoError(t, doc.Update(func(root *json.Object, p *presence.Presence) error { + root.GetArray("array").AddInteger(idx) + return nil + })) + } + + pack := doc.CreateChangePack() + for _, c := range pack.Changes { + serverSeq := docInfo.IncreaseServerSeq() + c.SetServerSeq(serverSeq) + } + + err := db.CreateChangeInfos( + ctx, + projectID, + docInfo, + initialServerSeq, + pack.Changes, + false, + ) + assert.NoError(t, err) + + // 02. Create a snapshot that reflect the latest doc info + updatedDocInfo, _ := db.FindDocInfoByRefKey(ctx, docRefKey) + assert.Equal(t, int64(6), updatedDocInfo.ServerSeq) + + pack = change.NewPack( + updatedDocInfo.Key, + change.InitialCheckpoint.NextServerSeq(updatedDocInfo.ServerSeq), + nil, + nil, + ) + assert.NoError(t, doc.ApplyChangePack(pack)) + assert.Equal(t, int64(6), doc.Checkpoint().ServerSeq) + + assert.NoError(t, db.CreateSnapshotInfo(ctx, docRefKey, doc.InternalDocument())) + + // 03. Find changeInfos with snapshot that reflect the latest doc info + snapshotInfo, _ := db.FindClosestSnapshotInfo( + ctx, + docRefKey, + updatedDocInfo.ServerSeq, + false, + ) + + changeInfos, _ := db.FindChangeInfosBetweenServerSeqs( + ctx, + docRefKey, + snapshotInfo.ServerSeq+1, + updatedDocInfo.ServerSeq, + ) + + assert.Len(t, changeInfos, 0) + }) + + t.Run("store changes and find changes test", func(t *testing.T) { + ctx := context.Background() + + docKey := key.Key(fmt.Sprintf("tests$%s", t.Name())) + + clientInfo, _ := db.ActivateClient(ctx, projectID, t.Name()) + docInfo, _ := db.FindDocInfoByKeyAndOwner(ctx, clientInfo.RefKey(), docKey, true) + docRefKey := docInfo.RefKey() + assert.NoError(t, clientInfo.AttachDocument(docInfo.ID, false)) + assert.NoError(t, db.UpdateClientInfoAfterPushPull(ctx, clientInfo, docInfo)) + + initialServerSeq := docInfo.ServerSeq + + // 01. Create a document and store changes + bytesID, _ := clientInfo.ID.Bytes() + actorID, _ := time.ActorIDFromBytes(bytesID) + doc := document.New(key.Key(t.Name())) + doc.SetActor(actorID) + assert.NoError(t, doc.Update(func(root *json.Object, p *presence.Presence) error { + root.SetNewArray("array") + return nil + })) + for idx := 0; idx < 5; idx++ { + assert.NoError(t, doc.Update(func(root *json.Object, p *presence.Presence) error { + root.GetArray("array").AddInteger(idx) + return nil + })) + } + pack := doc.CreateChangePack() + for _, c := range pack.Changes { + serverSeq := docInfo.IncreaseServerSeq() + c.SetServerSeq(serverSeq) + } + + err := db.CreateChangeInfos( + ctx, + projectID, + docInfo, + initialServerSeq, + pack.Changes, + false, + ) + assert.NoError(t, err) + + // 02. Find changes + changeInfos, err := db.FindChangeInfosBetweenServerSeqs( + ctx, + docRefKey, + 1, + 6, + ) + assert.NoError(t, err) + assert.Len(t, changeInfos, 6) + + changeInfos, err = db.FindChangeInfosBetweenServerSeqs( + ctx, + docRefKey, + 3, + 3, + ) + assert.NoError(t, err) + assert.Len(t, changeInfos, 1) + }) +} + // RunFindClosestSnapshotInfoTest runs the FindClosestSnapshotInfo test for the given db. func RunFindClosestSnapshotInfoTest(t *testing.T, db database.Database, projectID types.ID) { t.Run("store and find snapshots test", func(t *testing.T) { @@ -948,6 +1127,9 @@ func RunCreateChangeInfosTest(t *testing.T, db database.Database, projectID type // 01. Create a client and a document then attach the document to the client. clientInfo, _ := db.ActivateClient(ctx, projectID, t.Name()) docInfo1, _ := db.FindDocInfoByKeyAndOwner(ctx, clientInfo.RefKey(), docKey, true) + assert.Equal(t, docInfo1.Owner, clientInfo.ID) + assert.NotEqual(t, gotime.Date(1, gotime.January, 1, 0, 0, 0, 0, gotime.UTC), docInfo1.UpdatedAt) + assert.Equal(t, docInfo1.CreatedAt, docInfo1.UpdatedAt) docRefKey := docInfo1.RefKey() assert.NoError(t, clientInfo.AttachDocument(docRefKey.DocID, false)) assert.NoError(t, db.UpdateClientInfoAfterPushPull(ctx, clientInfo, docInfo1)) @@ -957,7 +1139,7 @@ func RunCreateChangeInfosTest(t *testing.T, db database.Database, projectID type doc := document.New(key.Key(t.Name())) doc.SetActor(actorID) - // 02. update document only presence + // 02. Update document only presence assert.NoError(t, doc.Update(func(root *json.Object, p *presence.Presence) error { p.Set("key", "val") return nil @@ -968,7 +1150,7 @@ func RunCreateChangeInfosTest(t *testing.T, db database.Database, projectID type docInfo2, _ := db.FindDocInfoByKeyAndOwner(ctx, clientInfo.RefKey(), docKey, true) assert.Equal(t, updatedAt, docInfo2.UpdatedAt) - // 03. update document presence and operation + // 03. Update document presence and operation assert.NoError(t, doc.Update(func(root *json.Object, p *presence.Presence) error { p.Set("key", "val") root.SetNewArray("array") diff --git a/server/profiling/prometheus/metrics.go b/server/profiling/prometheus/metrics.go index 1f2c2fe76..aa2155273 100644 --- a/server/profiling/prometheus/metrics.go +++ b/server/profiling/prometheus/metrics.go @@ -54,6 +54,8 @@ type Metrics struct { serverVersion *prometheus.GaugeVec serverHandledCounter *prometheus.CounterVec + backgroundGoroutinesTotal *prometheus.GaugeVec + pushPullResponseSeconds prometheus.Histogram pushPullReceivedChangesTotal prometheus.Counter pushPullSentChangesTotal prometheus.Counter @@ -62,7 +64,8 @@ type Metrics struct { pushPullSnapshotDurationSeconds prometheus.Histogram pushPullSnapshotBytesTotal prometheus.Counter - backgroundGoroutinesTotal *prometheus.GaugeVec + watchDocumentConnectionTotal *prometheus.GaugeVec + watchDocumentPayloadBytesTotal *prometheus.GaugeVec userAgentTotal *prometheus.CounterVec } @@ -143,6 +146,16 @@ func NewMetrics() (*Metrics, error) { Name: "goroutines_total", Help: "The total number of goroutines attached by a particular background task.", }, []string{taskTypeLabel}), + watchDocumentConnectionTotal: promauto.With(reg).NewGaugeVec(prometheus.GaugeOpts{ + Namespace: namespace, + Subsystem: "stream", + Name: "watch_document_stream_connection_total", + Help: "The total number of document watch stream connection.", + }, []string{ + projectIDLabel, + projectNameLabel, + hostnameLabel, + }), userAgentTotal: promauto.With(reg).NewCounterVec(prometheus.CounterOpts{ Namespace: namespace, Subsystem: "user_agent", @@ -257,6 +270,24 @@ func (m *Metrics) RemoveBackgroundGoroutines(taskType string) { }).Dec() } +// AddWatchDocumentConnection adds the number of document watch stream connection. +func (m *Metrics) AddWatchDocumentConnection(hostname string, project *types.Project) { + m.watchDocumentConnectionTotal.With(prometheus.Labels{ + projectIDLabel: project.ID.String(), + projectNameLabel: project.Name, + hostnameLabel: hostname, + }).Inc() +} + +// RemoveWatchDocumentConnection removes the number of document watch stream connection. +func (m *Metrics) RemoveWatchDocumentConnection(hostname string, project *types.Project) { + m.watchDocumentConnectionTotal.With(prometheus.Labels{ + projectIDLabel: project.ID.String(), + projectNameLabel: project.Name, + hostnameLabel: hostname, + }).Dec() +} + // Registry returns the registry of this metrics. func (m *Metrics) Registry() *prometheus.Registry { return m.registry diff --git a/server/rpc/yorkie_server.go b/server/rpc/yorkie_server.go index 22f5ee995..86c273080 100644 --- a/server/rpc/yorkie_server.go +++ b/server/rpc/yorkie_server.go @@ -430,8 +430,13 @@ func (s *yorkieServer) WatchDocument( logging.From(ctx).Error(err) return err } + s.backend.Metrics.AddWatchDocumentConnection(s.backend.Config.Hostname, project) defer func() { - s.unwatchDoc(subscription, docRefKey) + if err := s.unwatchDoc(subscription, docRefKey); err != nil { + logging.From(ctx).Error(err) + } else { + s.backend.Metrics.RemoveWatchDocumentConnection(s.backend.Config.Hostname, project) + } }() var pbClientIDs []string @@ -583,9 +588,14 @@ func (s *yorkieServer) watchDoc( func (s *yorkieServer) unwatchDoc( subscription *sync.Subscription, documentRefKey types.DocRefKey, -) { +) error { ctx := context.Background() - _ = s.backend.Coordinator.Unsubscribe(ctx, documentRefKey, subscription) + err := s.backend.Coordinator.Unsubscribe(ctx, documentRefKey, subscription) + if err != nil { + logging.From(ctx).Error(err) + return err + } + s.backend.Coordinator.Publish( ctx, subscription.Subscriber(), @@ -595,6 +605,8 @@ func (s *yorkieServer) unwatchDoc( DocumentRefKey: documentRefKey, }, ) + + return nil } func (s *yorkieServer) Broadcast( diff --git a/test/integration/array_test.go b/test/integration/array_test.go index f4935ef8a..5d41db06b 100644 --- a/test/integration/array_test.go +++ b/test/integration/array_test.go @@ -471,3 +471,139 @@ func TestArraySet(t *testing.T) { }) } } + +func TestArrayConcurrencyTable(t *testing.T) { + clients := activeClients(t, 2) + c0, c1 := clients[0], clients[1] + defer deactivateAndCloseClients(t, clients) + + initArr := []int{1, 2, 3, 4} + initMarshal := `[1,2,3,4]` + oneIdx := 1 + otherIdxs := []int{2, 3} + newValues := []int{5, 6} + + type arrayOp struct { + opName string + executor func(*json.Array, int) + } + + // NOTE(junseo): It tests all (op1, op2) pairs in operations. + // `oneIdx` is the index where both op1 and op2 reference. + // `opName` represents the parameter of operation selected as `oneIdx'. + // `otherIdxs` ensures that indexs other than `oneIdx` are not duplicated. + operations := []arrayOp{ + // insert + {"insert.prev", func(a *json.Array, cid int) { + a.InsertIntegerAfter(oneIdx, newValues[cid]) + }}, + {"insert.prev.next", func(a *json.Array, cid int) { + a.InsertIntegerAfter(oneIdx-1, newValues[cid]) + }}, + + // move + {"move.prev", func(a *json.Array, cid int) { + a.MoveAfterByIndex(oneIdx, otherIdxs[cid]) + }}, + {"move.prev.next", func(a *json.Array, cid int) { + a.MoveAfterByIndex(oneIdx-1, otherIdxs[cid]) + }}, + {"move.target", func(a *json.Array, cid int) { + a.MoveAfterByIndex(otherIdxs[cid], oneIdx) + }}, + + // set by index + {"set.target", func(a *json.Array, cid int) { + a.SetInteger(oneIdx, newValues[cid]) + }}, + + // remove + {"remove.target", func(a *json.Array, cid int) { + a.Delete(oneIdx) + }}, + } + + ctx := context.Background() + d0 := document.New(helper.TestDocKey(t)) + assert.NoError(t, c0.Attach(ctx, d0)) + d1 := document.New(helper.TestDocKey(t)) + assert.NoError(t, c1.Attach(ctx, d1)) + + runTest := func(op1, op2 arrayOp) testResult { + assert.NoError(t, d0.Update(func(root *json.Object, p *presence.Presence) error { + root.SetNewArray("a").AddInteger(initArr...) + assert.Equal(t, initMarshal, root.GetArray("a").Marshal()) + return nil + })) + + assert.NoError(t, c0.Sync(ctx)) + assert.NoError(t, c1.Sync(ctx)) + + assert.NoError(t, d0.Update(func(root *json.Object, p *presence.Presence) error { + op1.executor(root.GetArray("a"), 0) + return nil + })) + + assert.NoError(t, d1.Update(func(root *json.Object, p *presence.Presence) error { + op2.executor(root.GetArray("a"), 1) + return nil + })) + + flag := syncClientsThenCheckEqual(t, []clientAndDocPair{{c0, d0}, {c1, d1}}) + if flag { + return testResult{flag, `pass`} + } + return testResult{flag, `different result`} + } + + for _, op1 := range operations { + for _, op2 := range operations { + t.Run(op1.opName+" vs "+op2.opName, func(t *testing.T) { + result := runTest(op1, op2) + if !result.flag { + t.Skip(result.resultDesc) + } + }) + } + } +} + +func TestArraySetByIndex(t *testing.T) { + clients := activeClients(t, 2) + c1, c2 := clients[0], clients[1] + defer deactivateAndCloseClients(t, clients) + + t.Run("array set simple test", func(t *testing.T) { + ctx := context.Background() + d1 := document.New(helper.TestDocKey(t)) + err := c1.Attach(ctx, d1) + assert.NoError(t, err) + + d2 := document.New(helper.TestDocKey(t)) + err = c2.Attach(ctx, d2) + assert.NoError(t, err) + + assert.NoError(t, d1.Update(func(root *json.Object, p *presence.Presence) error { + root.SetNewArray("k1").AddInteger(-1, -2, -3) + assert.Equal(t, `{"k1":[-1,-2,-3]}`, root.Marshal()) + return nil + }, "add -1, -2, -3 by c1")) + + assert.NoError(t, c1.Sync(ctx)) + assert.NoError(t, c2.Sync(ctx)) + + assert.NoError(t, d2.Update(func(root *json.Object, p *presence.Presence) error { + root.GetArray("k1").SetInteger(1, -4) + assert.Equal(t, `{"k1":[-1,-4,-3]}`, root.Marshal()) + return nil + }, "set k1[1] to -4 by c2")) + + assert.NoError(t, d1.Update(func(root *json.Object, p *presence.Presence) error { + root.GetArray("k1").SetInteger(0, -5) + assert.Equal(t, `{"k1":[-5,-2,-3]}`, root.Marshal()) + return nil + }, "set k1[0] to -5 by c1")) + + syncClientsThenAssertEqual(t, []clientAndDocPair{{c1, d1}, {c2, d2}}) + }) +} diff --git a/test/sharding/mongo_client_test.go b/test/sharding/mongo_client_test.go index 0653e0200..5cb2bffe6 100644 --- a/test/sharding/mongo_client_test.go +++ b/test/sharding/mongo_client_test.go @@ -85,6 +85,10 @@ func TestClientWithShardedDB(t *testing.T) { testcases.RunFindChangesBetweenServerSeqsTest(t, cli, dummyProjectID) }) + t.Run("RunFindChangeInfosBetweenServerSeqsTest test", func(t *testing.T) { + testcases.RunFindChangeInfosBetweenServerSeqsTest(t, cli, dummyProjectID) + }) + t.Run("RunFindClosestSnapshotInfo test", func(t *testing.T) { testcases.RunFindClosestSnapshotInfoTest(t, cli, dummyProjectID) })