diff --git a/api/v2/markdown_service.go b/api/v2/markdown_service.go index 81f1486d..d61ea15e 100644 --- a/api/v2/markdown_service.go +++ b/api/v2/markdown_service.go @@ -76,6 +76,8 @@ func convertFromASTNode(rawNode ast.Node) *apiv2pb.Node { node.Node = &apiv2pb.Node_ImageNode{ImageNode: &apiv2pb.ImageNode{AltText: n.AltText, Url: n.URL}} case *ast.Link: node.Node = &apiv2pb.Node_LinkNode{LinkNode: &apiv2pb.LinkNode{Text: n.Text, Url: n.URL}} + case *ast.AutoLink: + node.Node = &apiv2pb.Node_AutoLinkNode{AutoLinkNode: &apiv2pb.AutoLinkNode{Url: n.URL}} case *ast.Tag: node.Node = &apiv2pb.Node_TagNode{TagNode: &apiv2pb.TagNode{Content: n.Content}} case *ast.Strikethrough: diff --git a/plugin/gomark/ast/ast.go b/plugin/gomark/ast/ast.go index e0599415..8f136a3c 100644 --- a/plugin/gomark/ast/ast.go +++ b/plugin/gomark/ast/ast.go @@ -22,6 +22,7 @@ const ( CodeNode ImageNode LinkNode + AutoLinkNode TagNode StrikethroughNode EscapingCharacterNode @@ -61,6 +62,8 @@ func (t NodeType) String() string { return "ImageNode" case LinkNode: return "LinkNode" + case AutoLinkNode: + return "AutoLinkNode" case TagNode: return "TagNode" case StrikethroughNode: diff --git a/plugin/gomark/ast/inline.go b/plugin/gomark/ast/inline.go index 82450fb0..4e8dfe62 100644 --- a/plugin/gomark/ast/inline.go +++ b/plugin/gomark/ast/inline.go @@ -82,6 +82,16 @@ func (*Link) Type() NodeType { return LinkNode } +type AutoLink struct { + BaseInline + + URL string +} + +func (*AutoLink) Type() NodeType { + return AutoLinkNode +} + type Tag struct { BaseInline diff --git a/plugin/gomark/parser/auto_link.go b/plugin/gomark/parser/auto_link.go new file mode 100644 index 00000000..ec47eb0b --- /dev/null +++ b/plugin/gomark/parser/auto_link.go @@ -0,0 +1,50 @@ +package parser + +import ( + "errors" + + "github.com/usememos/memos/plugin/gomark/ast" + "github.com/usememos/memos/plugin/gomark/parser/tokenizer" +) + +type AutoLinkParser struct{} + +func NewAutoLinkParser() *AutoLinkParser { + return &AutoLinkParser{} +} + +func (*AutoLinkParser) Match(tokens []*tokenizer.Token) (int, bool) { + if len(tokens) < 3 { + return 0, false + } + if tokens[0].Type != tokenizer.LessThan { + return 0, false + } + urlTokens := []*tokenizer.Token{} + for _, token := range tokens[1:] { + if token.Type == tokenizer.Newline || token.Type == tokenizer.Space { + return 0, false + } + if token.Type == tokenizer.GreaterThan { + break + } + urlTokens = append(urlTokens, token) + } + if 2+len(urlTokens) > len(tokens) { + return 0, false + } + + return 2 + len(urlTokens), true +} + +func (p *AutoLinkParser) Parse(tokens []*tokenizer.Token) (ast.Node, error) { + size, ok := p.Match(tokens) + if size == 0 || !ok { + return nil, errors.New("not matched") + } + + urlTokens := tokens[1 : size-1] + return &ast.AutoLink{ + URL: tokenizer.Stringify(urlTokens), + }, nil +} diff --git a/plugin/gomark/parser/auto_link_test.go b/plugin/gomark/parser/auto_link_test.go new file mode 100644 index 00000000..4f3e315c --- /dev/null +++ b/plugin/gomark/parser/auto_link_test.go @@ -0,0 +1,33 @@ +package parser + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/usememos/memos/plugin/gomark/ast" + "github.com/usememos/memos/plugin/gomark/parser/tokenizer" +) + +func TestAutoLinkParser(t *testing.T) { + tests := []struct { + text string + link ast.Node + }{ + { + text: "", + link: &ast.AutoLink{ + URL: "https://example.com", + }, + }, + } + for _, test := range tests { + tokens := tokenizer.Tokenize(test.text) + node, _ := NewAutoLinkParser().Parse(tokens) + require.Equal(t, StringifyNodes([]ast.Node{test.link}), StringifyNodes([]ast.Node{node})) + } +} diff --git a/plugin/gomark/parser/parser.go b/plugin/gomark/parser/parser.go index 3ceadcb2..c3e7633c 100644 --- a/plugin/gomark/parser/parser.go +++ b/plugin/gomark/parser/parser.go @@ -76,6 +76,7 @@ var defaultInlineParsers = []InlineParser{ NewBoldItalicParser(), NewImageParser(), NewLinkParser(), + NewAutoLinkParser(), NewBoldParser(), NewItalicParser(), NewCodeParser(), diff --git a/plugin/gomark/parser/parser_test.go b/plugin/gomark/parser/parser_test.go index cbde6b94..827e6dad 100644 --- a/plugin/gomark/parser/parser_test.go +++ b/plugin/gomark/parser/parser_test.go @@ -250,6 +250,8 @@ func StringifyNode(node ast.Node) string { return "Image(" + n.URL + ", " + n.AltText + ")" case *ast.Link: return "Link(" + n.Text + ", " + n.URL + ")" + case *ast.AutoLink: + return "AutoLink(" + n.URL + ")" case *ast.Tag: return "Tag(" + n.Content + ")" case *ast.Strikethrough: diff --git a/plugin/gomark/parser/tokenizer/tokenizer.go b/plugin/gomark/parser/tokenizer/tokenizer.go index de217037..ea79158e 100644 --- a/plugin/gomark/parser/tokenizer/tokenizer.go +++ b/plugin/gomark/parser/tokenizer/tokenizer.go @@ -16,6 +16,7 @@ const ( Hyphen TokenType = "-" PlusSign TokenType = "+" Dot TokenType = "." + LessThan TokenType = "<" GreaterThan TokenType = ">" Backslash TokenType = "\\" Newline TokenType = "\n" @@ -65,6 +66,8 @@ func Tokenize(text string) []*Token { tokens = append(tokens, NewToken(Tilde, "~")) case '-': tokens = append(tokens, NewToken(Hyphen, "-")) + case '<': + tokens = append(tokens, NewToken(LessThan, "<")) case '>': tokens = append(tokens, NewToken(GreaterThan, ">")) case '+': diff --git a/proto/api/v2/markdown_service.proto b/proto/api/v2/markdown_service.proto index 3ce0bf28..64357e23 100644 --- a/proto/api/v2/markdown_service.proto +++ b/proto/api/v2/markdown_service.proto @@ -41,9 +41,10 @@ enum NodeType { CODE = 14; IMAGE = 15; LINK = 16; - TAG = 17; - STRIKETHROUGH = 18; - ESCAPING_CHARACTER = 19; + AUTO_LINK = 17; + TAG = 18; + STRIKETHROUGH = 19; + ESCAPING_CHARACTER = 20; } message Node { @@ -65,9 +66,10 @@ message Node { CodeNode code_node = 15; ImageNode image_node = 16; LinkNode link_node = 17; - TagNode tag_node = 18; - StrikethroughNode strikethrough_node = 19; - EscapingCharacterNode escaping_character_node = 20; + AutoLinkNode auto_link_node = 18; + TagNode tag_node = 19; + StrikethroughNode strikethrough_node = 20; + EscapingCharacterNode escaping_character_node = 21; } } @@ -144,6 +146,10 @@ message LinkNode { string url = 2; } +message AutoLinkNode { + string url = 1; +} + message TagNode { string content = 1; } diff --git a/proto/gen/api/v2/README.md b/proto/gen/api/v2/README.md index 3fef6ec2..4dc5e244 100644 --- a/proto/gen/api/v2/README.md +++ b/proto/gen/api/v2/README.md @@ -66,6 +66,7 @@ - [InboxService](#memos-api-v2-InboxService) - [api/v2/markdown_service.proto](#api_v2_markdown_service-proto) + - [AutoLinkNode](#memos-api-v2-AutoLinkNode) - [BlockquoteNode](#memos-api-v2-BlockquoteNode) - [BoldItalicNode](#memos-api-v2-BoldItalicNode) - [BoldNode](#memos-api-v2-BoldNode) @@ -956,6 +957,21 @@ + + +### AutoLinkNode + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| url | [string](#string) | | | + + + + + + ### BlockquoteNode @@ -1163,6 +1179,7 @@ | code_node | [CodeNode](#memos-api-v2-CodeNode) | | | | image_node | [ImageNode](#memos-api-v2-ImageNode) | | | | link_node | [LinkNode](#memos-api-v2-LinkNode) | | | +| auto_link_node | [AutoLinkNode](#memos-api-v2-AutoLinkNode) | | | | tag_node | [TagNode](#memos-api-v2-TagNode) | | | | strikethrough_node | [StrikethroughNode](#memos-api-v2-StrikethroughNode) | | | | escaping_character_node | [EscapingCharacterNode](#memos-api-v2-EscapingCharacterNode) | | | @@ -1337,9 +1354,10 @@ | CODE | 14 | | | IMAGE | 15 | | | LINK | 16 | | -| TAG | 17 | | -| STRIKETHROUGH | 18 | | -| ESCAPING_CHARACTER | 19 | | +| AUTO_LINK | 17 | | +| TAG | 18 | | +| STRIKETHROUGH | 19 | | +| ESCAPING_CHARACTER | 20 | | diff --git a/proto/gen/api/v2/markdown_service.pb.go b/proto/gen/api/v2/markdown_service.pb.go index 16b93436..5e6ef7a6 100644 --- a/proto/gen/api/v2/markdown_service.pb.go +++ b/proto/gen/api/v2/markdown_service.pb.go @@ -41,9 +41,10 @@ const ( NodeType_CODE NodeType = 14 NodeType_IMAGE NodeType = 15 NodeType_LINK NodeType = 16 - NodeType_TAG NodeType = 17 - NodeType_STRIKETHROUGH NodeType = 18 - NodeType_ESCAPING_CHARACTER NodeType = 19 + NodeType_AUTO_LINK NodeType = 17 + NodeType_TAG NodeType = 18 + NodeType_STRIKETHROUGH NodeType = 19 + NodeType_ESCAPING_CHARACTER NodeType = 20 ) // Enum value maps for NodeType. @@ -66,9 +67,10 @@ var ( 14: "CODE", 15: "IMAGE", 16: "LINK", - 17: "TAG", - 18: "STRIKETHROUGH", - 19: "ESCAPING_CHARACTER", + 17: "AUTO_LINK", + 18: "TAG", + 19: "STRIKETHROUGH", + 20: "ESCAPING_CHARACTER", } NodeType_value = map[string]int32{ "NODE_UNSPECIFIED": 0, @@ -88,9 +90,10 @@ var ( "CODE": 14, "IMAGE": 15, "LINK": 16, - "TAG": 17, - "STRIKETHROUGH": 18, - "ESCAPING_CHARACTER": 19, + "AUTO_LINK": 17, + "TAG": 18, + "STRIKETHROUGH": 19, + "ESCAPING_CHARACTER": 20, } ) @@ -239,6 +242,7 @@ type Node struct { // *Node_CodeNode // *Node_ImageNode // *Node_LinkNode + // *Node_AutoLinkNode // *Node_TagNode // *Node_StrikethroughNode // *Node_EscapingCharacterNode @@ -403,6 +407,13 @@ func (x *Node) GetLinkNode() *LinkNode { return nil } +func (x *Node) GetAutoLinkNode() *AutoLinkNode { + if x, ok := x.GetNode().(*Node_AutoLinkNode); ok { + return x.AutoLinkNode + } + return nil +} + func (x *Node) GetTagNode() *TagNode { if x, ok := x.GetNode().(*Node_TagNode); ok { return x.TagNode @@ -492,16 +503,20 @@ type Node_LinkNode struct { LinkNode *LinkNode `protobuf:"bytes,17,opt,name=link_node,json=linkNode,proto3,oneof"` } +type Node_AutoLinkNode struct { + AutoLinkNode *AutoLinkNode `protobuf:"bytes,18,opt,name=auto_link_node,json=autoLinkNode,proto3,oneof"` +} + type Node_TagNode struct { - TagNode *TagNode `protobuf:"bytes,18,opt,name=tag_node,json=tagNode,proto3,oneof"` + TagNode *TagNode `protobuf:"bytes,19,opt,name=tag_node,json=tagNode,proto3,oneof"` } type Node_StrikethroughNode struct { - StrikethroughNode *StrikethroughNode `protobuf:"bytes,19,opt,name=strikethrough_node,json=strikethroughNode,proto3,oneof"` + StrikethroughNode *StrikethroughNode `protobuf:"bytes,20,opt,name=strikethrough_node,json=strikethroughNode,proto3,oneof"` } type Node_EscapingCharacterNode struct { - EscapingCharacterNode *EscapingCharacterNode `protobuf:"bytes,20,opt,name=escaping_character_node,json=escapingCharacterNode,proto3,oneof"` + EscapingCharacterNode *EscapingCharacterNode `protobuf:"bytes,21,opt,name=escaping_character_node,json=escapingCharacterNode,proto3,oneof"` } func (*Node_LineBreakNode) isNode_Node() {} @@ -536,6 +551,8 @@ func (*Node_ImageNode) isNode_Node() {} func (*Node_LinkNode) isNode_Node() {} +func (*Node_AutoLinkNode) isNode_Node() {} + func (*Node_TagNode) isNode_Node() {} func (*Node_StrikethroughNode) isNode_Node() {} @@ -1373,6 +1390,53 @@ func (x *LinkNode) GetUrl() string { return "" } +type AutoLinkNode struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Url string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"` +} + +func (x *AutoLinkNode) Reset() { + *x = AutoLinkNode{} + if protoimpl.UnsafeEnabled { + mi := &file_api_v2_markdown_service_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AutoLinkNode) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AutoLinkNode) ProtoMessage() {} + +func (x *AutoLinkNode) ProtoReflect() protoreflect.Message { + mi := &file_api_v2_markdown_service_proto_msgTypes[19] + 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 AutoLinkNode.ProtoReflect.Descriptor instead. +func (*AutoLinkNode) Descriptor() ([]byte, []int) { + return file_api_v2_markdown_service_proto_rawDescGZIP(), []int{19} +} + +func (x *AutoLinkNode) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + type TagNode struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1384,7 +1448,7 @@ type TagNode struct { func (x *TagNode) Reset() { *x = TagNode{} if protoimpl.UnsafeEnabled { - mi := &file_api_v2_markdown_service_proto_msgTypes[19] + mi := &file_api_v2_markdown_service_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1397,7 +1461,7 @@ func (x *TagNode) String() string { func (*TagNode) ProtoMessage() {} func (x *TagNode) ProtoReflect() protoreflect.Message { - mi := &file_api_v2_markdown_service_proto_msgTypes[19] + mi := &file_api_v2_markdown_service_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1410,7 +1474,7 @@ func (x *TagNode) ProtoReflect() protoreflect.Message { // Deprecated: Use TagNode.ProtoReflect.Descriptor instead. func (*TagNode) Descriptor() ([]byte, []int) { - return file_api_v2_markdown_service_proto_rawDescGZIP(), []int{19} + return file_api_v2_markdown_service_proto_rawDescGZIP(), []int{20} } func (x *TagNode) GetContent() string { @@ -1431,7 +1495,7 @@ type StrikethroughNode struct { func (x *StrikethroughNode) Reset() { *x = StrikethroughNode{} if protoimpl.UnsafeEnabled { - mi := &file_api_v2_markdown_service_proto_msgTypes[20] + mi := &file_api_v2_markdown_service_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1444,7 +1508,7 @@ func (x *StrikethroughNode) String() string { func (*StrikethroughNode) ProtoMessage() {} func (x *StrikethroughNode) ProtoReflect() protoreflect.Message { - mi := &file_api_v2_markdown_service_proto_msgTypes[20] + mi := &file_api_v2_markdown_service_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1457,7 +1521,7 @@ func (x *StrikethroughNode) ProtoReflect() protoreflect.Message { // Deprecated: Use StrikethroughNode.ProtoReflect.Descriptor instead. func (*StrikethroughNode) Descriptor() ([]byte, []int) { - return file_api_v2_markdown_service_proto_rawDescGZIP(), []int{20} + return file_api_v2_markdown_service_proto_rawDescGZIP(), []int{21} } func (x *StrikethroughNode) GetContent() string { @@ -1478,7 +1542,7 @@ type EscapingCharacterNode struct { func (x *EscapingCharacterNode) Reset() { *x = EscapingCharacterNode{} if protoimpl.UnsafeEnabled { - mi := &file_api_v2_markdown_service_proto_msgTypes[21] + mi := &file_api_v2_markdown_service_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1491,7 +1555,7 @@ func (x *EscapingCharacterNode) String() string { func (*EscapingCharacterNode) ProtoMessage() {} func (x *EscapingCharacterNode) ProtoReflect() protoreflect.Message { - mi := &file_api_v2_markdown_service_proto_msgTypes[21] + mi := &file_api_v2_markdown_service_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1504,7 +1568,7 @@ func (x *EscapingCharacterNode) ProtoReflect() protoreflect.Message { // Deprecated: Use EscapingCharacterNode.ProtoReflect.Descriptor instead. func (*EscapingCharacterNode) Descriptor() ([]byte, []int) { - return file_api_v2_markdown_service_proto_rawDescGZIP(), []int{21} + return file_api_v2_markdown_service_proto_rawDescGZIP(), []int{22} } func (x *EscapingCharacterNode) GetSymbol() string { @@ -1529,7 +1593,7 @@ var file_api_v2_markdown_service_proto_rawDesc = []byte{ 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x28, 0x0a, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x05, 0x6e, 0x6f, 0x64, - 0x65, 0x73, 0x22, 0xd3, 0x0a, 0x0a, 0x04, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x2a, 0x0a, 0x04, 0x74, + 0x65, 0x73, 0x22, 0x97, 0x0b, 0x0a, 0x04, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x2a, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x45, 0x0a, 0x0f, 0x6c, 0x69, 0x6e, 0x65, 0x5f, @@ -1599,136 +1663,143 @@ var file_api_v2_markdown_service_proto_rawDesc = []byte{ 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x35, 0x0a, 0x09, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x4c, 0x69, 0x6e, 0x6b, 0x4e, 0x6f, 0x64, 0x65, 0x48, - 0x00, 0x52, 0x08, 0x6c, 0x69, 0x6e, 0x6b, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x32, 0x0a, 0x08, 0x74, - 0x61, 0x67, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, - 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x54, 0x61, 0x67, - 0x4e, 0x6f, 0x64, 0x65, 0x48, 0x00, 0x52, 0x07, 0x74, 0x61, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x12, - 0x50, 0x0a, 0x12, 0x73, 0x74, 0x72, 0x69, 0x6b, 0x65, 0x74, 0x68, 0x72, 0x6f, 0x75, 0x67, 0x68, - 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6d, 0x65, - 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6b, - 0x65, 0x74, 0x68, 0x72, 0x6f, 0x75, 0x67, 0x68, 0x4e, 0x6f, 0x64, 0x65, 0x48, 0x00, 0x52, 0x11, - 0x73, 0x74, 0x72, 0x69, 0x6b, 0x65, 0x74, 0x68, 0x72, 0x6f, 0x75, 0x67, 0x68, 0x4e, 0x6f, 0x64, - 0x65, 0x12, 0x5d, 0x0a, 0x17, 0x65, 0x73, 0x63, 0x61, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x68, - 0x61, 0x72, 0x61, 0x63, 0x74, 0x65, 0x72, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x14, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, - 0x32, 0x2e, 0x45, 0x73, 0x63, 0x61, 0x70, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x72, 0x61, 0x63, - 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x48, 0x00, 0x52, 0x15, 0x65, 0x73, 0x63, 0x61, 0x70, - 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x72, 0x61, 0x63, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, - 0x42, 0x06, 0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x22, 0x0f, 0x0a, 0x0d, 0x4c, 0x69, 0x6e, 0x65, - 0x42, 0x72, 0x65, 0x61, 0x6b, 0x4e, 0x6f, 0x64, 0x65, 0x22, 0x3f, 0x0a, 0x0d, 0x50, 0x61, 0x72, - 0x61, 0x67, 0x72, 0x61, 0x70, 0x68, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x2e, 0x0a, 0x08, 0x63, 0x68, + 0x00, 0x52, 0x08, 0x6c, 0x69, 0x6e, 0x6b, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x42, 0x0a, 0x0e, 0x61, + 0x75, 0x74, 0x6f, 0x5f, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x12, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x76, 0x32, 0x2e, 0x41, 0x75, 0x74, 0x6f, 0x4c, 0x69, 0x6e, 0x6b, 0x4e, 0x6f, 0x64, 0x65, 0x48, + 0x00, 0x52, 0x0c, 0x61, 0x75, 0x74, 0x6f, 0x4c, 0x69, 0x6e, 0x6b, 0x4e, 0x6f, 0x64, 0x65, 0x12, + 0x32, 0x0a, 0x08, 0x74, 0x61, 0x67, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x13, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x15, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, + 0x2e, 0x54, 0x61, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x48, 0x00, 0x52, 0x07, 0x74, 0x61, 0x67, 0x4e, + 0x6f, 0x64, 0x65, 0x12, 0x50, 0x0a, 0x12, 0x73, 0x74, 0x72, 0x69, 0x6b, 0x65, 0x74, 0x68, 0x72, + 0x6f, 0x75, 0x67, 0x68, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1f, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x53, + 0x74, 0x72, 0x69, 0x6b, 0x65, 0x74, 0x68, 0x72, 0x6f, 0x75, 0x67, 0x68, 0x4e, 0x6f, 0x64, 0x65, + 0x48, 0x00, 0x52, 0x11, 0x73, 0x74, 0x72, 0x69, 0x6b, 0x65, 0x74, 0x68, 0x72, 0x6f, 0x75, 0x67, + 0x68, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x5d, 0x0a, 0x17, 0x65, 0x73, 0x63, 0x61, 0x70, 0x69, 0x6e, + 0x67, 0x5f, 0x63, 0x68, 0x61, 0x72, 0x61, 0x63, 0x74, 0x65, 0x72, 0x5f, 0x6e, 0x6f, 0x64, 0x65, + 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x45, 0x73, 0x63, 0x61, 0x70, 0x69, 0x6e, 0x67, 0x43, 0x68, + 0x61, 0x72, 0x61, 0x63, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x48, 0x00, 0x52, 0x15, 0x65, + 0x73, 0x63, 0x61, 0x70, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x72, 0x61, 0x63, 0x74, 0x65, 0x72, + 0x4e, 0x6f, 0x64, 0x65, 0x42, 0x06, 0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x22, 0x0f, 0x0a, 0x0d, + 0x4c, 0x69, 0x6e, 0x65, 0x42, 0x72, 0x65, 0x61, 0x6b, 0x4e, 0x6f, 0x64, 0x65, 0x22, 0x3f, 0x0a, + 0x0d, 0x50, 0x61, 0x72, 0x61, 0x67, 0x72, 0x61, 0x70, 0x68, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x2e, + 0x0a, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x12, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, + 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x22, 0x45, + 0x0a, 0x0d, 0x43, 0x6f, 0x64, 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x6f, 0x64, 0x65, 0x12, + 0x1a, 0x0a, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x53, 0x0a, 0x0b, 0x48, 0x65, 0x61, 0x64, 0x69, 0x6e, 0x67, + 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x2e, 0x0a, 0x08, 0x63, 0x68, + 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6d, + 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x4e, 0x6f, 0x64, 0x65, + 0x52, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x22, 0x2c, 0x0a, 0x12, 0x48, 0x6f, + 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x74, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x4e, 0x6f, 0x64, 0x65, + 0x12, 0x16, 0x0a, 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x22, 0x40, 0x0a, 0x0e, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x2e, 0x0a, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x4e, 0x6f, 0x64, 0x65, - 0x52, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x22, 0x45, 0x0a, 0x0d, 0x43, 0x6f, - 0x64, 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6c, - 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, - 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x22, 0x53, 0x0a, 0x0b, 0x48, 0x65, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, - 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, - 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x2e, 0x0a, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, - 0x65, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, - 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x08, 0x63, 0x68, - 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x22, 0x2c, 0x0a, 0x12, 0x48, 0x6f, 0x72, 0x69, 0x7a, 0x6f, - 0x6e, 0x74, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, - 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x79, - 0x6d, 0x62, 0x6f, 0x6c, 0x22, 0x40, 0x0a, 0x0e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x71, 0x75, 0x6f, - 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x2e, 0x0a, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, - 0x65, 0x6e, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, - 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x08, 0x63, 0x68, - 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x22, 0x59, 0x0a, 0x0f, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x65, - 0x64, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, - 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, - 0x72, 0x12, 0x2e, 0x0a, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, 0x02, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, - 0x76, 0x32, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, - 0x6e, 0x22, 0x5b, 0x0a, 0x11, 0x55, 0x6e, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x65, 0x64, 0x4c, 0x69, - 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x12, 0x2e, - 0x0a, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x12, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, - 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x22, 0x72, - 0x0a, 0x0c, 0x54, 0x61, 0x73, 0x6b, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x16, - 0x0a, 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, - 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, - 0x74, 0x65, 0x12, 0x2e, 0x0a, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, 0x03, + 0x52, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x22, 0x59, 0x0a, 0x0f, 0x4f, 0x72, + 0x64, 0x65, 0x72, 0x65, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, + 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x2e, 0x0a, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, + 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, + 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x08, 0x63, 0x68, 0x69, + 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x22, 0x5b, 0x0a, 0x11, 0x55, 0x6e, 0x6f, 0x72, 0x64, 0x65, 0x72, + 0x65, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x79, + 0x6d, 0x62, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x79, 0x6d, 0x62, + 0x6f, 0x6c, 0x12, 0x2e, 0x0a, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, - 0x65, 0x6e, 0x22, 0x24, 0x0a, 0x08, 0x54, 0x65, 0x78, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x18, - 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x52, 0x0a, 0x08, 0x42, 0x6f, 0x6c, 0x64, - 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x12, 0x2e, 0x0a, 0x08, - 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, - 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x4e, 0x6f, - 0x64, 0x65, 0x52, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x22, 0x3e, 0x0a, 0x0a, - 0x49, 0x74, 0x61, 0x6c, 0x69, 0x63, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x79, - 0x6d, 0x62, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x79, 0x6d, 0x62, - 0x6f, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x42, 0x0a, 0x0e, - 0x42, 0x6f, 0x6c, 0x64, 0x49, 0x74, 0x61, 0x6c, 0x69, 0x63, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x16, + 0x65, 0x6e, 0x22, 0x72, 0x0a, 0x0c, 0x54, 0x61, 0x73, 0x6b, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, + 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6f, + 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x63, 0x6f, + 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x2e, 0x0a, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, + 0x65, 0x6e, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x08, 0x63, 0x68, + 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x22, 0x24, 0x0a, 0x08, 0x54, 0x65, 0x78, 0x74, 0x4e, 0x6f, + 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x52, 0x0a, 0x08, + 0x42, 0x6f, 0x6c, 0x64, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x79, 0x6d, 0x62, + 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, + 0x12, 0x2e, 0x0a, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, + 0x32, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, + 0x22, 0x3e, 0x0a, 0x0a, 0x49, 0x74, 0x61, 0x6c, 0x69, 0x63, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x22, 0x24, 0x0a, 0x08, 0x43, 0x6f, 0x64, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, - 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x38, 0x0a, 0x09, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x4e, - 0x6f, 0x64, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x6c, 0x74, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x6c, 0x74, 0x54, 0x65, 0x78, 0x74, 0x12, 0x10, - 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, - 0x22, 0x30, 0x0a, 0x08, 0x4c, 0x69, 0x6e, 0x6b, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, - 0x74, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, - 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, - 0x72, 0x6c, 0x22, 0x23, 0x0a, 0x07, 0x54, 0x61, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, - 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x2d, 0x0a, 0x11, 0x53, 0x74, 0x72, 0x69, 0x6b, - 0x65, 0x74, 0x68, 0x72, 0x6f, 0x75, 0x67, 0x68, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, - 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x2f, 0x0a, 0x15, 0x45, 0x73, 0x63, 0x61, 0x70, 0x69, - 0x6e, 0x67, 0x43, 0x68, 0x61, 0x72, 0x61, 0x63, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x12, - 0x16, 0x0a, 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x2a, 0xba, 0x02, 0x0a, 0x08, 0x4e, 0x6f, 0x64, 0x65, - 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x10, 0x4e, 0x4f, 0x44, 0x45, 0x5f, 0x55, 0x4e, 0x53, - 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x4c, 0x49, - 0x4e, 0x45, 0x5f, 0x42, 0x52, 0x45, 0x41, 0x4b, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x50, 0x41, - 0x52, 0x41, 0x47, 0x52, 0x41, 0x50, 0x48, 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x43, 0x4f, 0x44, - 0x45, 0x5f, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x10, 0x03, 0x12, 0x0b, 0x0a, 0x07, 0x48, 0x45, 0x41, - 0x44, 0x49, 0x4e, 0x47, 0x10, 0x04, 0x12, 0x13, 0x0a, 0x0f, 0x48, 0x4f, 0x52, 0x49, 0x5a, 0x4f, - 0x4e, 0x54, 0x41, 0x4c, 0x5f, 0x52, 0x55, 0x4c, 0x45, 0x10, 0x05, 0x12, 0x0e, 0x0a, 0x0a, 0x42, - 0x4c, 0x4f, 0x43, 0x4b, 0x51, 0x55, 0x4f, 0x54, 0x45, 0x10, 0x06, 0x12, 0x10, 0x0a, 0x0c, 0x4f, - 0x52, 0x44, 0x45, 0x52, 0x45, 0x44, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x10, 0x07, 0x12, 0x12, 0x0a, - 0x0e, 0x55, 0x4e, 0x4f, 0x52, 0x44, 0x45, 0x52, 0x45, 0x44, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x10, - 0x08, 0x12, 0x0d, 0x0a, 0x09, 0x54, 0x41, 0x53, 0x4b, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x10, 0x09, - 0x12, 0x08, 0x0a, 0x04, 0x54, 0x45, 0x58, 0x54, 0x10, 0x0a, 0x12, 0x08, 0x0a, 0x04, 0x42, 0x4f, - 0x4c, 0x44, 0x10, 0x0b, 0x12, 0x0a, 0x0a, 0x06, 0x49, 0x54, 0x41, 0x4c, 0x49, 0x43, 0x10, 0x0c, - 0x12, 0x0f, 0x0a, 0x0b, 0x42, 0x4f, 0x4c, 0x44, 0x5f, 0x49, 0x54, 0x41, 0x4c, 0x49, 0x43, 0x10, - 0x0d, 0x12, 0x08, 0x0a, 0x04, 0x43, 0x4f, 0x44, 0x45, 0x10, 0x0e, 0x12, 0x09, 0x0a, 0x05, 0x49, - 0x4d, 0x41, 0x47, 0x45, 0x10, 0x0f, 0x12, 0x08, 0x0a, 0x04, 0x4c, 0x49, 0x4e, 0x4b, 0x10, 0x10, - 0x12, 0x07, 0x0a, 0x03, 0x54, 0x41, 0x47, 0x10, 0x11, 0x12, 0x11, 0x0a, 0x0d, 0x53, 0x54, 0x52, - 0x49, 0x4b, 0x45, 0x54, 0x48, 0x52, 0x4f, 0x55, 0x47, 0x48, 0x10, 0x12, 0x12, 0x16, 0x0a, 0x12, - 0x45, 0x53, 0x43, 0x41, 0x50, 0x49, 0x4e, 0x47, 0x5f, 0x43, 0x48, 0x41, 0x52, 0x41, 0x43, 0x54, - 0x45, 0x52, 0x10, 0x13, 0x32, 0x88, 0x01, 0x0a, 0x0f, 0x4d, 0x61, 0x72, 0x6b, 0x64, 0x6f, 0x77, - 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x75, 0x0a, 0x0d, 0x50, 0x61, 0x72, 0x73, - 0x65, 0x4d, 0x61, 0x72, 0x6b, 0x64, 0x6f, 0x77, 0x6e, 0x12, 0x22, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, - 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x4d, 0x61, - 0x72, 0x6b, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, - 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x50, 0x61, 0x72, - 0x73, 0x65, 0x4d, 0x61, 0x72, 0x6b, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x3a, 0x01, 0x2a, 0x22, 0x10, 0x2f, - 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x6d, 0x61, 0x72, 0x6b, 0x64, 0x6f, 0x77, 0x6e, 0x42, - 0xac, 0x01, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, - 0x69, 0x2e, 0x76, 0x32, 0x42, 0x14, 0x4d, 0x61, 0x72, 0x6b, 0x64, 0x6f, 0x77, 0x6e, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 0x67, 0x69, - 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x75, 0x73, 0x65, 0x6d, 0x65, 0x6d, 0x6f, - 0x73, 0x2f, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, - 0x6e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x3b, 0x61, 0x70, 0x69, 0x76, 0x32, 0xa2, 0x02, - 0x03, 0x4d, 0x41, 0x58, 0xaa, 0x02, 0x0c, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x70, 0x69, - 0x2e, 0x56, 0x32, 0xca, 0x02, 0x0c, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0x70, 0x69, 0x5c, - 0x56, 0x32, 0xe2, 0x02, 0x18, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0x70, 0x69, 0x5c, 0x56, - 0x32, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0e, - 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x41, 0x70, 0x69, 0x3a, 0x3a, 0x56, 0x32, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x22, 0x42, 0x0a, 0x0e, 0x42, 0x6f, 0x6c, 0x64, 0x49, 0x74, 0x61, 0x6c, 0x69, 0x63, 0x4e, 0x6f, + 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x22, 0x24, 0x0a, 0x08, 0x43, 0x6f, 0x64, 0x65, 0x4e, 0x6f, 0x64, 0x65, + 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x38, 0x0a, 0x09, 0x49, 0x6d, + 0x61, 0x67, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x6c, 0x74, 0x5f, 0x74, + 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x6c, 0x74, 0x54, 0x65, + 0x78, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x75, 0x72, 0x6c, 0x22, 0x30, 0x0a, 0x08, 0x4c, 0x69, 0x6e, 0x6b, 0x4e, 0x6f, 0x64, 0x65, + 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x74, 0x65, 0x78, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x22, 0x20, 0x0a, 0x0c, 0x41, 0x75, 0x74, 0x6f, 0x4c, 0x69, + 0x6e, 0x6b, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x22, 0x23, 0x0a, 0x07, 0x54, 0x61, 0x67, 0x4e, + 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x2d, 0x0a, + 0x11, 0x53, 0x74, 0x72, 0x69, 0x6b, 0x65, 0x74, 0x68, 0x72, 0x6f, 0x75, 0x67, 0x68, 0x4e, 0x6f, + 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x2f, 0x0a, 0x15, + 0x45, 0x73, 0x63, 0x61, 0x70, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x72, 0x61, 0x63, 0x74, 0x65, + 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x2a, 0xc9, 0x02, + 0x0a, 0x08, 0x4e, 0x6f, 0x64, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x10, 0x4e, 0x4f, + 0x44, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, + 0x12, 0x0e, 0x0a, 0x0a, 0x4c, 0x49, 0x4e, 0x45, 0x5f, 0x42, 0x52, 0x45, 0x41, 0x4b, 0x10, 0x01, + 0x12, 0x0d, 0x0a, 0x09, 0x50, 0x41, 0x52, 0x41, 0x47, 0x52, 0x41, 0x50, 0x48, 0x10, 0x02, 0x12, + 0x0e, 0x0a, 0x0a, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x10, 0x03, 0x12, + 0x0b, 0x0a, 0x07, 0x48, 0x45, 0x41, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x04, 0x12, 0x13, 0x0a, 0x0f, + 0x48, 0x4f, 0x52, 0x49, 0x5a, 0x4f, 0x4e, 0x54, 0x41, 0x4c, 0x5f, 0x52, 0x55, 0x4c, 0x45, 0x10, + 0x05, 0x12, 0x0e, 0x0a, 0x0a, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x51, 0x55, 0x4f, 0x54, 0x45, 0x10, + 0x06, 0x12, 0x10, 0x0a, 0x0c, 0x4f, 0x52, 0x44, 0x45, 0x52, 0x45, 0x44, 0x5f, 0x4c, 0x49, 0x53, + 0x54, 0x10, 0x07, 0x12, 0x12, 0x0a, 0x0e, 0x55, 0x4e, 0x4f, 0x52, 0x44, 0x45, 0x52, 0x45, 0x44, + 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x10, 0x08, 0x12, 0x0d, 0x0a, 0x09, 0x54, 0x41, 0x53, 0x4b, 0x5f, + 0x4c, 0x49, 0x53, 0x54, 0x10, 0x09, 0x12, 0x08, 0x0a, 0x04, 0x54, 0x45, 0x58, 0x54, 0x10, 0x0a, + 0x12, 0x08, 0x0a, 0x04, 0x42, 0x4f, 0x4c, 0x44, 0x10, 0x0b, 0x12, 0x0a, 0x0a, 0x06, 0x49, 0x54, + 0x41, 0x4c, 0x49, 0x43, 0x10, 0x0c, 0x12, 0x0f, 0x0a, 0x0b, 0x42, 0x4f, 0x4c, 0x44, 0x5f, 0x49, + 0x54, 0x41, 0x4c, 0x49, 0x43, 0x10, 0x0d, 0x12, 0x08, 0x0a, 0x04, 0x43, 0x4f, 0x44, 0x45, 0x10, + 0x0e, 0x12, 0x09, 0x0a, 0x05, 0x49, 0x4d, 0x41, 0x47, 0x45, 0x10, 0x0f, 0x12, 0x08, 0x0a, 0x04, + 0x4c, 0x49, 0x4e, 0x4b, 0x10, 0x10, 0x12, 0x0d, 0x0a, 0x09, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x4c, + 0x49, 0x4e, 0x4b, 0x10, 0x11, 0x12, 0x07, 0x0a, 0x03, 0x54, 0x41, 0x47, 0x10, 0x12, 0x12, 0x11, + 0x0a, 0x0d, 0x53, 0x54, 0x52, 0x49, 0x4b, 0x45, 0x54, 0x48, 0x52, 0x4f, 0x55, 0x47, 0x48, 0x10, + 0x13, 0x12, 0x16, 0x0a, 0x12, 0x45, 0x53, 0x43, 0x41, 0x50, 0x49, 0x4e, 0x47, 0x5f, 0x43, 0x48, + 0x41, 0x52, 0x41, 0x43, 0x54, 0x45, 0x52, 0x10, 0x14, 0x32, 0x88, 0x01, 0x0a, 0x0f, 0x4d, 0x61, + 0x72, 0x6b, 0x64, 0x6f, 0x77, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x75, 0x0a, + 0x0d, 0x50, 0x61, 0x72, 0x73, 0x65, 0x4d, 0x61, 0x72, 0x6b, 0x64, 0x6f, 0x77, 0x6e, 0x12, 0x22, + 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x50, 0x61, + 0x72, 0x73, 0x65, 0x4d, 0x61, 0x72, 0x6b, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, + 0x32, 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x4d, 0x61, 0x72, 0x6b, 0x64, 0x6f, 0x77, 0x6e, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x3a, + 0x01, 0x2a, 0x22, 0x10, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x6d, 0x61, 0x72, 0x6b, + 0x64, 0x6f, 0x77, 0x6e, 0x42, 0xac, 0x01, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x6d, 0x65, 0x6d, + 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x42, 0x14, 0x4d, 0x61, 0x72, 0x6b, 0x64, + 0x6f, 0x77, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, + 0x01, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x75, 0x73, + 0x65, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2f, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x3b, 0x61, 0x70, + 0x69, 0x76, 0x32, 0xa2, 0x02, 0x03, 0x4d, 0x41, 0x58, 0xaa, 0x02, 0x0c, 0x4d, 0x65, 0x6d, 0x6f, + 0x73, 0x2e, 0x41, 0x70, 0x69, 0x2e, 0x56, 0x32, 0xca, 0x02, 0x0c, 0x4d, 0x65, 0x6d, 0x6f, 0x73, + 0x5c, 0x41, 0x70, 0x69, 0x5c, 0x56, 0x32, 0xe2, 0x02, 0x18, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x5c, + 0x41, 0x70, 0x69, 0x5c, 0x56, 0x32, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0xea, 0x02, 0x0e, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x41, 0x70, 0x69, 0x3a, + 0x3a, 0x56, 0x32, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1744,7 +1815,7 @@ func file_api_v2_markdown_service_proto_rawDescGZIP() []byte { } var file_api_v2_markdown_service_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_api_v2_markdown_service_proto_msgTypes = make([]protoimpl.MessageInfo, 22) +var file_api_v2_markdown_service_proto_msgTypes = make([]protoimpl.MessageInfo, 23) var file_api_v2_markdown_service_proto_goTypes = []interface{}{ (NodeType)(0), // 0: memos.api.v2.NodeType (*ParseMarkdownRequest)(nil), // 1: memos.api.v2.ParseMarkdownRequest @@ -1766,9 +1837,10 @@ var file_api_v2_markdown_service_proto_goTypes = []interface{}{ (*CodeNode)(nil), // 17: memos.api.v2.CodeNode (*ImageNode)(nil), // 18: memos.api.v2.ImageNode (*LinkNode)(nil), // 19: memos.api.v2.LinkNode - (*TagNode)(nil), // 20: memos.api.v2.TagNode - (*StrikethroughNode)(nil), // 21: memos.api.v2.StrikethroughNode - (*EscapingCharacterNode)(nil), // 22: memos.api.v2.EscapingCharacterNode + (*AutoLinkNode)(nil), // 20: memos.api.v2.AutoLinkNode + (*TagNode)(nil), // 21: memos.api.v2.TagNode + (*StrikethroughNode)(nil), // 22: memos.api.v2.StrikethroughNode + (*EscapingCharacterNode)(nil), // 23: memos.api.v2.EscapingCharacterNode } var file_api_v2_markdown_service_proto_depIdxs = []int32{ 3, // 0: memos.api.v2.ParseMarkdownResponse.nodes:type_name -> memos.api.v2.Node @@ -1789,23 +1861,24 @@ var file_api_v2_markdown_service_proto_depIdxs = []int32{ 17, // 15: memos.api.v2.Node.code_node:type_name -> memos.api.v2.CodeNode 18, // 16: memos.api.v2.Node.image_node:type_name -> memos.api.v2.ImageNode 19, // 17: memos.api.v2.Node.link_node:type_name -> memos.api.v2.LinkNode - 20, // 18: memos.api.v2.Node.tag_node:type_name -> memos.api.v2.TagNode - 21, // 19: memos.api.v2.Node.strikethrough_node:type_name -> memos.api.v2.StrikethroughNode - 22, // 20: memos.api.v2.Node.escaping_character_node:type_name -> memos.api.v2.EscapingCharacterNode - 3, // 21: memos.api.v2.ParagraphNode.children:type_name -> memos.api.v2.Node - 3, // 22: memos.api.v2.HeadingNode.children:type_name -> memos.api.v2.Node - 3, // 23: memos.api.v2.BlockquoteNode.children:type_name -> memos.api.v2.Node - 3, // 24: memos.api.v2.OrderedListNode.children:type_name -> memos.api.v2.Node - 3, // 25: memos.api.v2.UnorderedListNode.children:type_name -> memos.api.v2.Node - 3, // 26: memos.api.v2.TaskListNode.children:type_name -> memos.api.v2.Node - 3, // 27: memos.api.v2.BoldNode.children:type_name -> memos.api.v2.Node - 1, // 28: memos.api.v2.MarkdownService.ParseMarkdown:input_type -> memos.api.v2.ParseMarkdownRequest - 2, // 29: memos.api.v2.MarkdownService.ParseMarkdown:output_type -> memos.api.v2.ParseMarkdownResponse - 29, // [29:30] is the sub-list for method output_type - 28, // [28:29] is the sub-list for method input_type - 28, // [28:28] is the sub-list for extension type_name - 28, // [28:28] is the sub-list for extension extendee - 0, // [0:28] is the sub-list for field type_name + 20, // 18: memos.api.v2.Node.auto_link_node:type_name -> memos.api.v2.AutoLinkNode + 21, // 19: memos.api.v2.Node.tag_node:type_name -> memos.api.v2.TagNode + 22, // 20: memos.api.v2.Node.strikethrough_node:type_name -> memos.api.v2.StrikethroughNode + 23, // 21: memos.api.v2.Node.escaping_character_node:type_name -> memos.api.v2.EscapingCharacterNode + 3, // 22: memos.api.v2.ParagraphNode.children:type_name -> memos.api.v2.Node + 3, // 23: memos.api.v2.HeadingNode.children:type_name -> memos.api.v2.Node + 3, // 24: memos.api.v2.BlockquoteNode.children:type_name -> memos.api.v2.Node + 3, // 25: memos.api.v2.OrderedListNode.children:type_name -> memos.api.v2.Node + 3, // 26: memos.api.v2.UnorderedListNode.children:type_name -> memos.api.v2.Node + 3, // 27: memos.api.v2.TaskListNode.children:type_name -> memos.api.v2.Node + 3, // 28: memos.api.v2.BoldNode.children:type_name -> memos.api.v2.Node + 1, // 29: memos.api.v2.MarkdownService.ParseMarkdown:input_type -> memos.api.v2.ParseMarkdownRequest + 2, // 30: memos.api.v2.MarkdownService.ParseMarkdown:output_type -> memos.api.v2.ParseMarkdownResponse + 30, // [30:31] is the sub-list for method output_type + 29, // [29:30] is the sub-list for method input_type + 29, // [29:29] is the sub-list for extension type_name + 29, // [29:29] is the sub-list for extension extendee + 0, // [0:29] is the sub-list for field type_name } func init() { file_api_v2_markdown_service_proto_init() } @@ -2043,7 +2116,7 @@ func file_api_v2_markdown_service_proto_init() { } } file_api_v2_markdown_service_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TagNode); i { + switch v := v.(*AutoLinkNode); i { case 0: return &v.state case 1: @@ -2055,7 +2128,7 @@ func file_api_v2_markdown_service_proto_init() { } } file_api_v2_markdown_service_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StrikethroughNode); i { + switch v := v.(*TagNode); i { case 0: return &v.state case 1: @@ -2067,6 +2140,18 @@ func file_api_v2_markdown_service_proto_init() { } } file_api_v2_markdown_service_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StrikethroughNode); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_v2_markdown_service_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*EscapingCharacterNode); i { case 0: return &v.state @@ -2096,6 +2181,7 @@ func file_api_v2_markdown_service_proto_init() { (*Node_CodeNode)(nil), (*Node_ImageNode)(nil), (*Node_LinkNode)(nil), + (*Node_AutoLinkNode)(nil), (*Node_TagNode)(nil), (*Node_StrikethroughNode)(nil), (*Node_EscapingCharacterNode)(nil), @@ -2106,7 +2192,7 @@ func file_api_v2_markdown_service_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_api_v2_markdown_service_proto_rawDesc, NumEnums: 1, - NumMessages: 22, + NumMessages: 23, NumExtensions: 0, NumServices: 1, }, diff --git a/web/src/components/MemoContent/AutoLink.tsx b/web/src/components/MemoContent/AutoLink.tsx new file mode 100644 index 00000000..4c747b82 --- /dev/null +++ b/web/src/components/MemoContent/AutoLink.tsx @@ -0,0 +1,17 @@ +interface Props { + url: string; +} + +const AutoLink: React.FC = ({ url }: Props) => { + return ( + + {url} + + ); +}; + +export default AutoLink; diff --git a/web/src/components/MemoContent/Link.tsx b/web/src/components/MemoContent/Link.tsx index 4298ef95..904c9820 100644 --- a/web/src/components/MemoContent/Link.tsx +++ b/web/src/components/MemoContent/Link.tsx @@ -5,7 +5,11 @@ interface Props { const Link: React.FC = ({ text, url }: Props) => { return ( - + {text} ); diff --git a/web/src/components/MemoContent/Renderer.tsx b/web/src/components/MemoContent/Renderer.tsx index 83eee7a6..49b171c0 100644 --- a/web/src/components/MemoContent/Renderer.tsx +++ b/web/src/components/MemoContent/Renderer.tsx @@ -1,4 +1,5 @@ import { + AutoLinkNode, BlockquoteNode, BoldItalicNode, BoldNode, @@ -20,6 +21,7 @@ import { TextNode, UnorderedListNode, } from "@/types/proto/api/v2/markdown_service"; +import AutoLink from "./AutoLink"; import Blockquote from "./Blockquote"; import Bold from "./Bold"; import BoldItalic from "./BoldItalic"; @@ -78,6 +80,8 @@ const Renderer: React.FC = ({ node }: Props) => { return ; case NodeType.LINK: return ; + case NodeType.AUTO_LINK: + return ; case NodeType.TAG: return ; case NodeType.STRIKETHROUGH: