From c1ec92f630c0f5a7a4aa7f440058afaebfbbb9e3 Mon Sep 17 00:00:00 2001 From: Federico Loi Date: Wed, 18 Dec 2024 17:37:24 +0100 Subject: [PATCH 1/4] Implementation of DotNet deps.json and packages.config extractors --- docs/supported_inventory_types.md | 2 + .../language/dotnet/depsjson/depsjson.go | 188 +++++++++++++ .../language/dotnet/depsjson/depsjson_test.go | 264 ++++++++++++++++++ .../language/dotnet/depsjson/testdata/empty | 1 + .../language/dotnet/depsjson/testdata/invalid | 2 + .../language/dotnet/depsjson/testdata/valid | 65 +++++ .../dotnet/packagesconfig/packagesconfig.go | 180 ++++++++++++ .../packagesconfig/packagesconfig_test.go | 254 +++++++++++++++++ .../dotnet/packagesconfig/testdata/invalid | 2 + .../dotnet/packagesconfig/testdata/valid | 5 + extractor/filesystem/list/list.go | 8 +- 11 files changed, 970 insertions(+), 1 deletion(-) create mode 100644 extractor/filesystem/language/dotnet/depsjson/depsjson.go create mode 100644 extractor/filesystem/language/dotnet/depsjson/depsjson_test.go create mode 100644 extractor/filesystem/language/dotnet/depsjson/testdata/empty create mode 100644 extractor/filesystem/language/dotnet/depsjson/testdata/invalid create mode 100644 extractor/filesystem/language/dotnet/depsjson/testdata/valid create mode 100644 extractor/filesystem/language/dotnet/packagesconfig/packagesconfig.go create mode 100644 extractor/filesystem/language/dotnet/packagesconfig/packagesconfig_test.go create mode 100644 extractor/filesystem/language/dotnet/packagesconfig/testdata/invalid create mode 100644 extractor/filesystem/language/dotnet/packagesconfig/testdata/valid diff --git a/docs/supported_inventory_types.md b/docs/supported_inventory_types.md index 63bc8d2f..3d2636f1 100644 --- a/docs/supported_inventory_types.md +++ b/docs/supported_inventory_types.md @@ -25,6 +25,8 @@ SCALIBR supports extracting software package information from a variety of OS an * .NET * packages.lock.json + * packages.config + * deps.json * C++ * Conan packages * Dart diff --git a/extractor/filesystem/language/dotnet/depsjson/depsjson.go b/extractor/filesystem/language/dotnet/depsjson/depsjson.go new file mode 100644 index 00000000..beb433e2 --- /dev/null +++ b/extractor/filesystem/language/dotnet/depsjson/depsjson.go @@ -0,0 +1,188 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package depsjson extracts packages from .NET deps.json files. +package depsjson + +import ( + "context" + "encoding/json" + "path/filepath" + "strings" + + "github.com/google/osv-scalibr/extractor" + "github.com/google/osv-scalibr/extractor/filesystem" + "github.com/google/osv-scalibr/extractor/filesystem/internal/units" + "github.com/google/osv-scalibr/log" + "github.com/google/osv-scalibr/plugin" + "github.com/google/osv-scalibr/purl" + "github.com/google/osv-scalibr/stats" +) + +const ( + // Name is the unique name of this extractor. + Name = "dotnet/depsjson" + + // defaultMaxFileSizeBytes is the maximum file size this extractor will process. + defaultMaxFileSizeBytes = 10 * units.MiB // 10 MB +) + +// Config is the configuration for the deps.json extractor. +type Config struct { + // Stats is a stats collector for reporting metrics. + Stats stats.Collector + // MaxFileSizeBytes is the maximum file size this extractor will unmarshal. If + // `FileRequired` gets a bigger file, it will return false. + MaxFileSizeBytes int64 +} + +// DefaultConfig returns the default configuration for the deps.json extractor. +func DefaultConfig() Config { + return Config{ + MaxFileSizeBytes: defaultMaxFileSizeBytes, + } +} + +// Extractor structure for deps.json files. +type Extractor struct { + stats stats.Collector + maxFileSizeBytes int64 +} + +// New returns a deps.json extractor. +func New(cfg Config) *Extractor { + return &Extractor{ + stats: cfg.Stats, + maxFileSizeBytes: cfg.MaxFileSizeBytes, + } +} + +// Config returns the configuration of the extractor. +func (e Extractor) Config() Config { + return Config{ + Stats: e.stats, + MaxFileSizeBytes: e.maxFileSizeBytes, + } +} + +// Name of the extractor. +func (e Extractor) Name() string { return Name } + +// Version of the extractor. +func (e Extractor) Version() int { return 0 } + +// Requirements of the extractor. +func (e Extractor) Requirements() *plugin.Capabilities { return &plugin.Capabilities{} } + +// FileRequired returns true if the specified file matches the deps.json pattern. +func (e Extractor) FileRequired(api filesystem.FileAPI) bool { + path := api.Path() + if !strings.HasSuffix(filepath.Base(path), ".deps.json") { + return false + } + + fileinfo, err := api.Stat() + if err != nil || (e.maxFileSizeBytes > 0 && fileinfo.Size() > e.maxFileSizeBytes) { + e.reportFileRequired(path, stats.FileRequiredResultSizeLimitExceeded) + return false + } + + e.reportFileRequired(path, stats.FileRequiredResultOK) + return true +} + +func (e Extractor) reportFileRequired(path string, result stats.FileRequiredResult) { + if e.stats == nil { + return + } + e.stats.AfterFileRequired(e.Name(), &stats.FileRequiredStats{ + Path: path, + Result: result, + }) +} + +// Extract parses the deps.json file to extract .NET package dependencies. +func (e Extractor) Extract(ctx context.Context, input *filesystem.ScanInput) ([]*extractor.Inventory, error) { + packages, err := e.extractFromInput(ctx, input) + if e.stats != nil { + var fileSizeBytes int64 + if input.Info != nil { + fileSizeBytes = input.Info.Size() + } + e.stats.AfterFileExtracted(e.Name(), &stats.FileExtractedStats{ + Path: input.Path, + Result: filesystem.ExtractorErrorToFileExtractedResult(err), + FileSizeBytes: fileSizeBytes, + }) + } + return packages, err +} + +type DepsJSON struct { + Libraries map[string]struct { + Version string `json:"version"` + } `json:"libraries"` +} + +func (e Extractor) extractFromInput(ctx context.Context, input *filesystem.ScanInput) ([]*extractor.Inventory, error) { + var pkgs []*extractor.Inventory + + var deps DepsJSON + decoder := json.NewDecoder(input.Reader) + if err := decoder.Decode(&deps); err != nil { + log.Errorf("Error parsing deps.json: %v", err) + return nil, err + } + + for nameVersion := range deps.Libraries { + // Split name and version from "package/version" format + name, version := splitNameAndVersion(nameVersion) + if name == "" || version == "" { + log.Warnf("Skipping library with missing name or version: %s", nameVersion) + continue + } + + i := &extractor.Inventory{ + Name: name, + Version: version, + Locations: []string{input.Path}, + } + pkgs = append(pkgs, i) + } + + return pkgs, nil +} + +// splitNameAndVersion splits the name and version from a "package/version" string. +func splitNameAndVersion(nameVersion string) (string, string) { + parts := strings.Split(nameVersion, "/") + if len(parts) != 2 { + return "", "" + } + return parts[0], parts[1] +} + +// ToPURL converts an inventory created by this extractor into a PURL. +func (e Extractor) ToPURL(i *extractor.Inventory) *purl.PackageURL { + return &purl.PackageURL{ + Type: purl.TypeNuget, + Name: i.Name, + Version: i.Version, + } +} + +// Ecosystem returns the OSV Ecosystem of the software extracted by this extractor. +func (Extractor) Ecosystem(i *extractor.Inventory) string { + return "NuGet" +} diff --git a/extractor/filesystem/language/dotnet/depsjson/depsjson_test.go b/extractor/filesystem/language/dotnet/depsjson/depsjson_test.go new file mode 100644 index 00000000..dcd018a2 --- /dev/null +++ b/extractor/filesystem/language/dotnet/depsjson/depsjson_test.go @@ -0,0 +1,264 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package depsjson_test + +import ( + "context" + "io/fs" + "os" + "path/filepath" + "reflect" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "github.com/google/osv-scalibr/extractor" + "github.com/google/osv-scalibr/extractor/filesystem" + "github.com/google/osv-scalibr/extractor/filesystem/internal/units" + "github.com/google/osv-scalibr/extractor/filesystem/language/dotnet/depsjson" + "github.com/google/osv-scalibr/extractor/filesystem/simplefileapi" + scalibrfs "github.com/google/osv-scalibr/fs" + "github.com/google/osv-scalibr/purl" + "github.com/google/osv-scalibr/stats" + "github.com/google/osv-scalibr/testing/fakefs" + "github.com/google/osv-scalibr/testing/testcollector" +) + +func TestNew(t *testing.T) { + tests := []struct { + name string + cfg depsjson.Config + wantCfg depsjson.Config + }{ + { + name: "default", + cfg: depsjson.DefaultConfig(), + wantCfg: depsjson.Config{ + MaxFileSizeBytes: 10 * units.MiB, + }, + }, + { + name: "custom", + cfg: depsjson.Config{ + MaxFileSizeBytes: 10, + }, + wantCfg: depsjson.Config{ + MaxFileSizeBytes: 10, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := depsjson.New(tt.cfg) + if !reflect.DeepEqual(got.Config(), tt.wantCfg) { + t.Errorf("New(%+v).Config(): got %+v, want %+v", tt.cfg, got.Config(), tt.wantCfg) + } + }) + } +} + +func TestFileRequired(t *testing.T) { + tests := []struct { + name string + path string + fileSizeBytes int64 + maxFileSizeBytes int64 + wantRequired bool + wantResultMetric stats.FileRequiredResult + }{ + { + name: "application1.deps.json file", + path: "application1.deps.json", + wantRequired: true, + wantResultMetric: stats.FileRequiredResultOK, + }, + { + name: "path application1.deps.json file", + path: "path/to/my/application1.deps.json", + wantRequired: true, + wantResultMetric: stats.FileRequiredResultOK, + }, + { + name: "file not required", + path: "/test.deps", + wantRequired: false, + }, + { + name: "application1.deps.json file required if file size < max file size", + path: "/application1.deps.json", + fileSizeBytes: 100 * units.KiB, + maxFileSizeBytes: 1000 * units.KiB, + wantRequired: true, + wantResultMetric: stats.FileRequiredResultOK, + }, + { + name: "application1.deps.json file required if file size == max file size", + path: "/application1.deps.json", + fileSizeBytes: 1000 * units.KiB, + maxFileSizeBytes: 1000 * units.KiB, + wantRequired: true, + wantResultMetric: stats.FileRequiredResultOK, + }, + { + name: "application1.deps.json file not required if file size > max file size", + path: "/application1.deps.json", + fileSizeBytes: 1000 * units.KiB, + maxFileSizeBytes: 100 * units.KiB, + wantRequired: false, + wantResultMetric: stats.FileRequiredResultSizeLimitExceeded, + }, + { + name: "application1.deps.json file required if max file size set to 0", + path: "/application1.deps.json", + fileSizeBytes: 100 * units.KiB, + maxFileSizeBytes: 0, + wantRequired: true, + wantResultMetric: stats.FileRequiredResultOK, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + collector := testcollector.New() + var e filesystem.Extractor = depsjson.New(depsjson.Config{ + Stats: collector, + MaxFileSizeBytes: tt.maxFileSizeBytes, + }) + + fileSizeBytes := tt.fileSizeBytes + if fileSizeBytes == 0 { + fileSizeBytes = 1000 + } + + isRequired := e.FileRequired(simplefileapi.New(tt.path, fakefs.FakeFileInfo{ + FileName: filepath.Base(tt.path), + FileMode: fs.ModePerm, + FileSize: fileSizeBytes, + })) + if isRequired != tt.wantRequired { + t.Fatalf("FileRequired(%s): got %v, want %v", tt.path, isRequired, tt.wantRequired) + } + + gotResultMetric := collector.FileRequiredResult(tt.path) + if tt.wantResultMetric != "" && gotResultMetric != tt.wantResultMetric { + t.Errorf("FileRequired(%s) recorded result metric %v, want result metric %v", tt.path, gotResultMetric, tt.wantResultMetric) + } + }) + } +} + +func TestExtract(t *testing.T) { + tests := []struct { + name string + path string + osrelease string + cfg depsjson.Config + wantInventory []*extractor.Inventory + wantErr error + wantResultMetric stats.FileExtractedResult + }{ + { + name: "valid application1.deps.json file", + path: "testdata/valid", + wantInventory: []*extractor.Inventory{ + { + Name: "TestLibrary", + Version: "1.0.0", + Locations: []string{"testdata/valid"}, + }, + { + Name: "AWSSDK.Core", + Version: "3.7.10.6", + Locations: []string{"testdata/valid"}, + }, + { + Name: "Microsoft.Extensions.DependencyInjection", + Version: "6.0.0", + Locations: []string{"testdata/valid"}, + }, + }, + wantResultMetric: stats.FileExtractedResultSuccess, + }, + { + name: "application1.deps.json file not json", + path: "testdata/invalid", + wantErr: cmpopts.AnyError, + wantResultMetric: stats.FileExtractedResultErrorUnknown, + }, + { + name: "application1.deps.json file empty", + path: "testdata/empty", + wantErr: cmpopts.AnyError, + wantResultMetric: stats.FileExtractedResultErrorUnknown, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + collector := testcollector.New() + var e filesystem.Extractor = depsjson.New(depsjson.Config{ + Stats: collector, + MaxFileSizeBytes: 100, + }) + + d := t.TempDir() + + // Opening and Reading the Test File + r, err := os.Open(tt.path) + defer func() { + if err = r.Close(); err != nil { + t.Errorf("Close(): %v", err) + } + }() + if err != nil { + t.Fatal(err) + } + + info, err := os.Stat(tt.path) + if err != nil { + t.Fatalf("Failed to stat test file: %v", err) + } + + input := &filesystem.ScanInput{ + FS: scalibrfs.DirFS(d), Path: tt.path, Reader: r, Root: d, Info: info, + } + + got, err := e.Extract(context.Background(), input) + + if diff := cmp.Diff(tt.wantInventory, got); diff != "" { + t.Errorf("Inventory mismatch (-want +got):\n%s", diff) + } + }) + } +} + +func TestToPURL(t *testing.T) { + e := depsjson.Extractor{} + i := &extractor.Inventory{ + Name: "Name", + Version: "1.2.3", + Locations: []string{"location"}, + } + want := &purl.PackageURL{ + Type: purl.TypeNuget, + Name: "Name", + Version: "1.2.3", + } + got := e.ToPURL(i) + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("ToPURL(%v) (-want +got):\n%s", i, diff) + } +} diff --git a/extractor/filesystem/language/dotnet/depsjson/testdata/empty b/extractor/filesystem/language/dotnet/depsjson/testdata/empty new file mode 100644 index 00000000..9e26dfee --- /dev/null +++ b/extractor/filesystem/language/dotnet/depsjson/testdata/empty @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/extractor/filesystem/language/dotnet/depsjson/testdata/invalid b/extractor/filesystem/language/dotnet/depsjson/testdata/invalid new file mode 100644 index 00000000..6127c7c0 --- /dev/null +++ b/extractor/filesystem/language/dotnet/depsjson/testdata/invalid @@ -0,0 +1,2 @@ +not +json \ No newline at end of file diff --git a/extractor/filesystem/language/dotnet/depsjson/testdata/valid b/extractor/filesystem/language/dotnet/depsjson/testdata/valid new file mode 100644 index 00000000..7cacc1c7 --- /dev/null +++ b/extractor/filesystem/language/dotnet/depsjson/testdata/valid @@ -0,0 +1,65 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v6.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v6.0": { + "TestLibrary/1.0.0": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection": "6.0.0", + "Microsoft.Extensions.Logging": "6.0.0", + "Newtonsoft.Json": "13.0.1", + "Serilog": "2.10.0", + "Serilog.Sinks.Console": "4.0.1", + "TestCommon": "1.0.0" + }, + "runtime": { + "TestLibrary.dll": {} + } + }, + "AWSSDK.Core/3.7.10.6": { + "runtime": { + "lib/netcoreapp3.1/AWSSDK.Core.dll": { + "assemblyVersion": "3.3.0.0", + "fileVersion": "3.7.10.6" + } + } + }, + "Microsoft.Extensions.DependencyInjection/6.0.0": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.DependencyInjection.dll": { + "assemblyVersion": "6.0.0.0", + "fileVersion": "6.0.21.52210" + } + } + } + } + }, + "libraries": { + "TestLibrary/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "AWSSDK.Core/3.7.10.6": { + "type": "package", + "serviceable": true, + "sha512": "sha512-kHBB+QmosVaG6DpngXQ8OlLVVNMzltNITfsRr68Z90qO7dSqJ2EHNd8dtBU1u3AQQLqqFHOY0lfmbpexeH6Pew==", + "path": "awssdk.core/3.7.10.6", + "hashPath": "awssdk.core.3.7.10.6.nupkg.sha512" + }, + "Microsoft.Extensions.DependencyInjection/6.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-k6PWQMuoBDGGHOQTtyois2u4AwyVcIwL2LaSLlTZQm2CYcJ1pxbt6jfAnpWmzENA/wfrYRI/X9DTLoUkE4AsLw==", + "path": "microsoft.extensions.dependencyinjection/6.0.0", + "hashPath": "microsoft.extensions.dependencyinjection.6.0.0.nupkg.sha512" + } + } +} diff --git a/extractor/filesystem/language/dotnet/packagesconfig/packagesconfig.go b/extractor/filesystem/language/dotnet/packagesconfig/packagesconfig.go new file mode 100644 index 00000000..6d416cfe --- /dev/null +++ b/extractor/filesystem/language/dotnet/packagesconfig/packagesconfig.go @@ -0,0 +1,180 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package dotnet extracts packages from .NET packages.config files. +package packagesconfig + +import ( + "context" + "encoding/xml" + "path/filepath" + + "github.com/google/osv-scalibr/extractor" + "github.com/google/osv-scalibr/extractor/filesystem" + "github.com/google/osv-scalibr/extractor/filesystem/internal/units" + "github.com/google/osv-scalibr/log" + "github.com/google/osv-scalibr/plugin" + "github.com/google/osv-scalibr/purl" + "github.com/google/osv-scalibr/stats" +) + +const ( + // Name is the unique name of this extractor. + Name = "dotnet/packagesconfig" + + // defaultMaxFileSizeBytes is the maximum file size this extractor will process. + defaultMaxFileSizeBytes = 10 * units.MiB // 10 MB +) + +// Config is the configuration for the .NET extractor. +type Config struct { + // Stats is a stats collector for reporting metrics. + Stats stats.Collector + // MaxFileSizeBytes is the maximum file size this extractor will unmarshal. If + // `FileRequired` gets a bigger file, it will return false, + MaxFileSizeBytes int64 +} + +// DefaultConfig returns the default configuration for the .NET extractor. +func DefaultConfig() Config { + return Config{ + MaxFileSizeBytes: defaultMaxFileSizeBytes, + } +} + +// Extractor structure for packages.config files. +type Extractor struct { + stats stats.Collector + maxFileSizeBytes int64 +} + +// New returns a .NET extractor. +func New(cfg Config) *Extractor { + return &Extractor{ + stats: cfg.Stats, + maxFileSizeBytes: cfg.MaxFileSizeBytes, + } +} + +// Config returns the configuration of the extractor. +func (e Extractor) Config() Config { + return Config{ + Stats: e.stats, + MaxFileSizeBytes: e.maxFileSizeBytes, + } +} + +// Name of the extractor. +func (e Extractor) Name() string { return Name } + +// Version of the extractor. +func (e Extractor) Version() int { return 0 } + +// Requirements of the extractor. +func (e Extractor) Requirements() *plugin.Capabilities { return &plugin.Capabilities{} } + +// FileRequired returns true if the specified file matches the packages.config pattern. +func (e Extractor) FileRequired(api filesystem.FileAPI) bool { + path := api.Path() + if filepath.Base(path) != "packages.config" { + return false + } + + fileinfo, err := api.Stat() + if err != nil || (e.maxFileSizeBytes > 0 && fileinfo.Size() > e.maxFileSizeBytes) { + e.reportFileRequired(path, stats.FileRequiredResultSizeLimitExceeded) + return false + } + + e.reportFileRequired(path, stats.FileRequiredResultOK) + return true +} + +func (e Extractor) reportFileRequired(path string, result stats.FileRequiredResult) { + if e.stats == nil { + return + } + e.stats.AfterFileRequired(e.Name(), &stats.FileRequiredStats{ + Path: path, + Result: result, + }) +} + +// Extract parses the packages.config file to extract .NET package dependencies. +func (e Extractor) Extract(ctx context.Context, input *filesystem.ScanInput) ([]*extractor.Inventory, error) { + packages, err := e.extractFromInput(ctx, input) + if e.stats != nil { + var fileSizeBytes int64 + if input.Info != nil { + fileSizeBytes = input.Info.Size() + } + e.stats.AfterFileExtracted(e.Name(), &stats.FileExtractedStats{ + Path: input.Path, + Result: filesystem.ExtractorErrorToFileExtractedResult(err), + FileSizeBytes: fileSizeBytes, + }) + } + return packages, err +} + +type Package struct { + ID string `xml:"id,attr"` + Version string `xml:"version,attr"` +} + +type Packages struct { + XMLName xml.Name `xml:"packages"` + Packages []Package `xml:"package"` +} + +func (e Extractor) extractFromInput(ctx context.Context, input *filesystem.ScanInput) ([]*extractor.Inventory, error) { + var pkgs []*extractor.Inventory + + var packages Packages + decoder := xml.NewDecoder(input.Reader) + if err := decoder.Decode(&packages); err != nil { + log.Errorf("Error parsing packages.config: %v", err) + return nil, err + } + + for _, pkg := range packages.Packages { + if pkg.ID == "" || pkg.Version == "" { + log.Warnf("Skipping package with missing name or version: %+v", pkg) + continue + } + + i := &extractor.Inventory{ + Name: pkg.ID, + Version: pkg.Version, + Locations: []string{input.Path}, + } + pkgs = append(pkgs, i) + } + + return pkgs, nil +} + +// ToPURL converts an inventory created by this extractor into a PURL. +func (e Extractor) ToPURL(i *extractor.Inventory) *purl.PackageURL { + return &purl.PackageURL{ + Type: purl.TypeNuget, + Name: i.Name, + Version: i.Version, + } +} + +// Ecosystem returns the OSV Ecosystem of the software extracted by this extractor. +func (Extractor) Ecosystem(i *extractor.Inventory) string { + return "NuGet" +} diff --git a/extractor/filesystem/language/dotnet/packagesconfig/packagesconfig_test.go b/extractor/filesystem/language/dotnet/packagesconfig/packagesconfig_test.go new file mode 100644 index 00000000..c5e641d3 --- /dev/null +++ b/extractor/filesystem/language/dotnet/packagesconfig/packagesconfig_test.go @@ -0,0 +1,254 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package packagesconfig_test + +import ( + "context" + "io/fs" + "os" + "path/filepath" + "reflect" + "testing" + + scalibrfs "github.com/google/osv-scalibr/fs" + "github.com/google/osv-scalibr/purl" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "github.com/google/osv-scalibr/extractor" + "github.com/google/osv-scalibr/extractor/filesystem" + "github.com/google/osv-scalibr/extractor/filesystem/internal/units" + "github.com/google/osv-scalibr/extractor/filesystem/language/dotnet/packagesconfig" + "github.com/google/osv-scalibr/extractor/filesystem/simplefileapi" + "github.com/google/osv-scalibr/stats" + "github.com/google/osv-scalibr/testing/fakefs" + "github.com/google/osv-scalibr/testing/testcollector" +) + +func TestNew(t *testing.T) { + tests := []struct { + name string + cfg packagesconfig.Config + wantCfg packagesconfig.Config + }{ + { + name: "default", + cfg: packagesconfig.DefaultConfig(), + wantCfg: packagesconfig.Config{ + MaxFileSizeBytes: 10 * units.MiB, + }, + }, + { + name: "custom", + cfg: packagesconfig.Config{ + MaxFileSizeBytes: 10, + }, + wantCfg: packagesconfig.Config{ + MaxFileSizeBytes: 10, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := packagesconfig.New(tt.cfg) + if !reflect.DeepEqual(got.Config(), tt.wantCfg) { + t.Errorf("New(%+v).Config(): got %+v, want %+v", tt.cfg, got.Config(), tt.wantCfg) + } + }) + } +} + +func TestFileRequired(t *testing.T) { + tests := []struct { + name string + path string + fileSizeBytes int64 + maxFileSizeBytes int64 + wantRequired bool + wantResultMetric stats.FileRequiredResult + }{ + { + name: "packages.config file", + path: "packages.config", + wantRequired: true, + wantResultMetric: stats.FileRequiredResultOK, + }, + { + name: "path packages.config file", + path: "path/to/my/packages.config", + wantRequired: true, + wantResultMetric: stats.FileRequiredResultOK, + }, + { + name: "file not required", + path: "/test.config", + wantRequired: false, + }, + { + name: "packages.config file required if file size < max file size", + path: "/packages.config", + fileSizeBytes: 100 * units.KiB, + maxFileSizeBytes: 1000 * units.KiB, + wantRequired: true, + wantResultMetric: stats.FileRequiredResultOK, + }, + { + name: "packages.config file required if file size == max file size", + path: "/packages.config", + fileSizeBytes: 1000 * units.KiB, + maxFileSizeBytes: 1000 * units.KiB, + wantRequired: true, + wantResultMetric: stats.FileRequiredResultOK, + }, + { + name: "packages.config file not required if file size > max file size", + path: "/packages.config", + fileSizeBytes: 1000 * units.KiB, + maxFileSizeBytes: 100 * units.KiB, + wantRequired: false, + wantResultMetric: stats.FileRequiredResultSizeLimitExceeded, + }, + { + name: "packages.config file required if max file size set to 0", + path: "/packages.config", + fileSizeBytes: 100 * units.KiB, + maxFileSizeBytes: 0, + wantRequired: true, + wantResultMetric: stats.FileRequiredResultOK, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + collector := testcollector.New() + var e filesystem.Extractor = packagesconfig.New(packagesconfig.Config{ + Stats: collector, + MaxFileSizeBytes: tt.maxFileSizeBytes, + }) + + fileSizeBytes := tt.fileSizeBytes + if fileSizeBytes == 0 { + fileSizeBytes = 1000 + } + + isRequired := e.FileRequired(simplefileapi.New(tt.path, fakefs.FakeFileInfo{ + FileName: filepath.Base(tt.path), + FileMode: fs.ModePerm, + FileSize: fileSizeBytes, + })) + if isRequired != tt.wantRequired { + t.Fatalf("FileRequired(%s): got %v, want %v", tt.path, isRequired, tt.wantRequired) + } + + gotResultMetric := collector.FileRequiredResult(tt.path) + if tt.wantResultMetric != "" && gotResultMetric != tt.wantResultMetric { + t.Errorf("FileRequired(%s) recorded result metric %v, want result metric %v", tt.path, gotResultMetric, tt.wantResultMetric) + } + }) + } +} + +func TestExtract(t *testing.T) { + tests := []struct { + name string + path string + osrelease string + cfg packagesconfig.Config + wantInventory []*extractor.Inventory + wantErr error + wantResultMetric stats.FileExtractedResult + }{ + { + name: "valid packages.config file", + path: "testdata/valid", + wantInventory: []*extractor.Inventory{ + { + Name: "Microsoft.CodeDom.Providers.DotNetCompilerPlatform", + Version: "1.0.0", + Locations: []string{"testdata/valid"}, + }, + { + Name: "Microsoft.Net.Compilers", + Version: "1.0.0", + Locations: []string{"testdata/valid"}, + }, + }, + wantResultMetric: stats.FileExtractedResultSuccess, + }, + { + name: "packages.config file not xml", + path: "testdata/invalid", + wantErr: cmpopts.AnyError, + wantResultMetric: stats.FileExtractedResultErrorUnknown, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + collector := testcollector.New() + var e filesystem.Extractor = packagesconfig.New(packagesconfig.Config{ + Stats: collector, + MaxFileSizeBytes: 100, + }) + + d := t.TempDir() + + // Opening and Reading the Test File + r, err := os.Open(tt.path) + defer func() { + if err = r.Close(); err != nil { + t.Errorf("Close(): %v", err) + } + }() + if err != nil { + t.Fatal(err) + } + + info, err := os.Stat(tt.path) + if err != nil { + t.Fatalf("Failed to stat test file: %v", err) + } + + input := &filesystem.ScanInput{ + FS: scalibrfs.DirFS(d), Path: tt.path, Reader: r, Root: d, Info: info, + } + + got, err := e.Extract(context.Background(), input) + + if diff := cmp.Diff(tt.wantInventory, got); diff != "" { + t.Errorf("Inventory mismatch (-want +got):\n%s", diff) + } + }) + } +} + +func TestToPURL(t *testing.T) { + e := packagesconfig.Extractor{} + i := &extractor.Inventory{ + Name: "Name", + Version: "1.2.3", + Locations: []string{"location"}, + } + want := &purl.PackageURL{ + Type: purl.TypeNuget, + Name: "Name", + Version: "1.2.3", + } + got := e.ToPURL(i) + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("ToPURL(%v) (-want +got):\n%s", i, diff) + } +} diff --git a/extractor/filesystem/language/dotnet/packagesconfig/testdata/invalid b/extractor/filesystem/language/dotnet/packagesconfig/testdata/invalid new file mode 100644 index 00000000..641d5aa5 --- /dev/null +++ b/extractor/filesystem/language/dotnet/packagesconfig/testdata/invalid @@ -0,0 +1,2 @@ +not +xml \ No newline at end of file diff --git a/extractor/filesystem/language/dotnet/packagesconfig/testdata/valid b/extractor/filesystem/language/dotnet/packagesconfig/testdata/valid new file mode 100644 index 00000000..15bce650 --- /dev/null +++ b/extractor/filesystem/language/dotnet/packagesconfig/testdata/valid @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/extractor/filesystem/list/list.go b/extractor/filesystem/list/list.go index f5933557..65340226 100644 --- a/extractor/filesystem/list/list.go +++ b/extractor/filesystem/list/list.go @@ -29,6 +29,8 @@ import ( "github.com/google/osv-scalibr/extractor/filesystem/containers/containerd" "github.com/google/osv-scalibr/extractor/filesystem/language/cpp/conanlock" "github.com/google/osv-scalibr/extractor/filesystem/language/dart/pubspec" + "github.com/google/osv-scalibr/extractor/filesystem/language/dotnet/depsjson" + "github.com/google/osv-scalibr/extractor/filesystem/language/dotnet/packagesconfig" "github.com/google/osv-scalibr/extractor/filesystem/language/dotnet/packageslockjson" "github.com/google/osv-scalibr/extractor/filesystem/language/erlang/mixlock" "github.com/google/osv-scalibr/extractor/filesystem/language/golang/gobinary" @@ -112,7 +114,11 @@ var ( // SBOM extractors. SBOM []filesystem.Extractor = []filesystem.Extractor{&cdx.Extractor{}, &spdx.Extractor{}} // Dotnet (.NET) extractors. - Dotnet []filesystem.Extractor = []filesystem.Extractor{packageslockjson.New(packageslockjson.DefaultConfig())} + Dotnet []filesystem.Extractor = []filesystem.Extractor{ + packagesconfig.New(packagesconfig.DefaultConfig()), + depsjson.New(depsjson.DefaultConfig()), + packageslockjson.New(packageslockjson.DefaultConfig()), + } // PHP extractors. PHP []filesystem.Extractor = []filesystem.Extractor{&composerlock.Extractor{}} // Containers extractors. From 720e45d543697f3906b085ea491a4eacdc481698 Mon Sep 17 00:00:00 2001 From: Federico Loi Date: Thu, 19 Dec 2024 11:56:43 +0100 Subject: [PATCH 2/4] Added some test cases --- .../language/dotnet/depsjson/depsjson_test.go | 17 +++++ .../dotnet/depsjson/testdata/nopackagename | 65 +++++++++++++++++++ .../dotnet/packagesconfig/packagesconfig.go | 10 +-- .../packagesconfig/packagesconfig_test.go | 24 +++++++ .../dotnet/packagesconfig/testdata/nopackage | 5 ++ .../dotnet/packagesconfig/testdata/noversion | 5 ++ 6 files changed, 121 insertions(+), 5 deletions(-) create mode 100644 extractor/filesystem/language/dotnet/depsjson/testdata/nopackagename create mode 100644 extractor/filesystem/language/dotnet/packagesconfig/testdata/nopackage create mode 100644 extractor/filesystem/language/dotnet/packagesconfig/testdata/noversion diff --git a/extractor/filesystem/language/dotnet/depsjson/depsjson_test.go b/extractor/filesystem/language/dotnet/depsjson/depsjson_test.go index dcd018a2..a243f459 100644 --- a/extractor/filesystem/language/dotnet/depsjson/depsjson_test.go +++ b/extractor/filesystem/language/dotnet/depsjson/depsjson_test.go @@ -204,6 +204,23 @@ func TestExtract(t *testing.T) { wantErr: cmpopts.AnyError, wantResultMetric: stats.FileExtractedResultErrorUnknown, }, + { + name: "valid application1.deps.json file", + path: "testdata/nopackagename", + wantInventory: []*extractor.Inventory{ + { + Name: "TestLibrary", + Version: "1.0.0", + Locations: []string{"testdata/nopackagename"}, + }, + { + Name: "AWSSDK.Core", + Version: "3.7.10.6", + Locations: []string{"testdata/nopackagename"}, + }, + }, + wantResultMetric: stats.FileExtractedResultSuccess, + }, } for _, tt := range tests { diff --git a/extractor/filesystem/language/dotnet/depsjson/testdata/nopackagename b/extractor/filesystem/language/dotnet/depsjson/testdata/nopackagename new file mode 100644 index 00000000..79515f3c --- /dev/null +++ b/extractor/filesystem/language/dotnet/depsjson/testdata/nopackagename @@ -0,0 +1,65 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v6.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v6.0": { + "TestLibrary/1.0.0": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection": "6.0.0", + "Microsoft.Extensions.Logging": "6.0.0", + "Newtonsoft.Json": "13.0.1", + "Serilog": "2.10.0", + "Serilog.Sinks.Console": "4.0.1", + "TestCommon": "1.0.0" + }, + "runtime": { + "TestLibrary.dll": {} + } + }, + "AWSSDK.Core/3.7.10.6": { + "runtime": { + "lib/netcoreapp3.1/AWSSDK.Core.dll": { + "assemblyVersion": "3.3.0.0", + "fileVersion": "3.7.10.6" + } + } + }, + "Microsoft.Extensions.DependencyInjection": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + }, + "runtime": { + "lib/net6.0/Microsoft.Extensions.DependencyInjection.dll": { + "assemblyVersion": "6.0.0.0", + "fileVersion": "6.0.21.52210" + } + } + } + } + }, + "libraries": { + "TestLibrary/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "AWSSDK.Core/3.7.10.6": { + "type": "package", + "serviceable": true, + "sha512": "sha512-kHBB+QmosVaG6DpngXQ8OlLVVNMzltNITfsRr68Z90qO7dSqJ2EHNd8dtBU1u3AQQLqqFHOY0lfmbpexeH6Pew==", + "path": "awssdk.core/3.7.10.6", + "hashPath": "awssdk.core.3.7.10.6.nupkg.sha512" + }, + "Microsoft.Extensions.DependencyInjection": { + "type": "package", + "serviceable": true, + "sha512": "sha512-k6PWQMuoBDGGHOQTtyois2u4AwyVcIwL2LaSLlTZQm2CYcJ1pxbt6jfAnpWmzENA/wfrYRI/X9DTLoUkE4AsLw==", + "path": "microsoft.extensions.dependencyinjection", + "hashPath": "microsoft.extensions.dependencyinjection.nupkg.sha512" + } + } +} diff --git a/extractor/filesystem/language/dotnet/packagesconfig/packagesconfig.go b/extractor/filesystem/language/dotnet/packagesconfig/packagesconfig.go index 6d416cfe..d0b89f7c 100644 --- a/extractor/filesystem/language/dotnet/packagesconfig/packagesconfig.go +++ b/extractor/filesystem/language/dotnet/packagesconfig/packagesconfig.go @@ -37,7 +37,7 @@ const ( defaultMaxFileSizeBytes = 10 * units.MiB // 10 MB ) -// Config is the configuration for the .NET extractor. +// Config is the configuration for the .NET packages.config extractor. type Config struct { // Stats is a stats collector for reporting metrics. Stats stats.Collector @@ -46,20 +46,20 @@ type Config struct { MaxFileSizeBytes int64 } -// DefaultConfig returns the default configuration for the .NET extractor. +// DefaultConfig returns the default configuration for the .NET packages.config extractor. func DefaultConfig() Config { return Config{ MaxFileSizeBytes: defaultMaxFileSizeBytes, } } -// Extractor structure for packages.config files. +// Extractor structure for .NET packages.config files. type Extractor struct { stats stats.Collector maxFileSizeBytes int64 } -// New returns a .NET extractor. +// New returns a .NET packages.config extractor. func New(cfg Config) *Extractor { return &Extractor{ stats: cfg.Stats, @@ -84,7 +84,7 @@ func (e Extractor) Version() int { return 0 } // Requirements of the extractor. func (e Extractor) Requirements() *plugin.Capabilities { return &plugin.Capabilities{} } -// FileRequired returns true if the specified file matches the packages.config pattern. +// FileRequired returns true if the specified file matches the .NET packages.config pattern. func (e Extractor) FileRequired(api filesystem.FileAPI) bool { path := api.Path() if filepath.Base(path) != "packages.config" { diff --git a/extractor/filesystem/language/dotnet/packagesconfig/packagesconfig_test.go b/extractor/filesystem/language/dotnet/packagesconfig/packagesconfig_test.go index c5e641d3..5576b2a5 100644 --- a/extractor/filesystem/language/dotnet/packagesconfig/packagesconfig_test.go +++ b/extractor/filesystem/language/dotnet/packagesconfig/packagesconfig_test.go @@ -194,6 +194,30 @@ func TestExtract(t *testing.T) { wantErr: cmpopts.AnyError, wantResultMetric: stats.FileExtractedResultErrorUnknown, }, + { + name: "packages without version", + path: "testdata/noversion", + wantInventory: []*extractor.Inventory{ + { + Name: "Microsoft.CodeDom.Providers.DotNetCompilerPlatform", + Version: "1.0.0", + Locations: []string{"testdata/noversion"}, + }, + }, + wantResultMetric: stats.FileExtractedResultSuccess, + }, + { + name: "packages without name", + path: "testdata/nopackage", + wantInventory: []*extractor.Inventory{ + { + Name: "Microsoft.CodeDom.Providers.DotNetCompilerPlatform", + Version: "1.0.0", + Locations: []string{"testdata/nopackage"}, + }, + }, + wantResultMetric: stats.FileExtractedResultSuccess, + }, } for _, tt := range tests { diff --git a/extractor/filesystem/language/dotnet/packagesconfig/testdata/nopackage b/extractor/filesystem/language/dotnet/packagesconfig/testdata/nopackage new file mode 100644 index 00000000..cf452bd7 --- /dev/null +++ b/extractor/filesystem/language/dotnet/packagesconfig/testdata/nopackage @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/extractor/filesystem/language/dotnet/packagesconfig/testdata/noversion b/extractor/filesystem/language/dotnet/packagesconfig/testdata/noversion new file mode 100644 index 00000000..76c5ca11 --- /dev/null +++ b/extractor/filesystem/language/dotnet/packagesconfig/testdata/noversion @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file From f953ef1f44b0c55cb01ac32ab790846994a02e82 Mon Sep 17 00:00:00 2001 From: Federico Loi Date: Thu, 19 Dec 2024 15:45:11 +0100 Subject: [PATCH 3/4] Fix issues and remove package.config extractor for a different PR --- .../language/dotnet/depsjson/depsjson.go | 9 +- .../language/dotnet/depsjson/depsjson_test.go | 10 +- .../dotnet/packagesconfig/packagesconfig.go | 180 ------------ .../packagesconfig/packagesconfig_test.go | 278 ------------------ .../dotnet/packagesconfig/testdata/invalid | 2 - .../dotnet/packagesconfig/testdata/nopackage | 5 - .../dotnet/packagesconfig/testdata/noversion | 5 - .../dotnet/packagesconfig/testdata/valid | 5 - extractor/filesystem/list/list.go | 2 - 9 files changed, 9 insertions(+), 487 deletions(-) delete mode 100644 extractor/filesystem/language/dotnet/packagesconfig/packagesconfig.go delete mode 100644 extractor/filesystem/language/dotnet/packagesconfig/packagesconfig_test.go delete mode 100644 extractor/filesystem/language/dotnet/packagesconfig/testdata/invalid delete mode 100644 extractor/filesystem/language/dotnet/packagesconfig/testdata/nopackage delete mode 100644 extractor/filesystem/language/dotnet/packagesconfig/testdata/noversion delete mode 100644 extractor/filesystem/language/dotnet/packagesconfig/testdata/valid diff --git a/extractor/filesystem/language/dotnet/depsjson/depsjson.go b/extractor/filesystem/language/dotnet/depsjson/depsjson.go index beb433e2..75dfe4d4 100644 --- a/extractor/filesystem/language/dotnet/depsjson/depsjson.go +++ b/extractor/filesystem/language/dotnet/depsjson/depsjson.go @@ -18,7 +18,6 @@ package depsjson import ( "context" "encoding/json" - "path/filepath" "strings" "github.com/google/osv-scalibr/extractor" @@ -88,7 +87,7 @@ func (e Extractor) Requirements() *plugin.Capabilities { return &plugin.Capabili // FileRequired returns true if the specified file matches the deps.json pattern. func (e Extractor) FileRequired(api filesystem.FileAPI) bool { path := api.Path() - if !strings.HasSuffix(filepath.Base(path), ".deps.json") { + if !strings.HasSuffix(path, ".deps.json") { return false } @@ -136,7 +135,6 @@ type DepsJSON struct { } func (e Extractor) extractFromInput(ctx context.Context, input *filesystem.ScanInput) ([]*extractor.Inventory, error) { - var pkgs []*extractor.Inventory var deps DepsJSON decoder := json.NewDecoder(input.Reader) @@ -145,6 +143,7 @@ func (e Extractor) extractFromInput(ctx context.Context, input *filesystem.ScanI return nil, err } + var inventories []*extractor.Inventory for nameVersion := range deps.Libraries { // Split name and version from "package/version" format name, version := splitNameAndVersion(nameVersion) @@ -158,10 +157,10 @@ func (e Extractor) extractFromInput(ctx context.Context, input *filesystem.ScanI Version: version, Locations: []string{input.Path}, } - pkgs = append(pkgs, i) + inventories = append(inventories, i) } - return pkgs, nil + return inventories, nil } // splitNameAndVersion splits the name and version from a "package/version" string. diff --git a/extractor/filesystem/language/dotnet/depsjson/depsjson_test.go b/extractor/filesystem/language/dotnet/depsjson/depsjson_test.go index a243f459..1910de81 100644 --- a/extractor/filesystem/language/dotnet/depsjson/depsjson_test.go +++ b/extractor/filesystem/language/dotnet/depsjson/depsjson_test.go @@ -98,7 +98,7 @@ func TestFileRequired(t *testing.T) { }, { name: "application1.deps.json file required if file size < max file size", - path: "/application1.deps.json", + path: "application1.deps.json", fileSizeBytes: 100 * units.KiB, maxFileSizeBytes: 1000 * units.KiB, wantRequired: true, @@ -106,7 +106,7 @@ func TestFileRequired(t *testing.T) { }, { name: "application1.deps.json file required if file size == max file size", - path: "/application1.deps.json", + path: "application1.deps.json", fileSizeBytes: 1000 * units.KiB, maxFileSizeBytes: 1000 * units.KiB, wantRequired: true, @@ -114,7 +114,7 @@ func TestFileRequired(t *testing.T) { }, { name: "application1.deps.json file not required if file size > max file size", - path: "/application1.deps.json", + path: "application1.deps.json", fileSizeBytes: 1000 * units.KiB, maxFileSizeBytes: 100 * units.KiB, wantRequired: false, @@ -122,7 +122,7 @@ func TestFileRequired(t *testing.T) { }, { name: "application1.deps.json file required if max file size set to 0", - path: "/application1.deps.json", + path: "application1.deps.json", fileSizeBytes: 100 * units.KiB, maxFileSizeBytes: 0, wantRequired: true, @@ -205,7 +205,7 @@ func TestExtract(t *testing.T) { wantResultMetric: stats.FileExtractedResultErrorUnknown, }, { - name: "valid application1.deps.json file", + name: "valid application1.deps.json file with an invalid package", path: "testdata/nopackagename", wantInventory: []*extractor.Inventory{ { diff --git a/extractor/filesystem/language/dotnet/packagesconfig/packagesconfig.go b/extractor/filesystem/language/dotnet/packagesconfig/packagesconfig.go deleted file mode 100644 index d0b89f7c..00000000 --- a/extractor/filesystem/language/dotnet/packagesconfig/packagesconfig.go +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright 2024 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package dotnet extracts packages from .NET packages.config files. -package packagesconfig - -import ( - "context" - "encoding/xml" - "path/filepath" - - "github.com/google/osv-scalibr/extractor" - "github.com/google/osv-scalibr/extractor/filesystem" - "github.com/google/osv-scalibr/extractor/filesystem/internal/units" - "github.com/google/osv-scalibr/log" - "github.com/google/osv-scalibr/plugin" - "github.com/google/osv-scalibr/purl" - "github.com/google/osv-scalibr/stats" -) - -const ( - // Name is the unique name of this extractor. - Name = "dotnet/packagesconfig" - - // defaultMaxFileSizeBytes is the maximum file size this extractor will process. - defaultMaxFileSizeBytes = 10 * units.MiB // 10 MB -) - -// Config is the configuration for the .NET packages.config extractor. -type Config struct { - // Stats is a stats collector for reporting metrics. - Stats stats.Collector - // MaxFileSizeBytes is the maximum file size this extractor will unmarshal. If - // `FileRequired` gets a bigger file, it will return false, - MaxFileSizeBytes int64 -} - -// DefaultConfig returns the default configuration for the .NET packages.config extractor. -func DefaultConfig() Config { - return Config{ - MaxFileSizeBytes: defaultMaxFileSizeBytes, - } -} - -// Extractor structure for .NET packages.config files. -type Extractor struct { - stats stats.Collector - maxFileSizeBytes int64 -} - -// New returns a .NET packages.config extractor. -func New(cfg Config) *Extractor { - return &Extractor{ - stats: cfg.Stats, - maxFileSizeBytes: cfg.MaxFileSizeBytes, - } -} - -// Config returns the configuration of the extractor. -func (e Extractor) Config() Config { - return Config{ - Stats: e.stats, - MaxFileSizeBytes: e.maxFileSizeBytes, - } -} - -// Name of the extractor. -func (e Extractor) Name() string { return Name } - -// Version of the extractor. -func (e Extractor) Version() int { return 0 } - -// Requirements of the extractor. -func (e Extractor) Requirements() *plugin.Capabilities { return &plugin.Capabilities{} } - -// FileRequired returns true if the specified file matches the .NET packages.config pattern. -func (e Extractor) FileRequired(api filesystem.FileAPI) bool { - path := api.Path() - if filepath.Base(path) != "packages.config" { - return false - } - - fileinfo, err := api.Stat() - if err != nil || (e.maxFileSizeBytes > 0 && fileinfo.Size() > e.maxFileSizeBytes) { - e.reportFileRequired(path, stats.FileRequiredResultSizeLimitExceeded) - return false - } - - e.reportFileRequired(path, stats.FileRequiredResultOK) - return true -} - -func (e Extractor) reportFileRequired(path string, result stats.FileRequiredResult) { - if e.stats == nil { - return - } - e.stats.AfterFileRequired(e.Name(), &stats.FileRequiredStats{ - Path: path, - Result: result, - }) -} - -// Extract parses the packages.config file to extract .NET package dependencies. -func (e Extractor) Extract(ctx context.Context, input *filesystem.ScanInput) ([]*extractor.Inventory, error) { - packages, err := e.extractFromInput(ctx, input) - if e.stats != nil { - var fileSizeBytes int64 - if input.Info != nil { - fileSizeBytes = input.Info.Size() - } - e.stats.AfterFileExtracted(e.Name(), &stats.FileExtractedStats{ - Path: input.Path, - Result: filesystem.ExtractorErrorToFileExtractedResult(err), - FileSizeBytes: fileSizeBytes, - }) - } - return packages, err -} - -type Package struct { - ID string `xml:"id,attr"` - Version string `xml:"version,attr"` -} - -type Packages struct { - XMLName xml.Name `xml:"packages"` - Packages []Package `xml:"package"` -} - -func (e Extractor) extractFromInput(ctx context.Context, input *filesystem.ScanInput) ([]*extractor.Inventory, error) { - var pkgs []*extractor.Inventory - - var packages Packages - decoder := xml.NewDecoder(input.Reader) - if err := decoder.Decode(&packages); err != nil { - log.Errorf("Error parsing packages.config: %v", err) - return nil, err - } - - for _, pkg := range packages.Packages { - if pkg.ID == "" || pkg.Version == "" { - log.Warnf("Skipping package with missing name or version: %+v", pkg) - continue - } - - i := &extractor.Inventory{ - Name: pkg.ID, - Version: pkg.Version, - Locations: []string{input.Path}, - } - pkgs = append(pkgs, i) - } - - return pkgs, nil -} - -// ToPURL converts an inventory created by this extractor into a PURL. -func (e Extractor) ToPURL(i *extractor.Inventory) *purl.PackageURL { - return &purl.PackageURL{ - Type: purl.TypeNuget, - Name: i.Name, - Version: i.Version, - } -} - -// Ecosystem returns the OSV Ecosystem of the software extracted by this extractor. -func (Extractor) Ecosystem(i *extractor.Inventory) string { - return "NuGet" -} diff --git a/extractor/filesystem/language/dotnet/packagesconfig/packagesconfig_test.go b/extractor/filesystem/language/dotnet/packagesconfig/packagesconfig_test.go deleted file mode 100644 index 5576b2a5..00000000 --- a/extractor/filesystem/language/dotnet/packagesconfig/packagesconfig_test.go +++ /dev/null @@ -1,278 +0,0 @@ -// Copyright 2024 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package packagesconfig_test - -import ( - "context" - "io/fs" - "os" - "path/filepath" - "reflect" - "testing" - - scalibrfs "github.com/google/osv-scalibr/fs" - "github.com/google/osv-scalibr/purl" - - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" - "github.com/google/osv-scalibr/extractor" - "github.com/google/osv-scalibr/extractor/filesystem" - "github.com/google/osv-scalibr/extractor/filesystem/internal/units" - "github.com/google/osv-scalibr/extractor/filesystem/language/dotnet/packagesconfig" - "github.com/google/osv-scalibr/extractor/filesystem/simplefileapi" - "github.com/google/osv-scalibr/stats" - "github.com/google/osv-scalibr/testing/fakefs" - "github.com/google/osv-scalibr/testing/testcollector" -) - -func TestNew(t *testing.T) { - tests := []struct { - name string - cfg packagesconfig.Config - wantCfg packagesconfig.Config - }{ - { - name: "default", - cfg: packagesconfig.DefaultConfig(), - wantCfg: packagesconfig.Config{ - MaxFileSizeBytes: 10 * units.MiB, - }, - }, - { - name: "custom", - cfg: packagesconfig.Config{ - MaxFileSizeBytes: 10, - }, - wantCfg: packagesconfig.Config{ - MaxFileSizeBytes: 10, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := packagesconfig.New(tt.cfg) - if !reflect.DeepEqual(got.Config(), tt.wantCfg) { - t.Errorf("New(%+v).Config(): got %+v, want %+v", tt.cfg, got.Config(), tt.wantCfg) - } - }) - } -} - -func TestFileRequired(t *testing.T) { - tests := []struct { - name string - path string - fileSizeBytes int64 - maxFileSizeBytes int64 - wantRequired bool - wantResultMetric stats.FileRequiredResult - }{ - { - name: "packages.config file", - path: "packages.config", - wantRequired: true, - wantResultMetric: stats.FileRequiredResultOK, - }, - { - name: "path packages.config file", - path: "path/to/my/packages.config", - wantRequired: true, - wantResultMetric: stats.FileRequiredResultOK, - }, - { - name: "file not required", - path: "/test.config", - wantRequired: false, - }, - { - name: "packages.config file required if file size < max file size", - path: "/packages.config", - fileSizeBytes: 100 * units.KiB, - maxFileSizeBytes: 1000 * units.KiB, - wantRequired: true, - wantResultMetric: stats.FileRequiredResultOK, - }, - { - name: "packages.config file required if file size == max file size", - path: "/packages.config", - fileSizeBytes: 1000 * units.KiB, - maxFileSizeBytes: 1000 * units.KiB, - wantRequired: true, - wantResultMetric: stats.FileRequiredResultOK, - }, - { - name: "packages.config file not required if file size > max file size", - path: "/packages.config", - fileSizeBytes: 1000 * units.KiB, - maxFileSizeBytes: 100 * units.KiB, - wantRequired: false, - wantResultMetric: stats.FileRequiredResultSizeLimitExceeded, - }, - { - name: "packages.config file required if max file size set to 0", - path: "/packages.config", - fileSizeBytes: 100 * units.KiB, - maxFileSizeBytes: 0, - wantRequired: true, - wantResultMetric: stats.FileRequiredResultOK, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - collector := testcollector.New() - var e filesystem.Extractor = packagesconfig.New(packagesconfig.Config{ - Stats: collector, - MaxFileSizeBytes: tt.maxFileSizeBytes, - }) - - fileSizeBytes := tt.fileSizeBytes - if fileSizeBytes == 0 { - fileSizeBytes = 1000 - } - - isRequired := e.FileRequired(simplefileapi.New(tt.path, fakefs.FakeFileInfo{ - FileName: filepath.Base(tt.path), - FileMode: fs.ModePerm, - FileSize: fileSizeBytes, - })) - if isRequired != tt.wantRequired { - t.Fatalf("FileRequired(%s): got %v, want %v", tt.path, isRequired, tt.wantRequired) - } - - gotResultMetric := collector.FileRequiredResult(tt.path) - if tt.wantResultMetric != "" && gotResultMetric != tt.wantResultMetric { - t.Errorf("FileRequired(%s) recorded result metric %v, want result metric %v", tt.path, gotResultMetric, tt.wantResultMetric) - } - }) - } -} - -func TestExtract(t *testing.T) { - tests := []struct { - name string - path string - osrelease string - cfg packagesconfig.Config - wantInventory []*extractor.Inventory - wantErr error - wantResultMetric stats.FileExtractedResult - }{ - { - name: "valid packages.config file", - path: "testdata/valid", - wantInventory: []*extractor.Inventory{ - { - Name: "Microsoft.CodeDom.Providers.DotNetCompilerPlatform", - Version: "1.0.0", - Locations: []string{"testdata/valid"}, - }, - { - Name: "Microsoft.Net.Compilers", - Version: "1.0.0", - Locations: []string{"testdata/valid"}, - }, - }, - wantResultMetric: stats.FileExtractedResultSuccess, - }, - { - name: "packages.config file not xml", - path: "testdata/invalid", - wantErr: cmpopts.AnyError, - wantResultMetric: stats.FileExtractedResultErrorUnknown, - }, - { - name: "packages without version", - path: "testdata/noversion", - wantInventory: []*extractor.Inventory{ - { - Name: "Microsoft.CodeDom.Providers.DotNetCompilerPlatform", - Version: "1.0.0", - Locations: []string{"testdata/noversion"}, - }, - }, - wantResultMetric: stats.FileExtractedResultSuccess, - }, - { - name: "packages without name", - path: "testdata/nopackage", - wantInventory: []*extractor.Inventory{ - { - Name: "Microsoft.CodeDom.Providers.DotNetCompilerPlatform", - Version: "1.0.0", - Locations: []string{"testdata/nopackage"}, - }, - }, - wantResultMetric: stats.FileExtractedResultSuccess, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - collector := testcollector.New() - var e filesystem.Extractor = packagesconfig.New(packagesconfig.Config{ - Stats: collector, - MaxFileSizeBytes: 100, - }) - - d := t.TempDir() - - // Opening and Reading the Test File - r, err := os.Open(tt.path) - defer func() { - if err = r.Close(); err != nil { - t.Errorf("Close(): %v", err) - } - }() - if err != nil { - t.Fatal(err) - } - - info, err := os.Stat(tt.path) - if err != nil { - t.Fatalf("Failed to stat test file: %v", err) - } - - input := &filesystem.ScanInput{ - FS: scalibrfs.DirFS(d), Path: tt.path, Reader: r, Root: d, Info: info, - } - - got, err := e.Extract(context.Background(), input) - - if diff := cmp.Diff(tt.wantInventory, got); diff != "" { - t.Errorf("Inventory mismatch (-want +got):\n%s", diff) - } - }) - } -} - -func TestToPURL(t *testing.T) { - e := packagesconfig.Extractor{} - i := &extractor.Inventory{ - Name: "Name", - Version: "1.2.3", - Locations: []string{"location"}, - } - want := &purl.PackageURL{ - Type: purl.TypeNuget, - Name: "Name", - Version: "1.2.3", - } - got := e.ToPURL(i) - if diff := cmp.Diff(want, got); diff != "" { - t.Errorf("ToPURL(%v) (-want +got):\n%s", i, diff) - } -} diff --git a/extractor/filesystem/language/dotnet/packagesconfig/testdata/invalid b/extractor/filesystem/language/dotnet/packagesconfig/testdata/invalid deleted file mode 100644 index 641d5aa5..00000000 --- a/extractor/filesystem/language/dotnet/packagesconfig/testdata/invalid +++ /dev/null @@ -1,2 +0,0 @@ -not -xml \ No newline at end of file diff --git a/extractor/filesystem/language/dotnet/packagesconfig/testdata/nopackage b/extractor/filesystem/language/dotnet/packagesconfig/testdata/nopackage deleted file mode 100644 index cf452bd7..00000000 --- a/extractor/filesystem/language/dotnet/packagesconfig/testdata/nopackage +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/extractor/filesystem/language/dotnet/packagesconfig/testdata/noversion b/extractor/filesystem/language/dotnet/packagesconfig/testdata/noversion deleted file mode 100644 index 76c5ca11..00000000 --- a/extractor/filesystem/language/dotnet/packagesconfig/testdata/noversion +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/extractor/filesystem/language/dotnet/packagesconfig/testdata/valid b/extractor/filesystem/language/dotnet/packagesconfig/testdata/valid deleted file mode 100644 index 15bce650..00000000 --- a/extractor/filesystem/language/dotnet/packagesconfig/testdata/valid +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/extractor/filesystem/list/list.go b/extractor/filesystem/list/list.go index 65340226..aa4b1c1a 100644 --- a/extractor/filesystem/list/list.go +++ b/extractor/filesystem/list/list.go @@ -30,7 +30,6 @@ import ( "github.com/google/osv-scalibr/extractor/filesystem/language/cpp/conanlock" "github.com/google/osv-scalibr/extractor/filesystem/language/dart/pubspec" "github.com/google/osv-scalibr/extractor/filesystem/language/dotnet/depsjson" - "github.com/google/osv-scalibr/extractor/filesystem/language/dotnet/packagesconfig" "github.com/google/osv-scalibr/extractor/filesystem/language/dotnet/packageslockjson" "github.com/google/osv-scalibr/extractor/filesystem/language/erlang/mixlock" "github.com/google/osv-scalibr/extractor/filesystem/language/golang/gobinary" @@ -115,7 +114,6 @@ var ( SBOM []filesystem.Extractor = []filesystem.Extractor{&cdx.Extractor{}, &spdx.Extractor{}} // Dotnet (.NET) extractors. Dotnet []filesystem.Extractor = []filesystem.Extractor{ - packagesconfig.New(packagesconfig.DefaultConfig()), depsjson.New(depsjson.DefaultConfig()), packageslockjson.New(packageslockjson.DefaultConfig()), } From 928343d70fafc1d232d5be7351c6d1687eeee9d9 Mon Sep 17 00:00:00 2001 From: Federico Loi Date: Fri, 20 Dec 2024 11:21:58 +0100 Subject: [PATCH 4/4] Add type metadata and fix issues --- binary/proto/proto.go | 9 + binary/proto/proto_test.go | 37 + binary/proto/scan_result.proto | 8 + .../scan_result_go_proto/scan_result.pb.go | 1149 +++++++++-------- .../language/dotnet/depsjson/depsjson.go | 17 +- .../language/dotnet/depsjson/depsjson_test.go | 45 +- .../language/dotnet/depsjson/metadata.go | 22 + 7 files changed, 751 insertions(+), 536 deletions(-) create mode 100644 extractor/filesystem/language/dotnet/depsjson/metadata.go diff --git a/binary/proto/proto.go b/binary/proto/proto.go index b2e705f1..ba6faac5 100644 --- a/binary/proto/proto.go +++ b/binary/proto/proto.go @@ -32,6 +32,7 @@ import ( scalibr "github.com/google/osv-scalibr" "github.com/google/osv-scalibr/extractor" ctrdfs "github.com/google/osv-scalibr/extractor/filesystem/containers/containerd" + "github.com/google/osv-scalibr/extractor/filesystem/language/dotnet/depsjson" "github.com/google/osv-scalibr/extractor/filesystem/language/java/archive" "github.com/google/osv-scalibr/extractor/filesystem/language/java/javalockfile" "github.com/google/osv-scalibr/extractor/filesystem/language/javascript/packagejson" @@ -246,6 +247,14 @@ func setProtoMetadata(meta any, i *spb.Inventory) { Maintainers: personsToProto(m.Maintainers), }, } + case *depsjson.Metadata: + i.Metadata = &spb.Inventory_DepsjsonMetadata{ + DepsjsonMetadata: &spb.DEPSJSONMetadata{ + PackageName: m.PackageName, + PackageVersion: m.PackageVersion, + Type: m.Type, + }, + } case *apk.Metadata: i.Metadata = &spb.Inventory_ApkMetadata{ ApkMetadata: &spb.APKPackageMetadata{ diff --git a/binary/proto/proto_test.go b/binary/proto/proto_test.go index 1a4ed7b9..0cf81dd6 100644 --- a/binary/proto/proto_test.go +++ b/binary/proto/proto_test.go @@ -29,6 +29,7 @@ import ( "github.com/google/osv-scalibr/detector" "github.com/google/osv-scalibr/extractor" ctrdfs "github.com/google/osv-scalibr/extractor/filesystem/containers/containerd" + "github.com/google/osv-scalibr/extractor/filesystem/language/dotnet/depsjson" "github.com/google/osv-scalibr/extractor/filesystem/language/javascript/packagejson" "github.com/google/osv-scalibr/extractor/filesystem/language/python/requirements" "github.com/google/osv-scalibr/extractor/filesystem/language/python/wheelegg" @@ -224,6 +225,40 @@ func TestScanResultToProto(t *testing.T) { Locations: []string{"/file1"}, Extractor: &packagejson.Extractor{}, } + + purlDotnetDepsJsonInventory := &extractor.Inventory{ + Name: "software", + Version: "1.0.0", + Metadata: &depsjson.Metadata{ + PackageName: "software", + PackageVersion: "1.0.0", + Type: "type", + }, + Locations: []string{"/file1"}, + Extractor: &depsjson.Extractor{}, + } + + purlDotnetDepsJsonInventoryProto := &spb.Inventory{ + Name: "software", + Version: "1.0.0", + Purl: &spb.Purl{ + Purl: "pkg:nuget/software@1.0.0", + Type: purl.TypeNuget, + Name: "software", + Version: "1.0.0", + }, + Ecosystem: "NuGet", + Locations: []string{"/file1"}, + Extractor: "dotnet/depsjson", + Metadata: &spb.Inventory_DepsjsonMetadata{ + DepsjsonMetadata: &spb.DEPSJSONMetadata{ + PackageName: "software", + PackageVersion: "1.0.0", + Type: "type", + }, + }, + } + windowsInventory := &extractor.Inventory{ Name: "windows_server_2019", Version: "10.0.17763.3406", @@ -644,6 +679,7 @@ func TestScanResultToProto(t *testing.T) { purlPythonInventory, pythonRequirementsInventory, purlJavascriptInventory, + purlDotnetDepsJsonInventory, cdxInventory, windowsInventory, purlPythonInventoryWithLayerDetails, @@ -696,6 +732,7 @@ func TestScanResultToProto(t *testing.T) { purlPythonInventoryProto, pythonRequirementsInventoryProto, purlJavascriptInventoryProto, + purlDotnetDepsJsonInventoryProto, cdxInventoryProto, windowsInventoryProto, purlPythonInventoryWithLayerDetailsProto, diff --git a/binary/proto/scan_result.proto b/binary/proto/scan_result.proto index 8f0a45f9..89f6e67c 100644 --- a/binary/proto/scan_result.proto +++ b/binary/proto/scan_result.proto @@ -86,6 +86,7 @@ message Inventory { DPKGPackageMetadata dpkg_metadata = 8; RPMPackageMetadata rpm_metadata = 9; COSPackageMetadata cos_metadata = 13; + DEPSJSONMetadata depsjson_metadata = 40; SPDXPackageMetadata spdx_metadata = 14; JavaArchiveMetadata java_archive_metadata = 15; JavaLockfileMetadata java_lockfile_metadata = 31; @@ -290,6 +291,13 @@ message PACMANPackageMetadata { string package_dependencies = 6; } +// The additional data found in .NET deps json packages. +message DEPSJSONMetadata { + string package_name = 1; + string package_version = 2; + string type = 3; +} + // The additional data found in SNAP packages. message SNAPPackageMetadata { string name = 1; diff --git a/binary/proto/scan_result_go_proto/scan_result.pb.go b/binary/proto/scan_result_go_proto/scan_result.pb.go index 6228c241..61a19df4 100644 --- a/binary/proto/scan_result_go_proto/scan_result.pb.go +++ b/binary/proto/scan_result_go_proto/scan_result.pb.go @@ -16,15 +16,15 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.33.0 -// protoc v3.21.1 +// protoc v3.12.4 // source: proto/scan_result.proto package scan_result_go_proto import ( + timestamp "github.com/golang/protobuf/ptypes/timestamp" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" - timestamppb "google.golang.org/protobuf/types/known/timestamppb" reflect "reflect" sync "sync" ) @@ -253,9 +253,9 @@ type ScanResult struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"` - StartTime *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=start_time,json=startTime,proto3" json:"start_time,omitempty"` - EndTime *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=end_time,json=endTime,proto3" json:"end_time,omitempty"` + Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"` + StartTime *timestamp.Timestamp `protobuf:"bytes,2,opt,name=start_time,json=startTime,proto3" json:"start_time,omitempty"` + EndTime *timestamp.Timestamp `protobuf:"bytes,3,opt,name=end_time,json=endTime,proto3" json:"end_time,omitempty"` // Status of the overall scan. Status *ScanStatus `protobuf:"bytes,4,opt,name=status,proto3" json:"status,omitempty"` // Status and versions of the inventory+vuln plugins that ran. @@ -303,14 +303,14 @@ func (x *ScanResult) GetVersion() string { return "" } -func (x *ScanResult) GetStartTime() *timestamppb.Timestamp { +func (x *ScanResult) GetStartTime() *timestamp.Timestamp { if x != nil { return x.StartTime } return nil } -func (x *ScanResult) GetEndTime() *timestamppb.Timestamp { +func (x *ScanResult) GetEndTime() *timestamp.Timestamp { if x != nil { return x.EndTime } @@ -497,6 +497,7 @@ type Inventory struct { // *Inventory_DpkgMetadata // *Inventory_RpmMetadata // *Inventory_CosMetadata + // *Inventory_DepsjsonMetadata // *Inventory_SpdxMetadata // *Inventory_JavaArchiveMetadata // *Inventory_JavaLockfileMetadata @@ -647,6 +648,13 @@ func (x *Inventory) GetCosMetadata() *COSPackageMetadata { return nil } +func (x *Inventory) GetDepsjsonMetadata() *DEPSJSONMetadata { + if x, ok := x.GetMetadata().(*Inventory_DepsjsonMetadata); ok { + return x.DepsjsonMetadata + } + return nil +} + func (x *Inventory) GetSpdxMetadata() *SPDXPackageMetadata { if x, ok := x.GetMetadata().(*Inventory_SpdxMetadata); ok { return x.SpdxMetadata @@ -780,6 +788,10 @@ type Inventory_CosMetadata struct { CosMetadata *COSPackageMetadata `protobuf:"bytes,13,opt,name=cos_metadata,json=cosMetadata,proto3,oneof"` } +type Inventory_DepsjsonMetadata struct { + DepsjsonMetadata *DEPSJSONMetadata `protobuf:"bytes,40,opt,name=depsjson_metadata,json=depsjsonMetadata,proto3,oneof"` +} + type Inventory_SpdxMetadata struct { SpdxMetadata *SPDXPackageMetadata `protobuf:"bytes,14,opt,name=spdx_metadata,json=spdxMetadata,proto3,oneof"` } @@ -844,6 +856,8 @@ func (*Inventory_RpmMetadata) isInventory_Metadata() {} func (*Inventory_CosMetadata) isInventory_Metadata() {} +func (*Inventory_DepsjsonMetadata) isInventory_Metadata() {} + func (*Inventory_SpdxMetadata) isInventory_Metadata() {} func (*Inventory_JavaArchiveMetadata) isInventory_Metadata() {} @@ -2190,6 +2204,70 @@ func (x *PACMANPackageMetadata) GetPackageDependencies() string { return "" } +// The additional data found in .NET deps json packages. +type DEPSJSONMetadata struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + PackageName string `protobuf:"bytes,1,opt,name=package_name,json=packageName,proto3" json:"package_name,omitempty"` + PackageVersion string `protobuf:"bytes,2,opt,name=package_version,json=packageVersion,proto3" json:"package_version,omitempty"` + Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"` +} + +func (x *DEPSJSONMetadata) Reset() { + *x = DEPSJSONMetadata{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_scan_result_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DEPSJSONMetadata) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DEPSJSONMetadata) ProtoMessage() {} + +func (x *DEPSJSONMetadata) ProtoReflect() protoreflect.Message { + mi := &file_proto_scan_result_proto_msgTypes[21] + 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 DEPSJSONMetadata.ProtoReflect.Descriptor instead. +func (*DEPSJSONMetadata) Descriptor() ([]byte, []int) { + return file_proto_scan_result_proto_rawDescGZIP(), []int{21} +} + +func (x *DEPSJSONMetadata) GetPackageName() string { + if x != nil { + return x.PackageName + } + return "" +} + +func (x *DEPSJSONMetadata) GetPackageVersion() string { + if x != nil { + return x.PackageVersion + } + return "" +} + +func (x *DEPSJSONMetadata) GetType() string { + if x != nil { + return x.Type + } + return "" +} + // The additional data found in SNAP packages. type SNAPPackageMetadata struct { state protoimpl.MessageState @@ -2209,7 +2287,7 @@ type SNAPPackageMetadata struct { func (x *SNAPPackageMetadata) Reset() { *x = SNAPPackageMetadata{} if protoimpl.UnsafeEnabled { - mi := &file_proto_scan_result_proto_msgTypes[21] + mi := &file_proto_scan_result_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2222,7 +2300,7 @@ func (x *SNAPPackageMetadata) String() string { func (*SNAPPackageMetadata) ProtoMessage() {} func (x *SNAPPackageMetadata) ProtoReflect() protoreflect.Message { - mi := &file_proto_scan_result_proto_msgTypes[21] + mi := &file_proto_scan_result_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2235,7 +2313,7 @@ func (x *SNAPPackageMetadata) ProtoReflect() protoreflect.Message { // Deprecated: Use SNAPPackageMetadata.ProtoReflect.Descriptor instead. func (*SNAPPackageMetadata) Descriptor() ([]byte, []int) { - return file_proto_scan_result_proto_rawDescGZIP(), []int{21} + return file_proto_scan_result_proto_rawDescGZIP(), []int{22} } func (x *SNAPPackageMetadata) GetName() string { @@ -2314,7 +2392,7 @@ type FlatpakPackageMetadata struct { func (x *FlatpakPackageMetadata) Reset() { *x = FlatpakPackageMetadata{} if protoimpl.UnsafeEnabled { - mi := &file_proto_scan_result_proto_msgTypes[22] + mi := &file_proto_scan_result_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2327,7 +2405,7 @@ func (x *FlatpakPackageMetadata) String() string { func (*FlatpakPackageMetadata) ProtoMessage() {} func (x *FlatpakPackageMetadata) ProtoReflect() protoreflect.Message { - mi := &file_proto_scan_result_proto_msgTypes[22] + mi := &file_proto_scan_result_proto_msgTypes[23] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2340,7 +2418,7 @@ func (x *FlatpakPackageMetadata) ProtoReflect() protoreflect.Message { // Deprecated: Use FlatpakPackageMetadata.ProtoReflect.Descriptor instead. func (*FlatpakPackageMetadata) Descriptor() ([]byte, []int) { - return file_proto_scan_result_proto_rawDescGZIP(), []int{22} + return file_proto_scan_result_proto_rawDescGZIP(), []int{23} } func (x *FlatpakPackageMetadata) GetPackageName() string { @@ -2427,7 +2505,7 @@ type MacAppsMetadata struct { func (x *MacAppsMetadata) Reset() { *x = MacAppsMetadata{} if protoimpl.UnsafeEnabled { - mi := &file_proto_scan_result_proto_msgTypes[23] + mi := &file_proto_scan_result_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2440,7 +2518,7 @@ func (x *MacAppsMetadata) String() string { func (*MacAppsMetadata) ProtoMessage() {} func (x *MacAppsMetadata) ProtoReflect() protoreflect.Message { - mi := &file_proto_scan_result_proto_msgTypes[23] + mi := &file_proto_scan_result_proto_msgTypes[24] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2453,7 +2531,7 @@ func (x *MacAppsMetadata) ProtoReflect() protoreflect.Message { // Deprecated: Use MacAppsMetadata.ProtoReflect.Descriptor instead. func (*MacAppsMetadata) Descriptor() ([]byte, []int) { - return file_proto_scan_result_proto_rawDescGZIP(), []int{23} + return file_proto_scan_result_proto_rawDescGZIP(), []int{24} } func (x *MacAppsMetadata) GetBundleDisplayName() string { @@ -2539,7 +2617,7 @@ type SPDXPackageMetadata struct { func (x *SPDXPackageMetadata) Reset() { *x = SPDXPackageMetadata{} if protoimpl.UnsafeEnabled { - mi := &file_proto_scan_result_proto_msgTypes[24] + mi := &file_proto_scan_result_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2552,7 +2630,7 @@ func (x *SPDXPackageMetadata) String() string { func (*SPDXPackageMetadata) ProtoMessage() {} func (x *SPDXPackageMetadata) ProtoReflect() protoreflect.Message { - mi := &file_proto_scan_result_proto_msgTypes[24] + mi := &file_proto_scan_result_proto_msgTypes[25] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2565,7 +2643,7 @@ func (x *SPDXPackageMetadata) ProtoReflect() protoreflect.Message { // Deprecated: Use SPDXPackageMetadata.ProtoReflect.Descriptor instead. func (*SPDXPackageMetadata) Descriptor() ([]byte, []int) { - return file_proto_scan_result_proto_rawDescGZIP(), []int{24} + return file_proto_scan_result_proto_rawDescGZIP(), []int{25} } func (x *SPDXPackageMetadata) GetPurl() *Purl { @@ -2595,7 +2673,7 @@ type CDXPackageMetadata struct { func (x *CDXPackageMetadata) Reset() { *x = CDXPackageMetadata{} if protoimpl.UnsafeEnabled { - mi := &file_proto_scan_result_proto_msgTypes[25] + mi := &file_proto_scan_result_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2608,7 +2686,7 @@ func (x *CDXPackageMetadata) String() string { func (*CDXPackageMetadata) ProtoMessage() {} func (x *CDXPackageMetadata) ProtoReflect() protoreflect.Message { - mi := &file_proto_scan_result_proto_msgTypes[25] + mi := &file_proto_scan_result_proto_msgTypes[26] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2621,7 +2699,7 @@ func (x *CDXPackageMetadata) ProtoReflect() protoreflect.Message { // Deprecated: Use CDXPackageMetadata.ProtoReflect.Descriptor instead. func (*CDXPackageMetadata) Descriptor() ([]byte, []int) { - return file_proto_scan_result_proto_rawDescGZIP(), []int{25} + return file_proto_scan_result_proto_rawDescGZIP(), []int{26} } func (x *CDXPackageMetadata) GetPurl() *Purl { @@ -2652,7 +2730,7 @@ type JavaArchiveMetadata struct { func (x *JavaArchiveMetadata) Reset() { *x = JavaArchiveMetadata{} if protoimpl.UnsafeEnabled { - mi := &file_proto_scan_result_proto_msgTypes[26] + mi := &file_proto_scan_result_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2665,7 +2743,7 @@ func (x *JavaArchiveMetadata) String() string { func (*JavaArchiveMetadata) ProtoMessage() {} func (x *JavaArchiveMetadata) ProtoReflect() protoreflect.Message { - mi := &file_proto_scan_result_proto_msgTypes[26] + mi := &file_proto_scan_result_proto_msgTypes[27] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2678,7 +2756,7 @@ func (x *JavaArchiveMetadata) ProtoReflect() protoreflect.Message { // Deprecated: Use JavaArchiveMetadata.ProtoReflect.Descriptor instead. func (*JavaArchiveMetadata) Descriptor() ([]byte, []int) { - return file_proto_scan_result_proto_rawDescGZIP(), []int{26} + return file_proto_scan_result_proto_rawDescGZIP(), []int{27} } func (x *JavaArchiveMetadata) GetArtifactId() string { @@ -2716,7 +2794,7 @@ type JavaLockfileMetadata struct { func (x *JavaLockfileMetadata) Reset() { *x = JavaLockfileMetadata{} if protoimpl.UnsafeEnabled { - mi := &file_proto_scan_result_proto_msgTypes[27] + mi := &file_proto_scan_result_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2729,7 +2807,7 @@ func (x *JavaLockfileMetadata) String() string { func (*JavaLockfileMetadata) ProtoMessage() {} func (x *JavaLockfileMetadata) ProtoReflect() protoreflect.Message { - mi := &file_proto_scan_result_proto_msgTypes[27] + mi := &file_proto_scan_result_proto_msgTypes[28] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2742,7 +2820,7 @@ func (x *JavaLockfileMetadata) ProtoReflect() protoreflect.Message { // Deprecated: Use JavaLockfileMetadata.ProtoReflect.Descriptor instead. func (*JavaLockfileMetadata) Descriptor() ([]byte, []int) { - return file_proto_scan_result_proto_rawDescGZIP(), []int{27} + return file_proto_scan_result_proto_rawDescGZIP(), []int{28} } func (x *JavaLockfileMetadata) GetArtifactId() string { @@ -2781,7 +2859,7 @@ type OSVPackageMetadata struct { func (x *OSVPackageMetadata) Reset() { *x = OSVPackageMetadata{} if protoimpl.UnsafeEnabled { - mi := &file_proto_scan_result_proto_msgTypes[28] + mi := &file_proto_scan_result_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2794,7 +2872,7 @@ func (x *OSVPackageMetadata) String() string { func (*OSVPackageMetadata) ProtoMessage() {} func (x *OSVPackageMetadata) ProtoReflect() protoreflect.Message { - mi := &file_proto_scan_result_proto_msgTypes[28] + mi := &file_proto_scan_result_proto_msgTypes[29] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2807,7 +2885,7 @@ func (x *OSVPackageMetadata) ProtoReflect() protoreflect.Message { // Deprecated: Use OSVPackageMetadata.ProtoReflect.Descriptor instead. func (*OSVPackageMetadata) Descriptor() ([]byte, []int) { - return file_proto_scan_result_proto_rawDescGZIP(), []int{28} + return file_proto_scan_result_proto_rawDescGZIP(), []int{29} } func (x *OSVPackageMetadata) GetPurlType() string { @@ -2850,7 +2928,7 @@ type PythonRequirementsMetadata struct { func (x *PythonRequirementsMetadata) Reset() { *x = PythonRequirementsMetadata{} if protoimpl.UnsafeEnabled { - mi := &file_proto_scan_result_proto_msgTypes[29] + mi := &file_proto_scan_result_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2863,7 +2941,7 @@ func (x *PythonRequirementsMetadata) String() string { func (*PythonRequirementsMetadata) ProtoMessage() {} func (x *PythonRequirementsMetadata) ProtoReflect() protoreflect.Message { - mi := &file_proto_scan_result_proto_msgTypes[29] + mi := &file_proto_scan_result_proto_msgTypes[30] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2876,7 +2954,7 @@ func (x *PythonRequirementsMetadata) ProtoReflect() protoreflect.Message { // Deprecated: Use PythonRequirementsMetadata.ProtoReflect.Descriptor instead. func (*PythonRequirementsMetadata) Descriptor() ([]byte, []int) { - return file_proto_scan_result_proto_rawDescGZIP(), []int{29} + return file_proto_scan_result_proto_rawDescGZIP(), []int{30} } func (x *PythonRequirementsMetadata) GetHashCheckingModeValues() []string { @@ -2914,7 +2992,7 @@ type ContainerdContainerMetadata struct { func (x *ContainerdContainerMetadata) Reset() { *x = ContainerdContainerMetadata{} if protoimpl.UnsafeEnabled { - mi := &file_proto_scan_result_proto_msgTypes[30] + mi := &file_proto_scan_result_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2927,7 +3005,7 @@ func (x *ContainerdContainerMetadata) String() string { func (*ContainerdContainerMetadata) ProtoMessage() {} func (x *ContainerdContainerMetadata) ProtoReflect() protoreflect.Message { - mi := &file_proto_scan_result_proto_msgTypes[30] + mi := &file_proto_scan_result_proto_msgTypes[31] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2940,7 +3018,7 @@ func (x *ContainerdContainerMetadata) ProtoReflect() protoreflect.Message { // Deprecated: Use ContainerdContainerMetadata.ProtoReflect.Descriptor instead. func (*ContainerdContainerMetadata) Descriptor() ([]byte, []int) { - return file_proto_scan_result_proto_rawDescGZIP(), []int{30} + return file_proto_scan_result_proto_rawDescGZIP(), []int{31} } func (x *ContainerdContainerMetadata) GetNamespaceName() string { @@ -3037,7 +3115,7 @@ type ContainerdRuntimeContainerMetadata struct { func (x *ContainerdRuntimeContainerMetadata) Reset() { *x = ContainerdRuntimeContainerMetadata{} if protoimpl.UnsafeEnabled { - mi := &file_proto_scan_result_proto_msgTypes[31] + mi := &file_proto_scan_result_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3050,7 +3128,7 @@ func (x *ContainerdRuntimeContainerMetadata) String() string { func (*ContainerdRuntimeContainerMetadata) ProtoMessage() {} func (x *ContainerdRuntimeContainerMetadata) ProtoReflect() protoreflect.Message { - mi := &file_proto_scan_result_proto_msgTypes[31] + mi := &file_proto_scan_result_proto_msgTypes[32] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3063,7 +3141,7 @@ func (x *ContainerdRuntimeContainerMetadata) ProtoReflect() protoreflect.Message // Deprecated: Use ContainerdRuntimeContainerMetadata.ProtoReflect.Descriptor instead. func (*ContainerdRuntimeContainerMetadata) Descriptor() ([]byte, []int) { - return file_proto_scan_result_proto_rawDescGZIP(), []int{31} + return file_proto_scan_result_proto_rawDescGZIP(), []int{32} } func (x *ContainerdRuntimeContainerMetadata) GetNamespaceName() string { @@ -3127,7 +3205,7 @@ type WindowsOSVersion struct { func (x *WindowsOSVersion) Reset() { *x = WindowsOSVersion{} if protoimpl.UnsafeEnabled { - mi := &file_proto_scan_result_proto_msgTypes[32] + mi := &file_proto_scan_result_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3140,7 +3218,7 @@ func (x *WindowsOSVersion) String() string { func (*WindowsOSVersion) ProtoMessage() {} func (x *WindowsOSVersion) ProtoReflect() protoreflect.Message { - mi := &file_proto_scan_result_proto_msgTypes[32] + mi := &file_proto_scan_result_proto_msgTypes[33] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3153,7 +3231,7 @@ func (x *WindowsOSVersion) ProtoReflect() protoreflect.Message { // Deprecated: Use WindowsOSVersion.ProtoReflect.Descriptor instead. func (*WindowsOSVersion) Descriptor() ([]byte, []int) { - return file_proto_scan_result_proto_rawDescGZIP(), []int{32} + return file_proto_scan_result_proto_rawDescGZIP(), []int{33} } func (x *WindowsOSVersion) GetProduct() string { @@ -3219,7 +3297,7 @@ var file_proto_scan_result_proto_rawDesc = []byte{ 0x6f, 0x6e, 0x12, 0x2b, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x53, 0x63, 0x61, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, - 0xf0, 0x0f, 0x0a, 0x09, 0x49, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x12, 0x0a, + 0xba, 0x10, 0x0a, 0x09, 0x49, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3e, 0x0a, 0x0b, 0x73, @@ -3261,429 +3339,441 @@ var file_proto_scan_result_proto_rawDesc = []byte{ 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x43, 0x4f, 0x53, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x0b, 0x63, 0x6f, - 0x73, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x43, 0x0a, 0x0d, 0x73, 0x70, 0x64, - 0x78, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1c, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x53, 0x50, 0x44, 0x58, 0x50, - 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x48, 0x00, - 0x52, 0x0c, 0x73, 0x70, 0x64, 0x78, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x52, - 0x0a, 0x15, 0x6a, 0x61, 0x76, 0x61, 0x5f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x5f, 0x6d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, - 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x4a, 0x61, 0x76, 0x61, 0x41, 0x72, 0x63, 0x68, - 0x69, 0x76, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x13, 0x6a, - 0x61, 0x76, 0x61, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x12, 0x55, 0x0a, 0x16, 0x6a, 0x61, 0x76, 0x61, 0x5f, 0x6c, 0x6f, 0x63, 0x6b, 0x66, - 0x69, 0x6c, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x1f, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x4a, 0x61, 0x76, - 0x61, 0x4c, 0x6f, 0x63, 0x6b, 0x66, 0x69, 0x6c, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x48, 0x00, 0x52, 0x14, 0x6a, 0x61, 0x76, 0x61, 0x4c, 0x6f, 0x63, 0x6b, 0x66, 0x69, 0x6c, - 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x49, 0x0a, 0x0f, 0x70, 0x61, 0x63, - 0x6d, 0x61, 0x6e, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x24, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x50, 0x41, 0x43, - 0x4d, 0x41, 0x4e, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x48, 0x00, 0x52, 0x0e, 0x70, 0x61, 0x63, 0x6d, 0x61, 0x6e, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x12, 0x40, 0x0a, 0x0c, 0x6f, 0x73, 0x76, 0x5f, 0x6d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x73, 0x63, 0x61, - 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x4f, 0x53, 0x56, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x0b, 0x6f, 0x73, 0x76, 0x4d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x67, 0x0a, 0x1c, 0x70, 0x79, 0x74, 0x68, 0x6f, 0x6e, - 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x5f, 0x6d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, - 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x50, 0x79, 0x74, 0x68, 0x6f, 0x6e, 0x52, 0x65, 0x71, - 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x48, 0x00, 0x52, 0x1a, 0x70, 0x79, 0x74, 0x68, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x69, - 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, - 0x6a, 0x0a, 0x1d, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x5f, 0x63, 0x6f, - 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, - 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x61, - 0x69, 0x6e, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x1b, - 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, - 0x6e, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x43, 0x0a, 0x0d, 0x73, - 0x6e, 0x61, 0x70, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x17, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x53, 0x4e, 0x41, - 0x50, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0x48, 0x00, 0x52, 0x0c, 0x73, 0x6e, 0x61, 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0x12, 0x4c, 0x0a, 0x10, 0x66, 0x6c, 0x61, 0x74, 0x70, 0x61, 0x6b, 0x5f, 0x6d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x73, 0x63, 0x61, - 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x46, 0x6c, 0x61, 0x74, 0x70, 0x61, 0x6b, 0x50, 0x61, 0x63, 0x6b, - 0x61, 0x67, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x0f, 0x66, - 0x6c, 0x61, 0x74, 0x70, 0x61, 0x6b, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x46, - 0x0a, 0x11, 0x6d, 0x61, 0x63, 0x5f, 0x61, 0x70, 0x70, 0x73, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x18, 0x22, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x73, 0x63, 0x61, 0x6c, - 0x69, 0x62, 0x72, 0x2e, 0x4d, 0x61, 0x63, 0x41, 0x70, 0x70, 0x73, 0x4d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x0f, 0x6d, 0x61, 0x63, 0x41, 0x70, 0x70, 0x73, 0x4d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x80, 0x01, 0x0a, 0x25, 0x63, 0x6f, 0x6e, 0x74, 0x61, - 0x69, 0x6e, 0x65, 0x72, 0x64, 0x5f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x63, 0x6f, - 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, - 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x52, 0x75, 0x6e, 0x74, 0x69, + 0x73, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x48, 0x0a, 0x11, 0x64, 0x65, 0x70, + 0x73, 0x6a, 0x73, 0x6f, 0x6e, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x28, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x44, + 0x45, 0x50, 0x53, 0x4a, 0x53, 0x4f, 0x4e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x48, + 0x00, 0x52, 0x10, 0x64, 0x65, 0x70, 0x73, 0x6a, 0x73, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x12, 0x43, 0x0a, 0x0d, 0x73, 0x70, 0x64, 0x78, 0x5f, 0x6d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x63, 0x61, + 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x53, 0x50, 0x44, 0x58, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x0c, 0x73, 0x70, 0x64, 0x78, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x52, 0x0a, 0x15, 0x6a, 0x61, 0x76, 0x61, + 0x5f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, + 0x72, 0x2e, 0x4a, 0x61, 0x76, 0x61, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x13, 0x6a, 0x61, 0x76, 0x61, 0x41, 0x72, 0x63, + 0x68, 0x69, 0x76, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x55, 0x0a, 0x16, + 0x6a, 0x61, 0x76, 0x61, 0x5f, 0x6c, 0x6f, 0x63, 0x6b, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x6d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x73, + 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x4a, 0x61, 0x76, 0x61, 0x4c, 0x6f, 0x63, 0x6b, 0x66, + 0x69, 0x6c, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x14, 0x6a, + 0x61, 0x76, 0x61, 0x4c, 0x6f, 0x63, 0x6b, 0x66, 0x69, 0x6c, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x12, 0x49, 0x0a, 0x0f, 0x70, 0x61, 0x63, 0x6d, 0x61, 0x6e, 0x5f, 0x6d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x24, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x73, + 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x50, 0x41, 0x43, 0x4d, 0x41, 0x4e, 0x50, 0x61, 0x63, + 0x6b, 0x61, 0x67, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x0e, + 0x70, 0x61, 0x63, 0x6d, 0x61, 0x6e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x40, + 0x0a, 0x0c, 0x6f, 0x73, 0x76, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x10, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x4f, + 0x53, 0x56, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x48, 0x00, 0x52, 0x0b, 0x6f, 0x73, 0x76, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x12, 0x67, 0x0a, 0x1c, 0x70, 0x79, 0x74, 0x68, 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, + 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, + 0x2e, 0x50, 0x79, 0x74, 0x68, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x73, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x1a, 0x70, + 0x79, 0x74, 0x68, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x73, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x6a, 0x0a, 0x1d, 0x63, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, + 0x72, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x24, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, + 0x69, 0x6e, 0x65, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x1b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, + 0x6e, 0x65, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x43, 0x0a, 0x0d, 0x73, 0x6e, 0x61, 0x70, 0x5f, 0x6d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, + 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x53, 0x4e, 0x41, 0x50, 0x50, 0x61, 0x63, 0x6b, 0x61, + 0x67, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x0c, 0x73, 0x6e, + 0x61, 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x4c, 0x0a, 0x10, 0x66, 0x6c, + 0x61, 0x74, 0x70, 0x61, 0x6b, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x18, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x46, + 0x6c, 0x61, 0x74, 0x70, 0x61, 0x6b, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x0f, 0x66, 0x6c, 0x61, 0x74, 0x70, 0x61, 0x6b, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x46, 0x0a, 0x11, 0x6d, 0x61, 0x63, 0x5f, + 0x61, 0x70, 0x70, 0x73, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x22, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x4d, 0x61, + 0x63, 0x41, 0x70, 0x70, 0x73, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, + 0x0f, 0x6d, 0x61, 0x63, 0x41, 0x70, 0x70, 0x73, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x12, 0x80, 0x01, 0x0a, 0x25, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x5f, + 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, + 0x72, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2b, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, + 0x69, 0x6e, 0x65, 0x72, 0x64, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x74, + 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, + 0x22, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x22, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, - 0x64, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, - 0x72, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x40, 0x0a, 0x0c, 0x63, 0x64, 0x78, - 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1b, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x43, 0x44, 0x58, 0x50, 0x61, 0x63, - 0x6b, 0x61, 0x67, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x0b, - 0x63, 0x64, 0x78, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x5a, 0x0a, 0x1b, 0x77, - 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x5f, 0x6f, 0x73, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x21, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x19, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x57, 0x69, 0x6e, 0x64, 0x6f, - 0x77, 0x73, 0x4f, 0x53, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x18, 0x77, - 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x4f, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x43, 0x0a, 0x0b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x1c, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x21, 0x2e, 0x73, - 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x49, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x79, - 0x2e, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x75, 0x6d, 0x52, - 0x0b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x3a, 0x0a, 0x0d, - 0x6c, 0x61, 0x79, 0x65, 0x72, 0x5f, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x18, 0x23, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x4c, 0x61, - 0x79, 0x65, 0x72, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x0c, 0x6c, 0x61, 0x79, 0x65, - 0x72, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x22, 0x60, 0x0a, 0x0e, 0x41, 0x6e, 0x6e, 0x6f, - 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, - 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x54, - 0x52, 0x41, 0x4e, 0x53, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x41, 0x4c, 0x10, 0x01, 0x12, 0x15, 0x0a, - 0x11, 0x49, 0x4e, 0x53, 0x49, 0x44, 0x45, 0x5f, 0x4f, 0x53, 0x5f, 0x50, 0x41, 0x43, 0x4b, 0x41, - 0x47, 0x45, 0x10, 0x02, 0x12, 0x14, 0x0a, 0x10, 0x49, 0x4e, 0x53, 0x49, 0x44, 0x45, 0x5f, 0x43, - 0x41, 0x43, 0x48, 0x45, 0x5f, 0x44, 0x49, 0x52, 0x10, 0x03, 0x42, 0x0a, 0x0a, 0x08, 0x6d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x4a, 0x04, 0x08, 0x04, - 0x10, 0x05, 0x22, 0x42, 0x0a, 0x14, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x6f, 0x64, 0x65, - 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x65, - 0x70, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x65, 0x70, 0x6f, 0x12, 0x16, - 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x22, 0x7b, 0x0a, 0x0c, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x44, - 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x17, 0x0a, 0x07, - 0x64, 0x69, 0x66, 0x66, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, - 0x69, 0x66, 0x66, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, - 0x22, 0x0a, 0x0d, 0x69, 0x6e, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x69, 0x6d, 0x61, 0x67, 0x65, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x6e, 0x42, 0x61, 0x73, 0x65, 0x49, 0x6d, - 0x61, 0x67, 0x65, 0x22, 0xc8, 0x01, 0x0a, 0x04, 0x50, 0x75, 0x72, 0x6c, 0x12, 0x12, 0x0a, 0x04, - 0x70, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x75, 0x72, 0x6c, - 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x12, 0x32, 0x0a, 0x0a, 0x71, 0x75, 0x61, 0x6c, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x18, 0x06, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x51, - 0x75, 0x61, 0x6c, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0a, 0x71, 0x75, 0x61, 0x6c, 0x69, 0x66, - 0x69, 0x65, 0x72, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x70, 0x61, 0x74, 0x68, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x70, 0x61, 0x74, 0x68, 0x22, 0x33, - 0x0a, 0x09, 0x51, 0x75, 0x61, 0x6c, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x6b, - 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x22, 0x92, 0x01, 0x0a, 0x07, 0x46, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, - 0x23, 0x0a, 0x03, 0x61, 0x64, 0x76, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x73, - 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x41, 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x79, 0x52, - 0x03, 0x61, 0x64, 0x76, 0x12, 0x2e, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x54, - 0x61, 0x72, 0x67, 0x65, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x06, 0x74, 0x61, - 0x72, 0x67, 0x65, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x78, 0x74, 0x72, 0x61, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x78, 0x74, 0x72, 0x61, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x65, - 0x74, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x64, - 0x65, 0x74, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x22, 0xa1, 0x02, 0x0a, 0x08, 0x41, 0x64, 0x76, - 0x69, 0x73, 0x6f, 0x72, 0x79, 0x12, 0x23, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x41, 0x64, 0x76, 0x69, - 0x73, 0x6f, 0x72, 0x79, 0x49, 0x64, 0x52, 0x02, 0x69, 0x64, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x79, - 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, - 0x62, 0x72, 0x2e, 0x41, 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x79, 0x2e, 0x54, 0x79, 0x70, 0x65, - 0x45, 0x6e, 0x75, 0x6d, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, - 0x74, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, - 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x26, 0x0a, 0x0e, 0x72, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x64, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x65, 0x63, 0x6f, - 0x6d, 0x6d, 0x65, 0x6e, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x03, 0x73, 0x65, - 0x76, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, - 0x72, 0x2e, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x52, 0x03, 0x73, 0x65, 0x76, 0x22, - 0x3b, 0x0a, 0x08, 0x54, 0x79, 0x70, 0x65, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x0b, 0x0a, 0x07, 0x55, - 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x56, 0x55, 0x4c, 0x4e, - 0x45, 0x52, 0x41, 0x42, 0x49, 0x4c, 0x49, 0x54, 0x59, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x43, - 0x49, 0x53, 0x5f, 0x46, 0x49, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x22, 0x48, 0x0a, 0x0a, - 0x41, 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x79, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x75, - 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, - 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x66, 0x65, - 0x72, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x66, - 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x22, 0xf1, 0x01, 0x0a, 0x08, 0x53, 0x65, 0x76, 0x65, 0x72, - 0x69, 0x74, 0x79, 0x12, 0x3a, 0x0a, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, - 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x2e, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, - 0x79, 0x45, 0x6e, 0x75, 0x6d, 0x52, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, - 0x26, 0x0a, 0x07, 0x63, 0x76, 0x73, 0x73, 0x5f, 0x76, 0x32, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x0d, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x43, 0x56, 0x53, 0x53, 0x52, - 0x06, 0x63, 0x76, 0x73, 0x73, 0x56, 0x32, 0x12, 0x26, 0x0a, 0x07, 0x63, 0x76, 0x73, 0x73, 0x5f, - 0x76, 0x33, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, - 0x62, 0x72, 0x2e, 0x43, 0x56, 0x53, 0x53, 0x52, 0x06, 0x63, 0x76, 0x73, 0x73, 0x56, 0x33, 0x22, - 0x59, 0x0a, 0x0c, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x45, 0x6e, 0x75, 0x6d, 0x12, - 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, - 0x12, 0x0b, 0x0a, 0x07, 0x4d, 0x49, 0x4e, 0x49, 0x4d, 0x41, 0x4c, 0x10, 0x01, 0x12, 0x07, 0x0a, - 0x03, 0x4c, 0x4f, 0x57, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x4d, 0x45, 0x44, 0x49, 0x55, 0x4d, - 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x49, 0x47, 0x48, 0x10, 0x04, 0x12, 0x0c, 0x0a, 0x08, - 0x43, 0x52, 0x49, 0x54, 0x49, 0x43, 0x41, 0x4c, 0x10, 0x05, 0x22, 0x7d, 0x0a, 0x04, 0x43, 0x56, - 0x53, 0x53, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x6f, 0x72, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x02, 0x52, 0x09, 0x62, 0x61, 0x73, 0x65, 0x53, 0x63, 0x6f, 0x72, - 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x6c, 0x5f, 0x73, 0x63, - 0x6f, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0d, 0x74, 0x65, 0x6d, 0x70, 0x6f, - 0x72, 0x61, 0x6c, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x2f, 0x0a, 0x13, 0x65, 0x6e, 0x76, 0x69, - 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x5f, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x02, 0x52, 0x12, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, - 0x6e, 0x74, 0x61, 0x6c, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x22, 0x5d, 0x0a, 0x0d, 0x54, 0x61, 0x72, - 0x67, 0x65, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x30, 0x0a, 0x09, 0x69, 0x6e, - 0x76, 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, - 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x49, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f, 0x72, - 0x79, 0x52, 0x09, 0x69, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x1a, 0x0a, 0x08, - 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, - 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x52, 0x0a, 0x15, 0x50, 0x79, 0x74, 0x68, - 0x6f, 0x6e, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x06, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x75, 0x74, - 0x68, 0x6f, 0x72, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0b, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x7d, 0x0a, 0x1d, - 0x4a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, - 0x65, 0x4a, 0x53, 0x4f, 0x4e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x16, 0x0a, - 0x06, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, - 0x75, 0x74, 0x68, 0x6f, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x6d, 0x61, 0x69, 0x6e, 0x74, 0x61, 0x69, - 0x6e, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x61, 0x69, 0x6e, - 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x72, - 0x69, 0x62, 0x75, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x63, - 0x6f, 0x6e, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x6f, 0x72, 0x73, 0x22, 0xef, 0x01, 0x0a, 0x12, - 0x41, 0x50, 0x4b, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x5f, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, - 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x72, 0x69, 0x67, - 0x69, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x13, 0x0a, 0x05, 0x6f, 0x73, 0x5f, 0x69, 0x64, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6f, 0x73, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x6f, - 0x73, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, - 0x1e, 0x0a, 0x0a, 0x6d, 0x61, 0x69, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x61, 0x69, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, - 0x22, 0x0a, 0x0c, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, - 0x75, 0x72, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x22, 0xee, 0x02, - 0x0a, 0x13, 0x44, 0x50, 0x4b, 0x47, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, - 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x61, 0x63, - 0x6b, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x61, 0x74, 0x61, 0x12, 0x40, 0x0a, 0x0c, 0x63, 0x64, 0x78, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x73, 0x63, 0x61, 0x6c, + 0x69, 0x62, 0x72, 0x2e, 0x43, 0x44, 0x58, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x0b, 0x63, 0x64, 0x78, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x5a, 0x0a, 0x1b, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, + 0x5f, 0x6f, 0x73, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x18, 0x21, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x63, 0x61, + 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x4f, 0x53, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x18, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, + 0x4f, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x12, 0x43, 0x0a, 0x0b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x18, 0x1c, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x21, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, + 0x2e, 0x49, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x41, 0x6e, 0x6e, 0x6f, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x75, 0x6d, 0x52, 0x0b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x3a, 0x0a, 0x0d, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x5f, + 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x18, 0x23, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, + 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x44, 0x65, 0x74, + 0x61, 0x69, 0x6c, 0x73, 0x52, 0x0c, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x44, 0x65, 0x74, 0x61, 0x69, + 0x6c, 0x73, 0x22, 0x60, 0x0a, 0x0e, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, + 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x49, 0x54, + 0x49, 0x4f, 0x4e, 0x41, 0x4c, 0x10, 0x01, 0x12, 0x15, 0x0a, 0x11, 0x49, 0x4e, 0x53, 0x49, 0x44, + 0x45, 0x5f, 0x4f, 0x53, 0x5f, 0x50, 0x41, 0x43, 0x4b, 0x41, 0x47, 0x45, 0x10, 0x02, 0x12, 0x14, + 0x0a, 0x10, 0x49, 0x4e, 0x53, 0x49, 0x44, 0x45, 0x5f, 0x43, 0x41, 0x43, 0x48, 0x45, 0x5f, 0x44, + 0x49, 0x52, 0x10, 0x03, 0x42, 0x0a, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x22, 0x42, 0x0a, 0x14, + 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x66, 0x69, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x65, 0x70, 0x6f, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x72, 0x65, 0x70, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, + 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, + 0x22, 0x7b, 0x0a, 0x0c, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, + 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x69, 0x66, 0x66, 0x5f, 0x69, + 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x69, 0x66, 0x66, 0x49, 0x64, 0x12, + 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x69, 0x6e, 0x5f, + 0x62, 0x61, 0x73, 0x65, 0x5f, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0b, 0x69, 0x6e, 0x42, 0x61, 0x73, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x22, 0xc8, 0x01, + 0x0a, 0x04, 0x50, 0x75, 0x72, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x75, 0x72, 0x6c, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x75, 0x72, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, + 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x32, 0x0a, 0x0a, 0x71, 0x75, + 0x61, 0x6c, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, + 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x51, 0x75, 0x61, 0x6c, 0x69, 0x66, 0x69, + 0x65, 0x72, 0x52, 0x0a, 0x71, 0x75, 0x61, 0x6c, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x12, 0x18, + 0x0a, 0x07, 0x73, 0x75, 0x62, 0x70, 0x61, 0x74, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x73, 0x75, 0x62, 0x70, 0x61, 0x74, 0x68, 0x22, 0x33, 0x0a, 0x09, 0x51, 0x75, 0x61, 0x6c, + 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x92, 0x01, + 0x0a, 0x07, 0x46, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x23, 0x0a, 0x03, 0x61, 0x64, 0x76, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, + 0x2e, 0x41, 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x79, 0x52, 0x03, 0x61, 0x64, 0x76, 0x12, 0x2e, + 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, + 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x44, + 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x14, + 0x0a, 0x05, 0x65, 0x78, 0x74, 0x72, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, + 0x78, 0x74, 0x72, 0x61, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x6f, 0x72, + 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x6f, + 0x72, 0x73, 0x22, 0xa1, 0x02, 0x0a, 0x08, 0x41, 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x79, 0x12, + 0x23, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x63, + 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x41, 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x79, 0x49, 0x64, + 0x52, 0x02, 0x69, 0x64, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x41, 0x64, 0x76, + 0x69, 0x73, 0x6f, 0x72, 0x79, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x45, 0x6e, 0x75, 0x6d, 0x52, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x0a, 0x0e, + 0x72, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x64, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x03, 0x73, 0x65, 0x76, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x53, 0x65, 0x76, 0x65, + 0x72, 0x69, 0x74, 0x79, 0x52, 0x03, 0x73, 0x65, 0x76, 0x22, 0x3b, 0x0a, 0x08, 0x54, 0x79, 0x70, + 0x65, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, + 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x56, 0x55, 0x4c, 0x4e, 0x45, 0x52, 0x41, 0x42, 0x49, 0x4c, + 0x49, 0x54, 0x59, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x43, 0x49, 0x53, 0x5f, 0x46, 0x49, 0x4e, + 0x44, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x22, 0x48, 0x0a, 0x0a, 0x41, 0x64, 0x76, 0x69, 0x73, 0x6f, + 0x72, 0x79, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, + 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, + 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, + 0x22, 0xf1, 0x01, 0x0a, 0x08, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x3a, 0x0a, + 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x1e, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, + 0x74, 0x79, 0x2e, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x45, 0x6e, 0x75, 0x6d, 0x52, + 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x26, 0x0a, 0x07, 0x63, 0x76, 0x73, + 0x73, 0x5f, 0x76, 0x32, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x73, 0x63, 0x61, + 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x43, 0x56, 0x53, 0x53, 0x52, 0x06, 0x63, 0x76, 0x73, 0x73, 0x56, + 0x32, 0x12, 0x26, 0x0a, 0x07, 0x63, 0x76, 0x73, 0x73, 0x5f, 0x76, 0x33, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x43, 0x56, 0x53, + 0x53, 0x52, 0x06, 0x63, 0x76, 0x73, 0x73, 0x56, 0x33, 0x22, 0x59, 0x0a, 0x0c, 0x53, 0x65, 0x76, + 0x65, 0x72, 0x69, 0x74, 0x79, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, + 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x4d, 0x49, + 0x4e, 0x49, 0x4d, 0x41, 0x4c, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x4c, 0x4f, 0x57, 0x10, 0x02, + 0x12, 0x0a, 0x0a, 0x06, 0x4d, 0x45, 0x44, 0x49, 0x55, 0x4d, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, + 0x48, 0x49, 0x47, 0x48, 0x10, 0x04, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x52, 0x49, 0x54, 0x49, 0x43, + 0x41, 0x4c, 0x10, 0x05, 0x22, 0x7d, 0x0a, 0x04, 0x43, 0x56, 0x53, 0x53, 0x12, 0x1d, 0x0a, 0x0a, + 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x02, + 0x52, 0x09, 0x62, 0x61, 0x73, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x74, + 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x6c, 0x5f, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x02, 0x52, 0x0d, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x6c, 0x53, 0x63, 0x6f, + 0x72, 0x65, 0x12, 0x2f, 0x0a, 0x13, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, + 0x74, 0x61, 0x6c, 0x5f, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x02, 0x52, + 0x12, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x53, 0x63, + 0x6f, 0x72, 0x65, 0x22, 0x5d, 0x0a, 0x0d, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x44, 0x65, 0x74, + 0x61, 0x69, 0x6c, 0x73, 0x12, 0x30, 0x0a, 0x09, 0x69, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f, 0x72, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, + 0x72, 0x2e, 0x49, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x09, 0x69, 0x6e, 0x76, + 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x22, 0x52, 0x0a, 0x15, 0x50, 0x79, 0x74, 0x68, 0x6f, 0x6e, 0x50, 0x61, 0x63, 0x6b, + 0x61, 0x67, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x16, 0x0a, 0x06, 0x61, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x5f, 0x65, 0x6d, + 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x7d, 0x0a, 0x1d, 0x4a, 0x61, 0x76, 0x61, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4a, 0x53, 0x4f, 0x4e, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x12, + 0x20, 0x0a, 0x0b, 0x6d, 0x61, 0x69, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x18, 0x02, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x61, 0x69, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, + 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x6f, 0x72, + 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x69, 0x62, + 0x75, 0x74, 0x6f, 0x72, 0x73, 0x22, 0xef, 0x01, 0x0a, 0x12, 0x41, 0x50, 0x4b, 0x50, 0x61, 0x63, + 0x6b, 0x61, 0x67, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x0c, + 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, + 0x1f, 0x0a, 0x0b, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x4e, 0x61, 0x6d, 0x65, + 0x12, 0x13, 0x0a, 0x05, 0x6f, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x6f, 0x73, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x6f, 0x73, 0x5f, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x73, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x61, 0x69, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, + 0x61, 0x69, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x72, 0x63, + 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0c, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x12, 0x18, 0x0a, + 0x07, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x22, 0xee, 0x02, 0x0a, 0x13, 0x44, 0x50, 0x4b, 0x47, + 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, + 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4e, + 0x61, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x0f, 0x70, 0x61, + 0x63, 0x6b, 0x61, 0x67, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0e, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x12, 0x13, 0x0a, 0x05, 0x6f, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x6f, 0x73, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x6f, 0x73, 0x5f, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x6f, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x43, 0x6f, 0x64, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x6f, 0x73, 0x5f, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x6f, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x0a, + 0x6d, 0x61, 0x69, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0a, 0x6d, 0x61, 0x69, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x22, 0x0a, 0x0c, + 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0c, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, + 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xb4, 0x02, 0x0a, 0x12, 0x52, 0x50, 0x4d, + 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, + 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x72, 0x70, 0x6d, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x70, + 0x6d, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x13, 0x0a, 0x05, 0x6f, 0x73, 0x5f, 0x69, 0x64, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6f, 0x73, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0d, + 0x6f, 0x73, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, + 0x12, 0x1e, 0x0a, 0x0b, 0x6f, 0x73, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x69, 0x64, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x73, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x64, + 0x12, 0x17, 0x0a, 0x07, 0x6f, 0x73, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x6f, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x65, 0x6e, + 0x64, 0x6f, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x76, 0x65, 0x6e, 0x64, 0x6f, + 0x72, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, + 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, + 0x63, 0x74, 0x75, 0x72, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, + 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x22, + 0xa1, 0x01, 0x0a, 0x12, 0x43, 0x4f, 0x53, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, + 0x12, 0x1d, 0x0a, 0x0a, 0x6f, 0x73, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, + 0x22, 0x0a, 0x0d, 0x6f, 0x73, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x49, 0x64, 0x22, 0x80, 0x02, 0x0a, 0x15, 0x50, 0x41, 0x43, 0x4d, 0x41, 0x4e, 0x50, 0x61, + 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x21, 0x0a, + 0x0c, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x70, 0x61, 0x63, 0x6b, 0x61, + 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x13, 0x0a, 0x05, 0x6f, 0x73, 0x5f, - 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6f, 0x73, 0x49, 0x64, 0x12, 0x2e, - 0x0a, 0x13, 0x6f, 0x73, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x64, - 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x6f, 0x73, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x22, + 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6f, 0x73, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x6f, 0x73, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x61, 0x69, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, - 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x61, 0x69, 0x6e, 0x74, 0x61, 0x69, 0x6e, - 0x65, 0x72, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, - 0x72, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, - 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xb4, - 0x02, 0x0a, 0x12, 0x52, 0x50, 0x4d, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, - 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x61, 0x63, - 0x6b, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x5f, 0x72, 0x70, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x52, 0x70, 0x6d, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x13, 0x0a, - 0x05, 0x6f, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6f, 0x73, - 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x6f, 0x73, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x73, 0x56, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x0b, 0x6f, 0x73, 0x5f, 0x62, 0x75, 0x69, - 0x6c, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x73, 0x42, - 0x75, 0x69, 0x6c, 0x64, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x6f, 0x73, 0x5f, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x12, - 0x16, 0x0a, 0x06, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x72, 0x63, 0x68, 0x69, - 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x61, - 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6c, - 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6c, 0x69, - 0x63, 0x65, 0x6e, 0x73, 0x65, 0x22, 0xa1, 0x01, 0x0a, 0x12, 0x43, 0x4f, 0x53, 0x50, 0x61, 0x63, - 0x6b, 0x61, 0x67, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x61, - 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x61, - 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x6f, 0x73, 0x5f, 0x76, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x73, 0x56, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0d, 0x6f, 0x73, 0x5f, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x73, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x80, 0x02, 0x0a, 0x15, 0x50, 0x41, - 0x43, 0x4d, 0x41, 0x4e, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x61, 0x63, 0x6b, 0x61, - 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, - 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x49, 0x64, 0x12, 0x2f, 0x0a, 0x13, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x5f, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x12, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x31, 0x0a, 0x14, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x5f, 0x64, + 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x13, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, + 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x22, 0x72, 0x0a, 0x10, 0x44, 0x45, 0x50, 0x53, 0x4a, 0x53, + 0x4f, 0x4e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, + 0x63, 0x6b, 0x61, 0x67, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x27, 0x0a, + 0x0f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0xfc, 0x01, 0x0a, 0x13, 0x53, + 0x4e, 0x41, 0x50, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x12, 0x14, 0x0a, 0x05, 0x67, 0x72, 0x61, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x67, 0x72, 0x61, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x61, 0x72, + 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x0d, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x73, + 0x12, 0x13, 0x0a, 0x05, 0x6f, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x6f, 0x73, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x6f, 0x73, 0x5f, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x11, 0x6f, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, + 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x6f, 0x73, 0x5f, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x73, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0xb6, 0x02, 0x0a, 0x16, 0x46, 0x6c, + 0x61, 0x74, 0x70, 0x61, 0x6b, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x61, 0x63, 0x6b, + 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x63, 0x6b, 0x61, + 0x67, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x63, + 0x6b, 0x61, 0x67, 0x65, 0x49, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, + 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, - 0x13, 0x0a, 0x05, 0x6f, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x6f, 0x73, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x6f, 0x73, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x73, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x2f, 0x0a, 0x13, 0x70, 0x61, 0x63, 0x6b, - 0x61, 0x67, 0x65, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x44, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x31, 0x0a, 0x14, 0x70, 0x61, 0x63, - 0x6b, 0x61, 0x67, 0x65, 0x5f, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, - 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, - 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x22, 0xfc, 0x01, 0x0a, - 0x13, 0x53, 0x4e, 0x41, 0x50, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x67, 0x72, 0x61, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x67, 0x72, 0x61, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x0d, - 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x05, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x0d, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, - 0x65, 0x73, 0x12, 0x13, 0x0a, 0x05, 0x6f, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x6f, 0x73, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x6f, 0x73, 0x5f, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x6f, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x43, - 0x6f, 0x64, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x6f, 0x73, 0x5f, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, - 0x6f, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0xb6, 0x02, 0x0a, 0x16, - 0x46, 0x6c, 0x61, 0x74, 0x70, 0x61, 0x6b, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, - 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x61, - 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x63, - 0x6b, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, - 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x49, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x70, 0x61, 0x63, 0x6b, - 0x61, 0x67, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0e, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x64, 0x61, 0x74, - 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, - 0x44, 0x61, 0x74, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x6f, 0x73, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x13, 0x0a, - 0x05, 0x6f, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6f, 0x73, - 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x6f, 0x73, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x73, 0x56, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x0b, 0x6f, 0x73, 0x5f, 0x62, 0x75, 0x69, - 0x6c, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x73, 0x42, - 0x75, 0x69, 0x6c, 0x64, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x6f, - 0x70, 0x65, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x64, 0x65, 0x76, 0x65, 0x6c, - 0x6f, 0x70, 0x65, 0x72, 0x22, 0xbb, 0x03, 0x0a, 0x0f, 0x4d, 0x61, 0x63, 0x41, 0x70, 0x70, 0x73, - 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x2e, 0x0a, 0x13, 0x62, 0x75, 0x6e, 0x64, - 0x6c, 0x65, 0x5f, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x44, 0x69, 0x73, - 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2b, 0x0a, 0x11, 0x62, 0x75, 0x6e, 0x64, - 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x10, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x3d, 0x0a, 0x1b, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x5f, - 0x73, 0x68, 0x6f, 0x72, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, - 0x72, 0x69, 0x6e, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x18, 0x62, 0x75, 0x6e, 0x64, - 0x6c, 0x65, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x74, - 0x72, 0x69, 0x6e, 0x67, 0x12, 0x2b, 0x0a, 0x11, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x5f, 0x65, - 0x78, 0x65, 0x63, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x10, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x61, 0x62, 0x6c, - 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x4e, 0x61, - 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x13, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x63, - 0x6b, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x11, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x54, 0x79, - 0x70, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x5f, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x62, 0x75, - 0x6e, 0x64, 0x6c, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x25, 0x0a, - 0x0e, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x56, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x5f, - 0x69, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, - 0x74, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x75, 0x72, - 0x6c, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, - 0x72, 0x6c, 0x22, 0x4c, 0x0a, 0x13, 0x53, 0x50, 0x44, 0x58, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, - 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x04, 0x70, 0x75, 0x72, - 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, - 0x72, 0x2e, 0x50, 0x75, 0x72, 0x6c, 0x52, 0x04, 0x70, 0x75, 0x72, 0x6c, 0x12, 0x12, 0x0a, 0x04, - 0x63, 0x70, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x63, 0x70, 0x65, 0x73, - 0x22, 0x4b, 0x0a, 0x12, 0x43, 0x44, 0x58, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x04, 0x70, 0x75, 0x72, 0x6c, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x50, - 0x75, 0x72, 0x6c, 0x52, 0x04, 0x70, 0x75, 0x72, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x70, 0x65, - 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x63, 0x70, 0x65, 0x73, 0x22, 0x65, 0x0a, - 0x13, 0x4a, 0x61, 0x76, 0x61, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, - 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x72, 0x74, 0x69, 0x66, - 0x61, 0x63, 0x74, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x69, - 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, - 0x12, 0x12, 0x0a, 0x04, 0x73, 0x68, 0x61, 0x31, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x73, 0x68, 0x61, 0x31, 0x22, 0x78, 0x0a, 0x14, 0x4a, 0x61, 0x76, 0x61, 0x4c, 0x6f, 0x63, 0x6b, - 0x66, 0x69, 0x6c, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1f, 0x0a, 0x0b, - 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0a, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x49, 0x64, 0x12, 0x19, 0x0a, - 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x64, 0x65, 0x70, 0x5f, - 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, - 0x52, 0x0c, 0x64, 0x65, 0x70, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x61, 0x6c, 0x73, 0x22, 0x86, - 0x01, 0x0a, 0x12, 0x4f, 0x53, 0x56, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x75, 0x72, 0x6c, 0x5f, 0x74, 0x79, - 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x75, 0x72, 0x6c, 0x54, 0x79, - 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x63, - 0x6f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x65, - 0x63, 0x6f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x70, - 0x61, 0x72, 0x65, 0x5f, 0x61, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, - 0x6d, 0x70, 0x61, 0x72, 0x65, 0x41, 0x73, 0x22, 0x86, 0x01, 0x0a, 0x1a, 0x50, 0x79, 0x74, 0x68, - 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x4d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x39, 0x0a, 0x19, 0x68, 0x61, 0x73, 0x68, 0x5f, 0x63, - 0x68, 0x65, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x5f, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x16, 0x68, 0x61, 0x73, 0x68, 0x43, - 0x68, 0x65, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x73, 0x12, 0x2d, 0x0a, 0x12, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6d, - 0x70, 0x61, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x61, 0x74, 0x6f, 0x72, - 0x22, 0xdc, 0x02, 0x0a, 0x1b, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x43, - 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0x12, 0x25, 0x0a, 0x0e, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, - 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6d, 0x61, - 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x5f, - 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x69, 0x6d, - 0x61, 0x67, 0x65, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x75, 0x6e, - 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x75, 0x6e, 0x74, - 0x69, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x03, 0x70, 0x69, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, - 0x74, 0x74, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x6e, 0x61, 0x70, - 0x73, 0x68, 0x6f, 0x74, 0x74, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x6e, 0x61, 0x70, 0x73, - 0x68, 0x6f, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, - 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x6f, - 0x77, 0x65, 0x72, 0x5f, 0x64, 0x69, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, - 0x6f, 0x77, 0x65, 0x72, 0x44, 0x69, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x75, 0x70, 0x70, 0x65, 0x72, - 0x5f, 0x64, 0x69, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x70, 0x70, 0x65, - 0x72, 0x44, 0x69, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x64, 0x69, 0x72, - 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x77, 0x6f, 0x72, 0x6b, 0x44, 0x69, 0x72, 0x12, - 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, - 0xea, 0x01, 0x0a, 0x22, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x52, 0x75, - 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x25, 0x0a, 0x0e, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, - 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, - 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, - 0x69, 0x6d, 0x61, 0x67, 0x65, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0b, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, - 0x18, 0x0a, 0x07, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x70, 0x69, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x72, - 0x6f, 0x6f, 0x74, 0x66, 0x73, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0a, 0x72, 0x6f, 0x6f, 0x74, 0x66, 0x73, 0x50, 0x61, 0x74, 0x68, 0x22, 0x4f, 0x0a, 0x10, - 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x4f, 0x53, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x75, - 0x6c, 0x6c, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0b, 0x66, 0x75, 0x6c, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x3f, 0x50, - 0x01, 0x5a, 0x3b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2f, 0x62, 0x69, 0x6e, - 0x61, 0x72, 0x79, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x73, 0x63, 0x61, 0x6e, 0x5f, 0x72, - 0x65, 0x73, 0x75, 0x6c, 0x74, 0x5f, 0x67, 0x6f, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x21, 0x0a, 0x0c, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x44, 0x61, + 0x74, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x6f, 0x73, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x13, 0x0a, 0x05, 0x6f, + 0x73, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6f, 0x73, 0x49, 0x64, + 0x12, 0x22, 0x0a, 0x0d, 0x6f, 0x73, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, + 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x0b, 0x6f, 0x73, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, + 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x73, 0x42, 0x75, 0x69, + 0x6c, 0x64, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, + 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, + 0x65, 0x72, 0x22, 0xbb, 0x03, 0x0a, 0x0f, 0x4d, 0x61, 0x63, 0x41, 0x70, 0x70, 0x73, 0x4d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x2e, 0x0a, 0x13, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, + 0x5f, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x11, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x44, 0x69, 0x73, 0x70, 0x6c, + 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2b, 0x0a, 0x11, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, + 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x10, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, + 0x69, 0x65, 0x72, 0x12, 0x3d, 0x0a, 0x1b, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x5f, 0x73, 0x68, + 0x6f, 0x72, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x18, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, + 0x53, 0x68, 0x6f, 0x72, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x12, 0x2b, 0x0a, 0x11, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x5f, 0x65, 0x78, 0x65, + 0x63, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x62, + 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x12, + 0x1f, 0x0a, 0x0b, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, + 0x12, 0x2e, 0x0a, 0x13, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x61, + 0x67, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x62, + 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x29, 0x0a, 0x10, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x74, 0x75, 0x72, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x62, 0x75, 0x6e, 0x64, + 0x6c, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x62, + 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0d, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x5f, 0x69, 0x64, + 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, + 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, + 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x72, 0x6c, + 0x22, 0x4c, 0x0a, 0x13, 0x53, 0x50, 0x44, 0x58, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x04, 0x70, 0x75, 0x72, 0x6c, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, + 0x50, 0x75, 0x72, 0x6c, 0x52, 0x04, 0x70, 0x75, 0x72, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x70, + 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x63, 0x70, 0x65, 0x73, 0x22, 0x4b, + 0x0a, 0x12, 0x43, 0x44, 0x58, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x04, 0x70, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2e, 0x50, 0x75, 0x72, + 0x6c, 0x52, 0x04, 0x70, 0x75, 0x72, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x70, 0x65, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x63, 0x70, 0x65, 0x73, 0x22, 0x65, 0x0a, 0x13, 0x4a, + 0x61, 0x76, 0x61, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x5f, 0x69, + 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, + 0x74, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12, 0x12, + 0x0a, 0x04, 0x73, 0x68, 0x61, 0x31, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x73, 0x68, + 0x61, 0x31, 0x22, 0x78, 0x0a, 0x14, 0x4a, 0x61, 0x76, 0x61, 0x4c, 0x6f, 0x63, 0x6b, 0x66, 0x69, + 0x6c, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x72, + 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0a, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x67, + 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x67, + 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x64, 0x65, 0x70, 0x5f, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, + 0x64, 0x65, 0x70, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x61, 0x6c, 0x73, 0x22, 0x86, 0x01, 0x0a, + 0x12, 0x4f, 0x53, 0x56, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x75, 0x72, 0x6c, 0x5f, 0x74, 0x79, 0x70, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x75, 0x72, 0x6c, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x63, 0x6f, 0x73, + 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x65, 0x63, 0x6f, + 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, + 0x65, 0x5f, 0x61, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6d, 0x70, + 0x61, 0x72, 0x65, 0x41, 0x73, 0x22, 0x86, 0x01, 0x0a, 0x1a, 0x50, 0x79, 0x74, 0x68, 0x6f, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x12, 0x39, 0x0a, 0x19, 0x68, 0x61, 0x73, 0x68, 0x5f, 0x63, 0x68, 0x65, + 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x16, 0x68, 0x61, 0x73, 0x68, 0x43, 0x68, 0x65, + 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, + 0x2d, 0x0a, 0x12, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, + 0x72, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x22, 0xdc, + 0x02, 0x0a, 0x1b, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x43, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x25, + 0x0a, 0x0e, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6d, 0x61, 0x67, 0x65, + 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x5f, 0x64, 0x69, + 0x67, 0x65, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x69, 0x6d, 0x61, 0x67, + 0x65, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x75, 0x6e, 0x74, 0x69, + 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, + 0x65, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, + 0x70, 0x69, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x74, + 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, + 0x6f, 0x74, 0x74, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, + 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x6e, 0x61, + 0x70, 0x73, 0x68, 0x6f, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x6f, 0x77, 0x65, + 0x72, 0x5f, 0x64, 0x69, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x77, + 0x65, 0x72, 0x44, 0x69, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x75, 0x70, 0x70, 0x65, 0x72, 0x5f, 0x64, + 0x69, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x70, 0x70, 0x65, 0x72, 0x44, + 0x69, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x64, 0x69, 0x72, 0x18, 0x0a, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x77, 0x6f, 0x72, 0x6b, 0x44, 0x69, 0x72, 0x12, 0x0e, 0x0a, + 0x02, 0x69, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0xea, 0x01, + 0x0a, 0x22, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x52, 0x75, 0x6e, 0x74, + 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x12, 0x25, 0x0a, 0x0e, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x61, + 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x69, + 0x6d, 0x61, 0x67, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6d, + 0x61, 0x67, 0x65, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, + 0x07, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x70, 0x69, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x6f, 0x6f, + 0x74, 0x66, 0x73, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, + 0x72, 0x6f, 0x6f, 0x74, 0x66, 0x73, 0x50, 0x61, 0x74, 0x68, 0x22, 0x4f, 0x0a, 0x10, 0x57, 0x69, + 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x4f, 0x53, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, + 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x75, 0x6c, 0x6c, + 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x66, 0x75, 0x6c, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x3f, 0x50, 0x01, 0x5a, + 0x3b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2f, 0x73, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x2f, 0x62, 0x69, 0x6e, 0x61, 0x72, + 0x79, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x73, 0x63, 0x61, 0x6e, 0x5f, 0x72, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x5f, 0x67, 0x6f, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -3699,7 +3789,7 @@ func file_proto_scan_result_proto_rawDescGZIP() []byte { } var file_proto_scan_result_proto_enumTypes = make([]protoimpl.EnumInfo, 4) -var file_proto_scan_result_proto_msgTypes = make([]protoimpl.MessageInfo, 33) +var file_proto_scan_result_proto_msgTypes = make([]protoimpl.MessageInfo, 34) var file_proto_scan_result_proto_goTypes = []interface{}{ (ScanStatus_ScanStatusEnum)(0), // 0: scalibr.ScanStatus.ScanStatusEnum (Inventory_AnnotationEnum)(0), // 1: scalibr.Inventory.AnnotationEnum @@ -3726,23 +3816,24 @@ var file_proto_scan_result_proto_goTypes = []interface{}{ (*RPMPackageMetadata)(nil), // 22: scalibr.RPMPackageMetadata (*COSPackageMetadata)(nil), // 23: scalibr.COSPackageMetadata (*PACMANPackageMetadata)(nil), // 24: scalibr.PACMANPackageMetadata - (*SNAPPackageMetadata)(nil), // 25: scalibr.SNAPPackageMetadata - (*FlatpakPackageMetadata)(nil), // 26: scalibr.FlatpakPackageMetadata - (*MacAppsMetadata)(nil), // 27: scalibr.MacAppsMetadata - (*SPDXPackageMetadata)(nil), // 28: scalibr.SPDXPackageMetadata - (*CDXPackageMetadata)(nil), // 29: scalibr.CDXPackageMetadata - (*JavaArchiveMetadata)(nil), // 30: scalibr.JavaArchiveMetadata - (*JavaLockfileMetadata)(nil), // 31: scalibr.JavaLockfileMetadata - (*OSVPackageMetadata)(nil), // 32: scalibr.OSVPackageMetadata - (*PythonRequirementsMetadata)(nil), // 33: scalibr.PythonRequirementsMetadata - (*ContainerdContainerMetadata)(nil), // 34: scalibr.ContainerdContainerMetadata - (*ContainerdRuntimeContainerMetadata)(nil), // 35: scalibr.ContainerdRuntimeContainerMetadata - (*WindowsOSVersion)(nil), // 36: scalibr.WindowsOSVersion - (*timestamppb.Timestamp)(nil), // 37: google.protobuf.Timestamp + (*DEPSJSONMetadata)(nil), // 25: scalibr.DEPSJSONMetadata + (*SNAPPackageMetadata)(nil), // 26: scalibr.SNAPPackageMetadata + (*FlatpakPackageMetadata)(nil), // 27: scalibr.FlatpakPackageMetadata + (*MacAppsMetadata)(nil), // 28: scalibr.MacAppsMetadata + (*SPDXPackageMetadata)(nil), // 29: scalibr.SPDXPackageMetadata + (*CDXPackageMetadata)(nil), // 30: scalibr.CDXPackageMetadata + (*JavaArchiveMetadata)(nil), // 31: scalibr.JavaArchiveMetadata + (*JavaLockfileMetadata)(nil), // 32: scalibr.JavaLockfileMetadata + (*OSVPackageMetadata)(nil), // 33: scalibr.OSVPackageMetadata + (*PythonRequirementsMetadata)(nil), // 34: scalibr.PythonRequirementsMetadata + (*ContainerdContainerMetadata)(nil), // 35: scalibr.ContainerdContainerMetadata + (*ContainerdRuntimeContainerMetadata)(nil), // 36: scalibr.ContainerdRuntimeContainerMetadata + (*WindowsOSVersion)(nil), // 37: scalibr.WindowsOSVersion + (*timestamp.Timestamp)(nil), // 38: google.protobuf.Timestamp } var file_proto_scan_result_proto_depIdxs = []int32{ - 37, // 0: scalibr.ScanResult.start_time:type_name -> google.protobuf.Timestamp - 37, // 1: scalibr.ScanResult.end_time:type_name -> google.protobuf.Timestamp + 38, // 0: scalibr.ScanResult.start_time:type_name -> google.protobuf.Timestamp + 38, // 1: scalibr.ScanResult.end_time:type_name -> google.protobuf.Timestamp 5, // 2: scalibr.ScanResult.status:type_name -> scalibr.ScanStatus 6, // 3: scalibr.ScanResult.plugin_status:type_name -> scalibr.PluginStatus 7, // 4: scalibr.ScanResult.inventories:type_name -> scalibr.Inventory @@ -3757,38 +3848,39 @@ var file_proto_scan_result_proto_depIdxs = []int32{ 21, // 13: scalibr.Inventory.dpkg_metadata:type_name -> scalibr.DPKGPackageMetadata 22, // 14: scalibr.Inventory.rpm_metadata:type_name -> scalibr.RPMPackageMetadata 23, // 15: scalibr.Inventory.cos_metadata:type_name -> scalibr.COSPackageMetadata - 28, // 16: scalibr.Inventory.spdx_metadata:type_name -> scalibr.SPDXPackageMetadata - 30, // 17: scalibr.Inventory.java_archive_metadata:type_name -> scalibr.JavaArchiveMetadata - 31, // 18: scalibr.Inventory.java_lockfile_metadata:type_name -> scalibr.JavaLockfileMetadata - 24, // 19: scalibr.Inventory.pacman_metadata:type_name -> scalibr.PACMANPackageMetadata - 32, // 20: scalibr.Inventory.osv_metadata:type_name -> scalibr.OSVPackageMetadata - 33, // 21: scalibr.Inventory.python_requirements_metadata:type_name -> scalibr.PythonRequirementsMetadata - 34, // 22: scalibr.Inventory.containerd_container_metadata:type_name -> scalibr.ContainerdContainerMetadata - 25, // 23: scalibr.Inventory.snap_metadata:type_name -> scalibr.SNAPPackageMetadata - 26, // 24: scalibr.Inventory.flatpak_metadata:type_name -> scalibr.FlatpakPackageMetadata - 27, // 25: scalibr.Inventory.mac_apps_metadata:type_name -> scalibr.MacAppsMetadata - 35, // 26: scalibr.Inventory.containerd_runtime_container_metadata:type_name -> scalibr.ContainerdRuntimeContainerMetadata - 29, // 27: scalibr.Inventory.cdx_metadata:type_name -> scalibr.CDXPackageMetadata - 36, // 28: scalibr.Inventory.windows_os_version_metadata:type_name -> scalibr.WindowsOSVersion - 1, // 29: scalibr.Inventory.annotations:type_name -> scalibr.Inventory.AnnotationEnum - 9, // 30: scalibr.Inventory.layer_details:type_name -> scalibr.LayerDetails - 11, // 31: scalibr.Purl.qualifiers:type_name -> scalibr.Qualifier - 13, // 32: scalibr.Finding.adv:type_name -> scalibr.Advisory - 17, // 33: scalibr.Finding.target:type_name -> scalibr.TargetDetails - 14, // 34: scalibr.Advisory.id:type_name -> scalibr.AdvisoryId - 2, // 35: scalibr.Advisory.type:type_name -> scalibr.Advisory.TypeEnum - 15, // 36: scalibr.Advisory.sev:type_name -> scalibr.Severity - 3, // 37: scalibr.Severity.severity:type_name -> scalibr.Severity.SeverityEnum - 16, // 38: scalibr.Severity.cvss_v2:type_name -> scalibr.CVSS - 16, // 39: scalibr.Severity.cvss_v3:type_name -> scalibr.CVSS - 7, // 40: scalibr.TargetDetails.inventory:type_name -> scalibr.Inventory - 10, // 41: scalibr.SPDXPackageMetadata.purl:type_name -> scalibr.Purl - 10, // 42: scalibr.CDXPackageMetadata.purl:type_name -> scalibr.Purl - 43, // [43:43] is the sub-list for method output_type - 43, // [43:43] is the sub-list for method input_type - 43, // [43:43] is the sub-list for extension type_name - 43, // [43:43] is the sub-list for extension extendee - 0, // [0:43] is the sub-list for field type_name + 25, // 16: scalibr.Inventory.depsjson_metadata:type_name -> scalibr.DEPSJSONMetadata + 29, // 17: scalibr.Inventory.spdx_metadata:type_name -> scalibr.SPDXPackageMetadata + 31, // 18: scalibr.Inventory.java_archive_metadata:type_name -> scalibr.JavaArchiveMetadata + 32, // 19: scalibr.Inventory.java_lockfile_metadata:type_name -> scalibr.JavaLockfileMetadata + 24, // 20: scalibr.Inventory.pacman_metadata:type_name -> scalibr.PACMANPackageMetadata + 33, // 21: scalibr.Inventory.osv_metadata:type_name -> scalibr.OSVPackageMetadata + 34, // 22: scalibr.Inventory.python_requirements_metadata:type_name -> scalibr.PythonRequirementsMetadata + 35, // 23: scalibr.Inventory.containerd_container_metadata:type_name -> scalibr.ContainerdContainerMetadata + 26, // 24: scalibr.Inventory.snap_metadata:type_name -> scalibr.SNAPPackageMetadata + 27, // 25: scalibr.Inventory.flatpak_metadata:type_name -> scalibr.FlatpakPackageMetadata + 28, // 26: scalibr.Inventory.mac_apps_metadata:type_name -> scalibr.MacAppsMetadata + 36, // 27: scalibr.Inventory.containerd_runtime_container_metadata:type_name -> scalibr.ContainerdRuntimeContainerMetadata + 30, // 28: scalibr.Inventory.cdx_metadata:type_name -> scalibr.CDXPackageMetadata + 37, // 29: scalibr.Inventory.windows_os_version_metadata:type_name -> scalibr.WindowsOSVersion + 1, // 30: scalibr.Inventory.annotations:type_name -> scalibr.Inventory.AnnotationEnum + 9, // 31: scalibr.Inventory.layer_details:type_name -> scalibr.LayerDetails + 11, // 32: scalibr.Purl.qualifiers:type_name -> scalibr.Qualifier + 13, // 33: scalibr.Finding.adv:type_name -> scalibr.Advisory + 17, // 34: scalibr.Finding.target:type_name -> scalibr.TargetDetails + 14, // 35: scalibr.Advisory.id:type_name -> scalibr.AdvisoryId + 2, // 36: scalibr.Advisory.type:type_name -> scalibr.Advisory.TypeEnum + 15, // 37: scalibr.Advisory.sev:type_name -> scalibr.Severity + 3, // 38: scalibr.Severity.severity:type_name -> scalibr.Severity.SeverityEnum + 16, // 39: scalibr.Severity.cvss_v2:type_name -> scalibr.CVSS + 16, // 40: scalibr.Severity.cvss_v3:type_name -> scalibr.CVSS + 7, // 41: scalibr.TargetDetails.inventory:type_name -> scalibr.Inventory + 10, // 42: scalibr.SPDXPackageMetadata.purl:type_name -> scalibr.Purl + 10, // 43: scalibr.CDXPackageMetadata.purl:type_name -> scalibr.Purl + 44, // [44:44] is the sub-list for method output_type + 44, // [44:44] is the sub-list for method input_type + 44, // [44:44] is the sub-list for extension type_name + 44, // [44:44] is the sub-list for extension extendee + 0, // [0:44] is the sub-list for field type_name } func init() { file_proto_scan_result_proto_init() } @@ -4050,7 +4142,7 @@ func file_proto_scan_result_proto_init() { } } file_proto_scan_result_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SNAPPackageMetadata); i { + switch v := v.(*DEPSJSONMetadata); i { case 0: return &v.state case 1: @@ -4062,7 +4154,7 @@ func file_proto_scan_result_proto_init() { } } file_proto_scan_result_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FlatpakPackageMetadata); i { + switch v := v.(*SNAPPackageMetadata); i { case 0: return &v.state case 1: @@ -4074,7 +4166,7 @@ func file_proto_scan_result_proto_init() { } } file_proto_scan_result_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MacAppsMetadata); i { + switch v := v.(*FlatpakPackageMetadata); i { case 0: return &v.state case 1: @@ -4086,7 +4178,7 @@ func file_proto_scan_result_proto_init() { } } file_proto_scan_result_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SPDXPackageMetadata); i { + switch v := v.(*MacAppsMetadata); i { case 0: return &v.state case 1: @@ -4098,7 +4190,7 @@ func file_proto_scan_result_proto_init() { } } file_proto_scan_result_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CDXPackageMetadata); i { + switch v := v.(*SPDXPackageMetadata); i { case 0: return &v.state case 1: @@ -4110,7 +4202,7 @@ func file_proto_scan_result_proto_init() { } } file_proto_scan_result_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JavaArchiveMetadata); i { + switch v := v.(*CDXPackageMetadata); i { case 0: return &v.state case 1: @@ -4122,7 +4214,7 @@ func file_proto_scan_result_proto_init() { } } file_proto_scan_result_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JavaLockfileMetadata); i { + switch v := v.(*JavaArchiveMetadata); i { case 0: return &v.state case 1: @@ -4134,7 +4226,7 @@ func file_proto_scan_result_proto_init() { } } file_proto_scan_result_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*OSVPackageMetadata); i { + switch v := v.(*JavaLockfileMetadata); i { case 0: return &v.state case 1: @@ -4146,7 +4238,7 @@ func file_proto_scan_result_proto_init() { } } file_proto_scan_result_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PythonRequirementsMetadata); i { + switch v := v.(*OSVPackageMetadata); i { case 0: return &v.state case 1: @@ -4158,7 +4250,7 @@ func file_proto_scan_result_proto_init() { } } file_proto_scan_result_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ContainerdContainerMetadata); i { + switch v := v.(*PythonRequirementsMetadata); i { case 0: return &v.state case 1: @@ -4170,7 +4262,7 @@ func file_proto_scan_result_proto_init() { } } file_proto_scan_result_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ContainerdRuntimeContainerMetadata); i { + switch v := v.(*ContainerdContainerMetadata); i { case 0: return &v.state case 1: @@ -4182,6 +4274,18 @@ func file_proto_scan_result_proto_init() { } } file_proto_scan_result_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ContainerdRuntimeContainerMetadata); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_scan_result_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*WindowsOSVersion); i { case 0: return &v.state @@ -4201,6 +4305,7 @@ func file_proto_scan_result_proto_init() { (*Inventory_DpkgMetadata)(nil), (*Inventory_RpmMetadata)(nil), (*Inventory_CosMetadata)(nil), + (*Inventory_DepsjsonMetadata)(nil), (*Inventory_SpdxMetadata)(nil), (*Inventory_JavaArchiveMetadata)(nil), (*Inventory_JavaLockfileMetadata)(nil), @@ -4221,7 +4326,7 @@ func file_proto_scan_result_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_proto_scan_result_proto_rawDesc, NumEnums: 4, - NumMessages: 33, + NumMessages: 34, NumExtensions: 0, NumServices: 0, }, diff --git a/extractor/filesystem/language/dotnet/depsjson/depsjson.go b/extractor/filesystem/language/dotnet/depsjson/depsjson.go index 75dfe4d4..d4ac5186 100644 --- a/extractor/filesystem/language/dotnet/depsjson/depsjson.go +++ b/extractor/filesystem/language/dotnet/depsjson/depsjson.go @@ -129,8 +129,12 @@ func (e Extractor) Extract(ctx context.Context, input *filesystem.ScanInput) ([] } type DepsJSON struct { + // Note: Libraries does not include transitive dependencies. + // Targets is not currently extracted because it introduces significant + // complexity and is not always necessary for basic dependency analysis. Libraries map[string]struct { Version string `json:"version"` + Type string `json:"type"` // Represents the package type, if present. } `json:"libraries"` } @@ -144,17 +148,22 @@ func (e Extractor) extractFromInput(ctx context.Context, input *filesystem.ScanI } var inventories []*extractor.Inventory - for nameVersion := range deps.Libraries { + for nameVersion, library := range deps.Libraries { // Split name and version from "package/version" format name, version := splitNameAndVersion(nameVersion) if name == "" || version == "" { log.Warnf("Skipping library with missing name or version: %s", nameVersion) continue } - + // If the library type is "project", this is the root/main package. i := &extractor.Inventory{ - Name: name, - Version: version, + Name: name, + Version: version, + Metadata: &Metadata{ + PackageName: name, + PackageVersion: version, + Type: library.Type, + }, Locations: []string{input.Path}, } inventories = append(inventories, i) diff --git a/extractor/filesystem/language/dotnet/depsjson/depsjson_test.go b/extractor/filesystem/language/dotnet/depsjson/depsjson_test.go index 1910de81..4a0dc726 100644 --- a/extractor/filesystem/language/dotnet/depsjson/depsjson_test.go +++ b/extractor/filesystem/language/dotnet/depsjson/depsjson_test.go @@ -175,18 +175,33 @@ func TestExtract(t *testing.T) { path: "testdata/valid", wantInventory: []*extractor.Inventory{ { - Name: "TestLibrary", - Version: "1.0.0", + Name: "TestLibrary", + Version: "1.0.0", + Metadata: &depsjson.Metadata{ + PackageName: "TestLibrary", + PackageVersion: "1.0.0", + Type: "project", + }, Locations: []string{"testdata/valid"}, }, { - Name: "AWSSDK.Core", - Version: "3.7.10.6", + Name: "AWSSDK.Core", + Version: "3.7.10.6", + Metadata: &depsjson.Metadata{ + PackageName: "AWSSDK.Core", + PackageVersion: "3.7.10.6", + Type: "package", + }, Locations: []string{"testdata/valid"}, }, { - Name: "Microsoft.Extensions.DependencyInjection", - Version: "6.0.0", + Name: "Microsoft.Extensions.DependencyInjection", + Version: "6.0.0", + Metadata: &depsjson.Metadata{ + PackageName: "Microsoft.Extensions.DependencyInjection", + PackageVersion: "6.0.0", + Type: "package", + }, Locations: []string{"testdata/valid"}, }, }, @@ -209,13 +224,23 @@ func TestExtract(t *testing.T) { path: "testdata/nopackagename", wantInventory: []*extractor.Inventory{ { - Name: "TestLibrary", - Version: "1.0.0", + Name: "TestLibrary", + Version: "1.0.0", + Metadata: &depsjson.Metadata{ + PackageName: "TestLibrary", + PackageVersion: "1.0.0", + Type: "project", + }, Locations: []string{"testdata/nopackagename"}, }, { - Name: "AWSSDK.Core", - Version: "3.7.10.6", + Name: "AWSSDK.Core", + Version: "3.7.10.6", + Metadata: &depsjson.Metadata{ + PackageName: "AWSSDK.Core", + PackageVersion: "3.7.10.6", + Type: "package", + }, Locations: []string{"testdata/nopackagename"}, }, }, diff --git a/extractor/filesystem/language/dotnet/depsjson/metadata.go b/extractor/filesystem/language/dotnet/depsjson/metadata.go new file mode 100644 index 00000000..8624f3cf --- /dev/null +++ b/extractor/filesystem/language/dotnet/depsjson/metadata.go @@ -0,0 +1,22 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package depsjson + +// Metadata holds parsing information for a depsjson package. +type Metadata struct { + PackageName string + PackageVersion string + Type string +}