From 01a14996006e0a9ce5b525693d5e34d79026d8b8 Mon Sep 17 00:00:00 2001 From: joeleonjr <20135619+joeleonjr@users.noreply.github.com> Date: Thu, 27 Jun 2024 13:22:06 -0400 Subject: [PATCH] New Source: HuggingFace (#3000) * initial spike on hf * added in user and org enum * adding huggingface source * updated with lint suggestions * updated readme * addressing resources that require org approval to access * removing unneeded code * updating with new error msg for 403 * deleted unused code + added resource check in main --- README.md | 21 + main.go | 54 + pkg/engine/huggingface.go | 80 + .../source_metadatapb/source_metadata.pb.go | 1103 ++++++++------ .../source_metadata.pb.validate.go | 160 ++ pkg/pb/sourcespb/sources.pb.go | 1284 ++++++++++------- pkg/pb/sourcespb/sources.pb.validate.go | 179 +++ pkg/sources/huggingface/client.go | 223 +++ pkg/sources/huggingface/huggingface.go | 680 +++++++++ .../huggingface/huggingface_client_test.go | 651 +++++++++ pkg/sources/huggingface/huggingface_test.go | 986 +++++++++++++ pkg/sources/huggingface/repo.go | 72 + proto/source_metadata.proto | 14 + proto/sources.proto | 25 + 14 files changed, 4568 insertions(+), 964 deletions(-) create mode 100644 pkg/engine/huggingface.go create mode 100644 pkg/sources/huggingface/client.go create mode 100644 pkg/sources/huggingface/huggingface.go create mode 100644 pkg/sources/huggingface/huggingface_client_test.go create mode 100644 pkg/sources/huggingface/huggingface_test.go create mode 100644 pkg/sources/huggingface/repo.go diff --git a/README.md b/README.md index 2d8c65e36..6e8cb6a38 100644 --- a/README.md +++ b/README.md @@ -301,6 +301,27 @@ trufflehog elasticsearch \ --api-key 'MlVtVjBZ...ZSYlduYnF1djh3NG5FQQ==' ``` +## 15. Scan HuggingFace + +### Scan a HuggingFace Model, Dataset or Space + +```bash +trufflehog huggingface --model --space --dataset +``` + +### Scan all Models, Datasets and Space belonging to a HuggingFace Org/User + +```bash +trufflehog huggingface --org --user +``` + +Optionally, skip scanning a type of resource with `--skip-models`, `--skip-datasets`, `--skip-spaces` or a particular resource with `--ignore-models/datasets/spaces `. + +### Scan Discussion and PR Comments +```bash +trufflehog huggingface --model --include-discussions --include-prs +``` + # :question: FAQ - All I see is `🐷🔑🐷 TruffleHog. Unearth your secrets. 🐷🔑🐷` and the program exits, what gives? diff --git a/main.go b/main.go index 511284c81..c4911c391 100644 --- a/main.go +++ b/main.go @@ -198,6 +198,27 @@ var ( jenkinsPassword = jenkinsScan.Flag("password", "Jenkins password").Envar("JENKINS_PASSWORD").String() jenkinsInsecureSkipVerifyTLS = jenkinsScan.Flag("insecure-skip-verify-tls", "Skip TLS verification").Envar("JENKINS_INSECURE_SKIP_VERIFY_TLS").Bool() + huggingfaceScan = cli.Command("huggingface", "Find credentials in HuggingFace datasets, models and spaces.") + huggingfaceEndpoint = huggingfaceScan.Flag("endpoint", "HuggingFace endpoint.").Default("https://huggingface.co").String() + huggingfaceModels = huggingfaceScan.Flag("model", "HuggingFace model to scan. You can repeat this flag. Example: 'username/model'").Strings() + huggingfaceSpaces = huggingfaceScan.Flag("space", "HuggingFace space to scan. You can repeat this flag. Example: 'username/space'").Strings() + huggingfaceDatasets = huggingfaceScan.Flag("dataset", "HuggingFace dataset to scan. You can repeat this flag. Example: 'username/dataset'").Strings() + huggingfaceOrgs = huggingfaceScan.Flag("org", `HuggingFace organization to scan. You can repeat this flag. Example: "trufflesecurity"`).Strings() + huggingfaceUsers = huggingfaceScan.Flag("user", `HuggingFace user to scan. You can repeat this flag. Example: "trufflesecurity"`).Strings() + huggingfaceToken = huggingfaceScan.Flag("token", "HuggingFace token. Can be provided with environment variable HUGGINGFACE_TOKEN.").Envar("HUGGINGFACE_TOKEN").String() + + huggingfaceIncludeModels = huggingfaceScan.Flag("include-models", "Models to include in scan. You can repeat this flag. Must use HuggingFace model full name. Example: 'username/model' (Only used with --user or --org)").Strings() + huggingfaceIncludeSpaces = huggingfaceScan.Flag("include-spaces", "Spaces to include in scan. You can repeat this flag. Must use HuggingFace space full name. Example: 'username/space' (Only used with --user or --org)").Strings() + huggingfaceIncludeDatasets = huggingfaceScan.Flag("include-datasets", "Datasets to include in scan. You can repeat this flag. Must use HuggingFace dataset full name. Example: 'username/dataset' (Only used with --user or --org)").Strings() + huggingfaceIgnoreModels = huggingfaceScan.Flag("ignore-models", "Models to ignore in scan. You can repeat this flag. Must use HuggingFace model full name. Example: 'username/model' (Only used with --user or --org)").Strings() + huggingfaceIgnoreSpaces = huggingfaceScan.Flag("ignore-spaces", "Spaces to ignore in scan. You can repeat this flag. Must use HuggingFace space full name. Example: 'username/space' (Only used with --user or --org)").Strings() + huggingfaceIgnoreDatasets = huggingfaceScan.Flag("ignore-datasets", "Datasets to ignore in scan. You can repeat this flag. Must use HuggingFace dataset full name. Example: 'username/dataset' (Only used with --user or --org)").Strings() + huggingfaceSkipAllModels = huggingfaceScan.Flag("skip-all-models", "Skip all model scans. (Only used with --user or --org)").Bool() + huggingfaceSkipAllSpaces = huggingfaceScan.Flag("skip-all-spaces", "Skip all space scans. (Only used with --user or --org)").Bool() + huggingfaceSkipAllDatasets = huggingfaceScan.Flag("skip-all-datasets", "Skip all dataset scans. (Only used with --user or --org)").Bool() + huggingfaceIncludeDiscussions = huggingfaceScan.Flag("include-discussions", "Include discussions in scan.").Bool() + huggingfaceIncludePrs = huggingfaceScan.Flag("include-prs", "Include pull requests in scan.").Bool() + usingTUI = false ) @@ -738,6 +759,39 @@ func runSingleScan(ctx context.Context, cmd string, cfg engine.Config) (metrics, if err := eng.ScanJenkins(ctx, cfg); err != nil { return scanMetrics, fmt.Errorf("failed to scan Jenkins: %v", err) } + case huggingfaceScan.FullCommand(): + if *huggingfaceEndpoint != "" { + *huggingfaceEndpoint = strings.TrimRight(*huggingfaceEndpoint, "/") + } + + if len(*huggingfaceModels) == 0 && len(*huggingfaceSpaces) == 0 && len(*huggingfaceDatasets) == 0 && len(*huggingfaceOrgs) == 0 && len(*huggingfaceUsers) == 0 { + return scanMetrics, fmt.Errorf("invalid config: you must specify at least one organization, user, model, space or dataset") + } + + cfg := engine.HuggingfaceConfig{ + Endpoint: *huggingfaceEndpoint, + Models: *huggingfaceModels, + Spaces: *huggingfaceSpaces, + Datasets: *huggingfaceDatasets, + Organizations: *huggingfaceOrgs, + Users: *huggingfaceUsers, + Token: *huggingfaceToken, + IncludeModels: *huggingfaceIncludeModels, + IncludeSpaces: *huggingfaceIncludeSpaces, + IncludeDatasets: *huggingfaceIncludeDatasets, + IgnoreModels: *huggingfaceIgnoreModels, + IgnoreSpaces: *huggingfaceIgnoreSpaces, + IgnoreDatasets: *huggingfaceIgnoreDatasets, + SkipAllModels: *huggingfaceSkipAllModels, + SkipAllSpaces: *huggingfaceSkipAllSpaces, + SkipAllDatasets: *huggingfaceSkipAllDatasets, + IncludeDiscussions: *huggingfaceIncludeDiscussions, + IncludePrs: *huggingfaceIncludePrs, + Concurrency: *concurrency, + } + if err := eng.ScanHuggingface(ctx, cfg); err != nil { + return scanMetrics, fmt.Errorf("failed to scan HuggingFace: %v", err) + } default: return scanMetrics, fmt.Errorf("invalid command: %s", cmd) } diff --git a/pkg/engine/huggingface.go b/pkg/engine/huggingface.go new file mode 100644 index 000000000..0ec8c48d5 --- /dev/null +++ b/pkg/engine/huggingface.go @@ -0,0 +1,80 @@ +package engine + +import ( + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/anypb" + + "github.com/trufflesecurity/trufflehog/v3/pkg/context" + "github.com/trufflesecurity/trufflehog/v3/pkg/pb/sourcespb" + "github.com/trufflesecurity/trufflehog/v3/pkg/sources/huggingface" +) + +// HuggingFaceConfig represents the configuration for HuggingFace. +type HuggingfaceConfig struct { + Endpoint string + Models []string + Spaces []string + Datasets []string + Organizations []string + Users []string + IncludeModels []string + IgnoreModels []string + IncludeSpaces []string + IgnoreSpaces []string + IncludeDatasets []string + IgnoreDatasets []string + SkipAllModels bool + SkipAllSpaces bool + SkipAllDatasets bool + IncludeDiscussions bool + IncludePrs bool + Token string + Concurrency int +} + +// ScanGitHub scans HuggingFace with the provided options. +func (e *Engine) ScanHuggingface(ctx context.Context, c HuggingfaceConfig) error { + connection := sourcespb.Huggingface{ + Endpoint: c.Endpoint, + Models: c.Models, + Spaces: c.Spaces, + Datasets: c.Datasets, + Organizations: c.Organizations, + Users: c.Users, + IncludeModels: c.IncludeModels, + IgnoreModels: c.IgnoreModels, + IncludeSpaces: c.IncludeSpaces, + IgnoreSpaces: c.IgnoreSpaces, + IncludeDatasets: c.IncludeDatasets, + IgnoreDatasets: c.IgnoreDatasets, + SkipAllModels: c.SkipAllModels, + SkipAllSpaces: c.SkipAllSpaces, + SkipAllDatasets: c.SkipAllDatasets, + IncludeDiscussions: c.IncludeDiscussions, + IncludePrs: c.IncludePrs, + } + if len(c.Token) > 0 { + connection.Credential = &sourcespb.Huggingface_Token{ + Token: c.Token, + } + } else { + connection.Credential = &sourcespb.Huggingface_Unauthenticated{} + } + + var conn anypb.Any + err := anypb.MarshalFrom(&conn, &connection, proto.MarshalOptions{}) + if err != nil { + ctx.Logger().Error(err, "failed to marshal huggingface connection") + return err + } + + sourceName := "trufflehog - huggingface" + sourceID, jobID, _ := e.sourceManager.GetIDs(ctx, sourceName, sourcespb.SourceType_SOURCE_TYPE_HUGGINGFACE) + + huggingfaceSource := &huggingface.Source{} + if err := huggingfaceSource.Init(ctx, sourceName, jobID, sourceID, true, &conn, c.Concurrency); err != nil { + return err + } + _, err = e.sourceManager.Run(ctx, sourceName, huggingfaceSource) + return err +} diff --git a/pkg/pb/source_metadatapb/source_metadata.pb.go b/pkg/pb/source_metadatapb/source_metadata.pb.go index c6b9f24df..37165f7bd 100644 --- a/pkg/pb/source_metadatapb/source_metadata.pb.go +++ b/pkg/pb/source_metadatapb/source_metadata.pb.go @@ -1300,6 +1300,125 @@ func (x *GCS) GetContentType() string { return "" } +type Huggingface struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Link string `protobuf:"bytes,1,opt,name=link,proto3" json:"link,omitempty"` + Username string `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"` + Repository string `protobuf:"bytes,3,opt,name=repository,proto3" json:"repository,omitempty"` + Commit string `protobuf:"bytes,4,opt,name=commit,proto3" json:"commit,omitempty"` + Email string `protobuf:"bytes,5,opt,name=email,proto3" json:"email,omitempty"` + File string `protobuf:"bytes,6,opt,name=file,proto3" json:"file,omitempty"` + Timestamp string `protobuf:"bytes,7,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + Line int64 `protobuf:"varint,8,opt,name=line,proto3" json:"line,omitempty"` + Visibility Visibility `protobuf:"varint,9,opt,name=visibility,proto3,enum=source_metadata.Visibility" json:"visibility,omitempty"` + ResourceType string `protobuf:"bytes,10,opt,name=resource_type,json=resourceType,proto3" json:"resource_type,omitempty"` +} + +func (x *Huggingface) Reset() { + *x = Huggingface{} + if protoimpl.UnsafeEnabled { + mi := &file_source_metadata_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Huggingface) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Huggingface) ProtoMessage() {} + +func (x *Huggingface) ProtoReflect() protoreflect.Message { + mi := &file_source_metadata_proto_msgTypes[13] + 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 Huggingface.ProtoReflect.Descriptor instead. +func (*Huggingface) Descriptor() ([]byte, []int) { + return file_source_metadata_proto_rawDescGZIP(), []int{13} +} + +func (x *Huggingface) GetLink() string { + if x != nil { + return x.Link + } + return "" +} + +func (x *Huggingface) GetUsername() string { + if x != nil { + return x.Username + } + return "" +} + +func (x *Huggingface) GetRepository() string { + if x != nil { + return x.Repository + } + return "" +} + +func (x *Huggingface) GetCommit() string { + if x != nil { + return x.Commit + } + return "" +} + +func (x *Huggingface) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +func (x *Huggingface) GetFile() string { + if x != nil { + return x.File + } + return "" +} + +func (x *Huggingface) GetTimestamp() string { + if x != nil { + return x.Timestamp + } + return "" +} + +func (x *Huggingface) GetLine() int64 { + if x != nil { + return x.Line + } + return 0 +} + +func (x *Huggingface) GetVisibility() Visibility { + if x != nil { + return x.Visibility + } + return Visibility_public +} + +func (x *Huggingface) GetResourceType() string { + if x != nil { + return x.ResourceType + } + return "" +} + type Jira struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1316,7 +1435,7 @@ type Jira struct { func (x *Jira) Reset() { *x = Jira{} if protoimpl.UnsafeEnabled { - mi := &file_source_metadata_proto_msgTypes[13] + mi := &file_source_metadata_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1329,7 +1448,7 @@ func (x *Jira) String() string { func (*Jira) ProtoMessage() {} func (x *Jira) ProtoReflect() protoreflect.Message { - mi := &file_source_metadata_proto_msgTypes[13] + mi := &file_source_metadata_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1342,7 +1461,7 @@ func (x *Jira) ProtoReflect() protoreflect.Message { // Deprecated: Use Jira.ProtoReflect.Descriptor instead. func (*Jira) Descriptor() ([]byte, []int) { - return file_source_metadata_proto_rawDescGZIP(), []int{13} + return file_source_metadata_proto_rawDescGZIP(), []int{14} } func (x *Jira) GetIssue() string { @@ -1402,7 +1521,7 @@ type NPM struct { func (x *NPM) Reset() { *x = NPM{} if protoimpl.UnsafeEnabled { - mi := &file_source_metadata_proto_msgTypes[14] + mi := &file_source_metadata_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1415,7 +1534,7 @@ func (x *NPM) String() string { func (*NPM) ProtoMessage() {} func (x *NPM) ProtoReflect() protoreflect.Message { - mi := &file_source_metadata_proto_msgTypes[14] + mi := &file_source_metadata_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1428,7 +1547,7 @@ func (x *NPM) ProtoReflect() protoreflect.Message { // Deprecated: Use NPM.ProtoReflect.Descriptor instead. func (*NPM) Descriptor() ([]byte, []int) { - return file_source_metadata_proto_rawDescGZIP(), []int{14} + return file_source_metadata_proto_rawDescGZIP(), []int{15} } func (x *NPM) GetFile() string { @@ -1481,7 +1600,7 @@ type PyPi struct { func (x *PyPi) Reset() { *x = PyPi{} if protoimpl.UnsafeEnabled { - mi := &file_source_metadata_proto_msgTypes[15] + mi := &file_source_metadata_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1494,7 +1613,7 @@ func (x *PyPi) String() string { func (*PyPi) ProtoMessage() {} func (x *PyPi) ProtoReflect() protoreflect.Message { - mi := &file_source_metadata_proto_msgTypes[15] + mi := &file_source_metadata_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1507,7 +1626,7 @@ func (x *PyPi) ProtoReflect() protoreflect.Message { // Deprecated: Use PyPi.ProtoReflect.Descriptor instead. func (*PyPi) Descriptor() ([]byte, []int) { - return file_source_metadata_proto_rawDescGZIP(), []int{15} + return file_source_metadata_proto_rawDescGZIP(), []int{16} } func (x *PyPi) GetFile() string { @@ -1560,7 +1679,7 @@ type S3 struct { func (x *S3) Reset() { *x = S3{} if protoimpl.UnsafeEnabled { - mi := &file_source_metadata_proto_msgTypes[16] + mi := &file_source_metadata_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1573,7 +1692,7 @@ func (x *S3) String() string { func (*S3) ProtoMessage() {} func (x *S3) ProtoReflect() protoreflect.Message { - mi := &file_source_metadata_proto_msgTypes[16] + mi := &file_source_metadata_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1586,7 +1705,7 @@ func (x *S3) ProtoReflect() protoreflect.Message { // Deprecated: Use S3.ProtoReflect.Descriptor instead. func (*S3) Descriptor() ([]byte, []int) { - return file_source_metadata_proto_rawDescGZIP(), []int{16} + return file_source_metadata_proto_rawDescGZIP(), []int{17} } func (x *S3) GetBucket() string { @@ -1643,7 +1762,7 @@ type Slack struct { func (x *Slack) Reset() { *x = Slack{} if protoimpl.UnsafeEnabled { - mi := &file_source_metadata_proto_msgTypes[17] + mi := &file_source_metadata_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1656,7 +1775,7 @@ func (x *Slack) String() string { func (*Slack) ProtoMessage() {} func (x *Slack) ProtoReflect() protoreflect.Message { - mi := &file_source_metadata_proto_msgTypes[17] + mi := &file_source_metadata_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1669,7 +1788,7 @@ func (x *Slack) ProtoReflect() protoreflect.Message { // Deprecated: Use Slack.ProtoReflect.Descriptor instead. func (*Slack) Descriptor() ([]byte, []int) { - return file_source_metadata_proto_rawDescGZIP(), []int{17} + return file_source_metadata_proto_rawDescGZIP(), []int{18} } func (x *Slack) GetChannelId() string { @@ -1751,7 +1870,7 @@ type Gerrit struct { func (x *Gerrit) Reset() { *x = Gerrit{} if protoimpl.UnsafeEnabled { - mi := &file_source_metadata_proto_msgTypes[18] + mi := &file_source_metadata_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1764,7 +1883,7 @@ func (x *Gerrit) String() string { func (*Gerrit) ProtoMessage() {} func (x *Gerrit) ProtoReflect() protoreflect.Message { - mi := &file_source_metadata_proto_msgTypes[18] + mi := &file_source_metadata_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1777,7 +1896,7 @@ func (x *Gerrit) ProtoReflect() protoreflect.Message { // Deprecated: Use Gerrit.ProtoReflect.Descriptor instead. func (*Gerrit) Descriptor() ([]byte, []int) { - return file_source_metadata_proto_rawDescGZIP(), []int{18} + return file_source_metadata_proto_rawDescGZIP(), []int{19} } func (x *Gerrit) GetCommit() string { @@ -1833,7 +1952,7 @@ type Test struct { func (x *Test) Reset() { *x = Test{} if protoimpl.UnsafeEnabled { - mi := &file_source_metadata_proto_msgTypes[19] + mi := &file_source_metadata_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1846,7 +1965,7 @@ func (x *Test) String() string { func (*Test) ProtoMessage() {} func (x *Test) ProtoReflect() protoreflect.Message { - mi := &file_source_metadata_proto_msgTypes[19] + mi := &file_source_metadata_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1859,7 +1978,7 @@ func (x *Test) ProtoReflect() protoreflect.Message { // Deprecated: Use Test.ProtoReflect.Descriptor instead. func (*Test) Descriptor() ([]byte, []int) { - return file_source_metadata_proto_rawDescGZIP(), []int{19} + return file_source_metadata_proto_rawDescGZIP(), []int{20} } func (x *Test) GetFile() string { @@ -1883,7 +2002,7 @@ type Jenkins struct { func (x *Jenkins) Reset() { *x = Jenkins{} if protoimpl.UnsafeEnabled { - mi := &file_source_metadata_proto_msgTypes[20] + mi := &file_source_metadata_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1896,7 +2015,7 @@ func (x *Jenkins) String() string { func (*Jenkins) ProtoMessage() {} func (x *Jenkins) ProtoReflect() protoreflect.Message { - mi := &file_source_metadata_proto_msgTypes[20] + mi := &file_source_metadata_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1909,7 +2028,7 @@ func (x *Jenkins) ProtoReflect() protoreflect.Message { // Deprecated: Use Jenkins.ProtoReflect.Descriptor instead. func (*Jenkins) Descriptor() ([]byte, []int) { - return file_source_metadata_proto_rawDescGZIP(), []int{20} + return file_source_metadata_proto_rawDescGZIP(), []int{21} } func (x *Jenkins) GetProjectName() string { @@ -1960,7 +2079,7 @@ type Teams struct { func (x *Teams) Reset() { *x = Teams{} if protoimpl.UnsafeEnabled { - mi := &file_source_metadata_proto_msgTypes[21] + mi := &file_source_metadata_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1973,7 +2092,7 @@ func (x *Teams) String() string { func (*Teams) ProtoMessage() {} func (x *Teams) ProtoReflect() protoreflect.Message { - mi := &file_source_metadata_proto_msgTypes[21] + mi := &file_source_metadata_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1986,7 +2105,7 @@ func (x *Teams) ProtoReflect() protoreflect.Message { // Deprecated: Use Teams.ProtoReflect.Descriptor instead. func (*Teams) Descriptor() ([]byte, []int) { - return file_source_metadata_proto_rawDescGZIP(), []int{21} + return file_source_metadata_proto_rawDescGZIP(), []int{22} } func (x *Teams) GetChannelId() string { @@ -2076,7 +2195,7 @@ type Artifactory struct { func (x *Artifactory) Reset() { *x = Artifactory{} if protoimpl.UnsafeEnabled { - mi := &file_source_metadata_proto_msgTypes[22] + mi := &file_source_metadata_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2089,7 +2208,7 @@ func (x *Artifactory) String() string { func (*Artifactory) ProtoMessage() {} func (x *Artifactory) ProtoReflect() protoreflect.Message { - mi := &file_source_metadata_proto_msgTypes[22] + mi := &file_source_metadata_proto_msgTypes[23] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2102,7 +2221,7 @@ func (x *Artifactory) ProtoReflect() protoreflect.Message { // Deprecated: Use Artifactory.ProtoReflect.Descriptor instead. func (*Artifactory) Descriptor() ([]byte, []int) { - return file_source_metadata_proto_rawDescGZIP(), []int{22} + return file_source_metadata_proto_rawDescGZIP(), []int{23} } func (x *Artifactory) GetRepo() string { @@ -2163,7 +2282,7 @@ type Syslog struct { func (x *Syslog) Reset() { *x = Syslog{} if protoimpl.UnsafeEnabled { - mi := &file_source_metadata_proto_msgTypes[23] + mi := &file_source_metadata_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2176,7 +2295,7 @@ func (x *Syslog) String() string { func (*Syslog) ProtoMessage() {} func (x *Syslog) ProtoReflect() protoreflect.Message { - mi := &file_source_metadata_proto_msgTypes[23] + mi := &file_source_metadata_proto_msgTypes[24] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2189,7 +2308,7 @@ func (x *Syslog) ProtoReflect() protoreflect.Message { // Deprecated: Use Syslog.ProtoReflect.Descriptor instead. func (*Syslog) Descriptor() ([]byte, []int) { - return file_source_metadata_proto_rawDescGZIP(), []int{23} + return file_source_metadata_proto_rawDescGZIP(), []int{24} } func (x *Syslog) GetHostname() string { @@ -2250,7 +2369,7 @@ type Forager struct { func (x *Forager) Reset() { *x = Forager{} if protoimpl.UnsafeEnabled { - mi := &file_source_metadata_proto_msgTypes[24] + mi := &file_source_metadata_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2263,7 +2382,7 @@ func (x *Forager) String() string { func (*Forager) ProtoMessage() {} func (x *Forager) ProtoReflect() protoreflect.Message { - mi := &file_source_metadata_proto_msgTypes[24] + mi := &file_source_metadata_proto_msgTypes[25] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2276,7 +2395,7 @@ func (x *Forager) ProtoReflect() protoreflect.Message { // Deprecated: Use Forager.ProtoReflect.Descriptor instead. func (*Forager) Descriptor() ([]byte, []int) { - return file_source_metadata_proto_rawDescGZIP(), []int{24} + return file_source_metadata_proto_rawDescGZIP(), []int{25} } func (m *Forager) GetMetadata() isForager_Metadata { @@ -2346,7 +2465,7 @@ type SharePoint struct { func (x *SharePoint) Reset() { *x = SharePoint{} if protoimpl.UnsafeEnabled { - mi := &file_source_metadata_proto_msgTypes[25] + mi := &file_source_metadata_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2359,7 +2478,7 @@ func (x *SharePoint) String() string { func (*SharePoint) ProtoMessage() {} func (x *SharePoint) ProtoReflect() protoreflect.Message { - mi := &file_source_metadata_proto_msgTypes[25] + mi := &file_source_metadata_proto_msgTypes[26] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2372,7 +2491,7 @@ func (x *SharePoint) ProtoReflect() protoreflect.Message { // Deprecated: Use SharePoint.ProtoReflect.Descriptor instead. func (*SharePoint) Descriptor() ([]byte, []int) { - return file_source_metadata_proto_rawDescGZIP(), []int{25} + return file_source_metadata_proto_rawDescGZIP(), []int{26} } func (x *SharePoint) GetLink() string { @@ -2441,7 +2560,7 @@ type GoogleDrive struct { func (x *GoogleDrive) Reset() { *x = GoogleDrive{} if protoimpl.UnsafeEnabled { - mi := &file_source_metadata_proto_msgTypes[26] + mi := &file_source_metadata_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2454,7 +2573,7 @@ func (x *GoogleDrive) String() string { func (*GoogleDrive) ProtoMessage() {} func (x *GoogleDrive) ProtoReflect() protoreflect.Message { - mi := &file_source_metadata_proto_msgTypes[26] + mi := &file_source_metadata_proto_msgTypes[27] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2467,7 +2586,7 @@ func (x *GoogleDrive) ProtoReflect() protoreflect.Message { // Deprecated: Use GoogleDrive.ProtoReflect.Descriptor instead. func (*GoogleDrive) Descriptor() ([]byte, []int) { - return file_source_metadata_proto_rawDescGZIP(), []int{26} + return file_source_metadata_proto_rawDescGZIP(), []int{27} } func (x *GoogleDrive) GetFile() string { @@ -2540,7 +2659,7 @@ type AzureRepos struct { func (x *AzureRepos) Reset() { *x = AzureRepos{} if protoimpl.UnsafeEnabled { - mi := &file_source_metadata_proto_msgTypes[27] + mi := &file_source_metadata_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2553,7 +2672,7 @@ func (x *AzureRepos) String() string { func (*AzureRepos) ProtoMessage() {} func (x *AzureRepos) ProtoReflect() protoreflect.Message { - mi := &file_source_metadata_proto_msgTypes[27] + mi := &file_source_metadata_proto_msgTypes[28] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2566,7 +2685,7 @@ func (x *AzureRepos) ProtoReflect() protoreflect.Message { // Deprecated: Use AzureRepos.ProtoReflect.Descriptor instead. func (*AzureRepos) Descriptor() ([]byte, []int) { - return file_source_metadata_proto_rawDescGZIP(), []int{27} + return file_source_metadata_proto_rawDescGZIP(), []int{28} } func (x *AzureRepos) GetLink() string { @@ -2671,7 +2790,7 @@ type Postman struct { func (x *Postman) Reset() { *x = Postman{} if protoimpl.UnsafeEnabled { - mi := &file_source_metadata_proto_msgTypes[28] + mi := &file_source_metadata_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2684,7 +2803,7 @@ func (x *Postman) String() string { func (*Postman) ProtoMessage() {} func (x *Postman) ProtoReflect() protoreflect.Message { - mi := &file_source_metadata_proto_msgTypes[28] + mi := &file_source_metadata_proto_msgTypes[29] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2697,7 +2816,7 @@ func (x *Postman) ProtoReflect() protoreflect.Message { // Deprecated: Use Postman.ProtoReflect.Descriptor instead. func (*Postman) Descriptor() ([]byte, []int) { - return file_source_metadata_proto_rawDescGZIP(), []int{28} + return file_source_metadata_proto_rawDescGZIP(), []int{29} } func (x *Postman) GetLink() string { @@ -2818,7 +2937,7 @@ type Vector struct { func (x *Vector) Reset() { *x = Vector{} if protoimpl.UnsafeEnabled { - mi := &file_source_metadata_proto_msgTypes[29] + mi := &file_source_metadata_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2831,7 +2950,7 @@ func (x *Vector) String() string { func (*Vector) ProtoMessage() {} func (x *Vector) ProtoReflect() protoreflect.Message { - mi := &file_source_metadata_proto_msgTypes[29] + mi := &file_source_metadata_proto_msgTypes[30] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2844,7 +2963,7 @@ func (x *Vector) ProtoReflect() protoreflect.Message { // Deprecated: Use Vector.ProtoReflect.Descriptor instead. func (*Vector) Descriptor() ([]byte, []int) { - return file_source_metadata_proto_rawDescGZIP(), []int{29} + return file_source_metadata_proto_rawDescGZIP(), []int{30} } func (x *Vector) GetTimestamp() *timestamppb.Timestamp { @@ -2882,7 +3001,7 @@ type Webhook struct { func (x *Webhook) Reset() { *x = Webhook{} if protoimpl.UnsafeEnabled { - mi := &file_source_metadata_proto_msgTypes[30] + mi := &file_source_metadata_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2895,7 +3014,7 @@ func (x *Webhook) String() string { func (*Webhook) ProtoMessage() {} func (x *Webhook) ProtoReflect() protoreflect.Message { - mi := &file_source_metadata_proto_msgTypes[30] + mi := &file_source_metadata_proto_msgTypes[31] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2908,7 +3027,7 @@ func (x *Webhook) ProtoReflect() protoreflect.Message { // Deprecated: Use Webhook.ProtoReflect.Descriptor instead. func (*Webhook) Descriptor() ([]byte, []int) { - return file_source_metadata_proto_rawDescGZIP(), []int{30} + return file_source_metadata_proto_rawDescGZIP(), []int{31} } func (m *Webhook) GetData() isWebhook_Data { @@ -2948,7 +3067,7 @@ type Elasticsearch struct { func (x *Elasticsearch) Reset() { *x = Elasticsearch{} if protoimpl.UnsafeEnabled { - mi := &file_source_metadata_proto_msgTypes[31] + mi := &file_source_metadata_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2961,7 +3080,7 @@ func (x *Elasticsearch) String() string { func (*Elasticsearch) ProtoMessage() {} func (x *Elasticsearch) ProtoReflect() protoreflect.Message { - mi := &file_source_metadata_proto_msgTypes[31] + mi := &file_source_metadata_proto_msgTypes[32] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2974,7 +3093,7 @@ func (x *Elasticsearch) ProtoReflect() protoreflect.Message { // Deprecated: Use Elasticsearch.ProtoReflect.Descriptor instead. func (*Elasticsearch) Descriptor() ([]byte, []int) { - return file_source_metadata_proto_rawDescGZIP(), []int{31} + return file_source_metadata_proto_rawDescGZIP(), []int{32} } func (x *Elasticsearch) GetIndex() string { @@ -3036,13 +3155,14 @@ type MetaData struct { // *MetaData_Postman // *MetaData_Webhook // *MetaData_Elasticsearch + // *MetaData_Huggingface Data isMetaData_Data `protobuf_oneof:"data"` } func (x *MetaData) Reset() { *x = MetaData{} if protoimpl.UnsafeEnabled { - mi := &file_source_metadata_proto_msgTypes[32] + mi := &file_source_metadata_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3055,7 +3175,7 @@ func (x *MetaData) String() string { func (*MetaData) ProtoMessage() {} func (x *MetaData) ProtoReflect() protoreflect.Message { - mi := &file_source_metadata_proto_msgTypes[32] + mi := &file_source_metadata_proto_msgTypes[33] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3068,7 +3188,7 @@ func (x *MetaData) ProtoReflect() protoreflect.Message { // Deprecated: Use MetaData.ProtoReflect.Descriptor instead. func (*MetaData) Descriptor() ([]byte, []int) { - return file_source_metadata_proto_rawDescGZIP(), []int{32} + return file_source_metadata_proto_rawDescGZIP(), []int{33} } func (m *MetaData) GetData() isMetaData_Data { @@ -3295,6 +3415,13 @@ func (x *MetaData) GetElasticsearch() *Elasticsearch { return nil } +func (x *MetaData) GetHuggingface() *Huggingface { + if x, ok := x.GetData().(*MetaData_Huggingface); ok { + return x.Huggingface + } + return nil +} + type isMetaData_Data interface { isMetaData_Data() } @@ -3423,6 +3550,10 @@ type MetaData_Elasticsearch struct { Elasticsearch *Elasticsearch `protobuf:"bytes,31,opt,name=elasticsearch,proto3,oneof"` } +type MetaData_Huggingface struct { + Huggingface *Huggingface `protobuf:"bytes,32,opt,name=huggingface,proto3,oneof"` +} + func (*MetaData_Azure) isMetaData_Data() {} func (*MetaData_Bitbucket) isMetaData_Data() {} @@ -3485,6 +3616,8 @@ func (*MetaData_Webhook) isMetaData_Data() {} func (*MetaData_Elasticsearch) isMetaData_Data() {} +func (*MetaData_Huggingface) isMetaData_Data() {} + var File_source_metadata_proto protoreflect.FileDescriptor var file_source_metadata_proto_rawDesc = []byte{ @@ -3644,17 +3777,44 @@ var file_source_metadata_proto_rawDesc = []byte{ 0x65, 0x64, 0x41, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x63, 0x6c, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x61, 0x63, 0x6c, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, - 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x22, 0x98, 0x01, 0x0a, 0x04, - 0x4a, 0x69, 0x72, 0x61, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x73, 0x73, 0x75, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x69, 0x73, 0x73, 0x75, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x75, - 0x74, 0x68, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x75, 0x74, 0x68, - 0x6f, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x77, 0x0a, 0x03, 0x4e, 0x50, 0x4d, 0x12, 0x12, 0x0a, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x22, 0xb3, 0x02, 0x0a, 0x0b, + 0x48, 0x75, 0x67, 0x67, 0x69, 0x6e, 0x67, 0x66, 0x61, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6c, + 0x69, 0x6e, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x12, + 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x72, + 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0a, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x63, + 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, 0x6f, 0x6d, + 0x6d, 0x69, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c, + 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x1c, 0x0a, + 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x6c, + 0x69, 0x6e, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x65, 0x12, + 0x3b, 0x0a, 0x0a, 0x76, 0x69, 0x73, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x18, 0x09, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x56, 0x69, 0x73, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, + 0x52, 0x0a, 0x76, 0x69, 0x73, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x23, 0x0a, 0x0d, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x0a, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x22, 0x98, 0x01, 0x0a, 0x04, 0x4a, 0x69, 0x72, 0x61, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x73, + 0x73, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x69, 0x73, 0x73, 0x75, 0x65, + 0x12, 0x16, 0x0a, 0x06, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x1a, 0x0a, 0x08, + 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, + 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x1c, + 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x77, 0x0a, 0x03, + 0x4e, 0x50, 0x4d, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x63, 0x6b, 0x61, + 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, + 0x65, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6c, + 0x69, 0x6e, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x12, + 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x78, 0x0a, 0x04, 0x50, 0x79, 0x50, 0x69, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x72, @@ -3662,315 +3822,312 @@ var file_source_metadata_proto_rawDesc = []byte{ 0x6c, 0x65, 0x61, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, - 0x78, 0x0a, 0x04, 0x50, 0x79, 0x50, 0x69, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, - 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, - 0x63, 0x6b, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x12, - 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, - 0x69, 0x6e, 0x6b, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x78, 0x0a, 0x02, 0x53, 0x33, 0x12, - 0x16, 0x0a, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6c, - 0x69, 0x6e, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x12, - 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x22, 0x97, 0x02, 0x0a, 0x05, 0x53, 0x6c, 0x61, 0x63, 0x6b, 0x12, 0x1d, 0x0a, - 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, - 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, - 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x17, 0x0a, - 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, - 0x6c, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x14, - 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, - 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x3b, 0x0a, 0x0a, 0x76, 0x69, 0x73, 0x69, 0x62, 0x69, 0x6c, 0x69, - 0x74, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x56, 0x69, 0x73, 0x69, 0x62, - 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x0a, 0x76, 0x69, 0x73, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, - 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x96, 0x01, - 0x0a, 0x06, 0x47, 0x65, 0x72, 0x72, 0x69, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, - 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, - 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x66, 0x69, 0x6c, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, - 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x72, 0x6f, - 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x65, 0x22, 0x1a, 0x0a, 0x04, 0x54, 0x65, 0x73, 0x74, 0x12, 0x12, - 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x69, - 0x6c, 0x65, 0x22, 0x81, 0x01, 0x0a, 0x07, 0x4a, 0x65, 0x6e, 0x6b, 0x69, 0x6e, 0x73, 0x12, 0x21, - 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, - 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, - 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x4e, 0x75, - 0x6d, 0x62, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x90, 0x02, 0x0a, 0x05, 0x54, 0x65, 0x61, 0x6d, 0x73, - 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x64, 0x12, - 0x21, 0x0a, 0x0c, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4e, 0x61, - 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, - 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x12, 0x0a, - 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c, - 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x65, 0x61, 0x6d, 0x5f, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x65, 0x61, 0x6d, 0x4e, 0x61, 0x6d, 0x65, - 0x12, 0x17, 0x0a, 0x07, 0x74, 0x65, 0x61, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x06, 0x74, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x22, 0x99, 0x01, 0x0a, 0x0b, 0x41, 0x72, - 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x65, 0x70, - 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x65, 0x70, 0x6f, 0x12, 0x12, 0x0a, - 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, - 0x68, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, - 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0xa8, 0x01, 0x0a, 0x06, 0x53, 0x79, 0x73, 0x6c, 0x6f, 0x67, - 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, - 0x61, 0x70, 0x70, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, - 0x70, 0x70, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x6f, 0x63, 0x69, 0x64, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x72, 0x6f, 0x63, 0x69, 0x64, 0x12, 0x1c, + 0x78, 0x0a, 0x02, 0x53, 0x33, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x12, 0x0a, + 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c, + 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x97, 0x02, 0x0a, 0x05, 0x53, 0x6c, + 0x61, 0x63, 0x6b, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, + 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, + 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x66, 0x69, 0x6c, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x3b, 0x0a, 0x0a, 0x76, 0x69, + 0x73, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, + 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x2e, 0x56, 0x69, 0x73, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x0a, 0x76, 0x69, 0x73, + 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x22, 0x96, 0x01, 0x0a, 0x06, 0x47, 0x65, 0x72, 0x72, 0x69, 0x74, 0x12, 0x16, + 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, + 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, + 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x65, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x65, 0x22, 0x1a, 0x0a, 0x04, + 0x54, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x22, 0x81, 0x01, 0x0a, 0x07, 0x4a, 0x65, 0x6e, + 0x6b, 0x69, 0x6e, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x75, 0x69, 0x6c, 0x64, + 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x62, + 0x75, 0x69, 0x6c, 0x64, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, + 0x6e, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x16, 0x0a, 0x06, - 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x61, 0x63, 0x69, 0x6c, 0x69, 0x74, 0x79, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x61, 0x63, 0x69, 0x6c, 0x69, 0x74, 0x79, - 0x22, 0x9f, 0x01, 0x0a, 0x07, 0x46, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x72, 0x12, 0x31, 0x0a, 0x06, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x47, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x48, 0x00, 0x52, 0x06, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x12, - 0x28, 0x0a, 0x03, 0x6e, 0x70, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x4e, - 0x50, 0x4d, 0x48, 0x00, 0x52, 0x03, 0x6e, 0x70, 0x6d, 0x12, 0x2b, 0x0a, 0x04, 0x70, 0x79, 0x70, - 0x69, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x50, 0x79, 0x50, 0x69, 0x48, 0x00, - 0x52, 0x04, 0x70, 0x79, 0x70, 0x69, 0x42, 0x0a, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x22, 0xae, 0x01, 0x0a, 0x0a, 0x53, 0x68, 0x61, 0x72, 0x65, 0x50, 0x6f, 0x69, 0x6e, - 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x74, - 0x69, 0x74, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, - 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x69, 0x65, 0x77, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x05, 0x76, 0x69, 0x65, 0x77, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x6f, 0x63, 0x69, 0x64, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x64, 0x6f, 0x63, 0x69, 0x64, 0x12, 0x14, 0x0a, - 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, - 0x61, 0x69, 0x6c, 0x22, 0xbf, 0x01, 0x0a, 0x0b, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x44, 0x72, - 0x69, 0x76, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x14, 0x0a, 0x05, 0x65, - 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, - 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, - 0x16, 0x0a, 0x06, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x06, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x12, 0x28, 0x0a, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x5f, - 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0e, 0x6c, 0x61, 0x73, 0x74, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x42, - 0x79, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x70, 0x61, 0x74, 0x68, 0x22, 0xcb, 0x02, 0x0a, 0x0a, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x52, - 0x65, 0x70, 0x6f, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, - 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, - 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, - 0x74, 0x6f, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x12, 0x14, 0x0a, 0x05, - 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, - 0x69, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x08, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x65, 0x12, 0x3b, 0x0a, 0x0a, 0x76, 0x69, 0x73, 0x69, - 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x56, - 0x69, 0x73, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x0a, 0x76, 0x69, 0x73, 0x69, 0x62, - 0x69, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, - 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, - 0x22, 0x0a, 0x0c, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x22, 0x8d, 0x04, 0x0a, 0x07, 0x50, 0x6f, 0x73, 0x74, 0x6d, 0x61, 0x6e, 0x12, - 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, - 0x69, 0x6e, 0x6b, 0x12, 0x25, 0x0a, 0x0e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x5f, 0x75, 0x75, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x77, 0x6f, 0x72, - 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x55, 0x75, 0x69, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x77, 0x6f, - 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4e, 0x61, 0x6d, - 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x73, 0x5f, 0x69, 0x64, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x73, 0x49, 0x64, - 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, - 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, - 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x25, - 0x0a, 0x0e, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, - 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, - 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x29, 0x0a, 0x10, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, - 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0f, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, - 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x09, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, - 0x21, 0x0a, 0x0c, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4e, 0x61, - 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, - 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x49, 0x64, 0x12, - 0x1f, 0x0a, 0x0b, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0c, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, - 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x0d, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, - 0x1d, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0e, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x23, - 0x0a, 0x0d, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, - 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x54, - 0x79, 0x70, 0x65, 0x22, 0x77, 0x0a, 0x06, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x38, 0x0a, - 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x22, 0x44, 0x0a, 0x07, - 0x57, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x12, 0x31, 0x0a, 0x06, 0x76, 0x65, 0x63, 0x74, 0x6f, - 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, - 0x48, 0x00, 0x52, 0x06, 0x76, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x42, 0x06, 0x0a, 0x04, 0x64, 0x61, - 0x74, 0x61, 0x22, 0x64, 0x0a, 0x0d, 0x45, 0x6c, 0x61, 0x73, 0x74, 0x69, 0x63, 0x73, 0x65, 0x61, - 0x72, 0x63, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x6f, 0x63, - 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, - 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x81, 0x0d, 0x0a, 0x08, 0x4d, 0x65, 0x74, - 0x61, 0x44, 0x61, 0x74, 0x61, 0x12, 0x2e, 0x0a, 0x05, 0x61, 0x7a, 0x75, 0x72, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x48, 0x00, 0x52, 0x05, - 0x61, 0x7a, 0x75, 0x72, 0x65, 0x12, 0x3a, 0x0a, 0x09, 0x62, 0x69, 0x74, 0x62, 0x75, 0x63, 0x6b, - 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x42, 0x69, 0x74, 0x62, 0x75, - 0x63, 0x6b, 0x65, 0x74, 0x48, 0x00, 0x52, 0x09, 0x62, 0x69, 0x74, 0x62, 0x75, 0x63, 0x6b, 0x65, - 0x74, 0x12, 0x37, 0x0a, 0x08, 0x63, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x63, 0x69, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x43, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x43, 0x49, 0x48, 0x00, - 0x52, 0x08, 0x63, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x63, 0x69, 0x12, 0x3d, 0x0a, 0x0a, 0x63, 0x6f, - 0x6e, 0x66, 0x6c, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, - 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x6c, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x48, 0x00, 0x52, 0x0a, 0x63, - 0x6f, 0x6e, 0x66, 0x6c, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x31, 0x0a, 0x06, 0x64, 0x6f, 0x63, - 0x6b, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x44, 0x6f, 0x63, 0x6b, - 0x65, 0x72, 0x48, 0x00, 0x52, 0x06, 0x64, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x03, - 0x65, 0x63, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x45, 0x43, 0x52, 0x48, - 0x00, 0x52, 0x03, 0x65, 0x63, 0x72, 0x12, 0x28, 0x0a, 0x03, 0x67, 0x63, 0x73, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x47, 0x43, 0x53, 0x48, 0x00, 0x52, 0x03, 0x67, 0x63, 0x73, - 0x12, 0x31, 0x0a, 0x06, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x17, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x2e, 0x47, 0x69, 0x74, 0x68, 0x75, 0x62, 0x48, 0x00, 0x52, 0x06, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x12, 0x31, 0x0a, 0x06, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x18, 0x09, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x47, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x48, 0x00, 0x52, 0x06, - 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x12, 0x2b, 0x0a, 0x04, 0x6a, 0x69, 0x72, 0x61, 0x18, 0x0a, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x4a, 0x69, 0x72, 0x61, 0x48, 0x00, 0x52, 0x04, 0x6a, - 0x69, 0x72, 0x61, 0x12, 0x28, 0x0a, 0x03, 0x6e, 0x70, 0x6d, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x14, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x2e, 0x4e, 0x50, 0x4d, 0x48, 0x00, 0x52, 0x03, 0x6e, 0x70, 0x6d, 0x12, 0x2b, 0x0a, - 0x04, 0x70, 0x79, 0x70, 0x69, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x50, 0x79, - 0x50, 0x69, 0x48, 0x00, 0x52, 0x04, 0x70, 0x79, 0x70, 0x69, 0x12, 0x25, 0x0a, 0x02, 0x73, 0x33, - 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, - 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x53, 0x33, 0x48, 0x00, 0x52, 0x02, 0x73, - 0x33, 0x12, 0x2e, 0x0a, 0x05, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x16, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x2e, 0x53, 0x6c, 0x61, 0x63, 0x6b, 0x48, 0x00, 0x52, 0x05, 0x73, 0x6c, 0x61, 0x63, - 0x6b, 0x12, 0x3d, 0x0a, 0x0a, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, - 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, - 0x65, 0x6d, 0x48, 0x00, 0x52, 0x0a, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, - 0x12, 0x28, 0x0a, 0x03, 0x67, 0x69, 0x74, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, + 0x09, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x90, 0x02, 0x0a, + 0x05, 0x54, 0x65, 0x61, 0x6d, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, + 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, + 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, + 0x69, 0x6e, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x1a, 0x0a, + 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x65, 0x61, + 0x6d, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x65, + 0x61, 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x74, 0x65, 0x61, 0x6d, 0x5f, 0x69, + 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x22, + 0x99, 0x01, 0x0a, 0x0b, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x12, + 0x12, 0x0a, 0x04, 0x72, 0x65, 0x70, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, + 0x65, 0x70, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x1c, 0x0a, 0x09, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, + 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, + 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0xa8, 0x01, 0x0a, 0x06, + 0x53, 0x79, 0x73, 0x6c, 0x6f, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x70, 0x70, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, + 0x70, 0x72, 0x6f, 0x63, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x72, + 0x6f, 0x63, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x61, + 0x63, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x61, + 0x63, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x22, 0x9f, 0x01, 0x0a, 0x07, 0x46, 0x6f, 0x72, 0x61, 0x67, + 0x65, 0x72, 0x12, 0x31, 0x0a, 0x06, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x2e, 0x47, 0x69, 0x74, 0x68, 0x75, 0x62, 0x48, 0x00, 0x52, 0x06, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x12, 0x28, 0x0a, 0x03, 0x6e, 0x70, 0x6d, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x2e, 0x4e, 0x50, 0x4d, 0x48, 0x00, 0x52, 0x03, 0x6e, 0x70, 0x6d, 0x12, + 0x2b, 0x0a, 0x04, 0x70, 0x79, 0x70, 0x69, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, - 0x47, 0x69, 0x74, 0x48, 0x00, 0x52, 0x03, 0x67, 0x69, 0x74, 0x12, 0x2b, 0x0a, 0x04, 0x74, 0x65, - 0x73, 0x74, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x48, - 0x00, 0x52, 0x04, 0x74, 0x65, 0x73, 0x74, 0x12, 0x3a, 0x0a, 0x09, 0x62, 0x75, 0x69, 0x6c, 0x64, - 0x6b, 0x69, 0x74, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x42, 0x75, 0x69, - 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x65, 0x48, 0x00, 0x52, 0x09, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, - 0x69, 0x74, 0x65, 0x12, 0x31, 0x0a, 0x06, 0x67, 0x65, 0x72, 0x72, 0x69, 0x74, 0x18, 0x13, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x47, 0x65, 0x72, 0x72, 0x69, 0x74, 0x48, 0x00, 0x52, 0x06, - 0x67, 0x65, 0x72, 0x72, 0x69, 0x74, 0x12, 0x34, 0x0a, 0x07, 0x6a, 0x65, 0x6e, 0x6b, 0x69, 0x6e, - 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x4a, 0x65, 0x6e, 0x6b, 0x69, 0x6e, - 0x73, 0x48, 0x00, 0x52, 0x07, 0x6a, 0x65, 0x6e, 0x6b, 0x69, 0x6e, 0x73, 0x12, 0x2e, 0x0a, 0x05, - 0x74, 0x65, 0x61, 0x6d, 0x73, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x65, - 0x61, 0x6d, 0x73, 0x48, 0x00, 0x52, 0x05, 0x74, 0x65, 0x61, 0x6d, 0x73, 0x12, 0x40, 0x0a, 0x0b, - 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x16, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x48, - 0x00, 0x52, 0x0b, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x31, - 0x0a, 0x06, 0x73, 0x79, 0x73, 0x6c, 0x6f, 0x67, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, + 0x50, 0x79, 0x50, 0x69, 0x48, 0x00, 0x52, 0x04, 0x70, 0x79, 0x70, 0x69, 0x42, 0x0a, 0x0a, 0x08, + 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0xae, 0x01, 0x0a, 0x0a, 0x53, 0x68, 0x61, + 0x72, 0x65, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x1c, 0x0a, 0x09, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x69, 0x65, 0x77, 0x73, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76, 0x69, 0x65, 0x77, 0x73, 0x12, 0x14, 0x0a, + 0x05, 0x64, 0x6f, 0x63, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x64, 0x6f, + 0x63, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0xbf, 0x01, 0x0a, 0x0b, 0x47, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x44, 0x72, 0x69, 0x76, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x12, 0x0a, + 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, + 0x6b, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x12, 0x28, 0x0a, + 0x10, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x62, + 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6c, 0x61, 0x73, 0x74, 0x4d, 0x6f, 0x64, + 0x69, 0x66, 0x69, 0x65, 0x64, 0x42, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x22, 0xcb, 0x02, 0x0a, 0x0a, + 0x41, 0x7a, 0x75, 0x72, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, + 0x6e, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x1a, + 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x65, + 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, + 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, + 0x6d, 0x6d, 0x69, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, + 0x69, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x1c, 0x0a, 0x09, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, + 0x6e, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x65, 0x12, 0x3b, + 0x0a, 0x0a, 0x76, 0x69, 0x73, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x2e, 0x56, 0x69, 0x73, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, + 0x0a, 0x76, 0x69, 0x73, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x70, + 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6f, 0x72, 0x67, + 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x8d, 0x04, 0x0a, 0x07, 0x50, 0x6f, + 0x73, 0x74, 0x6d, 0x61, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x25, 0x0a, 0x0e, 0x77, 0x6f, 0x72, + 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x75, 0x75, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x55, 0x75, 0x69, 0x64, + 0x12, 0x25, 0x0a, 0x0e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x67, 0x6c, 0x6f, 0x62, 0x61, + 0x6c, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x67, 0x6c, 0x6f, + 0x62, 0x61, 0x6c, 0x73, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, + 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x63, + 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, + 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x65, 0x6e, + 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x29, 0x0a, 0x10, 0x65, + 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, + 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x5f, 0x69, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x6f, 0x6c, 0x64, + 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x6f, 0x6c, + 0x64, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x66, 0x6f, 0x6c, 0x64, + 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, + 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, + 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, + 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x76, 0x61, 0x72, + 0x69, 0x61, 0x62, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x22, 0x77, 0x0a, 0x06, 0x56, 0x65, 0x63, + 0x74, 0x6f, 0x72, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1f, 0x0a, + 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, + 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, + 0x73, 0x74, 0x22, 0x44, 0x0a, 0x07, 0x57, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x12, 0x31, 0x0a, + 0x06, 0x76, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, + 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x48, 0x00, 0x52, 0x06, 0x76, 0x65, 0x63, 0x74, 0x6f, 0x72, + 0x42, 0x06, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x64, 0x0a, 0x0d, 0x45, 0x6c, 0x61, 0x73, + 0x74, 0x69, 0x63, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, + 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, + 0x1f, 0x0a, 0x0b, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x64, + 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0xc3, + 0x0d, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x44, 0x61, 0x74, 0x61, 0x12, 0x2e, 0x0a, 0x05, 0x61, + 0x7a, 0x75, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x41, 0x7a, 0x75, + 0x72, 0x65, 0x48, 0x00, 0x52, 0x05, 0x61, 0x7a, 0x75, 0x72, 0x65, 0x12, 0x3a, 0x0a, 0x09, 0x62, + 0x69, 0x74, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0x2e, 0x53, 0x79, 0x73, 0x6c, 0x6f, 0x67, 0x48, 0x00, 0x52, 0x06, 0x73, 0x79, 0x73, 0x6c, 0x6f, - 0x67, 0x12, 0x34, 0x0a, 0x07, 0x66, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x72, 0x18, 0x18, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x2e, 0x46, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x72, 0x48, 0x00, 0x52, 0x07, - 0x66, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x72, 0x12, 0x3d, 0x0a, 0x0a, 0x73, 0x68, 0x61, 0x72, 0x65, - 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x53, 0x68, - 0x61, 0x72, 0x65, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0a, 0x73, 0x68, 0x61, 0x72, - 0x65, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x40, 0x0a, 0x0b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x44, 0x72, 0x69, 0x76, 0x65, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x47, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x44, 0x72, 0x69, 0x76, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x44, 0x72, 0x69, 0x76, 0x65, 0x12, 0x3d, 0x0a, 0x0a, 0x61, 0x7a, 0x75, 0x72, - 0x65, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x41, - 0x7a, 0x75, 0x72, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x48, 0x00, 0x52, 0x0a, 0x61, 0x7a, 0x75, - 0x72, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x12, 0x37, 0x0a, 0x08, 0x74, 0x72, 0x61, 0x76, 0x69, - 0x73, 0x43, 0x49, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x72, 0x61, 0x76, - 0x69, 0x73, 0x43, 0x49, 0x48, 0x00, 0x52, 0x08, 0x74, 0x72, 0x61, 0x76, 0x69, 0x73, 0x43, 0x49, - 0x12, 0x34, 0x0a, 0x07, 0x70, 0x6f, 0x73, 0x74, 0x6d, 0x61, 0x6e, 0x18, 0x1d, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x18, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x6d, 0x61, 0x6e, 0x48, 0x00, 0x52, 0x07, 0x70, - 0x6f, 0x73, 0x74, 0x6d, 0x61, 0x6e, 0x12, 0x34, 0x0a, 0x07, 0x77, 0x65, 0x62, 0x68, 0x6f, 0x6f, - 0x6b, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x57, 0x65, 0x62, 0x68, 0x6f, 0x6f, - 0x6b, 0x48, 0x00, 0x52, 0x07, 0x77, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x12, 0x46, 0x0a, 0x0d, - 0x65, 0x6c, 0x61, 0x73, 0x74, 0x69, 0x63, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x18, 0x1f, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x45, 0x6c, 0x61, 0x73, 0x74, 0x69, 0x63, 0x73, 0x65, 0x61, - 0x72, 0x63, 0x68, 0x48, 0x00, 0x52, 0x0d, 0x65, 0x6c, 0x61, 0x73, 0x74, 0x69, 0x63, 0x73, 0x65, - 0x61, 0x72, 0x63, 0x68, 0x42, 0x06, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x2a, 0x3e, 0x0a, 0x0a, - 0x56, 0x69, 0x73, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x0a, 0x0a, 0x06, 0x70, 0x75, - 0x62, 0x6c, 0x69, 0x63, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, - 0x65, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x10, 0x02, 0x12, - 0x0b, 0x0a, 0x07, 0x75, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x10, 0x03, 0x42, 0x43, 0x5a, 0x41, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x72, 0x75, 0x66, 0x66, - 0x6c, 0x65, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x2f, 0x74, 0x72, 0x75, 0x66, 0x66, - 0x6c, 0x65, 0x68, 0x6f, 0x67, 0x2f, 0x76, 0x33, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x62, 0x2f, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x70, - 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x2e, 0x42, 0x69, 0x74, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x48, 0x00, 0x52, 0x09, 0x62, 0x69, + 0x74, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x37, 0x0a, 0x08, 0x63, 0x69, 0x72, 0x63, 0x6c, + 0x65, 0x63, 0x69, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x43, 0x69, 0x72, 0x63, + 0x6c, 0x65, 0x43, 0x49, 0x48, 0x00, 0x52, 0x08, 0x63, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x63, 0x69, + 0x12, 0x3d, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x6c, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x6c, 0x75, 0x65, 0x6e, 0x63, + 0x65, 0x48, 0x00, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x6c, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x12, + 0x31, 0x0a, 0x06, 0x64, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x17, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x2e, 0x44, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x48, 0x00, 0x52, 0x06, 0x64, 0x6f, 0x63, 0x6b, + 0x65, 0x72, 0x12, 0x28, 0x0a, 0x03, 0x65, 0x63, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x14, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x2e, 0x45, 0x43, 0x52, 0x48, 0x00, 0x52, 0x03, 0x65, 0x63, 0x72, 0x12, 0x28, 0x0a, 0x03, + 0x67, 0x63, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x47, 0x43, 0x53, 0x48, + 0x00, 0x52, 0x03, 0x67, 0x63, 0x73, 0x12, 0x31, 0x0a, 0x06, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, + 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x47, 0x69, 0x74, 0x68, 0x75, 0x62, 0x48, + 0x00, 0x52, 0x06, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x12, 0x31, 0x0a, 0x06, 0x67, 0x69, 0x74, + 0x6c, 0x61, 0x62, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x47, 0x69, 0x74, 0x6c, + 0x61, 0x62, 0x48, 0x00, 0x52, 0x06, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x12, 0x2b, 0x0a, 0x04, + 0x6a, 0x69, 0x72, 0x61, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x4a, 0x69, 0x72, + 0x61, 0x48, 0x00, 0x52, 0x04, 0x6a, 0x69, 0x72, 0x61, 0x12, 0x28, 0x0a, 0x03, 0x6e, 0x70, 0x6d, + 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, + 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x4e, 0x50, 0x4d, 0x48, 0x00, 0x52, 0x03, + 0x6e, 0x70, 0x6d, 0x12, 0x2b, 0x0a, 0x04, 0x70, 0x79, 0x70, 0x69, 0x18, 0x0c, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x2e, 0x50, 0x79, 0x50, 0x69, 0x48, 0x00, 0x52, 0x04, 0x70, 0x79, 0x70, 0x69, + 0x12, 0x25, 0x0a, 0x02, 0x73, 0x33, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x53, + 0x33, 0x48, 0x00, 0x52, 0x02, 0x73, 0x33, 0x12, 0x2e, 0x0a, 0x05, 0x73, 0x6c, 0x61, 0x63, 0x6b, + 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, + 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x53, 0x6c, 0x61, 0x63, 0x6b, 0x48, 0x00, + 0x52, 0x05, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x12, 0x3d, 0x0a, 0x0a, 0x66, 0x69, 0x6c, 0x65, 0x73, + 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x46, 0x69, + 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x48, 0x00, 0x52, 0x0a, 0x66, 0x69, 0x6c, 0x65, + 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x28, 0x0a, 0x03, 0x67, 0x69, 0x74, 0x18, 0x10, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x47, 0x69, 0x74, 0x48, 0x00, 0x52, 0x03, 0x67, 0x69, 0x74, + 0x12, 0x2b, 0x0a, 0x04, 0x74, 0x65, 0x73, 0x74, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, + 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x2e, 0x54, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x04, 0x74, 0x65, 0x73, 0x74, 0x12, 0x3a, 0x0a, + 0x09, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1a, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x65, 0x48, 0x00, 0x52, 0x09, + 0x62, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x65, 0x12, 0x31, 0x0a, 0x06, 0x67, 0x65, 0x72, + 0x72, 0x69, 0x74, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x47, 0x65, 0x72, 0x72, + 0x69, 0x74, 0x48, 0x00, 0x52, 0x06, 0x67, 0x65, 0x72, 0x72, 0x69, 0x74, 0x12, 0x34, 0x0a, 0x07, + 0x6a, 0x65, 0x6e, 0x6b, 0x69, 0x6e, 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, + 0x4a, 0x65, 0x6e, 0x6b, 0x69, 0x6e, 0x73, 0x48, 0x00, 0x52, 0x07, 0x6a, 0x65, 0x6e, 0x6b, 0x69, + 0x6e, 0x73, 0x12, 0x2e, 0x0a, 0x05, 0x74, 0x65, 0x61, 0x6d, 0x73, 0x18, 0x15, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x16, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x2e, 0x54, 0x65, 0x61, 0x6d, 0x73, 0x48, 0x00, 0x52, 0x05, 0x74, 0x65, 0x61, + 0x6d, 0x73, 0x12, 0x40, 0x0a, 0x0b, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x6f, 0x72, + 0x79, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, + 0x63, 0x74, 0x6f, 0x72, 0x79, 0x48, 0x00, 0x52, 0x0b, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, + 0x74, 0x6f, 0x72, 0x79, 0x12, 0x31, 0x0a, 0x06, 0x73, 0x79, 0x73, 0x6c, 0x6f, 0x67, 0x18, 0x17, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x53, 0x79, 0x73, 0x6c, 0x6f, 0x67, 0x48, 0x00, 0x52, + 0x06, 0x73, 0x79, 0x73, 0x6c, 0x6f, 0x67, 0x12, 0x34, 0x0a, 0x07, 0x66, 0x6f, 0x72, 0x61, 0x67, + 0x65, 0x72, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x46, 0x6f, 0x72, 0x61, 0x67, + 0x65, 0x72, 0x48, 0x00, 0x52, 0x07, 0x66, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x72, 0x12, 0x3d, 0x0a, + 0x0a, 0x73, 0x68, 0x61, 0x72, 0x65, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x19, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1b, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x65, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x48, 0x00, + 0x52, 0x0a, 0x73, 0x68, 0x61, 0x72, 0x65, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x40, 0x0a, 0x0b, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x44, 0x72, 0x69, 0x76, 0x65, 0x18, 0x1a, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x2e, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x44, 0x72, 0x69, 0x76, 0x65, 0x48, + 0x00, 0x52, 0x0b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x44, 0x72, 0x69, 0x76, 0x65, 0x12, 0x3d, + 0x0a, 0x0a, 0x61, 0x7a, 0x75, 0x72, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x18, 0x1b, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x2e, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x48, + 0x00, 0x52, 0x0a, 0x61, 0x7a, 0x75, 0x72, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x12, 0x37, 0x0a, + 0x08, 0x74, 0x72, 0x61, 0x76, 0x69, 0x73, 0x43, 0x49, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x19, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x2e, 0x54, 0x72, 0x61, 0x76, 0x69, 0x73, 0x43, 0x49, 0x48, 0x00, 0x52, 0x08, 0x74, 0x72, + 0x61, 0x76, 0x69, 0x73, 0x43, 0x49, 0x12, 0x34, 0x0a, 0x07, 0x70, 0x6f, 0x73, 0x74, 0x6d, 0x61, + 0x6e, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x6d, 0x61, + 0x6e, 0x48, 0x00, 0x52, 0x07, 0x70, 0x6f, 0x73, 0x74, 0x6d, 0x61, 0x6e, 0x12, 0x34, 0x0a, 0x07, + 0x77, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, + 0x57, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x48, 0x00, 0x52, 0x07, 0x77, 0x65, 0x62, 0x68, 0x6f, + 0x6f, 0x6b, 0x12, 0x46, 0x0a, 0x0d, 0x65, 0x6c, 0x61, 0x73, 0x74, 0x69, 0x63, 0x73, 0x65, 0x61, + 0x72, 0x63, 0x68, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x45, 0x6c, 0x61, 0x73, + 0x74, 0x69, 0x63, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x48, 0x00, 0x52, 0x0d, 0x65, 0x6c, 0x61, + 0x73, 0x74, 0x69, 0x63, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x40, 0x0a, 0x0b, 0x68, 0x75, + 0x67, 0x67, 0x69, 0x6e, 0x67, 0x66, 0x61, 0x63, 0x65, 0x18, 0x20, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1c, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x2e, 0x48, 0x75, 0x67, 0x67, 0x69, 0x6e, 0x67, 0x66, 0x61, 0x63, 0x65, 0x48, 0x00, 0x52, + 0x0b, 0x68, 0x75, 0x67, 0x67, 0x69, 0x6e, 0x67, 0x66, 0x61, 0x63, 0x65, 0x42, 0x06, 0x0a, 0x04, + 0x64, 0x61, 0x74, 0x61, 0x2a, 0x3e, 0x0a, 0x0a, 0x56, 0x69, 0x73, 0x69, 0x62, 0x69, 0x6c, 0x69, + 0x74, 0x79, 0x12, 0x0a, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x10, 0x00, 0x12, 0x0b, + 0x0a, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x73, + 0x68, 0x61, 0x72, 0x65, 0x64, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x75, 0x6e, 0x6b, 0x6e, 0x6f, + 0x77, 0x6e, 0x10, 0x03, 0x42, 0x43, 0x5a, 0x41, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x74, 0x72, 0x75, 0x66, 0x66, 0x6c, 0x65, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, + 0x74, 0x79, 0x2f, 0x74, 0x72, 0x75, 0x66, 0x66, 0x6c, 0x65, 0x68, 0x6f, 0x67, 0x2f, 0x76, 0x33, + 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x62, 0x2f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( @@ -3986,7 +4143,7 @@ func file_source_metadata_proto_rawDescGZIP() []byte { } var file_source_metadata_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_source_metadata_proto_msgTypes = make([]protoimpl.MessageInfo, 33) +var file_source_metadata_proto_msgTypes = make([]protoimpl.MessageInfo, 34) var file_source_metadata_proto_goTypes = []interface{}{ (Visibility)(0), // 0: source_metadata.Visibility (*Azure)(nil), // 1: source_metadata.Azure @@ -4002,73 +4159,76 @@ var file_source_metadata_proto_goTypes = []interface{}{ (*Github)(nil), // 11: source_metadata.Github (*Gitlab)(nil), // 12: source_metadata.Gitlab (*GCS)(nil), // 13: source_metadata.GCS - (*Jira)(nil), // 14: source_metadata.Jira - (*NPM)(nil), // 15: source_metadata.NPM - (*PyPi)(nil), // 16: source_metadata.PyPi - (*S3)(nil), // 17: source_metadata.S3 - (*Slack)(nil), // 18: source_metadata.Slack - (*Gerrit)(nil), // 19: source_metadata.Gerrit - (*Test)(nil), // 20: source_metadata.Test - (*Jenkins)(nil), // 21: source_metadata.Jenkins - (*Teams)(nil), // 22: source_metadata.Teams - (*Artifactory)(nil), // 23: source_metadata.Artifactory - (*Syslog)(nil), // 24: source_metadata.Syslog - (*Forager)(nil), // 25: source_metadata.Forager - (*SharePoint)(nil), // 26: source_metadata.SharePoint - (*GoogleDrive)(nil), // 27: source_metadata.GoogleDrive - (*AzureRepos)(nil), // 28: source_metadata.AzureRepos - (*Postman)(nil), // 29: source_metadata.Postman - (*Vector)(nil), // 30: source_metadata.Vector - (*Webhook)(nil), // 31: source_metadata.Webhook - (*Elasticsearch)(nil), // 32: source_metadata.Elasticsearch - (*MetaData)(nil), // 33: source_metadata.MetaData - (*timestamppb.Timestamp)(nil), // 34: google.protobuf.Timestamp + (*Huggingface)(nil), // 14: source_metadata.Huggingface + (*Jira)(nil), // 15: source_metadata.Jira + (*NPM)(nil), // 16: source_metadata.NPM + (*PyPi)(nil), // 17: source_metadata.PyPi + (*S3)(nil), // 18: source_metadata.S3 + (*Slack)(nil), // 19: source_metadata.Slack + (*Gerrit)(nil), // 20: source_metadata.Gerrit + (*Test)(nil), // 21: source_metadata.Test + (*Jenkins)(nil), // 22: source_metadata.Jenkins + (*Teams)(nil), // 23: source_metadata.Teams + (*Artifactory)(nil), // 24: source_metadata.Artifactory + (*Syslog)(nil), // 25: source_metadata.Syslog + (*Forager)(nil), // 26: source_metadata.Forager + (*SharePoint)(nil), // 27: source_metadata.SharePoint + (*GoogleDrive)(nil), // 28: source_metadata.GoogleDrive + (*AzureRepos)(nil), // 29: source_metadata.AzureRepos + (*Postman)(nil), // 30: source_metadata.Postman + (*Vector)(nil), // 31: source_metadata.Vector + (*Webhook)(nil), // 32: source_metadata.Webhook + (*Elasticsearch)(nil), // 33: source_metadata.Elasticsearch + (*MetaData)(nil), // 34: source_metadata.MetaData + (*timestamppb.Timestamp)(nil), // 35: google.protobuf.Timestamp } var file_source_metadata_proto_depIdxs = []int32{ 0, // 0: source_metadata.Github.visibility:type_name -> source_metadata.Visibility - 0, // 1: source_metadata.Slack.visibility:type_name -> source_metadata.Visibility - 11, // 2: source_metadata.Forager.github:type_name -> source_metadata.Github - 15, // 3: source_metadata.Forager.npm:type_name -> source_metadata.NPM - 16, // 4: source_metadata.Forager.pypi:type_name -> source_metadata.PyPi - 0, // 5: source_metadata.AzureRepos.visibility:type_name -> source_metadata.Visibility - 34, // 6: source_metadata.Vector.timestamp:type_name -> google.protobuf.Timestamp - 30, // 7: source_metadata.Webhook.vector:type_name -> source_metadata.Vector - 1, // 8: source_metadata.MetaData.azure:type_name -> source_metadata.Azure - 2, // 9: source_metadata.MetaData.bitbucket:type_name -> source_metadata.Bitbucket - 4, // 10: source_metadata.MetaData.circleci:type_name -> source_metadata.CircleCI - 6, // 11: source_metadata.MetaData.confluence:type_name -> source_metadata.Confluence - 7, // 12: source_metadata.MetaData.docker:type_name -> source_metadata.Docker - 8, // 13: source_metadata.MetaData.ecr:type_name -> source_metadata.ECR - 13, // 14: source_metadata.MetaData.gcs:type_name -> source_metadata.GCS - 11, // 15: source_metadata.MetaData.github:type_name -> source_metadata.Github - 12, // 16: source_metadata.MetaData.gitlab:type_name -> source_metadata.Gitlab - 14, // 17: source_metadata.MetaData.jira:type_name -> source_metadata.Jira - 15, // 18: source_metadata.MetaData.npm:type_name -> source_metadata.NPM - 16, // 19: source_metadata.MetaData.pypi:type_name -> source_metadata.PyPi - 17, // 20: source_metadata.MetaData.s3:type_name -> source_metadata.S3 - 18, // 21: source_metadata.MetaData.slack:type_name -> source_metadata.Slack - 9, // 22: source_metadata.MetaData.filesystem:type_name -> source_metadata.Filesystem - 10, // 23: source_metadata.MetaData.git:type_name -> source_metadata.Git - 20, // 24: source_metadata.MetaData.test:type_name -> source_metadata.Test - 3, // 25: source_metadata.MetaData.buildkite:type_name -> source_metadata.Buildkite - 19, // 26: source_metadata.MetaData.gerrit:type_name -> source_metadata.Gerrit - 21, // 27: source_metadata.MetaData.jenkins:type_name -> source_metadata.Jenkins - 22, // 28: source_metadata.MetaData.teams:type_name -> source_metadata.Teams - 23, // 29: source_metadata.MetaData.artifactory:type_name -> source_metadata.Artifactory - 24, // 30: source_metadata.MetaData.syslog:type_name -> source_metadata.Syslog - 25, // 31: source_metadata.MetaData.forager:type_name -> source_metadata.Forager - 26, // 32: source_metadata.MetaData.sharepoint:type_name -> source_metadata.SharePoint - 27, // 33: source_metadata.MetaData.googleDrive:type_name -> source_metadata.GoogleDrive - 28, // 34: source_metadata.MetaData.azureRepos:type_name -> source_metadata.AzureRepos - 5, // 35: source_metadata.MetaData.travisCI:type_name -> source_metadata.TravisCI - 29, // 36: source_metadata.MetaData.postman:type_name -> source_metadata.Postman - 31, // 37: source_metadata.MetaData.webhook:type_name -> source_metadata.Webhook - 32, // 38: source_metadata.MetaData.elasticsearch:type_name -> source_metadata.Elasticsearch - 39, // [39:39] is the sub-list for method output_type - 39, // [39:39] is the sub-list for method input_type - 39, // [39:39] is the sub-list for extension type_name - 39, // [39:39] is the sub-list for extension extendee - 0, // [0:39] is the sub-list for field type_name + 0, // 1: source_metadata.Huggingface.visibility:type_name -> source_metadata.Visibility + 0, // 2: source_metadata.Slack.visibility:type_name -> source_metadata.Visibility + 11, // 3: source_metadata.Forager.github:type_name -> source_metadata.Github + 16, // 4: source_metadata.Forager.npm:type_name -> source_metadata.NPM + 17, // 5: source_metadata.Forager.pypi:type_name -> source_metadata.PyPi + 0, // 6: source_metadata.AzureRepos.visibility:type_name -> source_metadata.Visibility + 35, // 7: source_metadata.Vector.timestamp:type_name -> google.protobuf.Timestamp + 31, // 8: source_metadata.Webhook.vector:type_name -> source_metadata.Vector + 1, // 9: source_metadata.MetaData.azure:type_name -> source_metadata.Azure + 2, // 10: source_metadata.MetaData.bitbucket:type_name -> source_metadata.Bitbucket + 4, // 11: source_metadata.MetaData.circleci:type_name -> source_metadata.CircleCI + 6, // 12: source_metadata.MetaData.confluence:type_name -> source_metadata.Confluence + 7, // 13: source_metadata.MetaData.docker:type_name -> source_metadata.Docker + 8, // 14: source_metadata.MetaData.ecr:type_name -> source_metadata.ECR + 13, // 15: source_metadata.MetaData.gcs:type_name -> source_metadata.GCS + 11, // 16: source_metadata.MetaData.github:type_name -> source_metadata.Github + 12, // 17: source_metadata.MetaData.gitlab:type_name -> source_metadata.Gitlab + 15, // 18: source_metadata.MetaData.jira:type_name -> source_metadata.Jira + 16, // 19: source_metadata.MetaData.npm:type_name -> source_metadata.NPM + 17, // 20: source_metadata.MetaData.pypi:type_name -> source_metadata.PyPi + 18, // 21: source_metadata.MetaData.s3:type_name -> source_metadata.S3 + 19, // 22: source_metadata.MetaData.slack:type_name -> source_metadata.Slack + 9, // 23: source_metadata.MetaData.filesystem:type_name -> source_metadata.Filesystem + 10, // 24: source_metadata.MetaData.git:type_name -> source_metadata.Git + 21, // 25: source_metadata.MetaData.test:type_name -> source_metadata.Test + 3, // 26: source_metadata.MetaData.buildkite:type_name -> source_metadata.Buildkite + 20, // 27: source_metadata.MetaData.gerrit:type_name -> source_metadata.Gerrit + 22, // 28: source_metadata.MetaData.jenkins:type_name -> source_metadata.Jenkins + 23, // 29: source_metadata.MetaData.teams:type_name -> source_metadata.Teams + 24, // 30: source_metadata.MetaData.artifactory:type_name -> source_metadata.Artifactory + 25, // 31: source_metadata.MetaData.syslog:type_name -> source_metadata.Syslog + 26, // 32: source_metadata.MetaData.forager:type_name -> source_metadata.Forager + 27, // 33: source_metadata.MetaData.sharepoint:type_name -> source_metadata.SharePoint + 28, // 34: source_metadata.MetaData.googleDrive:type_name -> source_metadata.GoogleDrive + 29, // 35: source_metadata.MetaData.azureRepos:type_name -> source_metadata.AzureRepos + 5, // 36: source_metadata.MetaData.travisCI:type_name -> source_metadata.TravisCI + 30, // 37: source_metadata.MetaData.postman:type_name -> source_metadata.Postman + 32, // 38: source_metadata.MetaData.webhook:type_name -> source_metadata.Webhook + 33, // 39: source_metadata.MetaData.elasticsearch:type_name -> source_metadata.Elasticsearch + 14, // 40: source_metadata.MetaData.huggingface:type_name -> source_metadata.Huggingface + 41, // [41:41] is the sub-list for method output_type + 41, // [41:41] is the sub-list for method input_type + 41, // [41:41] is the sub-list for extension type_name + 41, // [41:41] is the sub-list for extension extendee + 0, // [0:41] is the sub-list for field type_name } func init() { file_source_metadata_proto_init() } @@ -4234,7 +4394,7 @@ func file_source_metadata_proto_init() { } } file_source_metadata_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Jira); i { + switch v := v.(*Huggingface); i { case 0: return &v.state case 1: @@ -4246,7 +4406,7 @@ func file_source_metadata_proto_init() { } } file_source_metadata_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NPM); i { + switch v := v.(*Jira); i { case 0: return &v.state case 1: @@ -4258,7 +4418,7 @@ func file_source_metadata_proto_init() { } } file_source_metadata_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PyPi); i { + switch v := v.(*NPM); i { case 0: return &v.state case 1: @@ -4270,7 +4430,7 @@ func file_source_metadata_proto_init() { } } file_source_metadata_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*S3); i { + switch v := v.(*PyPi); i { case 0: return &v.state case 1: @@ -4282,7 +4442,7 @@ func file_source_metadata_proto_init() { } } file_source_metadata_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Slack); i { + switch v := v.(*S3); i { case 0: return &v.state case 1: @@ -4294,7 +4454,7 @@ func file_source_metadata_proto_init() { } } file_source_metadata_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Gerrit); i { + switch v := v.(*Slack); i { case 0: return &v.state case 1: @@ -4306,7 +4466,7 @@ func file_source_metadata_proto_init() { } } file_source_metadata_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Test); i { + switch v := v.(*Gerrit); i { case 0: return &v.state case 1: @@ -4318,7 +4478,7 @@ func file_source_metadata_proto_init() { } } file_source_metadata_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Jenkins); i { + switch v := v.(*Test); i { case 0: return &v.state case 1: @@ -4330,7 +4490,7 @@ func file_source_metadata_proto_init() { } } file_source_metadata_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Teams); i { + switch v := v.(*Jenkins); i { case 0: return &v.state case 1: @@ -4342,7 +4502,7 @@ func file_source_metadata_proto_init() { } } file_source_metadata_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Artifactory); i { + switch v := v.(*Teams); i { case 0: return &v.state case 1: @@ -4354,7 +4514,7 @@ func file_source_metadata_proto_init() { } } file_source_metadata_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Syslog); i { + switch v := v.(*Artifactory); i { case 0: return &v.state case 1: @@ -4366,7 +4526,7 @@ func file_source_metadata_proto_init() { } } file_source_metadata_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Forager); i { + switch v := v.(*Syslog); i { case 0: return &v.state case 1: @@ -4378,7 +4538,7 @@ func file_source_metadata_proto_init() { } } file_source_metadata_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SharePoint); i { + switch v := v.(*Forager); i { case 0: return &v.state case 1: @@ -4390,7 +4550,7 @@ func file_source_metadata_proto_init() { } } file_source_metadata_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GoogleDrive); i { + switch v := v.(*SharePoint); i { case 0: return &v.state case 1: @@ -4402,7 +4562,7 @@ func file_source_metadata_proto_init() { } } file_source_metadata_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AzureRepos); i { + switch v := v.(*GoogleDrive); i { case 0: return &v.state case 1: @@ -4414,7 +4574,7 @@ func file_source_metadata_proto_init() { } } file_source_metadata_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Postman); i { + switch v := v.(*AzureRepos); i { case 0: return &v.state case 1: @@ -4426,7 +4586,7 @@ func file_source_metadata_proto_init() { } } file_source_metadata_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Vector); i { + switch v := v.(*Postman); i { case 0: return &v.state case 1: @@ -4438,7 +4598,7 @@ func file_source_metadata_proto_init() { } } file_source_metadata_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Webhook); i { + switch v := v.(*Vector); i { case 0: return &v.state case 1: @@ -4450,7 +4610,7 @@ func file_source_metadata_proto_init() { } } file_source_metadata_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Elasticsearch); i { + switch v := v.(*Webhook); i { case 0: return &v.state case 1: @@ -4462,6 +4622,18 @@ func file_source_metadata_proto_init() { } } file_source_metadata_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Elasticsearch); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_source_metadata_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*MetaData); i { case 0: return &v.state @@ -4474,15 +4646,15 @@ func file_source_metadata_proto_init() { } } } - file_source_metadata_proto_msgTypes[24].OneofWrappers = []interface{}{ + file_source_metadata_proto_msgTypes[25].OneofWrappers = []interface{}{ (*Forager_Github)(nil), (*Forager_Npm)(nil), (*Forager_Pypi)(nil), } - file_source_metadata_proto_msgTypes[30].OneofWrappers = []interface{}{ + file_source_metadata_proto_msgTypes[31].OneofWrappers = []interface{}{ (*Webhook_Vector)(nil), } - file_source_metadata_proto_msgTypes[32].OneofWrappers = []interface{}{ + file_source_metadata_proto_msgTypes[33].OneofWrappers = []interface{}{ (*MetaData_Azure)(nil), (*MetaData_Bitbucket)(nil), (*MetaData_Circleci)(nil), @@ -4514,6 +4686,7 @@ func file_source_metadata_proto_init() { (*MetaData_Postman)(nil), (*MetaData_Webhook)(nil), (*MetaData_Elasticsearch)(nil), + (*MetaData_Huggingface)(nil), } type x struct{} out := protoimpl.TypeBuilder{ @@ -4521,7 +4694,7 @@ func file_source_metadata_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_source_metadata_proto_rawDesc, NumEnums: 1, - NumMessages: 33, + NumMessages: 34, NumExtensions: 0, NumServices: 0, }, diff --git a/pkg/pb/source_metadatapb/source_metadata.pb.validate.go b/pkg/pb/source_metadatapb/source_metadata.pb.validate.go index 8aa33f463..1d3e93416 100644 --- a/pkg/pb/source_metadatapb/source_metadata.pb.validate.go +++ b/pkg/pb/source_metadatapb/source_metadata.pb.validate.go @@ -1493,6 +1493,125 @@ var _ interface { ErrorName() string } = GCSValidationError{} +// Validate checks the field values on Huggingface with the rules defined in +// the proto definition for this message. If any rules are violated, the first +// error encountered is returned, or nil if there are no violations. +func (m *Huggingface) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on Huggingface with the rules defined in +// the proto definition for this message. If any rules are violated, the +// result is a list of violation errors wrapped in HuggingfaceMultiError, or +// nil if none found. +func (m *Huggingface) ValidateAll() error { + return m.validate(true) +} + +func (m *Huggingface) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for Link + + // no validation rules for Username + + // no validation rules for Repository + + // no validation rules for Commit + + // no validation rules for Email + + // no validation rules for File + + // no validation rules for Timestamp + + // no validation rules for Line + + // no validation rules for Visibility + + // no validation rules for ResourceType + + if len(errors) > 0 { + return HuggingfaceMultiError(errors) + } + + return nil +} + +// HuggingfaceMultiError is an error wrapping multiple validation errors +// returned by Huggingface.ValidateAll() if the designated constraints aren't met. +type HuggingfaceMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m HuggingfaceMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m HuggingfaceMultiError) AllErrors() []error { return m } + +// HuggingfaceValidationError is the validation error returned by +// Huggingface.Validate if the designated constraints aren't met. +type HuggingfaceValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e HuggingfaceValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e HuggingfaceValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e HuggingfaceValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e HuggingfaceValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e HuggingfaceValidationError) ErrorName() string { return "HuggingfaceValidationError" } + +// Error satisfies the builtin error interface +func (e HuggingfaceValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sHuggingface.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = HuggingfaceValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = HuggingfaceValidationError{} + // Validate checks the field values on Jira with the rules defined in the proto // definition for this message. If any rules are violated, the first error // encountered is returned, or nil if there are no violations. @@ -5074,6 +5193,47 @@ func (m *MetaData) validate(all bool) error { } } + case *MetaData_Huggingface: + if v == nil { + err := MetaDataValidationError{ + field: "Data", + reason: "oneof value cannot be a typed-nil", + } + if !all { + return err + } + errors = append(errors, err) + } + + if all { + switch v := interface{}(m.GetHuggingface()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, MetaDataValidationError{ + field: "Huggingface", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, MetaDataValidationError{ + field: "Huggingface", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetHuggingface()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return MetaDataValidationError{ + field: "Huggingface", + reason: "embedded message failed validation", + cause: err, + } + } + } + default: _ = v // ensures v is used } diff --git a/pkg/pb/sourcespb/sources.pb.go b/pkg/pb/sourcespb/sources.pb.go index 56a70e92b..c103bab17 100644 --- a/pkg/pb/sourcespb/sources.pb.go +++ b/pkg/pb/sourcespb/sources.pb.go @@ -64,6 +64,7 @@ const ( SourceType_SOURCE_TYPE_POSTMAN SourceType = 33 SourceType_SOURCE_TYPE_WEBHOOK SourceType = 34 SourceType_SOURCE_TYPE_ELASTICSEARCH SourceType = 35 + SourceType_SOURCE_TYPE_HUGGINGFACE SourceType = 36 ) // Enum value maps for SourceType. @@ -105,6 +106,7 @@ var ( 33: "SOURCE_TYPE_POSTMAN", 34: "SOURCE_TYPE_WEBHOOK", 35: "SOURCE_TYPE_ELASTICSEARCH", + 36: "SOURCE_TYPE_HUGGINGFACE", } SourceType_value = map[string]int32{ "SOURCE_TYPE_AZURE_STORAGE": 0, @@ -143,6 +145,7 @@ var ( "SOURCE_TYPE_POSTMAN": 33, "SOURCE_TYPE_WEBHOOK": 34, "SOURCE_TYPE_ELASTICSEARCH": 35, + "SOURCE_TYPE_HUGGINGFACE": 36, } ) @@ -2075,6 +2078,223 @@ type GoogleDrive_RefreshToken struct { func (*GoogleDrive_RefreshToken) isGoogleDrive_Credential() {} +type Huggingface struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Endpoint string `protobuf:"bytes,1,opt,name=endpoint,proto3" json:"endpoint,omitempty"` + // Types that are assignable to Credential: + // + // *Huggingface_Token + // *Huggingface_Unauthenticated + Credential isHuggingface_Credential `protobuf_oneof:"credential"` + Models []string `protobuf:"bytes,4,rep,name=models,proto3" json:"models,omitempty"` + Spaces []string `protobuf:"bytes,5,rep,name=spaces,proto3" json:"spaces,omitempty"` + Datasets []string `protobuf:"bytes,12,rep,name=datasets,proto3" json:"datasets,omitempty"` + Organizations []string `protobuf:"bytes,6,rep,name=organizations,proto3" json:"organizations,omitempty"` + Users []string `protobuf:"bytes,15,rep,name=users,proto3" json:"users,omitempty"` + IgnoreModels []string `protobuf:"bytes,7,rep,name=ignore_models,json=ignoreModels,proto3" json:"ignore_models,omitempty"` + IncludeModels []string `protobuf:"bytes,8,rep,name=include_models,json=includeModels,proto3" json:"include_models,omitempty"` + IgnoreSpaces []string `protobuf:"bytes,9,rep,name=ignore_spaces,json=ignoreSpaces,proto3" json:"ignore_spaces,omitempty"` + IncludeSpaces []string `protobuf:"bytes,10,rep,name=include_spaces,json=includeSpaces,proto3" json:"include_spaces,omitempty"` + IgnoreDatasets []string `protobuf:"bytes,13,rep,name=ignore_datasets,json=ignoreDatasets,proto3" json:"ignore_datasets,omitempty"` + IncludeDatasets []string `protobuf:"bytes,14,rep,name=include_datasets,json=includeDatasets,proto3" json:"include_datasets,omitempty"` + SkipAllModels bool `protobuf:"varint,16,opt,name=skip_all_models,json=skipAllModels,proto3" json:"skip_all_models,omitempty"` + SkipAllSpaces bool `protobuf:"varint,17,opt,name=skip_all_spaces,json=skipAllSpaces,proto3" json:"skip_all_spaces,omitempty"` + SkipAllDatasets bool `protobuf:"varint,18,opt,name=skip_all_datasets,json=skipAllDatasets,proto3" json:"skip_all_datasets,omitempty"` + IncludeDiscussions bool `protobuf:"varint,11,opt,name=include_discussions,json=includeDiscussions,proto3" json:"include_discussions,omitempty"` + IncludePrs bool `protobuf:"varint,19,opt,name=include_prs,json=includePrs,proto3" json:"include_prs,omitempty"` +} + +func (x *Huggingface) Reset() { + *x = Huggingface{} + if protoimpl.UnsafeEnabled { + mi := &file_sources_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Huggingface) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Huggingface) ProtoMessage() {} + +func (x *Huggingface) ProtoReflect() protoreflect.Message { + mi := &file_sources_proto_msgTypes[15] + 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 Huggingface.ProtoReflect.Descriptor instead. +func (*Huggingface) Descriptor() ([]byte, []int) { + return file_sources_proto_rawDescGZIP(), []int{15} +} + +func (x *Huggingface) GetEndpoint() string { + if x != nil { + return x.Endpoint + } + return "" +} + +func (m *Huggingface) GetCredential() isHuggingface_Credential { + if m != nil { + return m.Credential + } + return nil +} + +func (x *Huggingface) GetToken() string { + if x, ok := x.GetCredential().(*Huggingface_Token); ok { + return x.Token + } + return "" +} + +func (x *Huggingface) GetUnauthenticated() *credentialspb.Unauthenticated { + if x, ok := x.GetCredential().(*Huggingface_Unauthenticated); ok { + return x.Unauthenticated + } + return nil +} + +func (x *Huggingface) GetModels() []string { + if x != nil { + return x.Models + } + return nil +} + +func (x *Huggingface) GetSpaces() []string { + if x != nil { + return x.Spaces + } + return nil +} + +func (x *Huggingface) GetDatasets() []string { + if x != nil { + return x.Datasets + } + return nil +} + +func (x *Huggingface) GetOrganizations() []string { + if x != nil { + return x.Organizations + } + return nil +} + +func (x *Huggingface) GetUsers() []string { + if x != nil { + return x.Users + } + return nil +} + +func (x *Huggingface) GetIgnoreModels() []string { + if x != nil { + return x.IgnoreModels + } + return nil +} + +func (x *Huggingface) GetIncludeModels() []string { + if x != nil { + return x.IncludeModels + } + return nil +} + +func (x *Huggingface) GetIgnoreSpaces() []string { + if x != nil { + return x.IgnoreSpaces + } + return nil +} + +func (x *Huggingface) GetIncludeSpaces() []string { + if x != nil { + return x.IncludeSpaces + } + return nil +} + +func (x *Huggingface) GetIgnoreDatasets() []string { + if x != nil { + return x.IgnoreDatasets + } + return nil +} + +func (x *Huggingface) GetIncludeDatasets() []string { + if x != nil { + return x.IncludeDatasets + } + return nil +} + +func (x *Huggingface) GetSkipAllModels() bool { + if x != nil { + return x.SkipAllModels + } + return false +} + +func (x *Huggingface) GetSkipAllSpaces() bool { + if x != nil { + return x.SkipAllSpaces + } + return false +} + +func (x *Huggingface) GetSkipAllDatasets() bool { + if x != nil { + return x.SkipAllDatasets + } + return false +} + +func (x *Huggingface) GetIncludeDiscussions() bool { + if x != nil { + return x.IncludeDiscussions + } + return false +} + +func (x *Huggingface) GetIncludePrs() bool { + if x != nil { + return x.IncludePrs + } + return false +} + +type isHuggingface_Credential interface { + isHuggingface_Credential() +} + +type Huggingface_Token struct { + Token string `protobuf:"bytes,2,opt,name=token,proto3,oneof"` +} + +type Huggingface_Unauthenticated struct { + Unauthenticated *credentialspb.Unauthenticated `protobuf:"bytes,3,opt,name=unauthenticated,proto3,oneof"` +} + +func (*Huggingface_Token) isHuggingface_Credential() {} + +func (*Huggingface_Unauthenticated) isHuggingface_Credential() {} + type JIRA struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -2096,7 +2316,7 @@ type JIRA struct { func (x *JIRA) Reset() { *x = JIRA{} if protoimpl.UnsafeEnabled { - mi := &file_sources_proto_msgTypes[15] + mi := &file_sources_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2109,7 +2329,7 @@ func (x *JIRA) String() string { func (*JIRA) ProtoMessage() {} func (x *JIRA) ProtoReflect() protoreflect.Message { - mi := &file_sources_proto_msgTypes[15] + mi := &file_sources_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2122,7 +2342,7 @@ func (x *JIRA) ProtoReflect() protoreflect.Message { // Deprecated: Use JIRA.ProtoReflect.Descriptor instead. func (*JIRA) Descriptor() ([]byte, []int) { - return file_sources_proto_rawDescGZIP(), []int{15} + return file_sources_proto_rawDescGZIP(), []int{16} } func (x *JIRA) GetEndpoint() string { @@ -2230,7 +2450,7 @@ type NPMUnauthenticatedPackage struct { func (x *NPMUnauthenticatedPackage) Reset() { *x = NPMUnauthenticatedPackage{} if protoimpl.UnsafeEnabled { - mi := &file_sources_proto_msgTypes[16] + mi := &file_sources_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2243,7 +2463,7 @@ func (x *NPMUnauthenticatedPackage) String() string { func (*NPMUnauthenticatedPackage) ProtoMessage() {} func (x *NPMUnauthenticatedPackage) ProtoReflect() protoreflect.Message { - mi := &file_sources_proto_msgTypes[16] + mi := &file_sources_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2256,7 +2476,7 @@ func (x *NPMUnauthenticatedPackage) ProtoReflect() protoreflect.Message { // Deprecated: Use NPMUnauthenticatedPackage.ProtoReflect.Descriptor instead. func (*NPMUnauthenticatedPackage) Descriptor() ([]byte, []int) { - return file_sources_proto_rawDescGZIP(), []int{16} + return file_sources_proto_rawDescGZIP(), []int{17} } func (m *NPMUnauthenticatedPackage) GetCredential() isNPMUnauthenticatedPackage_Credential { @@ -2297,7 +2517,7 @@ type PyPIUnauthenticatedPackage struct { func (x *PyPIUnauthenticatedPackage) Reset() { *x = PyPIUnauthenticatedPackage{} if protoimpl.UnsafeEnabled { - mi := &file_sources_proto_msgTypes[17] + mi := &file_sources_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2310,7 +2530,7 @@ func (x *PyPIUnauthenticatedPackage) String() string { func (*PyPIUnauthenticatedPackage) ProtoMessage() {} func (x *PyPIUnauthenticatedPackage) ProtoReflect() protoreflect.Message { - mi := &file_sources_proto_msgTypes[17] + mi := &file_sources_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2323,7 +2543,7 @@ func (x *PyPIUnauthenticatedPackage) ProtoReflect() protoreflect.Message { // Deprecated: Use PyPIUnauthenticatedPackage.ProtoReflect.Descriptor instead. func (*PyPIUnauthenticatedPackage) Descriptor() ([]byte, []int) { - return file_sources_proto_rawDescGZIP(), []int{17} + return file_sources_proto_rawDescGZIP(), []int{18} } func (m *PyPIUnauthenticatedPackage) GetCredential() isPyPIUnauthenticatedPackage_Credential { @@ -2371,7 +2591,7 @@ type S3 struct { func (x *S3) Reset() { *x = S3{} if protoimpl.UnsafeEnabled { - mi := &file_sources_proto_msgTypes[18] + mi := &file_sources_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2384,7 +2604,7 @@ func (x *S3) String() string { func (*S3) ProtoMessage() {} func (x *S3) ProtoReflect() protoreflect.Message { - mi := &file_sources_proto_msgTypes[18] + mi := &file_sources_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2397,7 +2617,7 @@ func (x *S3) ProtoReflect() protoreflect.Message { // Deprecated: Use S3.ProtoReflect.Descriptor instead. func (*S3) Descriptor() ([]byte, []int) { - return file_sources_proto_rawDescGZIP(), []int{18} + return file_sources_proto_rawDescGZIP(), []int{19} } func (m *S3) GetCredential() isS3_Credential { @@ -2509,7 +2729,7 @@ type Slack struct { func (x *Slack) Reset() { *x = Slack{} if protoimpl.UnsafeEnabled { - mi := &file_sources_proto_msgTypes[19] + mi := &file_sources_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2522,7 +2742,7 @@ func (x *Slack) String() string { func (*Slack) ProtoMessage() {} func (x *Slack) ProtoReflect() protoreflect.Message { - mi := &file_sources_proto_msgTypes[19] + mi := &file_sources_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2535,7 +2755,7 @@ func (x *Slack) ProtoReflect() protoreflect.Message { // Deprecated: Use Slack.ProtoReflect.Descriptor instead. func (*Slack) Descriptor() ([]byte, []int) { - return file_sources_proto_rawDescGZIP(), []int{19} + return file_sources_proto_rawDescGZIP(), []int{20} } func (x *Slack) GetEndpoint() string { @@ -2605,7 +2825,7 @@ type Test struct { func (x *Test) Reset() { *x = Test{} if protoimpl.UnsafeEnabled { - mi := &file_sources_proto_msgTypes[20] + mi := &file_sources_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2618,7 +2838,7 @@ func (x *Test) String() string { func (*Test) ProtoMessage() {} func (x *Test) ProtoReflect() protoreflect.Message { - mi := &file_sources_proto_msgTypes[20] + mi := &file_sources_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2631,7 +2851,7 @@ func (x *Test) ProtoReflect() protoreflect.Message { // Deprecated: Use Test.ProtoReflect.Descriptor instead. func (*Test) Descriptor() ([]byte, []int) { - return file_sources_proto_rawDescGZIP(), []int{20} + return file_sources_proto_rawDescGZIP(), []int{21} } type Buildkite struct { @@ -2648,7 +2868,7 @@ type Buildkite struct { func (x *Buildkite) Reset() { *x = Buildkite{} if protoimpl.UnsafeEnabled { - mi := &file_sources_proto_msgTypes[21] + mi := &file_sources_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2661,7 +2881,7 @@ func (x *Buildkite) String() string { func (*Buildkite) ProtoMessage() {} func (x *Buildkite) ProtoReflect() protoreflect.Message { - mi := &file_sources_proto_msgTypes[21] + mi := &file_sources_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2674,7 +2894,7 @@ func (x *Buildkite) ProtoReflect() protoreflect.Message { // Deprecated: Use Buildkite.ProtoReflect.Descriptor instead. func (*Buildkite) Descriptor() ([]byte, []int) { - return file_sources_proto_rawDescGZIP(), []int{21} + return file_sources_proto_rawDescGZIP(), []int{22} } func (m *Buildkite) GetCredential() isBuildkite_Credential { @@ -2720,7 +2940,7 @@ type Gerrit struct { func (x *Gerrit) Reset() { *x = Gerrit{} if protoimpl.UnsafeEnabled { - mi := &file_sources_proto_msgTypes[22] + mi := &file_sources_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2733,7 +2953,7 @@ func (x *Gerrit) String() string { func (*Gerrit) ProtoMessage() {} func (x *Gerrit) ProtoReflect() protoreflect.Message { - mi := &file_sources_proto_msgTypes[22] + mi := &file_sources_proto_msgTypes[23] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2746,7 +2966,7 @@ func (x *Gerrit) ProtoReflect() protoreflect.Message { // Deprecated: Use Gerrit.ProtoReflect.Descriptor instead. func (*Gerrit) Descriptor() ([]byte, []int) { - return file_sources_proto_rawDescGZIP(), []int{22} + return file_sources_proto_rawDescGZIP(), []int{23} } func (x *Gerrit) GetEndpoint() string { @@ -2832,7 +3052,7 @@ type Jenkins struct { func (x *Jenkins) Reset() { *x = Jenkins{} if protoimpl.UnsafeEnabled { - mi := &file_sources_proto_msgTypes[23] + mi := &file_sources_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2845,7 +3065,7 @@ func (x *Jenkins) String() string { func (*Jenkins) ProtoMessage() {} func (x *Jenkins) ProtoReflect() protoreflect.Message { - mi := &file_sources_proto_msgTypes[23] + mi := &file_sources_proto_msgTypes[24] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2858,7 +3078,7 @@ func (x *Jenkins) ProtoReflect() protoreflect.Message { // Deprecated: Use Jenkins.ProtoReflect.Descriptor instead. func (*Jenkins) Descriptor() ([]byte, []int) { - return file_sources_proto_rawDescGZIP(), []int{23} + return file_sources_proto_rawDescGZIP(), []int{24} } func (x *Jenkins) GetEndpoint() string { @@ -2945,7 +3165,7 @@ type Teams struct { func (x *Teams) Reset() { *x = Teams{} if protoimpl.UnsafeEnabled { - mi := &file_sources_proto_msgTypes[24] + mi := &file_sources_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2958,7 +3178,7 @@ func (x *Teams) String() string { func (*Teams) ProtoMessage() {} func (x *Teams) ProtoReflect() protoreflect.Message { - mi := &file_sources_proto_msgTypes[24] + mi := &file_sources_proto_msgTypes[25] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2971,7 +3191,7 @@ func (x *Teams) ProtoReflect() protoreflect.Message { // Deprecated: Use Teams.ProtoReflect.Descriptor instead. func (*Teams) Descriptor() ([]byte, []int) { - return file_sources_proto_rawDescGZIP(), []int{24} + return file_sources_proto_rawDescGZIP(), []int{25} } func (x *Teams) GetEndpoint() string { @@ -3067,7 +3287,7 @@ type Syslog struct { func (x *Syslog) Reset() { *x = Syslog{} if protoimpl.UnsafeEnabled { - mi := &file_sources_proto_msgTypes[25] + mi := &file_sources_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3080,7 +3300,7 @@ func (x *Syslog) String() string { func (*Syslog) ProtoMessage() {} func (x *Syslog) ProtoReflect() protoreflect.Message { - mi := &file_sources_proto_msgTypes[25] + mi := &file_sources_proto_msgTypes[26] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3093,7 +3313,7 @@ func (x *Syslog) ProtoReflect() protoreflect.Message { // Deprecated: Use Syslog.ProtoReflect.Descriptor instead. func (*Syslog) Descriptor() ([]byte, []int) { - return file_sources_proto_rawDescGZIP(), []int{25} + return file_sources_proto_rawDescGZIP(), []int{26} } func (x *Syslog) GetProtocol() string { @@ -3148,7 +3368,7 @@ type Forager struct { func (x *Forager) Reset() { *x = Forager{} if protoimpl.UnsafeEnabled { - mi := &file_sources_proto_msgTypes[26] + mi := &file_sources_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3161,7 +3381,7 @@ func (x *Forager) String() string { func (*Forager) ProtoMessage() {} func (x *Forager) ProtoReflect() protoreflect.Message { - mi := &file_sources_proto_msgTypes[26] + mi := &file_sources_proto_msgTypes[27] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3174,7 +3394,7 @@ func (x *Forager) ProtoReflect() protoreflect.Message { // Deprecated: Use Forager.ProtoReflect.Descriptor instead. func (*Forager) Descriptor() ([]byte, []int) { - return file_sources_proto_rawDescGZIP(), []int{26} + return file_sources_proto_rawDescGZIP(), []int{27} } func (m *Forager) GetCredential() isForager_Credential { @@ -3236,7 +3456,7 @@ type SlackRealtime struct { func (x *SlackRealtime) Reset() { *x = SlackRealtime{} if protoimpl.UnsafeEnabled { - mi := &file_sources_proto_msgTypes[27] + mi := &file_sources_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3249,7 +3469,7 @@ func (x *SlackRealtime) String() string { func (*SlackRealtime) ProtoMessage() {} func (x *SlackRealtime) ProtoReflect() protoreflect.Message { - mi := &file_sources_proto_msgTypes[27] + mi := &file_sources_proto_msgTypes[28] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3262,7 +3482,7 @@ func (x *SlackRealtime) ProtoReflect() protoreflect.Message { // Deprecated: Use SlackRealtime.ProtoReflect.Descriptor instead. func (*SlackRealtime) Descriptor() ([]byte, []int) { - return file_sources_proto_rawDescGZIP(), []int{27} + return file_sources_proto_rawDescGZIP(), []int{28} } func (m *SlackRealtime) GetCredential() isSlackRealtime_Credential { @@ -3304,7 +3524,7 @@ type Sharepoint struct { func (x *Sharepoint) Reset() { *x = Sharepoint{} if protoimpl.UnsafeEnabled { - mi := &file_sources_proto_msgTypes[28] + mi := &file_sources_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3317,7 +3537,7 @@ func (x *Sharepoint) String() string { func (*Sharepoint) ProtoMessage() {} func (x *Sharepoint) ProtoReflect() protoreflect.Message { - mi := &file_sources_proto_msgTypes[28] + mi := &file_sources_proto_msgTypes[29] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3330,7 +3550,7 @@ func (x *Sharepoint) ProtoReflect() protoreflect.Message { // Deprecated: Use Sharepoint.ProtoReflect.Descriptor instead. func (*Sharepoint) Descriptor() ([]byte, []int) { - return file_sources_proto_rawDescGZIP(), []int{28} + return file_sources_proto_rawDescGZIP(), []int{29} } func (m *Sharepoint) GetCredential() isSharepoint_Credential { @@ -3390,7 +3610,7 @@ type AzureRepos struct { func (x *AzureRepos) Reset() { *x = AzureRepos{} if protoimpl.UnsafeEnabled { - mi := &file_sources_proto_msgTypes[29] + mi := &file_sources_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3403,7 +3623,7 @@ func (x *AzureRepos) String() string { func (*AzureRepos) ProtoMessage() {} func (x *AzureRepos) ProtoReflect() protoreflect.Message { - mi := &file_sources_proto_msgTypes[29] + mi := &file_sources_proto_msgTypes[30] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3416,7 +3636,7 @@ func (x *AzureRepos) ProtoReflect() protoreflect.Message { // Deprecated: Use AzureRepos.ProtoReflect.Descriptor instead. func (*AzureRepos) Descriptor() ([]byte, []int) { - return file_sources_proto_rawDescGZIP(), []int{29} + return file_sources_proto_rawDescGZIP(), []int{30} } func (x *AzureRepos) GetEndpoint() string { @@ -3559,7 +3779,7 @@ type Postman struct { func (x *Postman) Reset() { *x = Postman{} if protoimpl.UnsafeEnabled { - mi := &file_sources_proto_msgTypes[30] + mi := &file_sources_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3572,7 +3792,7 @@ func (x *Postman) String() string { func (*Postman) ProtoMessage() {} func (x *Postman) ProtoReflect() protoreflect.Message { - mi := &file_sources_proto_msgTypes[30] + mi := &file_sources_proto_msgTypes[31] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3585,7 +3805,7 @@ func (x *Postman) ProtoReflect() protoreflect.Message { // Deprecated: Use Postman.ProtoReflect.Descriptor instead. func (*Postman) Descriptor() ([]byte, []int) { - return file_sources_proto_rawDescGZIP(), []int{30} + return file_sources_proto_rawDescGZIP(), []int{31} } func (m *Postman) GetCredential() isPostman_Credential { @@ -3717,7 +3937,7 @@ type Webhook struct { func (x *Webhook) Reset() { *x = Webhook{} if protoimpl.UnsafeEnabled { - mi := &file_sources_proto_msgTypes[31] + mi := &file_sources_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3730,7 +3950,7 @@ func (x *Webhook) String() string { func (*Webhook) ProtoMessage() {} func (x *Webhook) ProtoReflect() protoreflect.Message { - mi := &file_sources_proto_msgTypes[31] + mi := &file_sources_proto_msgTypes[32] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3743,7 +3963,7 @@ func (x *Webhook) ProtoReflect() protoreflect.Message { // Deprecated: Use Webhook.ProtoReflect.Descriptor instead. func (*Webhook) Descriptor() ([]byte, []int) { - return file_sources_proto_rawDescGZIP(), []int{31} + return file_sources_proto_rawDescGZIP(), []int{32} } func (x *Webhook) GetListenAddress() string { @@ -3797,7 +4017,7 @@ type Elasticsearch struct { func (x *Elasticsearch) Reset() { *x = Elasticsearch{} if protoimpl.UnsafeEnabled { - mi := &file_sources_proto_msgTypes[32] + mi := &file_sources_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3810,7 +4030,7 @@ func (x *Elasticsearch) String() string { func (*Elasticsearch) ProtoMessage() {} func (x *Elasticsearch) ProtoReflect() protoreflect.Message { - mi := &file_sources_proto_msgTypes[32] + mi := &file_sources_proto_msgTypes[33] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3823,7 +4043,7 @@ func (x *Elasticsearch) ProtoReflect() protoreflect.Message { // Deprecated: Use Elasticsearch.ProtoReflect.Descriptor instead. func (*Elasticsearch) Descriptor() ([]byte, []int) { - return file_sources_proto_rawDescGZIP(), []int{32} + return file_sources_proto_rawDescGZIP(), []int{33} } func (x *Elasticsearch) GetNodes() []string { @@ -4211,343 +4431,391 @@ var file_sources_proto_rawDesc = []byte{ 0x76, 0x65, 0x12, 0x25, 0x0a, 0x0d, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0c, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0x80, 0x03, 0x0a, 0x04, 0x4a, 0x49, 0x52, 0x41, - 0x12, 0x24, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x90, 0x01, 0x01, 0x52, 0x08, 0x65, 0x6e, - 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x37, 0x0a, 0x0a, 0x62, 0x61, 0x73, 0x69, 0x63, 0x5f, - 0x61, 0x75, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x72, 0x65, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x42, 0x61, 0x73, 0x69, 0x63, 0x41, 0x75, - 0x74, 0x68, 0x48, 0x00, 0x52, 0x09, 0x62, 0x61, 0x73, 0x69, 0x63, 0x41, 0x75, 0x74, 0x68, 0x12, - 0x48, 0x0a, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, - 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, - 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, - 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x2b, 0x0a, 0x05, 0x6f, 0x61, 0x75, - 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x4f, 0x61, 0x75, 0x74, 0x68, 0x32, 0x48, 0x00, 0x52, - 0x05, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1a, - 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, - 0x52, 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x67, - 0x6e, 0x6f, 0x72, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x07, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x0e, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, - 0x63, 0x74, 0x73, 0x12, 0x37, 0x0a, 0x18, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x5f, - 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x5f, 0x74, 0x6c, 0x73, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x53, - 0x6b, 0x69, 0x70, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x54, 0x6c, 0x73, 0x42, 0x0c, 0x0a, 0x0a, - 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0x73, 0x0a, 0x19, 0x4e, 0x50, - 0x4d, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, - 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x12, 0x48, 0x0a, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, - 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1c, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x55, - 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x48, 0x00, - 0x52, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, - 0x64, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, - 0x74, 0x0a, 0x1a, 0x50, 0x79, 0x50, 0x49, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, - 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x12, 0x48, 0x0a, - 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, - 0x61, 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, - 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0xad, 0x03, 0x0a, 0x02, 0x53, 0x33, 0x12, 0x37, 0x0a, 0x0a, - 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x16, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x4b, - 0x65, 0x79, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x48, 0x00, 0x52, 0x09, 0x61, 0x63, 0x63, 0x65, - 0x73, 0x73, 0x4b, 0x65, 0x79, 0x12, 0x48, 0x0a, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, - 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0xe5, 0x05, 0x0a, 0x0b, 0x48, 0x75, 0x67, 0x67, + 0x69, 0x6e, 0x67, 0x66, 0x61, 0x63, 0x65, 0x12, 0x24, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, + 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, + 0x90, 0x01, 0x01, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x16, 0x0a, + 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, + 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x48, 0x0a, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, + 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, - 0x4c, 0x0a, 0x11, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, - 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x72, 0x65, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x45, 0x6e, - 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x10, 0x63, 0x6c, 0x6f, - 0x75, 0x64, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x49, 0x0a, - 0x0d, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, - 0x6c, 0x73, 0x2e, 0x41, 0x57, 0x53, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, - 0x65, 0x6e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x48, 0x00, 0x52, 0x0c, 0x73, 0x65, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x75, 0x63, 0x6b, - 0x65, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x62, 0x75, 0x63, 0x6b, 0x65, - 0x74, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x6d, 0x61, 0x78, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, - 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x6d, 0x61, 0x78, - 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x6f, - 0x6c, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x72, 0x6f, 0x6c, 0x65, 0x73, - 0x12, 0x25, 0x0a, 0x0e, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x5f, 0x62, 0x75, 0x63, 0x6b, 0x65, - 0x74, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, - 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0xc4, 0x01, 0x0a, 0x05, 0x53, 0x6c, 0x61, 0x63, 0x6b, 0x12, - 0x24, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x90, 0x01, 0x01, 0x52, 0x08, 0x65, 0x6e, 0x64, - 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x32, 0x0a, - 0x06, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, - 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x53, 0x6c, 0x61, 0x63, - 0x6b, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x48, 0x00, 0x52, 0x06, 0x74, 0x6f, 0x6b, 0x65, 0x6e, - 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x03, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x1f, 0x0a, - 0x0b, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x04, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x0a, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x0c, - 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0x06, 0x0a, 0x04, - 0x54, 0x65, 0x73, 0x74, 0x22, 0x31, 0x0a, 0x09, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, - 0x65, 0x12, 0x16, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x48, 0x00, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0xa5, 0x02, 0x0a, 0x06, 0x47, 0x65, 0x72, 0x72, - 0x69, 0x74, 0x12, 0x24, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x90, 0x01, 0x01, 0x52, 0x08, - 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x37, 0x0a, 0x0a, 0x62, 0x61, 0x73, 0x69, - 0x63, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, - 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x42, 0x61, 0x73, 0x69, 0x63, - 0x41, 0x75, 0x74, 0x68, 0x48, 0x00, 0x52, 0x09, 0x62, 0x61, 0x73, 0x69, 0x63, 0x41, 0x75, 0x74, - 0x68, 0x12, 0x48, 0x0a, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, - 0x61, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x72, 0x65, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, - 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, 0x0f, 0x75, 0x6e, 0x61, 0x75, - 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70, - 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, - 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x6b, 0x69, 0x70, 0x5f, - 0x62, 0x69, 0x6e, 0x61, 0x72, 0x69, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, - 0x73, 0x6b, 0x69, 0x70, 0x42, 0x69, 0x6e, 0x61, 0x72, 0x69, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, - 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x73, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x0c, 0x73, 0x6b, 0x69, 0x70, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, + 0x16, 0x0a, 0x06, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x06, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, + 0x1a, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x6f, + 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x0d, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x12, 0x14, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x67, 0x6e, 0x6f, 0x72, + 0x65, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, + 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x12, 0x25, 0x0a, 0x0e, + 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x18, 0x08, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x4d, 0x6f, 0x64, + 0x65, 0x6c, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x5f, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x69, 0x67, 0x6e, 0x6f, + 0x72, 0x65, 0x53, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x69, 0x6e, 0x63, 0x6c, + 0x75, 0x64, 0x65, 0x5f, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x0d, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x53, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, + 0x27, 0x0a, 0x0f, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x73, 0x65, + 0x74, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, + 0x44, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x69, 0x6e, 0x63, 0x6c, + 0x75, 0x64, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x73, 0x18, 0x0e, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x44, 0x61, 0x74, 0x61, 0x73, + 0x65, 0x74, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x61, 0x6c, 0x6c, 0x5f, + 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x18, 0x10, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x73, 0x6b, + 0x69, 0x70, 0x41, 0x6c, 0x6c, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x73, + 0x6b, 0x69, 0x70, 0x5f, 0x61, 0x6c, 0x6c, 0x5f, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x18, 0x11, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x73, 0x6b, 0x69, 0x70, 0x41, 0x6c, 0x6c, 0x53, 0x70, 0x61, + 0x63, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x61, 0x6c, 0x6c, 0x5f, + 0x64, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x73, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, + 0x73, 0x6b, 0x69, 0x70, 0x41, 0x6c, 0x6c, 0x44, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x73, 0x12, + 0x2f, 0x0a, 0x13, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x75, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x69, 0x6e, + 0x63, 0x6c, 0x75, 0x64, 0x65, 0x44, 0x69, 0x73, 0x63, 0x75, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, + 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x70, 0x72, 0x73, 0x18, + 0x13, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x50, 0x72, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, - 0xa8, 0x02, 0x0a, 0x07, 0x4a, 0x65, 0x6e, 0x6b, 0x69, 0x6e, 0x73, 0x12, 0x24, 0x0a, 0x08, 0x65, - 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, - 0x42, 0x05, 0x72, 0x03, 0x90, 0x01, 0x01, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, - 0x74, 0x12, 0x37, 0x0a, 0x0a, 0x62, 0x61, 0x73, 0x69, 0x63, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x61, 0x6c, 0x73, 0x2e, 0x42, 0x61, 0x73, 0x69, 0x63, 0x41, 0x75, 0x74, 0x68, 0x48, 0x00, 0x52, - 0x09, 0x62, 0x61, 0x73, 0x69, 0x63, 0x41, 0x75, 0x74, 0x68, 0x12, 0x2d, 0x0a, 0x06, 0x68, 0x65, - 0x61, 0x64, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x72, 0x65, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x48, - 0x00, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x48, 0x0a, 0x0f, 0x75, 0x6e, 0x61, - 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, + 0x80, 0x03, 0x0a, 0x04, 0x4a, 0x49, 0x52, 0x41, 0x12, 0x24, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, + 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, + 0x03, 0x90, 0x01, 0x01, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x37, + 0x0a, 0x0a, 0x62, 0x61, 0x73, 0x69, 0x63, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, + 0x2e, 0x42, 0x61, 0x73, 0x69, 0x63, 0x41, 0x75, 0x74, 0x68, 0x48, 0x00, 0x52, 0x09, 0x62, 0x61, + 0x73, 0x69, 0x63, 0x41, 0x75, 0x74, 0x68, 0x12, 0x48, 0x0a, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, + 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1c, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x55, + 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x48, 0x00, + 0x52, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, + 0x64, 0x12, 0x2b, 0x0a, 0x05, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x13, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x4f, + 0x61, 0x75, 0x74, 0x68, 0x32, 0x48, 0x00, 0x52, 0x05, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x12, 0x16, + 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, + 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, + 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, + 0x74, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x5f, 0x70, 0x72, 0x6f, + 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x69, 0x67, 0x6e, + 0x6f, 0x72, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x37, 0x0a, 0x18, 0x69, + 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x5f, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x76, 0x65, 0x72, + 0x69, 0x66, 0x79, 0x5f, 0x74, 0x6c, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x69, + 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x53, 0x6b, 0x69, 0x70, 0x56, 0x65, 0x72, 0x69, 0x66, + 0x79, 0x54, 0x6c, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x61, 0x6c, 0x22, 0x73, 0x0a, 0x19, 0x4e, 0x50, 0x4d, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, + 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x12, + 0x48, 0x0a, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, + 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, + 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0x74, 0x0a, 0x1a, 0x50, 0x79, 0x50, 0x49, 0x55, + 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x50, 0x61, + 0x63, 0x6b, 0x61, 0x67, 0x65, 0x12, 0x48, 0x0a, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, + 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, + 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x55, 0x6e, 0x61, + 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, 0x0f, + 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x42, + 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0xad, 0x03, + 0x0a, 0x02, 0x53, 0x33, 0x12, 0x37, 0x0a, 0x0a, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x4b, 0x65, 0x79, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, + 0x48, 0x00, 0x52, 0x09, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x12, 0x48, 0x0a, + 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, + 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x4c, 0x0a, 0x11, 0x63, 0x6c, 0x6f, 0x75, 0x64, + 0x5f, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, + 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, + 0x74, 0x48, 0x00, 0x52, 0x10, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, + 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x49, 0x0a, 0x0d, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x63, + 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x41, 0x57, 0x53, 0x53, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, + 0x48, 0x00, 0x52, 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, + 0x12, 0x18, 0x0a, 0x07, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x07, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x6d, 0x61, + 0x78, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x0d, 0x6d, 0x61, 0x78, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x69, + 0x7a, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x05, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x69, 0x67, 0x6e, 0x6f, + 0x72, 0x65, 0x5f, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x0d, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x42, + 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0xc4, 0x01, + 0x0a, 0x05, 0x53, 0x6c, 0x61, 0x63, 0x6b, 0x12, 0x24, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, + 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, + 0x90, 0x01, 0x01, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x16, 0x0a, + 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, + 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x32, 0x0a, 0x06, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x61, 0x6c, 0x73, 0x2e, 0x53, 0x6c, 0x61, 0x63, 0x6b, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x48, + 0x00, 0x52, 0x06, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x63, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x5f, + 0x6c, 0x69, 0x73, 0x74, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x67, 0x6e, 0x6f, + 0x72, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x61, 0x6c, 0x22, 0x06, 0x0a, 0x04, 0x54, 0x65, 0x73, 0x74, 0x22, 0x31, 0x0a, 0x09, + 0x42, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x05, 0x74, 0x6f, 0x6b, + 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, + 0x6e, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, + 0xa5, 0x02, 0x0a, 0x06, 0x47, 0x65, 0x72, 0x72, 0x69, 0x74, 0x12, 0x24, 0x0a, 0x08, 0x65, 0x6e, + 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, + 0x05, 0x72, 0x03, 0x90, 0x01, 0x01, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x12, 0x37, 0x0a, 0x0a, 0x62, 0x61, 0x73, 0x69, 0x63, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, + 0x6c, 0x73, 0x2e, 0x42, 0x61, 0x73, 0x69, 0x63, 0x41, 0x75, 0x74, 0x68, 0x48, 0x00, 0x52, 0x09, + 0x62, 0x61, 0x73, 0x69, 0x63, 0x41, 0x75, 0x74, 0x68, 0x12, 0x48, 0x0a, 0x0f, 0x75, 0x6e, 0x61, + 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, - 0x74, 0x65, 0x64, 0x12, 0x37, 0x0a, 0x18, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x5f, - 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x5f, 0x74, 0x6c, 0x73, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x53, - 0x6b, 0x69, 0x70, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x54, 0x6c, 0x73, 0x42, 0x0c, 0x0a, 0x0a, - 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0xa0, 0x02, 0x0a, 0x05, 0x54, - 0x65, 0x61, 0x6d, 0x73, 0x12, 0x24, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x90, 0x01, 0x01, - 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x05, 0x74, 0x6f, - 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x74, 0x6f, 0x6b, - 0x65, 0x6e, 0x12, 0x46, 0x0a, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, - 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x63, 0x72, 0x65, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x72, - 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x48, 0x00, 0x52, 0x0d, 0x61, 0x75, 0x74, - 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x2b, 0x0a, 0x05, 0x6f, 0x61, - 0x75, 0x74, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x72, 0x65, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x4f, 0x61, 0x75, 0x74, 0x68, 0x32, 0x48, 0x00, - 0x52, 0x05, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x5f, 0x6c, 0x69, - 0x73, 0x74, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, - 0x4c, 0x69, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x74, 0x65, 0x61, 0x6d, 0x5f, 0x69, 0x64, 0x73, - 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x74, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x73, 0x42, - 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0x95, 0x01, - 0x0a, 0x06, 0x53, 0x79, 0x73, 0x6c, 0x6f, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x25, 0x0a, 0x0e, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x5f, 0x61, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6c, 0x69, - 0x73, 0x74, 0x65, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x74, - 0x6c, 0x73, 0x43, 0x65, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x6c, - 0x73, 0x43, 0x65, 0x72, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x6c, 0x73, 0x4b, 0x65, 0x79, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x6c, 0x73, 0x4b, 0x65, 0x79, 0x12, 0x16, 0x0a, - 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, - 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x22, 0xca, 0x01, 0x0a, 0x07, 0x46, 0x6f, 0x72, 0x61, 0x67, 0x65, + 0x74, 0x65, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, + 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, + 0x23, 0x0a, 0x0d, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x69, 0x65, 0x73, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x73, 0x6b, 0x69, 0x70, 0x42, 0x69, 0x6e, 0x61, + 0x72, 0x69, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x61, 0x72, 0x63, + 0x68, 0x69, 0x76, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x73, 0x6b, 0x69, + 0x70, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0xa8, 0x02, 0x0a, 0x07, 0x4a, 0x65, 0x6e, 0x6b, + 0x69, 0x6e, 0x73, 0x12, 0x24, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x90, 0x01, 0x01, 0x52, + 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x37, 0x0a, 0x0a, 0x62, 0x61, 0x73, + 0x69, 0x63, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, + 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x42, 0x61, 0x73, 0x69, + 0x63, 0x41, 0x75, 0x74, 0x68, 0x48, 0x00, 0x52, 0x09, 0x62, 0x61, 0x73, 0x69, 0x63, 0x41, 0x75, + 0x74, 0x68, 0x12, 0x2d, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, + 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x48, 0x00, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x48, 0x0a, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, - 0x61, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, 0x0f, 0x75, 0x6e, 0x61, 0x75, - 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x64, - 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x64, 0x6f, - 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x64, 0x65, 0x70, - 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x44, 0x65, 0x70, - 0x74, 0x68, 0x12, 0x30, 0x0a, 0x05, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x73, - 0x69, 0x6e, 0x63, 0x65, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x61, 0x6c, 0x22, 0x51, 0x0a, 0x0d, 0x53, 0x6c, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x61, 0x6c, 0x74, - 0x69, 0x6d, 0x65, 0x12, 0x32, 0x0a, 0x06, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, - 0x73, 0x2e, 0x53, 0x6c, 0x61, 0x63, 0x6b, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x48, 0x00, 0x52, - 0x06, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0x62, 0x0a, 0x0a, 0x53, 0x68, 0x61, 0x72, 0x65, 0x70, 0x6f, - 0x69, 0x6e, 0x74, 0x12, 0x2b, 0x0a, 0x05, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, - 0x2e, 0x4f, 0x61, 0x75, 0x74, 0x68, 0x32, 0x48, 0x00, 0x52, 0x05, 0x6f, 0x61, 0x75, 0x74, 0x68, - 0x12, 0x19, 0x0a, 0x08, 0x73, 0x69, 0x74, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x73, 0x69, 0x74, 0x65, 0x55, 0x72, 0x6c, 0x42, 0x0c, 0x0a, 0x0a, 0x63, - 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0xf6, 0x03, 0x0a, 0x0a, 0x41, 0x7a, - 0x75, 0x72, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x12, 0x24, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, - 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, - 0x03, 0x90, 0x01, 0x01, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x16, - 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, - 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x2b, 0x0a, 0x05, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x61, 0x6c, 0x73, 0x2e, 0x4f, 0x61, 0x75, 0x74, 0x68, 0x32, 0x48, 0x00, 0x52, 0x05, 0x6f, 0x61, - 0x75, 0x74, 0x68, 0x12, 0x22, 0x0a, 0x0c, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, - 0x69, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x70, 0x6f, 0x73, - 0x69, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x6f, 0x72, 0x67, 0x61, 0x6e, - 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, - 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1a, 0x0a, - 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x63, - 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x66, 0x6f, 0x72, 0x6b, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x0c, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x46, 0x6f, 0x72, 0x6b, 0x73, 0x12, 0x21, - 0x0a, 0x0c, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x5f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x18, 0x08, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x70, 0x6f, - 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x72, 0x65, 0x70, - 0x6f, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, - 0x65, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, - 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x09, - 0x52, 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, - 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x6a, - 0x65, 0x63, 0x74, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x69, 0x67, 0x6e, 0x6f, - 0x72, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x6b, - 0x69, 0x70, 0x5f, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x69, 0x65, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x0c, 0x73, 0x6b, 0x69, 0x70, 0x42, 0x69, 0x6e, 0x61, 0x72, 0x69, 0x65, 0x73, 0x12, - 0x23, 0x0a, 0x0d, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x73, - 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x73, 0x6b, 0x69, 0x70, 0x41, 0x72, 0x63, 0x68, - 0x69, 0x76, 0x65, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x61, 0x6c, 0x22, 0xd5, 0x04, 0x0a, 0x07, 0x50, 0x6f, 0x73, 0x74, 0x6d, 0x61, 0x6e, 0x12, 0x48, - 0x0a, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, - 0x63, 0x61, 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, - 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, - 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, - 0x12, 0x1e, 0x0a, 0x0a, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x18, 0x03, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, - 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, - 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, - 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, - 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x2f, 0x0a, 0x13, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, - 0x65, 0x5f, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x06, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x12, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x43, 0x6f, 0x6c, 0x6c, - 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x31, 0x0a, 0x14, 0x65, 0x78, 0x63, 0x6c, 0x75, - 0x64, 0x65, 0x5f, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, - 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x45, 0x6e, - 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x2f, 0x0a, 0x13, 0x69, 0x6e, - 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, - 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x31, 0x0a, 0x14, 0x69, - 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, - 0x6e, 0x74, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x69, 0x6e, 0x63, 0x6c, 0x75, - 0x64, 0x65, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x2b, - 0x0a, 0x11, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x6b, 0x65, 0x79, 0x77, 0x6f, - 0x72, 0x64, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x64, 0x65, 0x74, 0x65, 0x63, - 0x74, 0x6f, 0x72, 0x4b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x77, - 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x0b, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x50, - 0x61, 0x74, 0x68, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, - 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x74, 0x68, 0x73, 0x12, - 0x2b, 0x0a, 0x11, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x70, - 0x61, 0x74, 0x68, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x65, 0x6e, 0x76, 0x69, - 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x61, 0x74, 0x68, 0x73, 0x42, 0x0c, 0x0a, 0x0a, - 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0x76, 0x0a, 0x07, 0x57, 0x65, - 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x12, 0x2e, 0x0a, 0x0e, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x5f, - 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, - 0x42, 0x04, 0x72, 0x02, 0x68, 0x01, 0x52, 0x0d, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x41, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2d, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x61, 0x6c, 0x73, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x48, 0x00, 0x52, 0x06, 0x68, 0x65, - 0x61, 0x64, 0x65, 0x72, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x61, 0x6c, 0x22, 0xcd, 0x02, 0x0a, 0x0d, 0x45, 0x6c, 0x61, 0x73, 0x74, 0x69, 0x63, 0x73, 0x65, - 0x61, 0x72, 0x63, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, - 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, - 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, - 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, - 0x72, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x49, 0x64, 0x12, 0x17, 0x0a, - 0x07, 0x61, 0x70, 0x69, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x61, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x69, - 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x18, 0x07, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0c, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x50, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, - 0x12, 0x1d, 0x0a, 0x0a, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x6a, 0x73, 0x6f, 0x6e, 0x18, 0x08, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x71, 0x75, 0x65, 0x72, 0x79, 0x4a, 0x73, 0x6f, 0x6e, 0x12, - 0x27, 0x0a, 0x0f, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x54, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x28, 0x0a, 0x10, 0x62, 0x65, 0x73, 0x74, - 0x5f, 0x65, 0x66, 0x66, 0x6f, 0x72, 0x74, 0x5f, 0x73, 0x63, 0x61, 0x6e, 0x18, 0x0a, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x0e, 0x62, 0x65, 0x73, 0x74, 0x45, 0x66, 0x66, 0x6f, 0x72, 0x74, 0x53, 0x63, - 0x61, 0x6e, 0x2a, 0xef, 0x07, 0x0a, 0x0a, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, - 0x65, 0x12, 0x1d, 0x0a, 0x19, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, - 0x5f, 0x41, 0x5a, 0x55, 0x52, 0x45, 0x5f, 0x53, 0x54, 0x4f, 0x52, 0x41, 0x47, 0x45, 0x10, 0x00, - 0x12, 0x19, 0x0a, 0x15, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, - 0x42, 0x49, 0x54, 0x42, 0x55, 0x43, 0x4b, 0x45, 0x54, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x53, - 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x49, 0x52, 0x43, 0x4c, - 0x45, 0x43, 0x49, 0x10, 0x02, 0x12, 0x1a, 0x0a, 0x16, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, - 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x4c, 0x55, 0x45, 0x4e, 0x43, 0x45, 0x10, - 0x03, 0x12, 0x16, 0x0a, 0x12, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, - 0x5f, 0x44, 0x4f, 0x43, 0x4b, 0x45, 0x52, 0x10, 0x04, 0x12, 0x13, 0x0a, 0x0f, 0x53, 0x4f, 0x55, - 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x45, 0x43, 0x52, 0x10, 0x05, 0x12, 0x13, - 0x0a, 0x0f, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x47, 0x43, - 0x53, 0x10, 0x06, 0x12, 0x16, 0x0a, 0x12, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, - 0x50, 0x45, 0x5f, 0x47, 0x49, 0x54, 0x48, 0x55, 0x42, 0x10, 0x07, 0x12, 0x1a, 0x0a, 0x16, 0x53, - 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, - 0x43, 0x5f, 0x47, 0x49, 0x54, 0x10, 0x08, 0x12, 0x16, 0x0a, 0x12, 0x53, 0x4f, 0x55, 0x52, 0x43, - 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x47, 0x49, 0x54, 0x4c, 0x41, 0x42, 0x10, 0x09, 0x12, - 0x14, 0x0a, 0x10, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4a, - 0x49, 0x52, 0x41, 0x10, 0x0a, 0x12, 0x24, 0x0a, 0x20, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, - 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4e, 0x50, 0x4d, 0x5f, 0x55, 0x4e, 0x41, 0x55, 0x54, 0x48, 0x44, - 0x5f, 0x50, 0x41, 0x43, 0x4b, 0x41, 0x47, 0x45, 0x53, 0x10, 0x0b, 0x12, 0x25, 0x0a, 0x21, 0x53, - 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x59, 0x50, 0x49, 0x5f, - 0x55, 0x4e, 0x41, 0x55, 0x54, 0x48, 0x44, 0x5f, 0x50, 0x41, 0x43, 0x4b, 0x41, 0x47, 0x45, 0x53, - 0x10, 0x0c, 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, - 0x45, 0x5f, 0x53, 0x33, 0x10, 0x0d, 0x12, 0x15, 0x0a, 0x11, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, - 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x4c, 0x41, 0x43, 0x4b, 0x10, 0x0e, 0x12, 0x1a, 0x0a, - 0x16, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x46, 0x49, 0x4c, - 0x45, 0x53, 0x59, 0x53, 0x54, 0x45, 0x4d, 0x10, 0x0f, 0x12, 0x13, 0x0a, 0x0f, 0x53, 0x4f, 0x55, - 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x47, 0x49, 0x54, 0x10, 0x10, 0x12, 0x14, - 0x0a, 0x10, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x54, 0x45, - 0x53, 0x54, 0x10, 0x11, 0x12, 0x1b, 0x0a, 0x17, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, - 0x59, 0x50, 0x45, 0x5f, 0x53, 0x33, 0x5f, 0x55, 0x4e, 0x41, 0x55, 0x54, 0x48, 0x45, 0x44, 0x10, - 0x12, 0x12, 0x2a, 0x0a, 0x26, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, - 0x5f, 0x47, 0x49, 0x54, 0x48, 0x55, 0x42, 0x5f, 0x55, 0x4e, 0x41, 0x55, 0x54, 0x48, 0x45, 0x4e, - 0x54, 0x49, 0x43, 0x41, 0x54, 0x45, 0x44, 0x5f, 0x4f, 0x52, 0x47, 0x10, 0x13, 0x12, 0x19, 0x0a, - 0x15, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x42, 0x55, 0x49, - 0x4c, 0x44, 0x4b, 0x49, 0x54, 0x45, 0x10, 0x14, 0x12, 0x16, 0x0a, 0x12, 0x53, 0x4f, 0x55, 0x52, - 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x47, 0x45, 0x52, 0x52, 0x49, 0x54, 0x10, 0x15, - 0x12, 0x17, 0x0a, 0x13, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, - 0x4a, 0x45, 0x4e, 0x4b, 0x49, 0x4e, 0x53, 0x10, 0x16, 0x12, 0x15, 0x0a, 0x11, 0x53, 0x4f, 0x55, - 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x54, 0x45, 0x41, 0x4d, 0x53, 0x10, 0x17, - 0x12, 0x21, 0x0a, 0x1d, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, - 0x4a, 0x46, 0x52, 0x4f, 0x47, 0x5f, 0x41, 0x52, 0x54, 0x49, 0x46, 0x41, 0x43, 0x54, 0x4f, 0x52, - 0x59, 0x10, 0x18, 0x12, 0x16, 0x0a, 0x12, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, - 0x50, 0x45, 0x5f, 0x53, 0x59, 0x53, 0x4c, 0x4f, 0x47, 0x10, 0x19, 0x12, 0x27, 0x0a, 0x23, 0x53, - 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, - 0x43, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x4d, 0x4f, 0x4e, 0x49, 0x54, 0x4f, 0x52, 0x49, - 0x4e, 0x47, 0x10, 0x1a, 0x12, 0x1e, 0x0a, 0x1a, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, - 0x59, 0x50, 0x45, 0x5f, 0x53, 0x4c, 0x41, 0x43, 0x4b, 0x5f, 0x52, 0x45, 0x41, 0x4c, 0x54, 0x49, - 0x4d, 0x45, 0x10, 0x1b, 0x12, 0x1c, 0x0a, 0x18, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, - 0x59, 0x50, 0x45, 0x5f, 0x47, 0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x44, 0x52, 0x49, 0x56, 0x45, - 0x10, 0x1c, 0x12, 0x1a, 0x0a, 0x16, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, - 0x45, 0x5f, 0x53, 0x48, 0x41, 0x52, 0x45, 0x50, 0x4f, 0x49, 0x4e, 0x54, 0x10, 0x1d, 0x12, 0x1c, - 0x0a, 0x18, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x47, 0x43, - 0x53, 0x5f, 0x55, 0x4e, 0x41, 0x55, 0x54, 0x48, 0x45, 0x44, 0x10, 0x1e, 0x12, 0x1b, 0x0a, 0x17, - 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x41, 0x5a, 0x55, 0x52, - 0x45, 0x5f, 0x52, 0x45, 0x50, 0x4f, 0x53, 0x10, 0x1f, 0x12, 0x18, 0x0a, 0x14, 0x53, 0x4f, 0x55, - 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x54, 0x52, 0x41, 0x56, 0x49, 0x53, 0x43, - 0x49, 0x10, 0x20, 0x12, 0x17, 0x0a, 0x13, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, - 0x50, 0x45, 0x5f, 0x50, 0x4f, 0x53, 0x54, 0x4d, 0x41, 0x4e, 0x10, 0x21, 0x12, 0x17, 0x0a, 0x13, - 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x57, 0x45, 0x42, 0x48, - 0x4f, 0x4f, 0x4b, 0x10, 0x22, 0x12, 0x1d, 0x0a, 0x19, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, - 0x54, 0x59, 0x50, 0x45, 0x5f, 0x45, 0x4c, 0x41, 0x53, 0x54, 0x49, 0x43, 0x53, 0x45, 0x41, 0x52, - 0x43, 0x48, 0x10, 0x23, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, - 0x6f, 0x6d, 0x2f, 0x74, 0x72, 0x75, 0x66, 0x66, 0x6c, 0x65, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, - 0x74, 0x79, 0x2f, 0x74, 0x72, 0x75, 0x66, 0x66, 0x6c, 0x65, 0x68, 0x6f, 0x67, 0x2f, 0x76, 0x33, - 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x62, 0x2f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x70, - 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x37, 0x0a, 0x18, 0x69, + 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x5f, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x76, 0x65, 0x72, + 0x69, 0x66, 0x79, 0x5f, 0x74, 0x6c, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x69, + 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x53, 0x6b, 0x69, 0x70, 0x56, 0x65, 0x72, 0x69, 0x66, + 0x79, 0x54, 0x6c, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x61, 0x6c, 0x22, 0xa0, 0x02, 0x0a, 0x05, 0x54, 0x65, 0x61, 0x6d, 0x73, 0x12, 0x24, 0x0a, 0x08, + 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, + 0xfa, 0x42, 0x05, 0x72, 0x03, 0x90, 0x01, 0x01, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x48, 0x00, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x46, 0x0a, 0x0d, 0x61, 0x75, + 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1e, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, + 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, + 0x73, 0x48, 0x00, 0x52, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, + 0x65, 0x64, 0x12, 0x2b, 0x0a, 0x05, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, + 0x4f, 0x61, 0x75, 0x74, 0x68, 0x32, 0x48, 0x00, 0x52, 0x05, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x12, + 0x1a, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x69, + 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x0a, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, + 0x74, 0x65, 0x61, 0x6d, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, + 0x74, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0x95, 0x01, 0x0a, 0x06, 0x53, 0x79, 0x73, 0x6c, 0x6f, 0x67, + 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x25, 0x0a, 0x0e, + 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x6c, 0x73, 0x43, 0x65, 0x72, 0x74, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x6c, 0x73, 0x43, 0x65, 0x72, 0x74, 0x12, 0x16, 0x0a, + 0x06, 0x74, 0x6c, 0x73, 0x4b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, + 0x6c, 0x73, 0x4b, 0x65, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x22, 0xca, 0x01, + 0x0a, 0x07, 0x46, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x72, 0x12, 0x48, 0x0a, 0x0f, 0x75, 0x6e, 0x61, + 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, + 0x2e, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, + 0x48, 0x00, 0x52, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, + 0x74, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x02, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x12, 0x1b, 0x0a, + 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x08, 0x6d, 0x61, 0x78, 0x44, 0x65, 0x70, 0x74, 0x68, 0x12, 0x30, 0x0a, 0x05, 0x73, 0x69, + 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x42, 0x0c, 0x0a, 0x0a, + 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0x51, 0x0a, 0x0d, 0x53, 0x6c, + 0x61, 0x63, 0x6b, 0x52, 0x65, 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x32, 0x0a, 0x06, 0x74, + 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x72, + 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x53, 0x6c, 0x61, 0x63, 0x6b, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x48, 0x00, 0x52, 0x06, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42, + 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0x62, 0x0a, + 0x0a, 0x53, 0x68, 0x61, 0x72, 0x65, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x2b, 0x0a, 0x05, 0x6f, + 0x61, 0x75, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x72, 0x65, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x4f, 0x61, 0x75, 0x74, 0x68, 0x32, 0x48, + 0x00, 0x52, 0x05, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x69, 0x74, 0x65, + 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x69, 0x74, 0x65, + 0x55, 0x72, 0x6c, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, + 0x6c, 0x22, 0xf6, 0x03, 0x0a, 0x0a, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x73, + 0x12, 0x24, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x90, 0x01, 0x01, 0x52, 0x08, 0x65, 0x6e, + 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x2b, + 0x0a, 0x05, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, + 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x4f, 0x61, 0x75, 0x74, + 0x68, 0x32, 0x48, 0x00, 0x52, 0x05, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x12, 0x22, 0x0a, 0x0c, 0x72, + 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x0c, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x12, + 0x24, 0x0a, 0x0d, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x66, 0x6f, 0x72, + 0x6b, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, + 0x65, 0x46, 0x6f, 0x72, 0x6b, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, + 0x5f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x69, 0x67, + 0x6e, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x63, + 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x0c, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x12, 0x29, + 0x0a, 0x10, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, + 0x74, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, + 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x67, 0x6e, + 0x6f, 0x72, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x0b, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x0e, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, + 0x74, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x62, 0x69, 0x6e, 0x61, 0x72, + 0x69, 0x65, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x73, 0x6b, 0x69, 0x70, 0x42, + 0x69, 0x6e, 0x61, 0x72, 0x69, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x6b, 0x69, 0x70, 0x5f, + 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, + 0x73, 0x6b, 0x69, 0x70, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x73, 0x42, 0x0c, 0x0a, 0x0a, + 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0xd5, 0x04, 0x0a, 0x07, 0x50, + 0x6f, 0x73, 0x74, 0x6d, 0x61, 0x6e, 0x12, 0x48, 0x0a, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, + 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1c, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x55, 0x6e, + 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, + 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, + 0x12, 0x16, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, + 0x00, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x77, 0x6f, 0x72, 0x6b, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x77, 0x6f, + 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6c, 0x6c, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x63, + 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x65, 0x6e, + 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x0c, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x2f, + 0x0a, 0x13, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x65, 0x78, 0x63, + 0x6c, 0x75, 0x64, 0x65, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, + 0x31, 0x0a, 0x14, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x65, 0x6e, 0x76, 0x69, 0x72, + 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x65, + 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, + 0x74, 0x73, 0x12, 0x2f, 0x0a, 0x13, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x63, 0x6f, + 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x12, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x12, 0x31, 0x0a, 0x14, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x65, + 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x13, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, + 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, + 0x6f, 0x72, 0x5f, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x10, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x4b, 0x65, 0x79, 0x77, 0x6f, + 0x72, 0x64, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x77, 0x6f, + 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x73, 0x12, 0x29, 0x0a, 0x10, + 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, + 0x18, 0x0c, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x50, 0x61, 0x74, 0x68, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x65, 0x6e, 0x76, 0x69, 0x72, + 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x0d, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x10, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x50, + 0x61, 0x74, 0x68, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x61, 0x6c, 0x22, 0x76, 0x0a, 0x07, 0x57, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x12, 0x2e, 0x0a, + 0x0e, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x68, 0x01, 0x52, 0x0d, + 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2d, 0x0a, + 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, + 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x48, 0x65, 0x61, 0x64, + 0x65, 0x72, 0x48, 0x00, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x42, 0x0c, 0x0a, 0x0a, + 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0xcd, 0x02, 0x0a, 0x0d, 0x45, + 0x6c, 0x61, 0x73, 0x74, 0x69, 0x63, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x14, 0x0a, 0x05, + 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x6e, 0x6f, 0x64, + 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, + 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x6c, + 0x6f, 0x75, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6c, + 0x6f, 0x75, 0x64, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x61, 0x70, 0x69, 0x5f, 0x6b, 0x65, 0x79, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x12, 0x23, + 0x0a, 0x0d, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x54, 0x6f, + 0x6b, 0x65, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x70, 0x61, 0x74, + 0x74, 0x65, 0x72, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x69, 0x6e, 0x64, 0x65, + 0x78, 0x50, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x71, 0x75, 0x65, 0x72, + 0x79, 0x5f, 0x6a, 0x73, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x71, 0x75, + 0x65, 0x72, 0x79, 0x4a, 0x73, 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x69, 0x6e, 0x63, 0x65, + 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0e, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x12, 0x28, 0x0a, 0x10, 0x62, 0x65, 0x73, 0x74, 0x5f, 0x65, 0x66, 0x66, 0x6f, 0x72, 0x74, 0x5f, + 0x73, 0x63, 0x61, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x62, 0x65, 0x73, 0x74, + 0x45, 0x66, 0x66, 0x6f, 0x72, 0x74, 0x53, 0x63, 0x61, 0x6e, 0x2a, 0x8c, 0x08, 0x0a, 0x0a, 0x53, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1d, 0x0a, 0x19, 0x53, 0x4f, 0x55, + 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x41, 0x5a, 0x55, 0x52, 0x45, 0x5f, 0x53, + 0x54, 0x4f, 0x52, 0x41, 0x47, 0x45, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x4f, 0x55, 0x52, + 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x42, 0x49, 0x54, 0x42, 0x55, 0x43, 0x4b, 0x45, + 0x54, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, + 0x50, 0x45, 0x5f, 0x43, 0x49, 0x52, 0x43, 0x4c, 0x45, 0x43, 0x49, 0x10, 0x02, 0x12, 0x1a, 0x0a, + 0x16, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x4f, 0x4e, + 0x46, 0x4c, 0x55, 0x45, 0x4e, 0x43, 0x45, 0x10, 0x03, 0x12, 0x16, 0x0a, 0x12, 0x53, 0x4f, 0x55, + 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x4f, 0x43, 0x4b, 0x45, 0x52, 0x10, + 0x04, 0x12, 0x13, 0x0a, 0x0f, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, + 0x5f, 0x45, 0x43, 0x52, 0x10, 0x05, 0x12, 0x13, 0x0a, 0x0f, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, + 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x47, 0x43, 0x53, 0x10, 0x06, 0x12, 0x16, 0x0a, 0x12, 0x53, + 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x47, 0x49, 0x54, 0x48, 0x55, + 0x42, 0x10, 0x07, 0x12, 0x1a, 0x0a, 0x16, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, + 0x50, 0x45, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x47, 0x49, 0x54, 0x10, 0x08, 0x12, + 0x16, 0x0a, 0x12, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x47, + 0x49, 0x54, 0x4c, 0x41, 0x42, 0x10, 0x09, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x4f, 0x55, 0x52, 0x43, + 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4a, 0x49, 0x52, 0x41, 0x10, 0x0a, 0x12, 0x24, 0x0a, + 0x20, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4e, 0x50, 0x4d, + 0x5f, 0x55, 0x4e, 0x41, 0x55, 0x54, 0x48, 0x44, 0x5f, 0x50, 0x41, 0x43, 0x4b, 0x41, 0x47, 0x45, + 0x53, 0x10, 0x0b, 0x12, 0x25, 0x0a, 0x21, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, + 0x50, 0x45, 0x5f, 0x50, 0x59, 0x50, 0x49, 0x5f, 0x55, 0x4e, 0x41, 0x55, 0x54, 0x48, 0x44, 0x5f, + 0x50, 0x41, 0x43, 0x4b, 0x41, 0x47, 0x45, 0x53, 0x10, 0x0c, 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x4f, + 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x33, 0x10, 0x0d, 0x12, 0x15, + 0x0a, 0x11, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x4c, + 0x41, 0x43, 0x4b, 0x10, 0x0e, 0x12, 0x1a, 0x0a, 0x16, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, + 0x54, 0x59, 0x50, 0x45, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x59, 0x53, 0x54, 0x45, 0x4d, 0x10, + 0x0f, 0x12, 0x13, 0x0a, 0x0f, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, + 0x5f, 0x47, 0x49, 0x54, 0x10, 0x10, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, + 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x54, 0x45, 0x53, 0x54, 0x10, 0x11, 0x12, 0x1b, 0x0a, 0x17, + 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x33, 0x5f, 0x55, + 0x4e, 0x41, 0x55, 0x54, 0x48, 0x45, 0x44, 0x10, 0x12, 0x12, 0x2a, 0x0a, 0x26, 0x53, 0x4f, 0x55, + 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x47, 0x49, 0x54, 0x48, 0x55, 0x42, 0x5f, + 0x55, 0x4e, 0x41, 0x55, 0x54, 0x48, 0x45, 0x4e, 0x54, 0x49, 0x43, 0x41, 0x54, 0x45, 0x44, 0x5f, + 0x4f, 0x52, 0x47, 0x10, 0x13, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, + 0x54, 0x59, 0x50, 0x45, 0x5f, 0x42, 0x55, 0x49, 0x4c, 0x44, 0x4b, 0x49, 0x54, 0x45, 0x10, 0x14, + 0x12, 0x16, 0x0a, 0x12, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, + 0x47, 0x45, 0x52, 0x52, 0x49, 0x54, 0x10, 0x15, 0x12, 0x17, 0x0a, 0x13, 0x53, 0x4f, 0x55, 0x52, + 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4a, 0x45, 0x4e, 0x4b, 0x49, 0x4e, 0x53, 0x10, + 0x16, 0x12, 0x15, 0x0a, 0x11, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, + 0x5f, 0x54, 0x45, 0x41, 0x4d, 0x53, 0x10, 0x17, 0x12, 0x21, 0x0a, 0x1d, 0x53, 0x4f, 0x55, 0x52, + 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4a, 0x46, 0x52, 0x4f, 0x47, 0x5f, 0x41, 0x52, + 0x54, 0x49, 0x46, 0x41, 0x43, 0x54, 0x4f, 0x52, 0x59, 0x10, 0x18, 0x12, 0x16, 0x0a, 0x12, 0x53, + 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x59, 0x53, 0x4c, 0x4f, + 0x47, 0x10, 0x19, 0x12, 0x27, 0x0a, 0x23, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, + 0x50, 0x45, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, + 0x4d, 0x4f, 0x4e, 0x49, 0x54, 0x4f, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x1a, 0x12, 0x1e, 0x0a, 0x1a, + 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x4c, 0x41, 0x43, + 0x4b, 0x5f, 0x52, 0x45, 0x41, 0x4c, 0x54, 0x49, 0x4d, 0x45, 0x10, 0x1b, 0x12, 0x1c, 0x0a, 0x18, + 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x47, 0x4f, 0x4f, 0x47, + 0x4c, 0x45, 0x5f, 0x44, 0x52, 0x49, 0x56, 0x45, 0x10, 0x1c, 0x12, 0x1a, 0x0a, 0x16, 0x53, 0x4f, + 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x48, 0x41, 0x52, 0x45, 0x50, + 0x4f, 0x49, 0x4e, 0x54, 0x10, 0x1d, 0x12, 0x1c, 0x0a, 0x18, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, + 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x47, 0x43, 0x53, 0x5f, 0x55, 0x4e, 0x41, 0x55, 0x54, 0x48, + 0x45, 0x44, 0x10, 0x1e, 0x12, 0x1b, 0x0a, 0x17, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, + 0x59, 0x50, 0x45, 0x5f, 0x41, 0x5a, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x50, 0x4f, 0x53, 0x10, + 0x1f, 0x12, 0x18, 0x0a, 0x14, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, + 0x5f, 0x54, 0x52, 0x41, 0x56, 0x49, 0x53, 0x43, 0x49, 0x10, 0x20, 0x12, 0x17, 0x0a, 0x13, 0x53, + 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x4f, 0x53, 0x54, 0x4d, + 0x41, 0x4e, 0x10, 0x21, 0x12, 0x17, 0x0a, 0x13, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, + 0x59, 0x50, 0x45, 0x5f, 0x57, 0x45, 0x42, 0x48, 0x4f, 0x4f, 0x4b, 0x10, 0x22, 0x12, 0x1d, 0x0a, + 0x19, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x45, 0x4c, 0x41, + 0x53, 0x54, 0x49, 0x43, 0x53, 0x45, 0x41, 0x52, 0x43, 0x48, 0x10, 0x23, 0x12, 0x1b, 0x0a, 0x17, + 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x48, 0x55, 0x47, 0x47, + 0x49, 0x4e, 0x47, 0x46, 0x41, 0x43, 0x45, 0x10, 0x24, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x72, 0x75, 0x66, 0x66, 0x6c, 0x65, 0x73, + 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x2f, 0x74, 0x72, 0x75, 0x66, 0x66, 0x6c, 0x65, 0x68, + 0x6f, 0x67, 0x2f, 0x76, 0x33, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x62, 0x2f, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x73, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -4563,7 +4831,7 @@ func file_sources_proto_rawDescGZIP() []byte { } var file_sources_proto_enumTypes = make([]protoimpl.EnumInfo, 2) -var file_sources_proto_msgTypes = make([]protoimpl.MessageInfo, 33) +var file_sources_proto_msgTypes = make([]protoimpl.MessageInfo, 34) var file_sources_proto_goTypes = []interface{}{ (SourceType)(0), // 0: sources.SourceType (Confluence_GetAllSpacesScope)(0), // 1: sources.Confluence.GetAllSpacesScope @@ -4582,94 +4850,96 @@ var file_sources_proto_goTypes = []interface{}{ (*GitLab)(nil), // 14: sources.GitLab (*GitHub)(nil), // 15: sources.GitHub (*GoogleDrive)(nil), // 16: sources.GoogleDrive - (*JIRA)(nil), // 17: sources.JIRA - (*NPMUnauthenticatedPackage)(nil), // 18: sources.NPMUnauthenticatedPackage - (*PyPIUnauthenticatedPackage)(nil), // 19: sources.PyPIUnauthenticatedPackage - (*S3)(nil), // 20: sources.S3 - (*Slack)(nil), // 21: sources.Slack - (*Test)(nil), // 22: sources.Test - (*Buildkite)(nil), // 23: sources.Buildkite - (*Gerrit)(nil), // 24: sources.Gerrit - (*Jenkins)(nil), // 25: sources.Jenkins - (*Teams)(nil), // 26: sources.Teams - (*Syslog)(nil), // 27: sources.Syslog - (*Forager)(nil), // 28: sources.Forager - (*SlackRealtime)(nil), // 29: sources.SlackRealtime - (*Sharepoint)(nil), // 30: sources.Sharepoint - (*AzureRepos)(nil), // 31: sources.AzureRepos - (*Postman)(nil), // 32: sources.Postman - (*Webhook)(nil), // 33: sources.Webhook - (*Elasticsearch)(nil), // 34: sources.Elasticsearch - (*durationpb.Duration)(nil), // 35: google.protobuf.Duration - (*anypb.Any)(nil), // 36: google.protobuf.Any - (*credentialspb.BasicAuth)(nil), // 37: credentials.BasicAuth - (*credentialspb.Unauthenticated)(nil), // 38: credentials.Unauthenticated - (*credentialspb.Oauth2)(nil), // 39: credentials.Oauth2 - (*credentialspb.KeySecret)(nil), // 40: credentials.KeySecret - (*credentialspb.CloudEnvironment)(nil), // 41: credentials.CloudEnvironment - (*credentialspb.SSHAuth)(nil), // 42: credentials.SSHAuth - (*credentialspb.GitHubApp)(nil), // 43: credentials.GitHubApp - (*credentialspb.AWSSessionTokenSecret)(nil), // 44: credentials.AWSSessionTokenSecret - (*credentialspb.SlackTokens)(nil), // 45: credentials.SlackTokens - (*credentialspb.Header)(nil), // 46: credentials.Header - (*credentialspb.ClientCredentials)(nil), // 47: credentials.ClientCredentials - (*timestamppb.Timestamp)(nil), // 48: google.protobuf.Timestamp + (*Huggingface)(nil), // 17: sources.Huggingface + (*JIRA)(nil), // 18: sources.JIRA + (*NPMUnauthenticatedPackage)(nil), // 19: sources.NPMUnauthenticatedPackage + (*PyPIUnauthenticatedPackage)(nil), // 20: sources.PyPIUnauthenticatedPackage + (*S3)(nil), // 21: sources.S3 + (*Slack)(nil), // 22: sources.Slack + (*Test)(nil), // 23: sources.Test + (*Buildkite)(nil), // 24: sources.Buildkite + (*Gerrit)(nil), // 25: sources.Gerrit + (*Jenkins)(nil), // 26: sources.Jenkins + (*Teams)(nil), // 27: sources.Teams + (*Syslog)(nil), // 28: sources.Syslog + (*Forager)(nil), // 29: sources.Forager + (*SlackRealtime)(nil), // 30: sources.SlackRealtime + (*Sharepoint)(nil), // 31: sources.Sharepoint + (*AzureRepos)(nil), // 32: sources.AzureRepos + (*Postman)(nil), // 33: sources.Postman + (*Webhook)(nil), // 34: sources.Webhook + (*Elasticsearch)(nil), // 35: sources.Elasticsearch + (*durationpb.Duration)(nil), // 36: google.protobuf.Duration + (*anypb.Any)(nil), // 37: google.protobuf.Any + (*credentialspb.BasicAuth)(nil), // 38: credentials.BasicAuth + (*credentialspb.Unauthenticated)(nil), // 39: credentials.Unauthenticated + (*credentialspb.Oauth2)(nil), // 40: credentials.Oauth2 + (*credentialspb.KeySecret)(nil), // 41: credentials.KeySecret + (*credentialspb.CloudEnvironment)(nil), // 42: credentials.CloudEnvironment + (*credentialspb.SSHAuth)(nil), // 43: credentials.SSHAuth + (*credentialspb.GitHubApp)(nil), // 44: credentials.GitHubApp + (*credentialspb.AWSSessionTokenSecret)(nil), // 45: credentials.AWSSessionTokenSecret + (*credentialspb.SlackTokens)(nil), // 46: credentials.SlackTokens + (*credentialspb.Header)(nil), // 47: credentials.Header + (*credentialspb.ClientCredentials)(nil), // 48: credentials.ClientCredentials + (*timestamppb.Timestamp)(nil), // 49: google.protobuf.Timestamp } var file_sources_proto_depIdxs = []int32{ - 35, // 0: sources.LocalSource.scan_interval:type_name -> google.protobuf.Duration - 36, // 1: sources.LocalSource.connection:type_name -> google.protobuf.Any - 37, // 2: sources.Artifactory.basic_auth:type_name -> credentials.BasicAuth - 38, // 3: sources.Artifactory.unauthenticated:type_name -> credentials.Unauthenticated - 37, // 4: sources.AzureStorage.basic_auth:type_name -> credentials.BasicAuth - 38, // 5: sources.AzureStorage.unauthenticated:type_name -> credentials.Unauthenticated - 39, // 6: sources.Bitbucket.oauth:type_name -> credentials.Oauth2 - 37, // 7: sources.Bitbucket.basic_auth:type_name -> credentials.BasicAuth - 38, // 8: sources.Confluence.unauthenticated:type_name -> credentials.Unauthenticated - 37, // 9: sources.Confluence.basic_auth:type_name -> credentials.BasicAuth + 36, // 0: sources.LocalSource.scan_interval:type_name -> google.protobuf.Duration + 37, // 1: sources.LocalSource.connection:type_name -> google.protobuf.Any + 38, // 2: sources.Artifactory.basic_auth:type_name -> credentials.BasicAuth + 39, // 3: sources.Artifactory.unauthenticated:type_name -> credentials.Unauthenticated + 38, // 4: sources.AzureStorage.basic_auth:type_name -> credentials.BasicAuth + 39, // 5: sources.AzureStorage.unauthenticated:type_name -> credentials.Unauthenticated + 40, // 6: sources.Bitbucket.oauth:type_name -> credentials.Oauth2 + 38, // 7: sources.Bitbucket.basic_auth:type_name -> credentials.BasicAuth + 39, // 8: sources.Confluence.unauthenticated:type_name -> credentials.Unauthenticated + 38, // 9: sources.Confluence.basic_auth:type_name -> credentials.BasicAuth 1, // 10: sources.Confluence.spaces_scope:type_name -> sources.Confluence.GetAllSpacesScope - 38, // 11: sources.Docker.unauthenticated:type_name -> credentials.Unauthenticated - 37, // 12: sources.Docker.basic_auth:type_name -> credentials.BasicAuth - 40, // 13: sources.ECR.access_key:type_name -> credentials.KeySecret - 38, // 14: sources.GCS.unauthenticated:type_name -> credentials.Unauthenticated - 41, // 15: sources.GCS.adc:type_name -> credentials.CloudEnvironment - 39, // 16: sources.GCS.oauth:type_name -> credentials.Oauth2 - 37, // 17: sources.Git.basic_auth:type_name -> credentials.BasicAuth - 38, // 18: sources.Git.unauthenticated:type_name -> credentials.Unauthenticated - 42, // 19: sources.Git.ssh_auth:type_name -> credentials.SSHAuth - 39, // 20: sources.GitLab.oauth:type_name -> credentials.Oauth2 - 37, // 21: sources.GitLab.basic_auth:type_name -> credentials.BasicAuth - 43, // 22: sources.GitHub.github_app:type_name -> credentials.GitHubApp - 38, // 23: sources.GitHub.unauthenticated:type_name -> credentials.Unauthenticated - 37, // 24: sources.GitHub.basic_auth:type_name -> credentials.BasicAuth - 37, // 25: sources.JIRA.basic_auth:type_name -> credentials.BasicAuth - 38, // 26: sources.JIRA.unauthenticated:type_name -> credentials.Unauthenticated - 39, // 27: sources.JIRA.oauth:type_name -> credentials.Oauth2 - 38, // 28: sources.NPMUnauthenticatedPackage.unauthenticated:type_name -> credentials.Unauthenticated - 38, // 29: sources.PyPIUnauthenticatedPackage.unauthenticated:type_name -> credentials.Unauthenticated - 40, // 30: sources.S3.access_key:type_name -> credentials.KeySecret - 38, // 31: sources.S3.unauthenticated:type_name -> credentials.Unauthenticated - 41, // 32: sources.S3.cloud_environment:type_name -> credentials.CloudEnvironment - 44, // 33: sources.S3.session_token:type_name -> credentials.AWSSessionTokenSecret - 45, // 34: sources.Slack.tokens:type_name -> credentials.SlackTokens - 37, // 35: sources.Gerrit.basic_auth:type_name -> credentials.BasicAuth - 38, // 36: sources.Gerrit.unauthenticated:type_name -> credentials.Unauthenticated - 37, // 37: sources.Jenkins.basic_auth:type_name -> credentials.BasicAuth - 46, // 38: sources.Jenkins.header:type_name -> credentials.Header - 38, // 39: sources.Jenkins.unauthenticated:type_name -> credentials.Unauthenticated - 47, // 40: sources.Teams.authenticated:type_name -> credentials.ClientCredentials - 39, // 41: sources.Teams.oauth:type_name -> credentials.Oauth2 - 38, // 42: sources.Forager.unauthenticated:type_name -> credentials.Unauthenticated - 48, // 43: sources.Forager.since:type_name -> google.protobuf.Timestamp - 45, // 44: sources.SlackRealtime.tokens:type_name -> credentials.SlackTokens - 39, // 45: sources.Sharepoint.oauth:type_name -> credentials.Oauth2 - 39, // 46: sources.AzureRepos.oauth:type_name -> credentials.Oauth2 - 38, // 47: sources.Postman.unauthenticated:type_name -> credentials.Unauthenticated - 46, // 48: sources.Webhook.header:type_name -> credentials.Header - 49, // [49:49] is the sub-list for method output_type - 49, // [49:49] is the sub-list for method input_type - 49, // [49:49] is the sub-list for extension type_name - 49, // [49:49] is the sub-list for extension extendee - 0, // [0:49] is the sub-list for field type_name + 39, // 11: sources.Docker.unauthenticated:type_name -> credentials.Unauthenticated + 38, // 12: sources.Docker.basic_auth:type_name -> credentials.BasicAuth + 41, // 13: sources.ECR.access_key:type_name -> credentials.KeySecret + 39, // 14: sources.GCS.unauthenticated:type_name -> credentials.Unauthenticated + 42, // 15: sources.GCS.adc:type_name -> credentials.CloudEnvironment + 40, // 16: sources.GCS.oauth:type_name -> credentials.Oauth2 + 38, // 17: sources.Git.basic_auth:type_name -> credentials.BasicAuth + 39, // 18: sources.Git.unauthenticated:type_name -> credentials.Unauthenticated + 43, // 19: sources.Git.ssh_auth:type_name -> credentials.SSHAuth + 40, // 20: sources.GitLab.oauth:type_name -> credentials.Oauth2 + 38, // 21: sources.GitLab.basic_auth:type_name -> credentials.BasicAuth + 44, // 22: sources.GitHub.github_app:type_name -> credentials.GitHubApp + 39, // 23: sources.GitHub.unauthenticated:type_name -> credentials.Unauthenticated + 38, // 24: sources.GitHub.basic_auth:type_name -> credentials.BasicAuth + 39, // 25: sources.Huggingface.unauthenticated:type_name -> credentials.Unauthenticated + 38, // 26: sources.JIRA.basic_auth:type_name -> credentials.BasicAuth + 39, // 27: sources.JIRA.unauthenticated:type_name -> credentials.Unauthenticated + 40, // 28: sources.JIRA.oauth:type_name -> credentials.Oauth2 + 39, // 29: sources.NPMUnauthenticatedPackage.unauthenticated:type_name -> credentials.Unauthenticated + 39, // 30: sources.PyPIUnauthenticatedPackage.unauthenticated:type_name -> credentials.Unauthenticated + 41, // 31: sources.S3.access_key:type_name -> credentials.KeySecret + 39, // 32: sources.S3.unauthenticated:type_name -> credentials.Unauthenticated + 42, // 33: sources.S3.cloud_environment:type_name -> credentials.CloudEnvironment + 45, // 34: sources.S3.session_token:type_name -> credentials.AWSSessionTokenSecret + 46, // 35: sources.Slack.tokens:type_name -> credentials.SlackTokens + 38, // 36: sources.Gerrit.basic_auth:type_name -> credentials.BasicAuth + 39, // 37: sources.Gerrit.unauthenticated:type_name -> credentials.Unauthenticated + 38, // 38: sources.Jenkins.basic_auth:type_name -> credentials.BasicAuth + 47, // 39: sources.Jenkins.header:type_name -> credentials.Header + 39, // 40: sources.Jenkins.unauthenticated:type_name -> credentials.Unauthenticated + 48, // 41: sources.Teams.authenticated:type_name -> credentials.ClientCredentials + 40, // 42: sources.Teams.oauth:type_name -> credentials.Oauth2 + 39, // 43: sources.Forager.unauthenticated:type_name -> credentials.Unauthenticated + 49, // 44: sources.Forager.since:type_name -> google.protobuf.Timestamp + 46, // 45: sources.SlackRealtime.tokens:type_name -> credentials.SlackTokens + 40, // 46: sources.Sharepoint.oauth:type_name -> credentials.Oauth2 + 40, // 47: sources.AzureRepos.oauth:type_name -> credentials.Oauth2 + 39, // 48: sources.Postman.unauthenticated:type_name -> credentials.Unauthenticated + 47, // 49: sources.Webhook.header:type_name -> credentials.Header + 50, // [50:50] is the sub-list for method output_type + 50, // [50:50] is the sub-list for method input_type + 50, // [50:50] is the sub-list for extension type_name + 50, // [50:50] is the sub-list for extension extendee + 0, // [0:50] is the sub-list for field type_name } func init() { file_sources_proto_init() } @@ -4859,7 +5129,7 @@ func file_sources_proto_init() { } } file_sources_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JIRA); i { + switch v := v.(*Huggingface); i { case 0: return &v.state case 1: @@ -4871,7 +5141,7 @@ func file_sources_proto_init() { } } file_sources_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NPMUnauthenticatedPackage); i { + switch v := v.(*JIRA); i { case 0: return &v.state case 1: @@ -4883,7 +5153,7 @@ func file_sources_proto_init() { } } file_sources_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PyPIUnauthenticatedPackage); i { + switch v := v.(*NPMUnauthenticatedPackage); i { case 0: return &v.state case 1: @@ -4895,7 +5165,7 @@ func file_sources_proto_init() { } } file_sources_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*S3); i { + switch v := v.(*PyPIUnauthenticatedPackage); i { case 0: return &v.state case 1: @@ -4907,7 +5177,7 @@ func file_sources_proto_init() { } } file_sources_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Slack); i { + switch v := v.(*S3); i { case 0: return &v.state case 1: @@ -4919,7 +5189,7 @@ func file_sources_proto_init() { } } file_sources_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Test); i { + switch v := v.(*Slack); i { case 0: return &v.state case 1: @@ -4931,7 +5201,7 @@ func file_sources_proto_init() { } } file_sources_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Buildkite); i { + switch v := v.(*Test); i { case 0: return &v.state case 1: @@ -4943,7 +5213,7 @@ func file_sources_proto_init() { } } file_sources_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Gerrit); i { + switch v := v.(*Buildkite); i { case 0: return &v.state case 1: @@ -4955,7 +5225,7 @@ func file_sources_proto_init() { } } file_sources_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Jenkins); i { + switch v := v.(*Gerrit); i { case 0: return &v.state case 1: @@ -4967,7 +5237,7 @@ func file_sources_proto_init() { } } file_sources_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Teams); i { + switch v := v.(*Jenkins); i { case 0: return &v.state case 1: @@ -4979,7 +5249,7 @@ func file_sources_proto_init() { } } file_sources_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Syslog); i { + switch v := v.(*Teams); i { case 0: return &v.state case 1: @@ -4991,7 +5261,7 @@ func file_sources_proto_init() { } } file_sources_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Forager); i { + switch v := v.(*Syslog); i { case 0: return &v.state case 1: @@ -5003,7 +5273,7 @@ func file_sources_proto_init() { } } file_sources_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SlackRealtime); i { + switch v := v.(*Forager); i { case 0: return &v.state case 1: @@ -5015,7 +5285,7 @@ func file_sources_proto_init() { } } file_sources_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Sharepoint); i { + switch v := v.(*SlackRealtime); i { case 0: return &v.state case 1: @@ -5027,7 +5297,7 @@ func file_sources_proto_init() { } } file_sources_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AzureRepos); i { + switch v := v.(*Sharepoint); i { case 0: return &v.state case 1: @@ -5039,7 +5309,7 @@ func file_sources_proto_init() { } } file_sources_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Postman); i { + switch v := v.(*AzureRepos); i { case 0: return &v.state case 1: @@ -5051,7 +5321,7 @@ func file_sources_proto_init() { } } file_sources_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Webhook); i { + switch v := v.(*Postman); i { case 0: return &v.state case 1: @@ -5063,6 +5333,18 @@ func file_sources_proto_init() { } } file_sources_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Webhook); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sources_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Elasticsearch); i { case 0: return &v.state @@ -5139,62 +5421,66 @@ func file_sources_proto_init() { (*GoogleDrive_RefreshToken)(nil), } file_sources_proto_msgTypes[15].OneofWrappers = []interface{}{ + (*Huggingface_Token)(nil), + (*Huggingface_Unauthenticated)(nil), + } + file_sources_proto_msgTypes[16].OneofWrappers = []interface{}{ (*JIRA_BasicAuth)(nil), (*JIRA_Unauthenticated)(nil), (*JIRA_Oauth)(nil), (*JIRA_Token)(nil), } - file_sources_proto_msgTypes[16].OneofWrappers = []interface{}{ + file_sources_proto_msgTypes[17].OneofWrappers = []interface{}{ (*NPMUnauthenticatedPackage_Unauthenticated)(nil), } - file_sources_proto_msgTypes[17].OneofWrappers = []interface{}{ + file_sources_proto_msgTypes[18].OneofWrappers = []interface{}{ (*PyPIUnauthenticatedPackage_Unauthenticated)(nil), } - file_sources_proto_msgTypes[18].OneofWrappers = []interface{}{ + file_sources_proto_msgTypes[19].OneofWrappers = []interface{}{ (*S3_AccessKey)(nil), (*S3_Unauthenticated)(nil), (*S3_CloudEnvironment)(nil), (*S3_SessionToken)(nil), } - file_sources_proto_msgTypes[19].OneofWrappers = []interface{}{ + file_sources_proto_msgTypes[20].OneofWrappers = []interface{}{ (*Slack_Token)(nil), (*Slack_Tokens)(nil), } - file_sources_proto_msgTypes[21].OneofWrappers = []interface{}{ + file_sources_proto_msgTypes[22].OneofWrappers = []interface{}{ (*Buildkite_Token)(nil), } - file_sources_proto_msgTypes[22].OneofWrappers = []interface{}{ + file_sources_proto_msgTypes[23].OneofWrappers = []interface{}{ (*Gerrit_BasicAuth)(nil), (*Gerrit_Unauthenticated)(nil), } - file_sources_proto_msgTypes[23].OneofWrappers = []interface{}{ + file_sources_proto_msgTypes[24].OneofWrappers = []interface{}{ (*Jenkins_BasicAuth)(nil), (*Jenkins_Header)(nil), (*Jenkins_Unauthenticated)(nil), } - file_sources_proto_msgTypes[24].OneofWrappers = []interface{}{ + file_sources_proto_msgTypes[25].OneofWrappers = []interface{}{ (*Teams_Token)(nil), (*Teams_Authenticated)(nil), (*Teams_Oauth)(nil), } - file_sources_proto_msgTypes[26].OneofWrappers = []interface{}{ + file_sources_proto_msgTypes[27].OneofWrappers = []interface{}{ (*Forager_Unauthenticated)(nil), } - file_sources_proto_msgTypes[27].OneofWrappers = []interface{}{ + file_sources_proto_msgTypes[28].OneofWrappers = []interface{}{ (*SlackRealtime_Tokens)(nil), } - file_sources_proto_msgTypes[28].OneofWrappers = []interface{}{ + file_sources_proto_msgTypes[29].OneofWrappers = []interface{}{ (*Sharepoint_Oauth)(nil), } - file_sources_proto_msgTypes[29].OneofWrappers = []interface{}{ + file_sources_proto_msgTypes[30].OneofWrappers = []interface{}{ (*AzureRepos_Token)(nil), (*AzureRepos_Oauth)(nil), } - file_sources_proto_msgTypes[30].OneofWrappers = []interface{}{ + file_sources_proto_msgTypes[31].OneofWrappers = []interface{}{ (*Postman_Unauthenticated)(nil), (*Postman_Token)(nil), } - file_sources_proto_msgTypes[31].OneofWrappers = []interface{}{ + file_sources_proto_msgTypes[32].OneofWrappers = []interface{}{ (*Webhook_Header)(nil), } type x struct{} @@ -5203,7 +5489,7 @@ func file_sources_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_sources_proto_rawDesc, NumEnums: 2, - NumMessages: 33, + NumMessages: 34, NumExtensions: 0, NumServices: 0, }, diff --git a/pkg/pb/sourcespb/sources.pb.validate.go b/pkg/pb/sourcespb/sources.pb.validate.go index d275e096e..304b8cd5b 100644 --- a/pkg/pb/sourcespb/sources.pb.validate.go +++ b/pkg/pb/sourcespb/sources.pb.validate.go @@ -2875,6 +2875,185 @@ var _ interface { ErrorName() string } = GoogleDriveValidationError{} +// Validate checks the field values on Huggingface with the rules defined in +// the proto definition for this message. If any rules are violated, the first +// error encountered is returned, or nil if there are no violations. +func (m *Huggingface) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on Huggingface with the rules defined in +// the proto definition for this message. If any rules are violated, the +// result is a list of violation errors wrapped in HuggingfaceMultiError, or +// nil if none found. +func (m *Huggingface) ValidateAll() error { + return m.validate(true) +} + +func (m *Huggingface) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if _, err := url.Parse(m.GetEndpoint()); err != nil { + err = HuggingfaceValidationError{ + field: "Endpoint", + reason: "value must be a valid URI", + cause: err, + } + if !all { + return err + } + errors = append(errors, err) + } + + // no validation rules for SkipAllModels + + // no validation rules for SkipAllSpaces + + // no validation rules for SkipAllDatasets + + // no validation rules for IncludeDiscussions + + // no validation rules for IncludePrs + + switch v := m.Credential.(type) { + case *Huggingface_Token: + if v == nil { + err := HuggingfaceValidationError{ + field: "Credential", + reason: "oneof value cannot be a typed-nil", + } + if !all { + return err + } + errors = append(errors, err) + } + // no validation rules for Token + case *Huggingface_Unauthenticated: + if v == nil { + err := HuggingfaceValidationError{ + field: "Credential", + reason: "oneof value cannot be a typed-nil", + } + if !all { + return err + } + errors = append(errors, err) + } + + if all { + switch v := interface{}(m.GetUnauthenticated()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, HuggingfaceValidationError{ + field: "Unauthenticated", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, HuggingfaceValidationError{ + field: "Unauthenticated", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetUnauthenticated()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return HuggingfaceValidationError{ + field: "Unauthenticated", + reason: "embedded message failed validation", + cause: err, + } + } + } + + default: + _ = v // ensures v is used + } + + if len(errors) > 0 { + return HuggingfaceMultiError(errors) + } + + return nil +} + +// HuggingfaceMultiError is an error wrapping multiple validation errors +// returned by Huggingface.ValidateAll() if the designated constraints aren't met. +type HuggingfaceMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m HuggingfaceMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m HuggingfaceMultiError) AllErrors() []error { return m } + +// HuggingfaceValidationError is the validation error returned by +// Huggingface.Validate if the designated constraints aren't met. +type HuggingfaceValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e HuggingfaceValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e HuggingfaceValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e HuggingfaceValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e HuggingfaceValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e HuggingfaceValidationError) ErrorName() string { return "HuggingfaceValidationError" } + +// Error satisfies the builtin error interface +func (e HuggingfaceValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sHuggingface.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = HuggingfaceValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = HuggingfaceValidationError{} + // Validate checks the field values on JIRA with the rules defined in the proto // definition for this message. If any rules are violated, the first error // encountered is returned, or nil if there are no violations. diff --git a/pkg/sources/huggingface/client.go b/pkg/sources/huggingface/client.go new file mode 100644 index 000000000..f963d2cc7 --- /dev/null +++ b/pkg/sources/huggingface/client.go @@ -0,0 +1,223 @@ +package huggingface + +import ( + "encoding/json" + "errors" + "fmt" + "net/http" + "time" + + "github.com/trufflesecurity/trufflehog/v3/pkg/context" +) + +// Maps for API and HTML paths +var apiPaths = map[string]string{ + DATASET: DatasetsRoute, + MODEL: ModelsAPIRoute, + SPACE: SpacesRoute, +} + +var htmlPaths = map[string]string{ + DATASET: DatasetsRoute, + MODEL: "", + SPACE: SpacesRoute, +} + +type Author struct { + Username string `json:"name"` +} + +type Latest struct { + Raw string `json:"raw"` +} + +type Data struct { + Latest Latest `json:"latest"` +} + +type Event struct { + Type string `json:"type"` + Author Author `json:"author"` + CreatedAt string `json:"createdAt"` + Data Data `json:"data"` + ID string `json:"id"` +} + +func (e Event) GetAuthor() string { + return e.Author.Username +} + +func (e Event) GetCreatedAt() string { + return e.CreatedAt +} + +func (e Event) GetID() string { + return e.ID +} + +type RepoData struct { + FullName string `json:"name"` + ResourceType string `json:"type"` +} + +type Discussion struct { + ID int `json:"num"` + IsPR bool `json:"isPullRequest"` + CreatedAt string `json:"createdAt"` + Title string `json:"title"` + Events []Event `json:"events"` + Repo RepoData `json:"repo"` +} + +func (d Discussion) GetID() string { + return fmt.Sprint(d.ID) +} + +func (d Discussion) GetTitle() string { + return d.Title +} + +func (d Discussion) GetCreatedAt() string { + return d.CreatedAt +} + +func (d Discussion) GetRepo() string { + return d.Repo.FullName +} + +// GetDiscussionPath returns the path (ex: "/models/user/repo/discussions/1") for the discussion +func (d Discussion) GetDiscussionPath() string { + basePath := fmt.Sprintf("%s/%s/%s", d.GetRepo(), DiscussionsRoute, d.GetID()) + if d.Repo.ResourceType == "model" { + return basePath + } + return fmt.Sprintf("%s/%s", getResourceHTMLPath(d.Repo.ResourceType), basePath) +} + +// GetGitPath returns the path (ex: "/models/user/repo.git") for the repo's git directory +func (d Discussion) GetGitPath() string { + basePath := fmt.Sprintf("%s.git", d.GetRepo()) + if d.Repo.ResourceType == "model" { + return basePath + } + return fmt.Sprintf("%s/%s", getResourceHTMLPath(d.Repo.ResourceType), basePath) +} + +type DiscussionList struct { + Discussions []Discussion `json:"discussions"` +} + +type Repo struct { + IsPrivate bool `json:"private"` + Owner string `json:"author"` + RepoID string `json:"id"` +} + +type HFClient struct { + BaseURL string + APIKey string + HTTPClient *http.Client +} + +// NewClient creates a new API client +func NewHFClient(baseURL, apiKey string, timeout time.Duration) *HFClient { + return &HFClient{ + BaseURL: baseURL, + APIKey: apiKey, + HTTPClient: &http.Client{ + Timeout: timeout, + }, + } +} + +// get makes a GET request to the Hugging Face API +// Note: not addressing rate limit, since it seems very permissive. (ex: "If \ +// your account suddenly sends 10k requests then you’re likely to receive 503") +func (c *HFClient) get(ctx context.Context, url string, target interface{}) error { + ctx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + + req, err := http.NewRequestWithContext(ctx, "GET", url, nil) + if err != nil { + return fmt.Errorf("failed to create HuggingFace API request: %w", err) + } + + req.Header.Set("Authorization", "Bearer "+c.APIKey) + + resp, err := c.HTTPClient.Do(req) + if err != nil { + return fmt.Errorf("failed to make request to HuggingFace API: %w", err) + } + + if resp.StatusCode == http.StatusUnauthorized { + return errors.New("invalid API key.") + } + + if resp.StatusCode == http.StatusForbidden { + return errors.New("access to this repo is restricted and you are not in the authorized list. Visit the repository to ask for access.") + } + + defer resp.Body.Close() + + return json.NewDecoder(resp.Body).Decode(target) +} + +// GetRepo retrieves repo from the Hugging Face API +func (c *HFClient) GetRepo(ctx context.Context, repoName string, resourceType string) (Repo, error) { + var repo Repo + url, err := buildAPIURL(c.BaseURL, resourceType, repoName) + if err != nil { + return repo, err + } + err = c.get(ctx, url, &repo) + return repo, err +} + +// ListDiscussions retrieves discussions from the Hugging Face API +func (c *HFClient) ListDiscussions(ctx context.Context, repoInfo repoInfo) (DiscussionList, error) { + var discussions DiscussionList + baseURL, err := buildAPIURL(c.BaseURL, string(repoInfo.resourceType), repoInfo.fullName) + if err != nil { + return discussions, err + } + url := fmt.Sprintf("%s/%s", baseURL, DiscussionsRoute) + err = c.get(ctx, url, &discussions) + return discussions, err +} + +func (c *HFClient) GetDiscussionByID(ctx context.Context, repoInfo repoInfo, discussionID string) (Discussion, error) { + var discussion Discussion + baseURL, err := buildAPIURL(c.BaseURL, string(repoInfo.resourceType), repoInfo.fullName) + if err != nil { + return discussion, err + } + url := fmt.Sprintf("%s/%s/%s", baseURL, DiscussionsRoute, discussionID) + err = c.get(ctx, url, &discussion) + return discussion, err +} + +// ListReposByAuthor retrieves repos from the Hugging Face API by author (user or org) +// Note: not addressing pagination b/c allow by default 1000 results, which should be enough for 99.99% of cases +func (c *HFClient) ListReposByAuthor(ctx context.Context, resourceType string, author string) ([]Repo, error) { + var repos []Repo + url := fmt.Sprintf("%s/%s/%s?limit=1000&author=%s", c.BaseURL, APIRoute, getResourceAPIPath(resourceType), author) + err := c.get(ctx, url, &repos) + return repos, err +} + +// getResourceAPIPath returns the API path for the given resource type +func getResourceAPIPath(resourceType string) string { + return apiPaths[resourceType] +} + +// getResourceHTMLPath returns the HTML path for the given resource type +func getResourceHTMLPath(resourceType string) string { + return htmlPaths[resourceType] +} + +func buildAPIURL(endpoint string, resourceType string, repoName string) (string, error) { + if endpoint == "" || resourceType == "" || repoName == "" { + return "", errors.New("endpoint, resourceType, and repoName must not be empty") + } + return fmt.Sprintf("%s/%s/%s/%s", endpoint, APIRoute, getResourceAPIPath(resourceType), repoName), nil +} diff --git a/pkg/sources/huggingface/huggingface.go b/pkg/sources/huggingface/huggingface.go new file mode 100644 index 000000000..b3f78f245 --- /dev/null +++ b/pkg/sources/huggingface/huggingface.go @@ -0,0 +1,680 @@ +package huggingface + +import ( + "fmt" + "os" + "sort" + "strings" + "sync" + "sync/atomic" + "time" + + "github.com/go-logr/logr" + "github.com/gobwas/glob" + "golang.org/x/sync/errgroup" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/anypb" + + "github.com/trufflesecurity/trufflehog/v3/pkg/cache" + "github.com/trufflesecurity/trufflehog/v3/pkg/cache/memory" + "github.com/trufflesecurity/trufflehog/v3/pkg/common" + "github.com/trufflesecurity/trufflehog/v3/pkg/context" + "github.com/trufflesecurity/trufflehog/v3/pkg/giturl" + "github.com/trufflesecurity/trufflehog/v3/pkg/pb/source_metadatapb" + "github.com/trufflesecurity/trufflehog/v3/pkg/pb/sourcespb" + "github.com/trufflesecurity/trufflehog/v3/pkg/sanitizer" + "github.com/trufflesecurity/trufflehog/v3/pkg/sources" + "github.com/trufflesecurity/trufflehog/v3/pkg/sources/git" +) + +const ( + SourceType = sourcespb.SourceType_SOURCE_TYPE_HUGGINGFACE + DatasetsRoute = "datasets" + SpacesRoute = "spaces" + ModelsAPIRoute = "models" + DiscussionsRoute = "discussions" + APIRoute = "api" + DATASET = "dataset" + MODEL = "model" + SPACE = "space" + defaultPagination = 100 +) + +type resourceType string + +type Source struct { + name string + huggingfaceToken string + + sourceID sources.SourceID + jobID sources.JobID + verify bool + useCustomContentWriter bool + orgsCache cache.Cache[string] + usersCache cache.Cache[string] + + models []string + spaces []string + datasets []string + + filteredModelsCache *filteredRepoCache + filteredSpacesCache *filteredRepoCache + filteredDatasetsCache *filteredRepoCache + + repoInfoCache repoInfoCache + + git *git.Git + + scanOptions *git.ScanOptions + + apiClient *HFClient + log logr.Logger + conn *sourcespb.Huggingface + jobPool *errgroup.Group + resumeInfoMutex sync.Mutex + resumeInfoSlice []string + + skipAllModels bool + skipAllSpaces bool + skipAllDatasets bool + includeDiscussions bool + includePrs bool + + sources.Progress + sources.CommonSourceUnitUnmarshaller +} + +// Ensure the Source satisfies the interfaces at compile time +var _ sources.Source = (*Source)(nil) +var _ sources.SourceUnitUnmarshaller = (*Source)(nil) + +// WithCustomContentWriter sets the useCustomContentWriter flag on the source. +func (s *Source) WithCustomContentWriter() { s.useCustomContentWriter = true } + +// Type returns the type of source. +// It is used for matching source types in configuration and job input. +func (s *Source) Type() sourcespb.SourceType { + return SourceType +} + +func (s *Source) SourceID() sources.SourceID { + return s.sourceID +} + +func (s *Source) JobID() sources.JobID { + return s.jobID +} + +// filteredRepoCache is a wrapper around cache.Cache that filters out repos +// based on include and exclude globs. +type filteredRepoCache struct { + cache.Cache[string] + include, exclude []glob.Glob +} + +func (s *Source) newFilteredRepoCache(c cache.Cache[string], include, exclude []string) *filteredRepoCache { + includeGlobs := make([]glob.Glob, 0, len(include)) + excludeGlobs := make([]glob.Glob, 0, len(exclude)) + for _, ig := range include { + g, err := glob.Compile(ig) + if err != nil { + s.log.V(1).Info("invalid include glob", "include_value", ig, "err", err) + continue + } + includeGlobs = append(includeGlobs, g) + } + for _, eg := range exclude { + g, err := glob.Compile(eg) + if err != nil { + s.log.V(1).Info("invalid exclude glob", "exclude_value", eg, "err", err) + continue + } + excludeGlobs = append(excludeGlobs, g) + } + return &filteredRepoCache{Cache: c, include: includeGlobs, exclude: excludeGlobs} +} + +// Set overrides the cache.Cache Set method to filter out repos based on +// include and exclude globs. +func (c *filteredRepoCache) Set(key, val string) { + if c.ignoreRepo(key) { + return + } + if !c.includeRepo(key) { + return + } + c.Cache.Set(key, val) +} + +func (c *filteredRepoCache) ignoreRepo(s string) bool { + for _, g := range c.exclude { + if g.Match(s) { + return true + } + } + return false +} + +func (c *filteredRepoCache) includeRepo(s string) bool { + if len(c.include) == 0 { + return true + } + + for _, g := range c.include { + if g.Match(s) { + return true + } + } + return false +} + +// Init returns an initialized HuggingFace source. +func (s *Source) Init(aCtx context.Context, name string, jobID sources.JobID, sourceID sources.SourceID, verify bool, connection *anypb.Any, concurrency int) error { + err := git.CmdCheck() + if err != nil { + return err + } + + s.log = aCtx.Logger() + + s.name = name + s.sourceID = sourceID + s.jobID = jobID + s.verify = verify + s.jobPool = &errgroup.Group{} + s.jobPool.SetLimit(concurrency) + + var conn sourcespb.Huggingface + err = anypb.UnmarshalTo(connection, &conn, proto.UnmarshalOptions{}) + if err != nil { + return fmt.Errorf("error unmarshalling connection: %w", err) + } + s.conn = &conn + + s.orgsCache = memory.New[string]() + for _, org := range s.conn.Organizations { + s.orgsCache.Set(org, org) + } + + s.usersCache = memory.New[string]() + for _, user := range s.conn.Users { + s.usersCache.Set(user, user) + } + + //Verify ignore and include models, spaces, and datasets are valid + // this ensures that calling --org --ignore-model contains the proper + // repo format of org/model. Otherwise, we would scan the entire org. + if err := s.validateIgnoreIncludeRepos(); err != nil { + return err + } + + s.filteredModelsCache = s.newFilteredRepoCache(memory.New[string](), + append(s.conn.GetModels(), s.conn.GetIncludeModels()...), + s.conn.GetIgnoreModels(), + ) + + s.filteredSpacesCache = s.newFilteredRepoCache(memory.New[string](), + append(s.conn.GetSpaces(), s.conn.GetIncludeSpaces()...), + s.conn.GetIgnoreSpaces(), + ) + + s.filteredDatasetsCache = s.newFilteredRepoCache(memory.New[string](), + append(s.conn.GetDatasets(), s.conn.GetIncludeDatasets()...), + s.conn.GetIgnoreDatasets(), + ) + + s.models = initializeRepos(s.filteredModelsCache, s.conn.Models, fmt.Sprintf("%s/%s.git", s.conn.Endpoint, "%s")) + s.spaces = initializeRepos(s.filteredSpacesCache, s.conn.Spaces, fmt.Sprintf("%s/%s/%s.git", s.conn.Endpoint, SpacesRoute, "%s")) + s.datasets = initializeRepos(s.filteredDatasetsCache, s.conn.Datasets, fmt.Sprintf("%s/%s/%s.git", s.conn.Endpoint, DatasetsRoute, "%s")) + s.repoInfoCache = newRepoInfoCache() + + s.includeDiscussions = s.conn.IncludeDiscussions + s.includePrs = s.conn.IncludePrs + + cfg := &git.Config{ + SourceName: s.name, + JobID: s.jobID, + SourceID: s.sourceID, + SourceType: s.Type(), + Verify: s.verify, + Concurrency: concurrency, + SourceMetadataFunc: func(file, email, commit, timestamp, repository string, line int64) *source_metadatapb.MetaData { + return &source_metadatapb.MetaData{ + Data: &source_metadatapb.MetaData_Huggingface{ + Huggingface: &source_metadatapb.Huggingface{ + Commit: sanitizer.UTF8(commit), + File: sanitizer.UTF8(file), + Email: sanitizer.UTF8(email), + Repository: sanitizer.UTF8(repository), + Link: giturl.GenerateLink(repository, commit, file, line), + Timestamp: sanitizer.UTF8(timestamp), + Line: line, + Visibility: s.visibilityOf(aCtx, repository), + ResourceType: s.getResourceType(aCtx, repository), + }, + }, + } + }, + UseCustomContentWriter: s.useCustomContentWriter, + } + s.git = git.NewGit(cfg) + + s.huggingfaceToken = s.conn.GetToken() + s.apiClient = NewHFClient(s.conn.Endpoint, s.huggingfaceToken, 10*time.Second) + + s.skipAllModels = s.conn.SkipAllModels + s.skipAllSpaces = s.conn.SkipAllSpaces + s.skipAllDatasets = s.conn.SkipAllDatasets + + return nil +} + +func (s *Source) validateIgnoreIncludeRepos() error { + if err := verifySlashSeparatedStrings(s.conn.IgnoreModels); err != nil { + return err + } + if err := verifySlashSeparatedStrings(s.conn.IncludeModels); err != nil { + return err + } + if err := verifySlashSeparatedStrings(s.conn.IgnoreSpaces); err != nil { + return err + } + if err := verifySlashSeparatedStrings(s.conn.IncludeSpaces); err != nil { + return err + } + if err := verifySlashSeparatedStrings(s.conn.IgnoreDatasets); err != nil { + return err + } + if err := verifySlashSeparatedStrings(s.conn.IncludeDatasets); err != nil { + return err + } + return nil +} + +func verifySlashSeparatedStrings(s []string) error { + for _, str := range s { + if !strings.Contains(str, "/") { + return fmt.Errorf("invalid owner/repo: %s", str) + } + } + return nil +} + +func initializeRepos(cache *filteredRepoCache, repos []string, urlPattern string) []string { + returnRepos := make([]string, 0) + for _, repo := range repos { + if !cache.ignoreRepo(repo) { + url := fmt.Sprintf(urlPattern, repo) + cache.Set(repo, url) + returnRepos = append(returnRepos, repo) + } + } + return returnRepos +} + +func (s *Source) getResourceType(ctx context.Context, repoURL string) string { + repoInfo, ok := s.repoInfoCache.get(repoURL) + if !ok { + // This should never happen. + err := fmt.Errorf("no repoInfo for URL: %s", repoURL) + ctx.Logger().Error(err, "failed to get repository resource type") + return "" + } + + return string(repoInfo.resourceType) +} + +func (s *Source) visibilityOf(ctx context.Context, repoURL string) source_metadatapb.Visibility { + repoInfo, ok := s.repoInfoCache.get(repoURL) + if !ok { + // This should never happen. + err := fmt.Errorf("no repoInfo for URL: %s", repoURL) + ctx.Logger().Error(err, "failed to get repository visibility") + return source_metadatapb.Visibility_unknown + } + + return repoInfo.visibility +} + +// Chunks emits chunks of bytes over a channel. +func (s *Source) Chunks(ctx context.Context, chunksChan chan *sources.Chunk, targets ...sources.ChunkingTarget) error { + err := s.enumerate(ctx) + if err != nil { + return err + } + return s.scan(ctx, chunksChan) +} + +func (s *Source) enumerate(ctx context.Context) error { + s.enumerateAuthors(ctx) + + s.models = make([]string, 0, s.filteredModelsCache.Count()) + for _, repo := range s.filteredModelsCache.Keys() { + if err := s.cacheRepoInfo(ctx, repo, MODEL, s.filteredModelsCache); err != nil { + continue + } + } + + s.spaces = make([]string, 0, s.filteredSpacesCache.Count()) + for _, repo := range s.filteredSpacesCache.Keys() { + if err := s.cacheRepoInfo(ctx, repo, SPACE, s.filteredSpacesCache); err != nil { + continue + } + } + + s.datasets = make([]string, 0, s.filteredDatasetsCache.Count()) + for _, repo := range s.filteredDatasetsCache.Keys() { + if err := s.cacheRepoInfo(ctx, repo, DATASET, s.filteredDatasetsCache); err != nil { + continue + } + } + + s.log.Info("Completed enumeration", "num_models", len(s.models), "num_spaces", len(s.spaces), "num_datasets", len(s.datasets)) + + // We must sort the repos so we can resume later if necessary. + sort.Strings(s.models) + sort.Strings(s.datasets) + sort.Strings(s.spaces) + return nil +} + +func (s *Source) cacheRepoInfo(ctx context.Context, repo string, repoType string, repoCache *filteredRepoCache) error { + repoURL, _ := repoCache.Get(repo) + repoCtx := context.WithValue(ctx, repoType, repoURL) + + if _, ok := s.repoInfoCache.get(repoURL); !ok { + repoCtx.Logger().V(2).Info("Caching " + repoType + " info") + repo, err := s.apiClient.GetRepo(repoCtx, repo, repoType) + if err != nil { + repoCtx.Logger().Error(err, "failed to fetch "+repoType) + return err + } + // check if repo empty + if repo.RepoID == "" { + repoCtx.Logger().Error(fmt.Errorf("no repo found for repo"), repoURL) + return nil + } + s.repoInfoCache.put(repoURL, repoInfo{ + owner: repo.Owner, + name: strings.Split(repo.RepoID, "/")[1], + fullName: repo.RepoID, + visibility: getVisibility(repo.IsPrivate), + resourceType: resourceType(repoType), + }) + } + s.updateRepoLists(repoURL, repoType) + return nil +} + +func getVisibility(isPrivate bool) source_metadatapb.Visibility { + if isPrivate { + return source_metadatapb.Visibility_private + } + return source_metadatapb.Visibility_public +} + +func (s *Source) updateRepoLists(repoURL string, repoType string) { + switch repoType { + case MODEL: + s.models = append(s.models, repoURL) + case SPACE: + s.spaces = append(s.spaces, repoURL) + case DATASET: + s.datasets = append(s.datasets, repoURL) + } +} + +func (s *Source) fetchAndCacheRepos(ctx context.Context, resourceType string, org string) error { + var repos []Repo + var err error + var url string + var filteredCache *filteredRepoCache + switch resourceType { + case MODEL: + filteredCache = s.filteredModelsCache + url = fmt.Sprintf("%s/%s.git", s.conn.Endpoint, "%s") + repos, err = s.apiClient.ListReposByAuthor(ctx, MODEL, org) + case SPACE: + filteredCache = s.filteredSpacesCache + url = fmt.Sprintf("%s/%s/%s.git", s.conn.Endpoint, SpacesRoute, "%s") + repos, err = s.apiClient.ListReposByAuthor(ctx, SPACE, org) + case DATASET: + filteredCache = s.filteredDatasetsCache + url = fmt.Sprintf("%s/%s/%s.git", s.conn.Endpoint, DatasetsRoute, "%s") + repos, err = s.apiClient.ListReposByAuthor(ctx, DATASET, org) + } + if err != nil { + return err + } + + for _, repo := range repos { + repoURL := fmt.Sprintf(url, repo.RepoID) + filteredCache.Set(repo.RepoID, repoURL) + if err := s.cacheRepoInfo(ctx, repo.RepoID, resourceType, filteredCache); err != nil { + continue + } + } + return nil +} + +func (s *Source) enumerateAuthors(ctx context.Context) { + for _, org := range s.orgsCache.Keys() { + orgCtx := context.WithValue(ctx, "organization", org) + if !s.skipAllModels { + if err := s.fetchAndCacheRepos(orgCtx, MODEL, org); err != nil { + orgCtx.Logger().Error(err, "Failed to fetch models for organization") + continue + } + } + if !s.skipAllSpaces { + if err := s.fetchAndCacheRepos(orgCtx, SPACE, org); err != nil { + orgCtx.Logger().Error(err, "Failed to fetch spaces for organization") + continue + } + } + if !s.skipAllDatasets { + if err := s.fetchAndCacheRepos(orgCtx, DATASET, org); err != nil { + orgCtx.Logger().Error(err, "Failed to fetch datasets for organization") + continue + } + } + } + for _, user := range s.usersCache.Keys() { + userCtx := context.WithValue(ctx, "user", user) + if !s.skipAllModels { + if err := s.fetchAndCacheRepos(userCtx, MODEL, user); err != nil { + userCtx.Logger().Error(err, "Failed to fetch models for user") + continue + } + } + if !s.skipAllSpaces { + if err := s.fetchAndCacheRepos(userCtx, SPACE, user); err != nil { + userCtx.Logger().Error(err, "Failed to fetch spaces for user") + continue + } + } + if !s.skipAllDatasets { + if err := s.fetchAndCacheRepos(userCtx, DATASET, user); err != nil { + userCtx.Logger().Error(err, "Failed to fetch datasets for user") + continue + } + } + } +} + +func (s *Source) scanRepos(ctx context.Context, chunksChan chan *sources.Chunk, resourceType string) error { + var scannedCount uint64 = 1 + + repos := s.getReposListByType(resourceType) + + s.log.V(2).Info("Found "+resourceType+" to scan", "count", len(repos)) + + // If there is resume information available, limit this scan to only the repos that still need scanning. + reposToScan, progressIndexOffset := sources.FilterReposToResume(repos, s.GetProgress().EncodedResumeInfo) + repos = reposToScan + + scanErrs := sources.NewScanErrors() + + if s.scanOptions == nil { + s.scanOptions = &git.ScanOptions{} + } + + for i, repoURL := range repos { + i, repoURL := i, repoURL + s.jobPool.Go(func() error { + if common.IsDone(ctx) { + return nil + } + + // TODO: set progress complete is being called concurrently with i + s.setProgressCompleteWithRepo(i, progressIndexOffset, repoURL, resourceType, repos) + // Ensure the repo is removed from the resume info after being scanned. + defer func(s *Source, repoURL string) { + s.resumeInfoMutex.Lock() + defer s.resumeInfoMutex.Unlock() + s.resumeInfoSlice = sources.RemoveRepoFromResumeInfo(s.resumeInfoSlice, repoURL) + }(s, repoURL) + + // Scan the repository + repoInfo, ok := s.repoInfoCache.get(repoURL) + if !ok { + // This should never happen. + err := fmt.Errorf("no repoInfo for URL: %s", repoURL) + s.log.Error(err, "failed to scan "+resourceType) + return nil + } + repoCtx := context.WithValues(ctx, resourceType, repoURL) + duration, err := s.cloneAndScanRepo(repoCtx, repoURL, repoInfo, chunksChan) + if err != nil { + scanErrs.Add(err) + return nil + } + + // Scan discussions and PRs, if enabled. + if s.includeDiscussions || s.includePrs { + if err = s.scanDiscussions(repoCtx, repoInfo, chunksChan); err != nil { + scanErrs.Add(fmt.Errorf("error scanning discussions/PRs in repo %s: %w", repoURL, err)) + return nil + } + } + + repoCtx.Logger().V(2).Info(fmt.Sprintf("scanned %d/%d "+resourceType+"s", scannedCount, len(s.models)), "duration_seconds", duration) + atomic.AddUint64(&scannedCount, 1) + return nil + }) + } + + _ = s.jobPool.Wait() + if scanErrs.Count() > 0 { + s.log.V(0).Info("failed to scan some repositories", "error_count", scanErrs.Count(), "errors", scanErrs.String()) + } + s.SetProgressComplete(len(repos), len(repos), "Completed HuggingFace "+resourceType+" scan", "") + return nil +} + +func (s *Source) getReposListByType(resourceType string) []string { + switch resourceType { + case MODEL: + return s.models + case SPACE: + return s.spaces + case DATASET: + return s.datasets + } + return nil +} + +func (s *Source) scan(ctx context.Context, chunksChan chan *sources.Chunk) error { + if err := s.scanRepos(ctx, chunksChan, MODEL); err != nil { + return err + } + if err := s.scanRepos(ctx, chunksChan, SPACE); err != nil { + return err + } + if err := s.scanRepos(ctx, chunksChan, DATASET); err != nil { + return err + } + return nil +} + +func (s *Source) cloneAndScanRepo(ctx context.Context, repoURL string, repoInfo repoInfo, chunksChan chan *sources.Chunk) (time.Duration, error) { + ctx.Logger().V(2).Info("attempting to clone %s", repoInfo.resourceType) + path, repo, err := s.cloneRepo(ctx, repoURL) + if err != nil { + return 0, err + } + defer os.RemoveAll(path) + + var logger logr.Logger + logger.V(2).Info("scanning %s", repoInfo.resourceType) + + start := time.Now() + if err = s.git.ScanRepo(ctx, repo, path, s.scanOptions, sources.ChanReporter{Ch: chunksChan}); err != nil { + return 0, fmt.Errorf("error scanning repo %s: %w", repoURL, err) + } + return time.Since(start), nil +} + +// setProgressCompleteWithRepo calls the s.SetProgressComplete after safely setting up the encoded resume info string. +func (s *Source) setProgressCompleteWithRepo(index int, offset int, repoURL string, resourceType string, repos []string) { + s.resumeInfoMutex.Lock() + defer s.resumeInfoMutex.Unlock() + + // Add the repoURL to the resume info slice. + s.resumeInfoSlice = append(s.resumeInfoSlice, repoURL) + sort.Strings(s.resumeInfoSlice) + + // Make the resume info string from the slice. + encodedResumeInfo := sources.EncodeResumeInfo(s.resumeInfoSlice) + s.SetProgressComplete(index+offset, len(repos)+offset, fmt.Sprintf("%ss: %s", resourceType, repoURL), encodedResumeInfo) +} + +func (s *Source) scanDiscussions(ctx context.Context, repoInfo repoInfo, chunksChan chan *sources.Chunk) error { + discussions, err := s.apiClient.ListDiscussions(ctx, repoInfo) + if err != nil { + return err + } + for _, discussion := range discussions.Discussions { + if (discussion.IsPR && s.includePrs) || (!discussion.IsPR && s.includeDiscussions) { + d, err := s.apiClient.GetDiscussionByID(ctx, repoInfo, discussion.GetID()) + if err != nil { + return err + } + // Note: there is no discussion "description" or similar to chunk, only comments + if err = s.chunkDiscussionComments(ctx, repoInfo, d, chunksChan); err != nil { + return err + } + } + } + return nil +} + +func (s *Source) chunkDiscussionComments(ctx context.Context, repoInfo repoInfo, discussion Discussion, chunksChan chan *sources.Chunk) error { + for _, comment := range discussion.Events { + chunk := &sources.Chunk{ + SourceName: s.name, + SourceID: s.SourceID(), + JobID: s.JobID(), + SourceType: s.Type(), + SourceMetadata: &source_metadatapb.MetaData{ + Data: &source_metadatapb.MetaData_Huggingface{ + Huggingface: &source_metadatapb.Huggingface{ + Link: sanitizer.UTF8(fmt.Sprintf("%s/%s#%s", s.conn.Endpoint, discussion.GetDiscussionPath(), comment.GetID())), + Username: sanitizer.UTF8(comment.GetAuthor()), + Repository: sanitizer.UTF8(fmt.Sprintf("%s/%s", s.conn.Endpoint, discussion.GetGitPath())), + Timestamp: sanitizer.UTF8(comment.GetCreatedAt()), + Visibility: repoInfo.visibility, + }, + }, + }, + Data: []byte(comment.Data.Latest.Raw), + Verify: s.verify, + } + select { + case <-ctx.Done(): + return ctx.Err() + case chunksChan <- chunk: + } + } + return nil +} diff --git a/pkg/sources/huggingface/huggingface_client_test.go b/pkg/sources/huggingface/huggingface_client_test.go new file mode 100644 index 000000000..15977d10e --- /dev/null +++ b/pkg/sources/huggingface/huggingface_client_test.go @@ -0,0 +1,651 @@ +package huggingface + +import ( + "fmt" + "strconv" + "testing" + "time" + + "github.com/trufflesecurity/trufflehog/v3/pkg/context" + + "github.com/stretchr/testify/assert" + "gopkg.in/h2non/gock.v1" +) + +const ( + TEST_TOKEN = "test token" +) + +func initTestClient() *HFClient { + return NewHFClient("https://huggingface.co", TEST_TOKEN, 10*time.Second) +} + +func TestGetRepo(t *testing.T) { + resourceType := MODEL + repoName := "test-model" + repoOwner := "test-author" + defer gock.Off() + + gock.New("https://huggingface.co"). + Get("/"+APIRoute+"/"+getResourceAPIPath(resourceType)+"/"+repoName). + MatchHeader("Authorization", "Bearer "+TEST_TOKEN). + Reply(200). + JSON(map[string]interface{}{ + "id": repoOwner + "/" + repoName, + "author": repoOwner, + "private": true, + }) + + client := initTestClient() + model, err := client.GetRepo(context.Background(), repoName, resourceType) + + assert.Nil(t, err) + assert.NotNil(t, model) + assert.Equal(t, repoOwner+"/"+repoName, model.RepoID) + assert.Equal(t, repoOwner, model.Owner) + assert.Equal(t, true, model.IsPrivate) + assert.False(t, gock.HasUnmatchedRequest()) + assert.True(t, gock.IsDone()) +} + +func TestGetRepo_NotFound(t *testing.T) { + resourceType := MODEL + repoName := "doesnotexist" + defer gock.Off() + + gock.New("https://huggingface.co"). + Get("/"+APIRoute+"/"+getResourceAPIPath(resourceType)+"/"+repoName). + MatchHeader("Authorization", "Bearer "+TEST_TOKEN). + Reply(404). + JSON(map[string]interface{}{ + "id": "", + "author": "", + "private": false, + }) + + client := initTestClient() + model, err := client.GetRepo(context.Background(), repoName, resourceType) + + assert.Nil(t, err) + assert.NotNil(t, model) + assert.Equal(t, "", model.RepoID) + assert.Equal(t, "", model.Owner) + assert.Equal(t, false, model.IsPrivate) + assert.False(t, gock.HasUnmatchedRequest()) + assert.True(t, gock.IsDone()) +} + +func TestGetModel_Error(t *testing.T) { + resourceType := MODEL + repoName := "doesnotexist" + defer gock.Off() + + gock.New("https://huggingface.co"). + Get("/"+APIRoute+"/"+getResourceAPIPath(resourceType)+"/"+repoName). + MatchHeader("Authorization", "Bearer "+TEST_TOKEN). + Reply(500) + + client := initTestClient() + model, err := client.GetRepo(context.Background(), repoName, resourceType) + + assert.NotNil(t, err) + assert.NotNil(t, model) + assert.False(t, gock.HasUnmatchedRequest()) + assert.True(t, gock.IsDone()) +} + +func TestListDiscussions(t *testing.T) { + repoInfo := repoInfo{ + fullName: "test-author/test-model", + resourceType: MODEL, + } + + jsonBlob := `{ + "discussions": [ + { + "num": 2, + "author": { + "avatarUrl": "/avatars/test.svg", + "fullname": "TEST", + "name": "test-author", + "type": "user", + "isPro": false, + "isHf": false, + "isMod": false + }, + "repo": { + "name": "test-author/test-model", + "type": "model" + }, + "title": "new PR", + "status": "open", + "createdAt": "2024-06-18T14:34:21.000Z", + "isPullRequest": true, + "numComments": 2, + "pinned": false + }, + { + "num": 1, + "author": { + "avatarUrl": "/avatars/test.svg", + "fullname": "TEST", + "name": "test-author", + "type": "user", + "isPro": false, + "isHf": false, + "isMod": false + }, + "repo": { + "name": "test-author/test-model", + "type": "model" + }, + "title": "secret in comment", + "status": "closed", + "createdAt": "2024-06-18T14:31:57.000Z", + "isPullRequest": false, + "numComments": 2, + "pinned": false + } + ], + "count": 2, + "start": 0, + "numClosedDiscussions": 1 + }` + + defer gock.Off() + + gock.New("https://huggingface.co"). + Get("/"+APIRoute+"/"+getResourceAPIPath(string(repoInfo.resourceType))+"/"+repoInfo.fullName+"/"+DiscussionsRoute). + MatchHeader("Authorization", "Bearer "+TEST_TOKEN). + Reply(200). + JSON(jsonBlob) + + client := initTestClient() + discussions, err := client.ListDiscussions(context.Background(), repoInfo) + + assert.Nil(t, err) + assert.NotNil(t, discussions) + assert.Equal(t, 2, len(discussions.Discussions)) + assert.False(t, gock.HasUnmatchedRequest()) + assert.True(t, gock.IsDone()) +} + +func TestListDiscussions_NotFound(t *testing.T) { + repoInfo := repoInfo{ + fullName: "test-author/doesnotexist", + resourceType: MODEL, + } + defer gock.Off() + + gock.New("https://huggingface.co"). + Get("/"+APIRoute+"/"+getResourceAPIPath(string(repoInfo.resourceType))+"/"+repoInfo.fullName+"/"+DiscussionsRoute). + MatchHeader("Authorization", "Bearer "+TEST_TOKEN). + Reply(404). + JSON(map[string]interface{}{ + "discussions": []map[string]interface{}{}, + }) + + client := initTestClient() + discussions, err := client.ListDiscussions(context.Background(), repoInfo) + + assert.Nil(t, err) + assert.NotNil(t, discussions) + assert.Equal(t, 0, len(discussions.Discussions)) + assert.False(t, gock.HasUnmatchedRequest()) + assert.True(t, gock.IsDone()) +} + +func TestListDiscussions_Error(t *testing.T) { + repoInfo := repoInfo{ + fullName: "test-author/doesnotexist", + resourceType: MODEL, + } + defer gock.Off() + + gock.New("https://huggingface.co"). + Get("/"+APIRoute+"/"+getResourceAPIPath(string(repoInfo.resourceType))+"/"+repoInfo.fullName+"/"+DiscussionsRoute). + MatchHeader("Authorization", "Bearer "+TEST_TOKEN). + Reply(500) + + client := initTestClient() + discussions, err := client.ListDiscussions(context.Background(), repoInfo) + + assert.NotNil(t, err) + assert.NotNil(t, discussions) + assert.False(t, gock.HasUnmatchedRequest()) + assert.True(t, gock.IsDone()) +} + +func TestGetDiscussionByID(t *testing.T) { + repoInfo := repoInfo{ + fullName: "test-author/test-model", + resourceType: MODEL, + } + discussionID := "1" + + jsonBlob := `{ + "author": { + "avatarUrl": "/avatars/test.svg", + "fullname": "TEST", + "name": "test-author", + "type": "user", + "isPro": false, + "isHf": false, + "isMod": false + }, + "num": 1, + "repo": { + "name": "test-author/test-model", + "type": "model" + }, + "title": "secret in initial", + "status": "open", + "createdAt": "2024-06-18T14:31:46.000Z", + "events": [ + { + "id": "525", + "author": { + "avatarUrl": "/avatars/test.svg", + "fullname": "TEST", + "name": "test-author", + "type": "user", + "isPro": false, + "isHf": false, + "isMod": false, + "isOwner": true, + "isOrgMember": false + }, + "createdAt": "2024-06-18T14:31:46.000Z", + "type": "comment", + "data": { + "edited": true, + "hidden": false, + "latest": { + "raw": "dd", + "html": "

dd

\n", + "updatedAt": "2024-06-18T14:33:32.066Z", + "author": { + "avatarUrl": "/avatars/test.svg", + "fullname": "TEST", + "name": "test-author", + "type": "user", + "isPro": false, + "isHf": false, + "isMod": false + } + }, + "numEdits": 1, + "editors": ["trufflej"], + "reactions": [], + "identifiedLanguage": { + "language": "en", + "probability": 0.40104949474334717 + }, + "isReport": false + } + }, + { + "id": "526", + "author": { + "avatarUrl": "/avatars/test.svg", + "fullname": "TEST", + "name": "test-author", + "type": "user", + "isPro": false, + "isHf": false, + "isMod": false, + "isOwner": true, + "isOrgMember": false + }, + "createdAt": "2024-06-18T14:32:40.000Z", + "type": "status-change", + "data": { + "status": "closed" + } + }, + { + "id": "527", + "author": { + "avatarUrl": "/avatars/test.svg", + "fullname": "TEST", + "name": "test-author", + "type": "user", + "isPro": false, + "isHf": false, + "isMod": false, + "isOwner": true, + "isOrgMember": false + }, + "createdAt": "2024-06-18T14:33:27.000Z", + "type": "status-change", + "data": { + "status": "open" + } + } + ], + "pinned": false, + "locked": false, + "isPullRequest": false, + "isReport": false + }` + + defer gock.Off() + + gock.New("https://huggingface.co"). + Get("/"+APIRoute+"/"+getResourceAPIPath(string(repoInfo.resourceType))+"/"+repoInfo.fullName+"/"+DiscussionsRoute+"/"+discussionID). + MatchHeader("Authorization", "Bearer "+TEST_TOKEN). + Reply(200). + JSON(jsonBlob) + + client := initTestClient() + discussion, err := client.GetDiscussionByID(context.Background(), repoInfo, discussionID) + + assert.Nil(t, err) + assert.NotNil(t, discussion) + assert.Equal(t, discussionID, strconv.Itoa(discussion.ID)) + assert.Equal(t, 3, len(discussion.Events)) + assert.Equal(t, false, discussion.IsPR) + assert.Equal(t, "secret in initial", discussion.Title) + assert.Equal(t, repoInfo.fullName, discussion.Repo.FullName) + assert.Equal(t, string(repoInfo.resourceType), discussion.Repo.ResourceType) + assert.False(t, gock.HasUnmatchedRequest()) + assert.True(t, gock.IsDone()) +} + +func TestGetDiscussionByID_NotFound(t *testing.T) { + repoInfo := repoInfo{ + fullName: "test-author/test-model", + resourceType: MODEL, + } + discussionID := "doesnotexist" + defer gock.Off() + + gock.New("https://huggingface.co"). + Get("/"+APIRoute+"/"+getResourceAPIPath(string(repoInfo.resourceType))+"/"+repoInfo.fullName+"/"+DiscussionsRoute+"/"+discussionID). + MatchHeader("Authorization", "Bearer "+TEST_TOKEN). + Reply(404). + JSON(map[string]interface{}{}) + + client := initTestClient() + discussion, err := client.GetDiscussionByID(context.Background(), repoInfo, discussionID) + + assert.Nil(t, err) + assert.NotNil(t, discussion) + assert.Equal(t, 0, len(discussion.Events)) + assert.False(t, gock.HasUnmatchedRequest()) + assert.True(t, gock.IsDone()) +} + +func TestGetDiscussionByID_Error(t *testing.T) { + repoInfo := repoInfo{ + fullName: "test-author/test-model", + resourceType: MODEL, + } + discussionID := "doesnotexist" + defer gock.Off() + + gock.New("https://huggingface.co"). + Get("/"+APIRoute+"/"+getResourceAPIPath(string(repoInfo.resourceType))+"/"+repoInfo.fullName+"/"+DiscussionsRoute+"/"+discussionID). + MatchHeader("Authorization", "Bearer "+TEST_TOKEN). + Reply(500) + + client := initTestClient() + discussion, err := client.GetDiscussionByID(context.Background(), repoInfo, discussionID) + + assert.NotNil(t, err) + assert.NotNil(t, discussion) + assert.Equal(t, "", discussion.Title) + assert.Equal(t, 0, len(discussion.Events)) + assert.False(t, gock.HasUnmatchedRequest()) + assert.True(t, gock.IsDone()) +} + +func TestListReposByAuthor(t *testing.T) { + resourceType := MODEL + author := "test-author" + repo := "test-model" + repo2 := "test-model2" + + defer gock.Off() + + gock.New("https://huggingface.co"). + Get(fmt.Sprintf("/%s/%s", APIRoute, getResourceAPIPath(resourceType))). + MatchParam("author", author). + MatchParam("limit", "1000"). + MatchHeader("Authorization", "Bearer "+TEST_TOKEN). + Reply(200). + JSON([]map[string]interface{}{ + { + "_id": "1", + "id": author + "/" + repo, + "modelId": author + "/" + repo, + "private": true, + }, + { + "_id": "2", + "id": author + "/" + repo2, + "modelId": author + "/" + repo2, + "private": false, + }, + }) + + for _, mock := range gock.Pending() { + fmt.Println(mock.Request().URLStruct.String()) + } + + client := initTestClient() + repos, err := client.ListReposByAuthor(context.Background(), resourceType, author) + assert.Nil(t, err) + assert.NotNil(t, repos) + assert.Equal(t, 2, len(repos)) + // count of repos with private flag + countOfPrivateRepos := 0 + for _, repo := range repos { + if repo.IsPrivate { + countOfPrivateRepos++ + } + } + assert.Equal(t, 1, countOfPrivateRepos) + // there is no author field in JSON, so assert repo.Owner is empty + for _, repo := range repos { + assert.Equal(t, "", repo.Owner) + } + assert.False(t, gock.HasUnmatchedRequest()) + assert.True(t, gock.IsDone()) +} + +func TestListReposByAuthor_NotFound(t *testing.T) { + resourceType := MODEL + author := "authordoesntexist" + + defer gock.Off() + + gock.New("https://huggingface.co"). + Get(fmt.Sprintf("/%s/%s", APIRoute, getResourceAPIPath(resourceType))). + MatchParam("author", author). + MatchParam("limit", "1000"). + MatchHeader("Authorization", "Bearer "+TEST_TOKEN). + Reply(404). + JSON([]map[string]interface{}{}) + + client := initTestClient() + repos, err := client.ListReposByAuthor(context.Background(), resourceType, author) + + assert.Nil(t, err) + assert.NotNil(t, repos) + assert.Equal(t, 0, len(repos)) + assert.False(t, gock.HasUnmatchedRequest()) + assert.True(t, gock.IsDone()) +} + +func TestListReposByAuthor_Error(t *testing.T) { + resourceType := MODEL + author := "doesnotexist" + + defer gock.Off() + + gock.New("https://huggingface.co"). + Get(fmt.Sprintf("/%s/%s", APIRoute, getResourceAPIPath(resourceType))). + MatchParam("author", author). + MatchParam("limit", "1000"). + MatchHeader("Authorization", "Bearer "+TEST_TOKEN). + Reply(500) + + client := initTestClient() + repos, err := client.ListReposByAuthor(context.Background(), resourceType, author) + assert.NotNil(t, err) + assert.Nil(t, repos) + assert.False(t, gock.HasUnmatchedRequest()) + assert.True(t, gock.IsDone()) +} + +func TestGetResourceAPIPath(t *testing.T) { + assert.Equal(t, "models", getResourceAPIPath(MODEL)) + assert.Equal(t, "datasets", getResourceAPIPath(DATASET)) + assert.Equal(t, "spaces", getResourceAPIPath(SPACE)) +} + +func TestGetResourceHTMLPath(t *testing.T) { + assert.Equal(t, "", getResourceHTMLPath(MODEL)) + assert.Equal(t, "datasets", getResourceHTMLPath(DATASET)) + assert.Equal(t, "spaces", getResourceHTMLPath(SPACE)) +} + +func TestBuildAPIURL_ValidInputs(t *testing.T) { + endpoint := "https://huggingface.co" + resourceType := MODEL + repoName := "test-repo" + + expectedURL := "https://huggingface.co/api/models/test-repo" + + url, err := buildAPIURL(endpoint, resourceType, repoName) + + assert.Nil(t, err) + assert.Equal(t, expectedURL, url) +} + +func TestBuildAPIURL_EmptyEndpoint(t *testing.T) { + endpoint := "" + resourceType := MODEL + repoName := "test-repo" + + url, err := buildAPIURL(endpoint, resourceType, repoName) + + assert.NotNil(t, err) + assert.Equal(t, "", url) + assert.Equal(t, "endpoint, resourceType, and repoName must not be empty", err.Error()) +} + +func TestBuildAPIURL_EmptyResourceType(t *testing.T) { + endpoint := "https://huggingface.co" + resourceType := "" + repoName := "test-repo" + + url, err := buildAPIURL(endpoint, resourceType, repoName) + + assert.NotNil(t, err) + assert.Equal(t, "", url) + assert.Equal(t, "endpoint, resourceType, and repoName must not be empty", err.Error()) +} + +func TestBuildAPIURL_EmptyRepoName(t *testing.T) { + endpoint := "https://huggingface.co" + resourceType := "model" + repoName := "" + + url, err := buildAPIURL(endpoint, resourceType, repoName) + + assert.NotNil(t, err) + assert.Equal(t, "", url) + assert.Equal(t, "endpoint, resourceType, and repoName must not be empty", err.Error()) +} + +func TestGetDiscussionPath_ModelResource(t *testing.T) { + discussion := Discussion{ + Repo: RepoData{ + FullName: "test-author/test-model", + ResourceType: "model", + }, + ID: 1, + } + + expectedPath := "test-author/test-model/discussions/1" + + path := discussion.GetDiscussionPath() + assert.Equal(t, expectedPath, path) +} + +func TestGetDiscussionPath_DatasetResource(t *testing.T) { + discussion := Discussion{ + Repo: RepoData{ + FullName: "test-author/test-dataset", + ResourceType: "dataset", + }, + ID: 1, + } + + expectedPath := "datasets/test-author/test-dataset/discussions/1" + + path := discussion.GetDiscussionPath() + assert.Equal(t, expectedPath, path) +} + +func TestGetDiscussionPath_SpaceResource(t *testing.T) { + discussion := Discussion{ + Repo: RepoData{ + FullName: "test-author/test-space", + ResourceType: "space", + }, + ID: 1, + } + + expectedPath := "spaces/test-author/test-space/discussions/1" + + path := discussion.GetDiscussionPath() + assert.Equal(t, expectedPath, path) +} + +func TestGetGitPath_ModelResource(t *testing.T) { + discussion := Discussion{ + Repo: RepoData{ + FullName: "test-author/test-model", + ResourceType: "model", + }, + ID: 1, + } + + expectedPath := "test-author/test-model.git" + + path := discussion.GetGitPath() + assert.Equal(t, expectedPath, path) +} + +func TestGetGitPath_DatasetResource(t *testing.T) { + discussion := Discussion{ + Repo: RepoData{ + FullName: "test-author/test-dataset", + ResourceType: "dataset", + }, + ID: 1, + } + + expectedPath := "datasets/test-author/test-dataset.git" + + path := discussion.GetGitPath() + assert.Equal(t, expectedPath, path) +} + +func TestGetGitPath_SpaceResource(t *testing.T) { + discussion := Discussion{ + Repo: RepoData{ + FullName: "test-author/test-space", + ResourceType: "space", + }, + ID: 1, + } + + expectedPath := "spaces/test-author/test-space.git" + + path := discussion.GetGitPath() + assert.Equal(t, expectedPath, path) +} diff --git a/pkg/sources/huggingface/huggingface_test.go b/pkg/sources/huggingface/huggingface_test.go new file mode 100644 index 000000000..2e12dc94f --- /dev/null +++ b/pkg/sources/huggingface/huggingface_test.go @@ -0,0 +1,986 @@ +package huggingface + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/trufflesecurity/trufflehog/v3/pkg/context" + "github.com/trufflesecurity/trufflehog/v3/pkg/pb/source_metadatapb" + "github.com/trufflesecurity/trufflehog/v3/pkg/pb/sourcespb" + "google.golang.org/protobuf/types/known/anypb" + "gopkg.in/h2non/gock.v1" +) + +func createTestSource(src *sourcespb.Huggingface) (*Source, *anypb.Any) { + s := &Source{} + conn, err := anypb.New(src) + if err != nil { + panic(err) + } + return s, conn +} + +// test include exclude ignore/include orgs, users + +func TestInit(t *testing.T) { + s, conn := createTestSource(&sourcespb.Huggingface{ + Endpoint: "https://huggingface.co", + Credential: &sourcespb.Huggingface_Token{ + Token: "super secret token", + }, + Models: []string{"user/model1", "user/model2", "user/ignorethismodel"}, + IgnoreModels: []string{"user/ignorethismodel"}, + Spaces: []string{"user/space1", "user/space2", "user/ignorethisspace"}, + IgnoreSpaces: []string{"user/ignorethisspace"}, + Datasets: []string{"user/dataset1", "user/dataset2", "user/ignorethisdataset"}, + IgnoreDatasets: []string{"user/ignorethisdataset"}, + Organizations: []string{"org1", "org2"}, + Users: []string{"user1", "user2"}, + }) + err := s.Init(context.Background(), "test - huggingface", 0, 1337, false, conn, 1) + assert.Nil(t, err) + + assert.ElementsMatch(t, []string{"user/model1", "user/model2"}, s.models) + for _, model := range s.models { + modelURL, _ := s.filteredModelsCache.Get(model) + assert.Equal(t, modelURL, s.conn.Endpoint+"/"+model+".git") + } + + assert.ElementsMatch(t, []string{"user/space1", "user/space2"}, s.spaces) + for _, space := range s.spaces { + spaceURL, _ := s.filteredSpacesCache.Get(space) + assert.Equal(t, spaceURL, s.conn.Endpoint+"/"+getResourceHTMLPath(SPACE)+"/"+space+".git") + } + + assert.ElementsMatch(t, []string{"user/dataset1", "user/dataset2"}, s.datasets) + for _, dataset := range s.datasets { + datasetURL, _ := s.filteredDatasetsCache.Get(dataset) + assert.Equal(t, datasetURL, s.conn.Endpoint+"/"+getResourceHTMLPath(DATASET)+"/"+dataset+".git") + } + + assert.ElementsMatch(t, s.conn.Organizations, s.orgsCache.Keys()) + assert.ElementsMatch(t, s.conn.Users, s.usersCache.Keys()) +} + +func TestGetResourceType(t *testing.T) { + repo := "author/model1" + s, conn := createTestSource(&sourcespb.Huggingface{ + Endpoint: "https://huggingface.co", + Credential: &sourcespb.Huggingface_Token{ + Token: "super secret token", + }, + Models: []string{repo}, + }) + err := s.Init(context.Background(), "test - huggingface", 0, 1337, false, conn, 1) + assert.Nil(t, err) + + defer gock.Off() + + // mock the request to the huggingface api + gock.New("https://huggingface.co"). + Get("/api/models/author/model1"). + Reply(200). + JSON(map[string]interface{}{ + "id": "author/model1", + "author": "author", + "private": true, + }) + + err = s.enumerate(context.Background()) + assert.Nil(t, err) + assert.Equal(t, MODEL, s.getResourceType(context.Background(), (s.conn.Endpoint+"/"+repo+".git"))) +} + +func TestVisibilityOf(t *testing.T) { + repo := "author/model1" + s, conn := createTestSource(&sourcespb.Huggingface{ + Endpoint: "https://huggingface.co", + Credential: &sourcespb.Huggingface_Token{ + Token: "super secret token", + }, + Models: []string{repo}, + }) + err := s.Init(context.Background(), "test - huggingface", 0, 1337, false, conn, 1) + assert.Nil(t, err) + + defer gock.Off() + + // mock the request to the huggingface api + gock.New("https://huggingface.co"). + Get("/api/models/author/model1"). + Reply(200). + JSON(map[string]interface{}{ + "id": "author/model1", + "author": "author", + "private": true, + }) + + err = s.enumerate(context.Background()) + assert.Nil(t, err) + assert.Equal(t, source_metadatapb.Visibility(1), s.visibilityOf(context.Background(), (s.conn.Endpoint+"/"+repo+".git"))) +} + +func TestEnumerate(t *testing.T) { + s, conn := createTestSource(&sourcespb.Huggingface{ + Endpoint: "https://huggingface.co", + Credential: &sourcespb.Huggingface_Token{ + Token: "super secret token", + }, + Models: []string{"author/model1"}, + Datasets: []string{"author/dataset1"}, + Spaces: []string{"author/space1"}, + }) + + err := s.Init(context.Background(), "test - huggingface", 0, 1337, false, conn, 1) + assert.Nil(t, err) + + defer gock.Off() + + // mock the request to the huggingface api + gock.New("https://huggingface.co"). + Get("/api/models/author/model1"). + Reply(200). + JSON(map[string]interface{}{ + "id": "author/model1", + "author": "author", + "private": true, + }) + + gock.New("https://huggingface.co"). + Get("/api/datasets/author/dataset1"). + Reply(200). + JSON(map[string]interface{}{ + "id": "author/dataset1", + "author": "author", + "private": false, + }) + + gock.New("https://huggingface.co"). + Get("/api/spaces/author/space1"). + Reply(200). + JSON(map[string]interface{}{ + "id": "author/space1", + "author": "author", + "private": false, + }) + + err = s.enumerate(context.Background()) + assert.Nil(t, err) + + modelGitURL := "https://huggingface.co/author/model1.git" + datasetGitURL := "https://huggingface.co/datasets/author/dataset1.git" + spaceGitURL := "https://huggingface.co/spaces/author/space1.git" + + assert.Equal(t, []string{modelGitURL}, s.models) + assert.Equal(t, []string{datasetGitURL}, s.datasets) + assert.Equal(t, []string{spaceGitURL}, s.spaces) + + r, _ := s.repoInfoCache.get(modelGitURL) + assert.Equal(t, r, repoInfo{ + visibility: source_metadatapb.Visibility_private, + resourceType: MODEL, + owner: "author", + name: "model1", + fullName: "author/model1", + }) + + r, _ = s.repoInfoCache.get(datasetGitURL) + assert.Equal(t, r, repoInfo{ + visibility: source_metadatapb.Visibility_public, + resourceType: DATASET, + owner: "author", + name: "dataset1", + fullName: "author/dataset1", + }) + + r, _ = s.repoInfoCache.get(spaceGitURL) + assert.Equal(t, r, repoInfo{ + visibility: source_metadatapb.Visibility_public, + resourceType: SPACE, + owner: "author", + name: "space1", + fullName: "author/space1", + }) + +} + +func TestUpdateRepoList(t *testing.T) { + s, conn := createTestSource(&sourcespb.Huggingface{ + Endpoint: "https://huggingface.co", + Credential: &sourcespb.Huggingface_Token{ + Token: "super secret token", + }, + }) + + err := s.Init(context.Background(), "test - huggingface", 0, 1337, false, conn, 1) + assert.Nil(t, err) + + modelGitURL := "https://huggingface.co/author/model1.git" + datasetGitURL := "https://huggingface.co/datasets/author/dataset1.git" + spaceGitURL := "https://huggingface.co/spaces/author/space1.git" + + s.updateRepoLists(modelGitURL, MODEL) + s.updateRepoLists(datasetGitURL, DATASET) + s.updateRepoLists(spaceGitURL, SPACE) + + assert.Equal(t, []string{modelGitURL}, s.models) + assert.Equal(t, []string{datasetGitURL}, s.datasets) + assert.Equal(t, []string{spaceGitURL}, s.spaces) +} + +func TestGetReposListByType(t *testing.T) { + s, conn := createTestSource(&sourcespb.Huggingface{ + Endpoint: "https://huggingface.co", + Credential: &sourcespb.Huggingface_Token{ + Token: "super secret token", + }, + Models: []string{"author/model1", "author/model2"}, + Datasets: []string{"author/dataset1", "author/dataset2"}, + Spaces: []string{"author/space1", "author/space2"}, + }) + + err := s.Init(context.Background(), "test - huggingface", 0, 1337, false, conn, 1) + assert.Nil(t, err) + + assert.Equal(t, s.getReposListByType(MODEL), s.models) + assert.Equal(t, s.getReposListByType(DATASET), s.datasets) + assert.Equal(t, s.getReposListByType(SPACE), s.spaces) +} + +func TestGetVisibility(t *testing.T) { + assert.Equal(t, source_metadatapb.Visibility(1), getVisibility(true)) + assert.Equal(t, source_metadatapb.Visibility(0), getVisibility(false)) +} + +func TestEnumerateAuthorsOrg(t *testing.T) { + s, conn := createTestSource(&sourcespb.Huggingface{ + Endpoint: "https://huggingface.co", + Credential: &sourcespb.Huggingface_Token{ + Token: "super secret token", + }, + Organizations: []string{"org"}, + }) + + err := s.Init(context.Background(), "test - huggingface", 0, 1337, false, conn, 1) + assert.Nil(t, err) + + defer gock.Off() + + // mock the request to the huggingface api + gock.New("https://huggingface.co"). + Get(fmt.Sprintf("/%s/%s", APIRoute, getResourceAPIPath(MODEL))). + MatchParam("author", "org"). + MatchParam("limit", "1000"). + Reply(200). + JSON([]map[string]interface{}{ + { + "_id": "1", + "id": "org/model", + "modelId": "org/model", + "private": true, + }, + }) + + gock.New("https://huggingface.co"). + Get("/api/models/org/model"). + Reply(200). + JSON(map[string]interface{}{ + "id": "org/model", + "author": "org", + "private": true, + }) + + gock.New("https://huggingface.co"). + Get(fmt.Sprintf("/%s/%s", APIRoute, getResourceAPIPath(DATASET))). + MatchParam("author", "org"). + MatchParam("limit", "1000"). + Reply(200). + JSON([]map[string]interface{}{ + { + "_id": "3", + "id": "org/dataset", + "modelId": "org/dataset", + "private": true, + }, + }) + + gock.New("https://huggingface.co"). + Get("/api/datasets/org/dataset"). + Reply(200). + JSON(map[string]interface{}{ + "id": "org/dataset", + "author": "org", + "private": true, + }) + + gock.New("https://huggingface.co"). + Get(fmt.Sprintf("/%s/%s", APIRoute, getResourceAPIPath(SPACE))). + MatchParam("author", "org"). + MatchParam("limit", "1000"). + Reply(200). + JSON([]map[string]interface{}{ + { + "_id": "5", + "id": "org/space", + "modelId": "org/space", + "private": true, + }, + }) + + gock.New("https://huggingface.co"). + Get("/api/spaces/org/space"). + Reply(200). + JSON(map[string]interface{}{ + "id": "org/space", + "author": "org", + "private": true, + }) + + err = s.enumerate(context.Background()) + assert.Nil(t, err) + + modelGitURL := "https://huggingface.co/org/model.git" + datasetGitURL := "https://huggingface.co/datasets/org/dataset.git" + spaceGitURL := "https://huggingface.co/spaces/org/space.git" + + assert.Equal(t, []string{modelGitURL}, s.models) + assert.Equal(t, []string{datasetGitURL}, s.datasets) + assert.Equal(t, []string{spaceGitURL}, s.spaces) + + r, _ := s.repoInfoCache.get(modelGitURL) + assert.Equal(t, r, repoInfo{ + visibility: source_metadatapb.Visibility_private, + resourceType: MODEL, + owner: "org", + name: "model", + fullName: "org/model", + }) + + r, _ = s.repoInfoCache.get(datasetGitURL) + assert.Equal(t, r, repoInfo{ + visibility: source_metadatapb.Visibility_private, + resourceType: DATASET, + owner: "org", + name: "dataset", + fullName: "org/dataset", + }) + + r, _ = s.repoInfoCache.get(spaceGitURL) + assert.Equal(t, r, repoInfo{ + visibility: source_metadatapb.Visibility_private, + resourceType: SPACE, + owner: "org", + name: "space", + fullName: "org/space", + }) +} + +func TestEnumerateAuthorsOrgSkipAll(t *testing.T) { + s, conn := createTestSource(&sourcespb.Huggingface{ + Endpoint: "https://huggingface.co", + Credential: &sourcespb.Huggingface_Token{ + Token: "super secret token", + }, + Organizations: []string{"org"}, + SkipAllModels: true, + SkipAllDatasets: true, + SkipAllSpaces: true, + }) + + err := s.Init(context.Background(), "test - huggingface", 0, 1337, false, conn, 1) + assert.Nil(t, err) + + defer gock.Off() + + // mock the request to the huggingface api + gock.New("https://huggingface.co"). + Get(fmt.Sprintf("/%s/%s", APIRoute, getResourceAPIPath(MODEL))). + MatchParam("author", "org"). + MatchParam("limit", "1000"). + Reply(200). + JSON([]map[string]interface{}{ + { + "_id": "1", + "id": "org/model", + "modelId": "org/model", + "private": true, + }, + }) + + gock.New("https://huggingface.co"). + Get("/api/models/org/model"). + Reply(200). + JSON(map[string]interface{}{ + "id": "org/model", + "author": "org", + "private": true, + }) + + gock.New("https://huggingface.co"). + Get(fmt.Sprintf("/%s/%s", APIRoute, getResourceAPIPath(DATASET))). + MatchParam("author", "org"). + MatchParam("limit", "1000"). + Reply(200). + JSON([]map[string]interface{}{ + { + "_id": "3", + "id": "org/dataset", + "modelId": "org/dataset", + "private": true, + }, + }) + + gock.New("https://huggingface.co"). + Get("/api/datasets/org/dataset"). + Reply(200). + JSON(map[string]interface{}{ + "id": "org/dataset", + "author": "org", + "private": true, + }) + + gock.New("https://huggingface.co"). + Get(fmt.Sprintf("/%s/%s", APIRoute, getResourceAPIPath(SPACE))). + MatchParam("author", "org"). + MatchParam("limit", "1000"). + Reply(200). + JSON([]map[string]interface{}{ + { + "_id": "5", + "id": "org/space", + "modelId": "org/space", + "private": true, + }, + }) + + gock.New("https://huggingface.co"). + Get("/api/spaces/org/space"). + Reply(200). + JSON(map[string]interface{}{ + "id": "org/space", + "author": "org", + "private": true, + }) + + err = s.enumerate(context.Background()) + assert.Nil(t, err) + + modelGitURL := "https://huggingface.co/org/model.git" + datasetGitURL := "https://huggingface.co/datasets/org/dataset.git" + spaceGitURL := "https://huggingface.co/spaces/org/space.git" + + assert.Equal(t, []string{}, s.models) + assert.Equal(t, []string{}, s.datasets) + assert.Equal(t, []string{}, s.spaces) + + r, _ := s.repoInfoCache.get(modelGitURL) + assert.Equal(t, r, repoInfo{}) + + r, _ = s.repoInfoCache.get(datasetGitURL) + assert.Equal(t, r, repoInfo{}) + + r, _ = s.repoInfoCache.get(spaceGitURL) + assert.Equal(t, r, repoInfo{}) +} + +func TestEnumerateAuthorsOrgIgnores(t *testing.T) { + s, conn := createTestSource(&sourcespb.Huggingface{ + Endpoint: "https://huggingface.co", + Credential: &sourcespb.Huggingface_Token{ + Token: "super secret token", + }, + Organizations: []string{"org"}, + IgnoreModels: []string{"org/model"}, + IgnoreDatasets: []string{"org/dataset"}, + IgnoreSpaces: []string{"org/space"}, + }) + + err := s.Init(context.Background(), "test - huggingface", 0, 1337, false, conn, 1) + assert.Nil(t, err) + + defer gock.Off() + + // mock the request to the huggingface api + gock.New("https://huggingface.co"). + Get(fmt.Sprintf("/%s/%s", APIRoute, getResourceAPIPath(MODEL))). + MatchParam("author", "org"). + MatchParam("limit", "1000"). + Reply(200). + JSON([]map[string]interface{}{ + { + "_id": "1", + "id": "org/model", + "modelId": "org/model", + "private": true, + }, + }) + + gock.New("https://huggingface.co"). + Get("/api/models/org/model"). + Reply(200). + JSON(map[string]interface{}{ + "id": "org/model", + "author": "org", + "private": true, + }) + + gock.New("https://huggingface.co"). + Get(fmt.Sprintf("/%s/%s", APIRoute, getResourceAPIPath(DATASET))). + MatchParam("author", "org"). + MatchParam("limit", "1000"). + Reply(200). + JSON([]map[string]interface{}{ + { + "_id": "3", + "id": "org/dataset", + "modelId": "org/dataset", + "private": true, + }, + }) + + gock.New("https://huggingface.co"). + Get("/api/datasets/org/dataset"). + Reply(200). + JSON(map[string]interface{}{ + "id": "org/dataset", + "author": "org", + "private": true, + }) + + gock.New("https://huggingface.co"). + Get(fmt.Sprintf("/%s/%s", APIRoute, getResourceAPIPath(SPACE))). + MatchParam("author", "org"). + MatchParam("limit", "1000"). + Reply(200). + JSON([]map[string]interface{}{ + { + "_id": "5", + "id": "org/space", + "modelId": "org/space", + "private": true, + }, + }) + + gock.New("https://huggingface.co"). + Get("/api/spaces/org/space"). + Reply(200). + JSON(map[string]interface{}{ + "id": "org/space", + "author": "org", + "private": true, + }) + + err = s.enumerate(context.Background()) + assert.Nil(t, err) + + modelGitURL := "https://huggingface.co/org/model.git" + datasetGitURL := "https://huggingface.co/datasets/org/dataset.git" + spaceGitURL := "https://huggingface.co/spaces/org/space.git" + + assert.Equal(t, []string{}, s.models) + assert.Equal(t, []string{}, s.datasets) + assert.Equal(t, []string{}, s.spaces) + + r, _ := s.repoInfoCache.get(modelGitURL) + assert.Equal(t, r, repoInfo{}) + + r, _ = s.repoInfoCache.get(datasetGitURL) + assert.Equal(t, r, repoInfo{}) + + r, _ = s.repoInfoCache.get(spaceGitURL) + assert.Equal(t, r, repoInfo{}) +} + +func TestEnumerateAuthorsUser(t *testing.T) { + s, conn := createTestSource(&sourcespb.Huggingface{ + Endpoint: "https://huggingface.co", + Credential: &sourcespb.Huggingface_Token{ + Token: "super secret token", + }, + Users: []string{"user"}, + }) + + err := s.Init(context.Background(), "test - huggingface", 0, 1337, false, conn, 1) + assert.Nil(t, err) + + defer gock.Off() + + gock.New("https://huggingface.co"). + Get(fmt.Sprintf("/%s/%s", APIRoute, getResourceAPIPath(MODEL))). + MatchParam("author", "user"). + MatchParam("limit", "1000"). + Reply(200). + JSON([]map[string]interface{}{ + { + "_id": "2", + "id": "user/model", + "modelId": "user/model", + "private": false, + }, + }) + + gock.New("https://huggingface.co"). + Get("/api/models/user/model"). + Reply(200). + JSON(map[string]interface{}{ + "id": "user/model", + "author": "user", + "private": false, + }) + + gock.New("https://huggingface.co"). + Get(fmt.Sprintf("/%s/%s", APIRoute, getResourceAPIPath(DATASET))). + MatchParam("author", "user"). + MatchParam("limit", "1000"). + Reply(200). + JSON([]map[string]interface{}{ + { + "_id": "4", + "id": "user/dataset", + "modelId": "user/dataset", + "private": false, + }, + }) + + gock.New("https://huggingface.co"). + Get("/api/datasets/user/dataset"). + Reply(200). + JSON(map[string]interface{}{ + "id": "user/dataset", + "author": "user", + "private": false, + }) + + gock.New("https://huggingface.co"). + Get(fmt.Sprintf("/%s/%s", APIRoute, getResourceAPIPath(SPACE))). + MatchParam("author", "user"). + MatchParam("limit", "1000"). + Reply(200). + JSON([]map[string]interface{}{ + { + "_id": "6", + "id": "user/space", + "modelId": "user/space", + "private": false, + }, + }) + + gock.New("https://huggingface.co"). + Get("/api/spaces/user/space"). + Reply(200). + JSON(map[string]interface{}{ + "id": "user/space", + "author": "user", + "private": false, + }) + + err = s.enumerate(context.Background()) + assert.Nil(t, err) + + modelGitURL := "https://huggingface.co/user/model.git" + datasetGitURL := "https://huggingface.co/datasets/user/dataset.git" + spaceGitURL := "https://huggingface.co/spaces/user/space.git" + + assert.Equal(t, []string{modelGitURL}, s.models) + assert.Equal(t, []string{datasetGitURL}, s.datasets) + assert.Equal(t, []string{spaceGitURL}, s.spaces) + + r, _ := s.repoInfoCache.get(modelGitURL) + assert.Equal(t, r, repoInfo{ + visibility: source_metadatapb.Visibility_public, + resourceType: MODEL, + owner: "user", + name: "model", + fullName: "user/model", + }) + + r, _ = s.repoInfoCache.get(datasetGitURL) + assert.Equal(t, r, repoInfo{ + visibility: source_metadatapb.Visibility_public, + resourceType: DATASET, + owner: "user", + name: "dataset", + fullName: "user/dataset", + }) + + r, _ = s.repoInfoCache.get(spaceGitURL) + assert.Equal(t, r, repoInfo{ + visibility: source_metadatapb.Visibility_public, + resourceType: SPACE, + owner: "user", + name: "space", + fullName: "user/space", + }) +} + +func TestEnumerateAuthorsUserSkipAll(t *testing.T) { + s, conn := createTestSource(&sourcespb.Huggingface{ + Endpoint: "https://huggingface.co", + Credential: &sourcespb.Huggingface_Token{ + Token: "super secret token", + }, + Users: []string{"user"}, + SkipAllModels: true, + SkipAllDatasets: true, + SkipAllSpaces: true, + }) + + err := s.Init(context.Background(), "test - huggingface", 0, 1337, false, conn, 1) + assert.Nil(t, err) + + defer gock.Off() + + gock.New("https://huggingface.co"). + Get(fmt.Sprintf("/%s/%s", APIRoute, getResourceAPIPath(MODEL))). + MatchParam("author", "user"). + MatchParam("limit", "1000"). + Reply(200). + JSON([]map[string]interface{}{ + { + "_id": "2", + "id": "user/model", + "modelId": "user/model", + "private": false, + }, + }) + + gock.New("https://huggingface.co"). + Get("/api/models/user/model"). + Reply(200). + JSON(map[string]interface{}{ + "id": "user/model", + "author": "user", + "private": false, + }) + + gock.New("https://huggingface.co"). + Get(fmt.Sprintf("/%s/%s", APIRoute, getResourceAPIPath(DATASET))). + MatchParam("author", "user"). + MatchParam("limit", "1000"). + Reply(200). + JSON([]map[string]interface{}{ + { + "_id": "4", + "id": "user/dataset", + "modelId": "user/dataset", + "private": false, + }, + }) + + gock.New("https://huggingface.co"). + Get("/api/datasets/user/dataset"). + Reply(200). + JSON(map[string]interface{}{ + "id": "user/dataset", + "author": "user", + "private": false, + }) + + gock.New("https://huggingface.co"). + Get(fmt.Sprintf("/%s/%s", APIRoute, getResourceAPIPath(SPACE))). + MatchParam("author", "user"). + MatchParam("limit", "1000"). + Reply(200). + JSON([]map[string]interface{}{ + { + "_id": "6", + "id": "user/space", + "modelId": "user/space", + "private": false, + }, + }) + + gock.New("https://huggingface.co"). + Get("/api/spaces/user/space"). + Reply(200). + JSON(map[string]interface{}{ + "id": "user/space", + "author": "user", + "private": false, + }) + + err = s.enumerate(context.Background()) + assert.Nil(t, err) + + modelGitURL := "https://huggingface.co/user/model.git" + datasetGitURL := "https://huggingface.co/datasets/user/dataset.git" + spaceGitURL := "https://huggingface.co/spaces/user/space.git" + + assert.Equal(t, []string{}, s.models) + assert.Equal(t, []string{}, s.datasets) + assert.Equal(t, []string{}, s.spaces) + + r, _ := s.repoInfoCache.get(modelGitURL) + assert.Equal(t, r, repoInfo{}) + + r, _ = s.repoInfoCache.get(datasetGitURL) + assert.Equal(t, r, repoInfo{}) + + r, _ = s.repoInfoCache.get(spaceGitURL) + assert.Equal(t, r, repoInfo{}) +} + +func TestEnumerateAuthorsUserIgnores(t *testing.T) { + s, conn := createTestSource(&sourcespb.Huggingface{ + Endpoint: "https://huggingface.co", + Credential: &sourcespb.Huggingface_Token{ + Token: "super secret token", + }, + Users: []string{"user"}, + IgnoreModels: []string{"user/model"}, + IgnoreDatasets: []string{"user/dataset"}, + IgnoreSpaces: []string{"user/space"}, + }) + + err := s.Init(context.Background(), "test - huggingface", 0, 1337, false, conn, 1) + assert.Nil(t, err) + + defer gock.Off() + + gock.New("https://huggingface.co"). + Get(fmt.Sprintf("/%s/%s", APIRoute, getResourceAPIPath(MODEL))). + MatchParam("author", "user"). + MatchParam("limit", "1000"). + Reply(200). + JSON([]map[string]interface{}{ + { + "_id": "2", + "id": "user/model", + "modelId": "user/model", + "private": false, + }, + }) + + gock.New("https://huggingface.co"). + Get("/api/models/user/model"). + Reply(200). + JSON(map[string]interface{}{ + "id": "user/model", + "author": "user", + "private": false, + }) + + gock.New("https://huggingface.co"). + Get(fmt.Sprintf("/%s/%s", APIRoute, getResourceAPIPath(DATASET))). + MatchParam("author", "user"). + MatchParam("limit", "1000"). + Reply(200). + JSON([]map[string]interface{}{ + { + "_id": "4", + "id": "user/dataset", + "modelId": "user/dataset", + "private": false, + }, + }) + + gock.New("https://huggingface.co"). + Get("/api/datasets/user/dataset"). + Reply(200). + JSON(map[string]interface{}{ + "id": "user/dataset", + "author": "user", + "private": false, + }) + + gock.New("https://huggingface.co"). + Get(fmt.Sprintf("/%s/%s", APIRoute, getResourceAPIPath(SPACE))). + MatchParam("author", "user"). + MatchParam("limit", "1000"). + Reply(200). + JSON([]map[string]interface{}{ + { + "_id": "6", + "id": "user/space", + "modelId": "user/space", + "private": false, + }, + }) + + gock.New("https://huggingface.co"). + Get("/api/spaces/user/space"). + Reply(200). + JSON(map[string]interface{}{ + "id": "user/space", + "author": "user", + "private": false, + }) + + err = s.enumerate(context.Background()) + assert.Nil(t, err) + + modelGitURL := "https://huggingface.co/user/model.git" + datasetGitURL := "https://huggingface.co/datasets/user/dataset.git" + spaceGitURL := "https://huggingface.co/spaces/user/space.git" + + assert.Equal(t, []string{}, s.models) + assert.Equal(t, []string{}, s.datasets) + assert.Equal(t, []string{}, s.spaces) + + r, _ := s.repoInfoCache.get(modelGitURL) + assert.Equal(t, r, repoInfo{}) + + r, _ = s.repoInfoCache.get(datasetGitURL) + assert.Equal(t, r, repoInfo{}) + + r, _ = s.repoInfoCache.get(spaceGitURL) + assert.Equal(t, r, repoInfo{}) +} + +func TestVerifySlashSeparatedStrings(t *testing.T) { + assert.Error(t, verifySlashSeparatedStrings([]string{"orgmodel"})) + assert.NoError(t, verifySlashSeparatedStrings([]string{"org/model"})) + assert.Error(t, verifySlashSeparatedStrings([]string{"org/model", "orgmodel2"})) + assert.NoError(t, verifySlashSeparatedStrings([]string{"org/model", "org/model2"})) +} + +func TestValidateIgnoreIncludeReposRepos(t *testing.T) { + s, conn := createTestSource(&sourcespb.Huggingface{ + Endpoint: "https://huggingface.co", + Credential: &sourcespb.Huggingface_Token{ + Token: "super secret token", + }, + Organizations: []string{"org"}, + IgnoreModels: []string{"orgmodel1"}, + IgnoreDatasets: []string{"org/dataset1"}, + IgnoreSpaces: []string{"org/space1"}, + }) + + err := s.Init(context.Background(), "test - huggingface", 0, 1337, false, conn, 1) + assert.NotNil(t, err) +} + +func TestValidateIgnoreIncludeReposDatasets(t *testing.T) { + s, conn := createTestSource(&sourcespb.Huggingface{ + Endpoint: "https://huggingface.co", + Credential: &sourcespb.Huggingface_Token{ + Token: "super secret token", + }, + Organizations: []string{"org"}, + IgnoreModels: []string{"org/model1"}, + IgnoreDatasets: []string{"orgdataset1"}, + IgnoreSpaces: []string{"org/space1"}, + }) + + err := s.Init(context.Background(), "test - huggingface", 0, 1337, false, conn, 1) + assert.NotNil(t, err) +} + +func TestValidateIgnoreIncludeReposSpaces(t *testing.T) { + s, conn := createTestSource(&sourcespb.Huggingface{ + Endpoint: "https://huggingface.co", + Credential: &sourcespb.Huggingface_Token{ + Token: "super secret token", + }, + Organizations: []string{"org"}, + IgnoreModels: []string{"org/model1"}, + IgnoreDatasets: []string{"org/dataset1"}, + IgnoreSpaces: []string{"orgspace1"}, + }) + + err := s.Init(context.Background(), "test - huggingface", 0, 1337, false, conn, 1) + assert.NotNil(t, err) +} + +// repeat this with all skip flags, and then include/ignore flags diff --git a/pkg/sources/huggingface/repo.go b/pkg/sources/huggingface/repo.go new file mode 100644 index 000000000..38778dd41 --- /dev/null +++ b/pkg/sources/huggingface/repo.go @@ -0,0 +1,72 @@ +package huggingface + +import ( + "fmt" + "sync" + + gogit "github.com/go-git/go-git/v5" + "github.com/trufflesecurity/trufflehog/v3/pkg/context" + "github.com/trufflesecurity/trufflehog/v3/pkg/pb/source_metadatapb" + "github.com/trufflesecurity/trufflehog/v3/pkg/pb/sourcespb" + "github.com/trufflesecurity/trufflehog/v3/pkg/sources/git" +) + +type repoInfoCache struct { + mu sync.RWMutex + cache map[string]repoInfo +} + +func newRepoInfoCache() repoInfoCache { + return repoInfoCache{ + cache: make(map[string]repoInfo), + } +} + +func (r *repoInfoCache) put(repoURL string, info repoInfo) { + r.mu.Lock() + defer r.mu.Unlock() + r.cache[repoURL] = info +} + +func (r *repoInfoCache) get(repoURL string) (repoInfo, bool) { + r.mu.RLock() + defer r.mu.RUnlock() + + info, ok := r.cache[repoURL] + return info, ok +} + +type repoInfo struct { + owner string + name string + fullName string + visibility source_metadatapb.Visibility + resourceType resourceType +} + +func (s *Source) cloneRepo( + ctx context.Context, + repoURL string, +) (string, *gogit.Repository, error) { + var ( + path string + repo *gogit.Repository + err error + ) + + switch s.conn.GetCredential().(type) { + case *sourcespb.Huggingface_Unauthenticated: + path, repo, err = git.CloneRepoUsingUnauthenticated(ctx, repoURL) + if err != nil { + return "", nil, err + } + case *sourcespb.Huggingface_Token: + path, repo, err = git.CloneRepoUsingToken(ctx, s.huggingfaceToken, repoURL, "") + if err != nil { + return "", nil, err + } + default: + return "", nil, fmt.Errorf("unhandled credential type for repo %s: %T", repoURL, s.conn.GetCredential()) + } + return path, repo, nil +} diff --git a/proto/source_metadata.proto b/proto/source_metadata.proto index 5897cc902..a29739567 100644 --- a/proto/source_metadata.proto +++ b/proto/source_metadata.proto @@ -136,6 +136,19 @@ message GCS { string content_type = 8; } +message Huggingface { + string link = 1; + string username = 2; + string repository = 3; + string commit = 4; + string email = 5; + string file = 6; + string timestamp = 7; + int64 line = 8; + Visibility visibility = 9; + string resource_type = 10; +} + message Jira { string issue = 1; string author = 2; @@ -351,5 +364,6 @@ message MetaData { Postman postman = 29; Webhook webhook = 30; Elasticsearch elasticsearch = 31; + Huggingface huggingface = 32; } } diff --git a/proto/sources.proto b/proto/sources.proto index 7a3e0bdd4..ec0f0209a 100644 --- a/proto/sources.proto +++ b/proto/sources.proto @@ -48,6 +48,7 @@ enum SourceType { SOURCE_TYPE_POSTMAN = 33; SOURCE_TYPE_WEBHOOK = 34; SOURCE_TYPE_ELASTICSEARCH = 35; + SOURCE_TYPE_HUGGINGFACE = 36; } message LocalSource { @@ -248,6 +249,30 @@ message GoogleDrive { } } +message Huggingface { + string endpoint = 1 [(validate.rules).string.uri_ref = true]; + oneof credential { + string token = 2; + credentials.Unauthenticated unauthenticated = 3; + } + repeated string models = 4; + repeated string spaces = 5; + repeated string datasets = 12; + repeated string organizations = 6; + repeated string users = 15; + repeated string ignore_models = 7; + repeated string include_models = 8; + repeated string ignore_spaces = 9; + repeated string include_spaces = 10; + repeated string ignore_datasets = 13; + repeated string include_datasets = 14; + bool skip_all_models = 16; + bool skip_all_spaces = 17; + bool skip_all_datasets = 18; + bool include_discussions = 11; + bool include_prs = 19; +} + message JIRA { string endpoint = 1 [(validate.rules).string.uri_ref = true]; oneof credential {