diff --git a/docs/docs/developers/build/dashboards/canvas-widgets/custom-viz.md b/docs/docs/developers/build/dashboards/canvas-widgets/custom-viz.md new file mode 100644 index 000000000000..49430988d495 --- /dev/null +++ b/docs/docs/developers/build/dashboards/canvas-widgets/custom-viz.md @@ -0,0 +1,109 @@ +--- +title: "Custom Viz Components" +sidebar_label: "Custom Viz" +sidebar_position: 15 +--- + +Custom viz components are reusable visualizations defined as standalone `type: component` files. A component declares typed **params** and renders a [custom chart](/reference/project-files/component) built from Metrics SQL queries and a Vega-Lite spec. Canvas dashboards reference the component by name and bind values to its params, so one visualization can be reused across many dashboards with different metrics views, measures, and dimensions. + +Unlike an inline `custom_chart` widget, a custom viz lives in its own file (conventionally under `viz_library/`), has a declared parameter contract that Rill validates, and can be developed in a dedicated editor with a live preview. + +## Creating a custom viz + +In Rill Developer, click **Add → Custom viz → Blank** (or create a file under `viz_library/` by hand): + +```yaml +# viz_library/measure_trend.yaml +type: component +display_name: Measure trend + +params: + - name: metrics_view + type: metrics_view + required: true + - name: measure + type: measure + required: true + - name: time_dim + type: time_dimension + required: true + +custom_chart: + metrics_sql: | + SELECT {{ .params.time_dim }}, {{ .params.measure }} + FROM {{ .params.metrics_view }} + ORDER BY {{ .params.time_dim }} + vega_spec: | + { + "$schema": "https://vega.github.io/schema/vega-lite/v5.json", + "width": "container", + "height": "container", + "autosize": {"type": "fit"}, + "data": {"name": "query1"}, + "mark": "line", + "encoding": { + "x": {"field": "{{ .params.time_dim }}", "type": "temporal"}, + "y": {"field": "{{ .params.measure }}", "type": "quantitative"} + } + } +``` + +The component editor shows a live preview. Use the **Test values** panel to bind preview-only values to the params; dashboards set their own values. The **Used by** panel lists every dashboard referencing the component. + +## Params + +Params are the component's contract with dashboards. Each param has a `name`, a `type`, and optionally `required`, `default`, `description`, and (for scalars) `options`: + +| Type | Bound value | Notes | +|---|---|---| +| `metrics_view` | A metrics view name | Must be named `metrics_view` or end with `_metrics_view` | +| `measure` | A measure of the bound metrics view | Validated at reconcile time | +| `dimension` | A dimension of the bound metrics view | Validated at reconcile time | +| `time_dimension` | A time dimension of the bound metrics view | The primary time dimension or a time-typed dimension | +| `string`, `number`, `boolean` | A scalar value | Injected as native [Vega-Lite params](https://vega.github.io/vega-lite/docs/parameter.html) | + +Field-typed params are substituted into `metrics_sql` and `vega_spec` through templating: `{{ .params.measure }}`. Scalar params are additionally available directly in Vega expressions by name (e.g. `"expr": "smooth ? 'monotone' : 'linear'"`), and if the spec declares a Vega-Lite param with the same name, its `bind` and `expr` are preserved and only its value is overridden. + +When evolving a component that dashboards already use, prefer adding params with a `default` (or `optional`) so existing references keep working. Renaming or removing a param surfaces a validation error on every dashboard that binds it. + +## Referencing from a canvas + +In the canvas visual editor, open **Add widget → Your components** and pick the component: Rill pre-selects sensible bindings (a metrics view with a time dimension, its first measure, and so on), and the inspector shows a form generated from the declared params. In YAML, a reference looks like: + +```yaml +# dashboards/overview.yaml +type: canvas +rows: + - items: + - component: measure_trend + params: + metrics_view: bids_metrics + measure: total_bids + time_dim: __time + width: 8 + - component: measure_trend + params: + metrics_view: bids_metrics + measure: avg_bid_price + time_dim: __time + width: 4 +``` + +Bindings are validated when the canvas reconciles: unknown params, missing required params, and fields that don't exist in the bound metrics view are reported as errors on the dashboard. Canvas-level time and dimension filters apply to custom viz like any other widget. + +## Extracting an inline custom chart + +To turn an existing inline `custom_chart` widget into a reusable component, open the widget's **⋯** menu and choose **Save as custom viz…**. Rill writes the component file, lifts the metrics view (and any fields you check) into params, and replaces the inline widget with a reference — the dashboard renders identically. The inverse also exists: **Detach copy** on a referenced widget materializes its current bindings back into an inline chart you can tweak independently. + +## Starting from a Vega-Lite example + +**Add → Custom viz → From Vega-Lite example…** opens a gallery of examples from the [Vega-Lite example gallery](https://vega.github.io/vega-lite/examples/) (vendored, so it works offline). Importing an example takes only its visual design: the example's spec is handed to the AI assistant, which authors the component against your project's data — a required `metrics_view` param plus one typed param per encoded field (`dimension`, `measure`, or `time_dimension`), params named after their chart role (`x_axis`, `color`, …), a simple templated `metrics_sql`, and a transform-free Vega spec. You're taken to the component immediately and watch an "Importing example using AI…" screen while it generates; the editor appears once the component reconciles. When the AI assistant is unavailable, simple encoding-driven examples are converted deterministically instead, and complex ones import verbatim with their sample data for manual conversion. + +:::note Feature flag +Custom viz is currently gated behind the `customComponents` feature flag. Enable it in `rill.yaml`: + +```yaml +features: + - customComponents +``` +::: diff --git a/docs/docs/reference/project-files/canvas-dashboards.md b/docs/docs/reference/project-files/canvas-dashboards.md index 6a620ef72089..88138015ed84 100644 --- a/docs/docs/reference/project-files/canvas-dashboards.md +++ b/docs/docs/reference/project-files/canvas-dashboards.md @@ -52,6 +52,8 @@ _[array of object]_ - Refers to all of the rows displayed on the Canvas. Each en - **donut_chart** - Donut or Pie chart to display sums of total + - **`params`** - _[object]_ - Values bound to the referenced component's declared params. Only valid together with `component`. Values must be scalars. + - **`width`** - _[string, integer]_ - Width of the component (can be a number or string with unit) - **`name`** - _[string]_ - Stable identifier for a tab group, used as its deep-link URL key. Defaults to `group-` if omitted. Only used for tab-group entries. diff --git a/docs/docs/reference/project-files/component.md b/docs/docs/reference/project-files/component.md index 8cafb1f2301d..ef065b27c16c 100644 --- a/docs/docs/reference/project-files/component.md +++ b/docs/docs/reference/project-files/component.md @@ -20,6 +20,24 @@ _[string]_ - Refers to the display name for the component _[string]_ - Detailed description of the component's purpose and functionality +### `params` + +_[array of object]_ - List of typed parameters that canvases can bind values to when referencing this component. Bound values are available in the renderer properties' templating as `{{ .params. }}`. + + - **`name`** - _[string]_ - Param name. Must be a valid identifier; referenced in the renderer properties' templating as `{{ .params. }}`. _(required)_ + + - **`type`** - _[string]_ - Param type. Params of type `metrics_view` must be named `metrics_view` or end with `_metrics_view`. _(required)_ + + - **`description`** - _[string]_ - Human-facing description of the param + + - **`required`** - _[boolean]_ - If true, a canvas item referencing this component must bind a value for the param. Mutually exclusive with `default`. + + - **`default`** - _[string, number, boolean]_ - Default value used when the param is not bound + + - **`metrics_view`** - _[string]_ - For `measure`, `dimension` and `time_dimension` params, the name of a sibling param of type `metrics_view` whose bound metrics view the field must belong to. May be omitted when exactly one `metrics_view` param is declared. + + - **`options`** - _[array]_ - For scalar params, the allowed values. Renders as a select input in visual editors. + ### `input` _[array of object]_ - List of input variables that can be passed to the component diff --git a/proto/gen/rill/runtime/v1/queries.pb.go b/proto/gen/rill/runtime/v1/queries.pb.go index ba5c9d99b222..14dfe032c3ce 100644 --- a/proto/gen/rill/runtime/v1/queries.pb.go +++ b/proto/gen/rill/runtime/v1/queries.pb.go @@ -5398,6 +5398,8 @@ type ResolveComponentResponse struct { // Renderer properties with templating resolved for the provided args RendererProperties *structpb.Struct `protobuf:"bytes,2,opt,name=renderer_properties,json=rendererProperties,proto3" json:"renderer_properties,omitempty"` + // The effective args used for resolution: the component's declared param defaults merged with the provided args. + ResolvedArgs *structpb.Struct `protobuf:"bytes,3,opt,name=resolved_args,json=resolvedArgs,proto3" json:"resolved_args,omitempty"` } func (x *ResolveComponentResponse) Reset() { @@ -5439,6 +5441,13 @@ func (x *ResolveComponentResponse) GetRendererProperties() *structpb.Struct { return nil } +func (x *ResolveComponentResponse) GetResolvedArgs() *structpb.Struct { + if x != nil { + return x.ResolvedArgs + } + return nil +} + type ResolveTemplatedStringRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -9884,266 +9893,121 @@ var file_rill_runtime_v1_queries_proto_rawDesc = []byte{ 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x12, 0x2b, 0x0a, 0x04, 0x61, 0x72, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x04, 0x61, 0x72, - 0x67, 0x73, 0x22, 0x64, 0x0a, 0x18, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x43, 0x6f, 0x6d, - 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x48, - 0x0a, 0x13, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x65, 0x72, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x65, - 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, - 0x72, 0x75, 0x63, 0x74, 0x52, 0x12, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x65, 0x72, 0x50, 0x72, - 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0xd9, 0x03, 0x0a, 0x1d, 0x52, 0x65, 0x73, - 0x6f, 0x6c, 0x76, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x53, 0x74, 0x72, - 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, - 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x62, - 0x6f, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, - 0x2a, 0x0a, 0x11, 0x75, 0x73, 0x65, 0x5f, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x5f, 0x74, 0x6f, - 0x6b, 0x65, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x75, 0x73, 0x65, 0x46, - 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x12, 0x98, 0x01, 0x0a, 0x20, - 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x77, 0x68, 0x65, 0x72, 0x65, - 0x5f, 0x62, 0x79, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x76, 0x69, 0x65, 0x77, - 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x50, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, - 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, - 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, - 0x6c, 0x57, 0x68, 0x65, 0x72, 0x65, 0x42, 0x79, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, - 0x69, 0x65, 0x77, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x1c, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x61, 0x6c, 0x57, 0x68, 0x65, 0x72, 0x65, 0x42, 0x79, 0x4d, 0x65, 0x74, 0x72, 0x69, - 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x12, 0x4e, 0x0a, 0x15, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, - 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, - 0x65, 0x52, 0x13, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x54, 0x69, 0x6d, - 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x1a, 0x6c, 0x0a, 0x21, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x61, 0x6c, 0x57, 0x68, 0x65, 0x72, 0x65, 0x42, 0x79, 0x4d, 0x65, 0x74, 0x72, 0x69, - 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, - 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x31, 0x0a, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x72, - 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, - 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x3a, 0x02, 0x38, 0x01, 0x22, 0x34, 0x0a, 0x1e, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x54, + 0x67, 0x73, 0x22, 0xa2, 0x01, 0x0a, 0x18, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x43, 0x6f, + 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x48, 0x0a, 0x13, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x65, 0x72, 0x5f, 0x70, 0x72, 0x6f, 0x70, + 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, + 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x12, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x65, 0x72, 0x50, + 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x3c, 0x0a, 0x0d, 0x72, 0x65, 0x73, + 0x6f, 0x6c, 0x76, 0x65, 0x64, 0x5f, 0x61, 0x72, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x0c, 0x72, 0x65, 0x73, 0x6f, 0x6c, + 0x76, 0x65, 0x64, 0x41, 0x72, 0x67, 0x73, 0x22, 0xd9, 0x03, 0x0a, 0x1d, 0x52, 0x65, 0x73, 0x6f, + 0x6c, 0x76, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x53, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, + 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, + 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, + 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x2a, + 0x0a, 0x11, 0x75, 0x73, 0x65, 0x5f, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x5f, 0x74, 0x6f, 0x6b, + 0x65, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x75, 0x73, 0x65, 0x46, 0x6f, + 0x72, 0x6d, 0x61, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x12, 0x98, 0x01, 0x0a, 0x20, 0x61, + 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x77, 0x68, 0x65, 0x72, 0x65, 0x5f, + 0x62, 0x79, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x18, + 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x50, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, + 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x22, 0x8f, 0x02, 0x0a, 0x1b, 0x43, - 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x6f, 0x6c, 0x6c, 0x75, 0x70, 0x49, 0x6e, 0x74, 0x65, 0x72, - 0x76, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, + 0x57, 0x68, 0x65, 0x72, 0x65, 0x42, 0x79, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, + 0x65, 0x77, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x1c, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x61, 0x6c, 0x57, 0x68, 0x65, 0x72, 0x65, 0x42, 0x79, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, + 0x73, 0x56, 0x69, 0x65, 0x77, 0x12, 0x4e, 0x0a, 0x15, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x61, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, + 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, + 0x52, 0x13, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x54, 0x69, 0x6d, 0x65, + 0x52, 0x61, 0x6e, 0x67, 0x65, 0x1a, 0x6c, 0x0a, 0x21, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x61, 0x6c, 0x57, 0x68, 0x65, 0x72, 0x65, 0x42, 0x79, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, + 0x73, 0x56, 0x69, 0x65, 0x77, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x31, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x72, 0x69, + 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, + 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, + 0x02, 0x38, 0x01, 0x22, 0x34, 0x0a, 0x1e, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x54, 0x65, + 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x22, 0x8f, 0x02, 0x0a, 0x1b, 0x43, 0x6f, + 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x6f, 0x6c, 0x6c, 0x75, 0x70, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, + 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, + 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, + 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, + 0x62, 0x61, 0x73, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, + 0x62, 0x61, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, + 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, + 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x26, 0x0a, + 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x09, 0x74, 0x61, 0x62, 0x6c, + 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x0b, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, + 0x02, 0x10, 0x01, 0x52, 0x0a, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, + 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0xb6, 0x01, 0x0a, 0x1c, + 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x6f, 0x6c, 0x6c, 0x75, 0x70, 0x49, 0x6e, 0x74, 0x65, + 0x72, 0x76, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x05, + 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x2c, + 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x12, 0x36, 0x0a, 0x08, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, + 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x47, 0x72, 0x61, 0x69, 0x6e, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x76, 0x61, 0x6c, 0x22, 0xa5, 0x02, 0x0a, 0x11, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, + 0x6f, 0x70, 0x4b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x63, - 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x61, 0x74, - 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x61, 0x74, + 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, - 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, + 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x26, 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x0b, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x61, 0x6d, 0x65, - 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0xb6, 0x01, 0x0a, - 0x1c, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x6f, 0x6c, 0x6c, 0x75, 0x70, 0x49, 0x6e, 0x74, - 0x65, 0x72, 0x76, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, - 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, - 0x2c, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x12, 0x36, 0x0a, - 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x1a, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x47, 0x72, 0x61, 0x69, 0x6e, 0x52, 0x08, 0x69, 0x6e, 0x74, - 0x65, 0x72, 0x76, 0x61, 0x6c, 0x22, 0xa5, 0x02, 0x0a, 0x11, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, - 0x54, 0x6f, 0x70, 0x4b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, - 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, - 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x61, - 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x61, - 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, - 0x73, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, - 0x26, 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x09, 0x74, 0x61, - 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x0b, 0x63, 0x6f, 0x6c, 0x75, 0x6d, - 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, - 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x61, 0x6d, - 0x65, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x67, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x61, 0x67, 0x67, 0x12, 0x0c, 0x0a, 0x01, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x01, - 0x6b, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x6a, 0x0a, - 0x12, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x6f, 0x70, 0x4b, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x13, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x63, - 0x61, 0x6c, 0x5f, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x23, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x53, 0x75, - 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x12, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x63, - 0x61, 0x6c, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x22, 0x6e, 0x0a, 0x12, 0x43, 0x61, 0x74, - 0x65, 0x67, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, - 0x2c, 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x5f, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, - 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x54, 0x6f, 0x70, 0x4b, 0x48, 0x00, 0x52, 0x04, 0x74, 0x6f, 0x70, 0x4b, 0x12, 0x22, 0x0a, - 0x0b, 0x63, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x01, 0x48, 0x00, 0x52, 0x0b, 0x63, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, - 0x79, 0x42, 0x06, 0x0a, 0x04, 0x63, 0x61, 0x73, 0x65, 0x22, 0x8a, 0x01, 0x0a, 0x04, 0x54, 0x6f, - 0x70, 0x4b, 0x12, 0x35, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, - 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x6f, 0x70, 0x4b, 0x2e, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x1a, 0x4b, 0x0a, 0x05, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, - 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x8a, 0x02, 0x0a, 0x16, 0x43, 0x6f, 0x6c, 0x75, 0x6d, - 0x6e, 0x4e, 0x75, 0x6c, 0x6c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, - 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, - 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, - 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, - 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x26, 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, - 0x10, 0x01, 0x52, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, - 0x0b, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x63, 0x6f, 0x6c, - 0x75, 0x6d, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, - 0x69, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, - 0x69, 0x74, 0x79, 0x22, 0x2f, 0x0a, 0x17, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x75, 0x6c, - 0x6c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, - 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x63, - 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x96, 0x02, 0x0a, 0x22, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x44, - 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, - 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, - 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, - 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x61, - 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x61, - 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, - 0x73, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, - 0x26, 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x09, 0x74, 0x61, - 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x0b, 0x63, 0x6f, 0x6c, 0x75, 0x6d, - 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, - 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x61, 0x6d, - 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x6f, 0x0a, - 0x23, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, - 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x48, 0x0a, 0x0f, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x5f, - 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, + 0x12, 0x10, 0x0a, 0x03, 0x61, 0x67, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x61, + 0x67, 0x67, 0x12, 0x0c, 0x0a, 0x01, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x01, 0x6b, + 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x6a, 0x0a, 0x12, + 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x6f, 0x70, 0x4b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x54, 0x0a, 0x13, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x63, 0x61, + 0x6c, 0x5f, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x23, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x53, 0x75, 0x6d, + 0x6d, 0x61, 0x72, 0x79, 0x52, 0x12, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x63, 0x61, + 0x6c, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x22, 0x6e, 0x0a, 0x12, 0x43, 0x61, 0x74, 0x65, + 0x67, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x2c, + 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x5f, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x0e, - 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x22, 0x9b, - 0x02, 0x0a, 0x0e, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, - 0x79, 0x12, 0x5d, 0x0a, 0x16, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x5f, 0x68, 0x69, 0x73, - 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x5f, 0x62, 0x69, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x48, 0x69, 0x73, 0x74, 0x6f, - 0x67, 0x72, 0x61, 0x6d, 0x42, 0x69, 0x6e, 0x73, 0x48, 0x00, 0x52, 0x14, 0x6e, 0x75, 0x6d, 0x65, - 0x72, 0x69, 0x63, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x42, 0x69, 0x6e, 0x73, - 0x12, 0x53, 0x0a, 0x12, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x5f, 0x73, 0x74, 0x61, 0x74, - 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, - 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, - 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, - 0x48, 0x00, 0x52, 0x11, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x53, 0x74, 0x61, 0x74, 0x69, - 0x73, 0x74, 0x69, 0x63, 0x73, 0x12, 0x4d, 0x0a, 0x10, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, - 0x5f, 0x6f, 0x75, 0x74, 0x6c, 0x69, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x20, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x4f, 0x75, 0x74, 0x6c, 0x69, 0x65, 0x72, - 0x73, 0x48, 0x00, 0x52, 0x0f, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x4f, 0x75, 0x74, 0x6c, - 0x69, 0x65, 0x72, 0x73, 0x42, 0x06, 0x0a, 0x04, 0x63, 0x61, 0x73, 0x65, 0x22, 0xcc, 0x01, 0x0a, - 0x14, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, - 0x6d, 0x42, 0x69, 0x6e, 0x73, 0x12, 0x3d, 0x0a, 0x04, 0x62, 0x69, 0x6e, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, - 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x48, 0x69, 0x73, - 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x42, 0x69, 0x6e, 0x73, 0x2e, 0x42, 0x69, 0x6e, 0x52, 0x04, - 0x62, 0x69, 0x6e, 0x73, 0x1a, 0x75, 0x0a, 0x03, 0x42, 0x69, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x62, - 0x75, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x62, 0x75, 0x63, - 0x6b, 0x65, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6c, 0x6f, 0x77, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, - 0x52, 0x03, 0x6c, 0x6f, 0x77, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x69, 0x64, 0x70, 0x6f, 0x69, 0x6e, - 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x08, 0x6d, 0x69, 0x64, 0x70, 0x6f, 0x69, 0x6e, - 0x74, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x69, 0x67, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, - 0x04, 0x68, 0x69, 0x67, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x91, 0x01, 0x0a, 0x11, - 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, - 0x73, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, - 0x6d, 0x69, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x61, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, - 0x52, 0x03, 0x6d, 0x61, 0x78, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x65, 0x61, 0x6e, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x01, 0x52, 0x04, 0x6d, 0x65, 0x61, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x71, 0x32, 0x35, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x71, 0x32, 0x35, 0x12, 0x10, 0x0a, 0x03, 0x71, - 0x35, 0x30, 0x18, 0x05, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x71, 0x35, 0x30, 0x12, 0x10, 0x0a, - 0x03, 0x71, 0x37, 0x35, 0x18, 0x06, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x71, 0x37, 0x35, 0x12, - 0x0e, 0x0a, 0x02, 0x73, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x01, 0x52, 0x02, 0x73, 0x64, 0x22, - 0xd0, 0x01, 0x0a, 0x0f, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x4f, 0x75, 0x74, 0x6c, 0x69, - 0x65, 0x72, 0x73, 0x12, 0x44, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x6c, 0x69, 0x65, 0x72, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, - 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x4f, - 0x75, 0x74, 0x6c, 0x69, 0x65, 0x72, 0x73, 0x2e, 0x4f, 0x75, 0x74, 0x6c, 0x69, 0x65, 0x72, 0x52, - 0x08, 0x6f, 0x75, 0x74, 0x6c, 0x69, 0x65, 0x72, 0x73, 0x1a, 0x77, 0x0a, 0x07, 0x4f, 0x75, 0x74, - 0x6c, 0x69, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x10, 0x0a, 0x03, - 0x6c, 0x6f, 0x77, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x6c, 0x6f, 0x77, 0x12, 0x12, - 0x0a, 0x04, 0x68, 0x69, 0x67, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x04, 0x68, 0x69, - 0x67, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x07, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x22, 0x8a, 0x02, 0x0a, 0x16, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, - 0x65, 0x47, 0x72, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, - 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1c, - 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, - 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x61, 0x74, 0x61, - 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, - 0x61, 0x12, 0x26, 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x09, - 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x0b, 0x63, 0x6f, 0x6c, - 0x75, 0x6d, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, - 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, - 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, - 0x54, 0x0a, 0x17, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x47, 0x72, 0x61, - 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x0a, 0x74, 0x69, - 0x6d, 0x65, 0x5f, 0x67, 0x72, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, - 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x47, 0x72, 0x61, 0x69, 0x6e, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, - 0x47, 0x72, 0x61, 0x69, 0x6e, 0x22, 0xde, 0x02, 0x0a, 0x1d, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, - 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, - 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, - 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, - 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6e, - 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, - 0x73, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, - 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, - 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x61, 0x74, - 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x26, 0x0a, 0x0a, 0x74, - 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, - 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, - 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x0b, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x5f, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, - 0x01, 0x52, 0x0a, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x4b, 0x0a, - 0x10, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, - 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, - 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, - 0x72, 0x61, 0x6d, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x0f, 0x68, 0x69, 0x73, 0x74, 0x6f, - 0x67, 0x72, 0x61, 0x6d, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, - 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, - 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x6a, 0x0a, 0x1e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, - 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x48, 0x0a, 0x0f, 0x6e, 0x75, 0x6d, 0x65, - 0x72, 0x69, 0x63, 0x5f, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1f, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x53, 0x75, 0x6d, 0x6d, 0x61, - 0x72, 0x79, 0x52, 0x0e, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x53, 0x75, 0x6d, 0x6d, 0x61, - 0x72, 0x79, 0x22, 0x8d, 0x02, 0x0a, 0x19, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x75, 0x67, - 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x54, 0x6f, 0x70, 0x4b, 0x48, 0x00, 0x52, 0x04, 0x74, 0x6f, 0x70, 0x4b, 0x12, 0x22, 0x0a, 0x0b, + 0x63, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x01, 0x48, 0x00, 0x52, 0x0b, 0x63, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, + 0x42, 0x06, 0x0a, 0x04, 0x63, 0x61, 0x73, 0x65, 0x22, 0x8a, 0x01, 0x0a, 0x04, 0x54, 0x6f, 0x70, + 0x4b, 0x12, 0x35, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, + 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x6f, 0x70, 0x4b, 0x2e, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x1a, 0x4b, 0x0a, 0x05, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, + 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x8a, 0x02, 0x0a, 0x16, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, + 0x4e, 0x75, 0x6c, 0x6c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x05, @@ -10159,669 +10023,818 @@ var file_rill_runtime_v1_queries_proto_rawDesc = []byte{ 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, - 0x74, 0x79, 0x22, 0x66, 0x0a, 0x1a, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x75, 0x67, 0x48, - 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x48, 0x0a, 0x0f, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x5f, 0x73, 0x75, 0x6d, 0x6d, - 0x61, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x72, 0x69, 0x6c, 0x6c, - 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x75, 0x6d, 0x65, - 0x72, 0x69, 0x63, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x0e, 0x6e, 0x75, 0x6d, 0x65, - 0x72, 0x69, 0x63, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x22, 0x8a, 0x02, 0x0a, 0x16, 0x43, - 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, - 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, - 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, - 0x74, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, - 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x68, - 0x65, 0x6d, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x62, - 0x61, 0x73, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x26, 0x0a, 0x0a, 0x74, 0x61, 0x62, - 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, - 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, - 0x65, 0x12, 0x28, 0x0a, 0x0b, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, - 0x0a, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, - 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, - 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x6a, 0x0a, 0x17, 0x43, 0x6f, 0x6c, 0x75, 0x6d, - 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x4f, 0x0a, 0x12, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, - 0x5f, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, + 0x74, 0x79, 0x22, 0x2f, 0x0a, 0x17, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x75, 0x6c, 0x6c, + 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, + 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x22, 0x96, 0x02, 0x0a, 0x22, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x44, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, + 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, + 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x63, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x61, 0x74, + 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x61, 0x74, + 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, + 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, + 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x26, + 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x09, 0x74, 0x61, 0x62, + 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x0b, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, + 0x72, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x61, 0x6d, 0x65, + 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x6f, 0x0a, 0x23, + 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x76, + 0x65, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x48, 0x0a, 0x0f, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x5f, 0x73, + 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x72, + 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, + 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x0e, 0x6e, + 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x22, 0x9b, 0x02, + 0x0a, 0x0e, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, + 0x12, 0x5d, 0x0a, 0x16, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x5f, 0x68, 0x69, 0x73, 0x74, + 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x5f, 0x62, 0x69, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x25, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, + 0x72, 0x61, 0x6d, 0x42, 0x69, 0x6e, 0x73, 0x48, 0x00, 0x52, 0x14, 0x6e, 0x75, 0x6d, 0x65, 0x72, + 0x69, 0x63, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x42, 0x69, 0x6e, 0x73, 0x12, + 0x53, 0x0a, 0x12, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x69, + 0x73, 0x74, 0x69, 0x63, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x69, + 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x75, + 0x6d, 0x65, 0x72, 0x69, 0x63, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x48, + 0x00, 0x52, 0x11, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, + 0x74, 0x69, 0x63, 0x73, 0x12, 0x4d, 0x0a, 0x10, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x5f, + 0x6f, 0x75, 0x74, 0x6c, 0x69, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, - 0x79, 0x52, 0x10, 0x74, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x75, 0x6d, 0x6d, - 0x61, 0x72, 0x79, 0x22, 0xa8, 0x01, 0x0a, 0x10, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, - 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x2c, 0x0a, 0x03, 0x6d, 0x69, 0x6e, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x52, 0x03, 0x6d, 0x69, 0x6e, 0x12, 0x2c, 0x0a, 0x03, 0x6d, 0x61, 0x78, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, - 0x03, 0x6d, 0x61, 0x78, 0x12, 0x38, 0x0a, 0x09, 0x77, 0x61, 0x74, 0x65, 0x72, 0x6d, 0x61, 0x72, - 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x52, 0x09, 0x77, 0x61, 0x74, 0x65, 0x72, 0x6d, 0x61, 0x72, 0x6b, 0x22, 0x8c, - 0x02, 0x0a, 0x18, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x43, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, - 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, + 0x2e, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x4f, 0x75, 0x74, 0x6c, 0x69, 0x65, 0x72, 0x73, + 0x48, 0x00, 0x52, 0x0f, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x4f, 0x75, 0x74, 0x6c, 0x69, + 0x65, 0x72, 0x73, 0x42, 0x06, 0x0a, 0x04, 0x63, 0x61, 0x73, 0x65, 0x22, 0xcc, 0x01, 0x0a, 0x14, + 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, + 0x42, 0x69, 0x6e, 0x73, 0x12, 0x3d, 0x0a, 0x04, 0x62, 0x69, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, + 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x48, 0x69, 0x73, 0x74, + 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x42, 0x69, 0x6e, 0x73, 0x2e, 0x42, 0x69, 0x6e, 0x52, 0x04, 0x62, + 0x69, 0x6e, 0x73, 0x1a, 0x75, 0x0a, 0x03, 0x42, 0x69, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, + 0x63, 0x6b, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x62, 0x75, 0x63, 0x6b, + 0x65, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6c, 0x6f, 0x77, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, + 0x03, 0x6c, 0x6f, 0x77, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x69, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x08, 0x6d, 0x69, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x12, 0x12, 0x0a, 0x04, 0x68, 0x69, 0x67, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, 0x04, + 0x68, 0x69, 0x67, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x01, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x91, 0x01, 0x0a, 0x11, 0x4e, + 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, + 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x6d, + 0x69, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x61, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, + 0x03, 0x6d, 0x61, 0x78, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x65, 0x61, 0x6e, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x01, 0x52, 0x04, 0x6d, 0x65, 0x61, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x71, 0x32, 0x35, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x71, 0x32, 0x35, 0x12, 0x10, 0x0a, 0x03, 0x71, 0x35, + 0x30, 0x18, 0x05, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x71, 0x35, 0x30, 0x12, 0x10, 0x0a, 0x03, + 0x71, 0x37, 0x35, 0x18, 0x06, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x71, 0x37, 0x35, 0x12, 0x0e, + 0x0a, 0x02, 0x73, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x01, 0x52, 0x02, 0x73, 0x64, 0x22, 0xd0, + 0x01, 0x0a, 0x0f, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x4f, 0x75, 0x74, 0x6c, 0x69, 0x65, + 0x72, 0x73, 0x12, 0x44, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x6c, 0x69, 0x65, 0x72, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, + 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x4f, 0x75, + 0x74, 0x6c, 0x69, 0x65, 0x72, 0x73, 0x2e, 0x4f, 0x75, 0x74, 0x6c, 0x69, 0x65, 0x72, 0x52, 0x08, + 0x6f, 0x75, 0x74, 0x6c, 0x69, 0x65, 0x72, 0x73, 0x1a, 0x77, 0x0a, 0x07, 0x4f, 0x75, 0x74, 0x6c, + 0x69, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6c, + 0x6f, 0x77, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x6c, 0x6f, 0x77, 0x12, 0x12, 0x0a, + 0x04, 0x68, 0x69, 0x67, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x04, 0x68, 0x69, 0x67, + 0x68, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x07, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x22, 0x8a, 0x02, 0x0a, 0x16, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, + 0x47, 0x72, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, + 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, + 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x64, + 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, + 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x62, + 0x61, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, + 0x12, 0x26, 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x09, 0x74, + 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x0b, 0x63, 0x6f, 0x6c, 0x75, + 0x6d, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, + 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x54, + 0x0a, 0x17, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x47, 0x72, 0x61, 0x69, + 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x0a, 0x74, 0x69, 0x6d, + 0x65, 0x5f, 0x67, 0x72, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, + 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, + 0x54, 0x69, 0x6d, 0x65, 0x47, 0x72, 0x61, 0x69, 0x6e, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x47, + 0x72, 0x61, 0x69, 0x6e, 0x22, 0xde, 0x02, 0x0a, 0x1d, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, + 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, + 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, + 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, + 0x63, 0x74, 0x6f, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, + 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, + 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x63, + 0x68, 0x65, 0x6d, 0x61, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x61, 0x74, 0x61, + 0x62, 0x61, 0x73, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x26, 0x0a, 0x0a, 0x74, 0x61, + 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, + 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x0b, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, + 0x52, 0x0a, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x4b, 0x0a, 0x10, + 0x68, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, + 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, + 0x61, 0x6d, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x0f, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x67, + 0x72, 0x61, 0x6d, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, + 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, + 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x6a, 0x0a, 0x1e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, + 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x48, 0x0a, 0x0f, 0x6e, 0x75, 0x6d, 0x65, 0x72, + 0x69, 0x63, 0x5f, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1f, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, + 0x79, 0x52, 0x0e, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, + 0x79, 0x22, 0x8d, 0x02, 0x0a, 0x19, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x75, 0x67, 0x48, + 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, + 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, + 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x61, + 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x63, 0x68, + 0x65, 0x6d, 0x61, 0x12, 0x26, 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, + 0x52, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x0b, 0x63, + 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x63, 0x6f, 0x6c, 0x75, 0x6d, + 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, + 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, + 0x79, 0x22, 0x66, 0x0a, 0x1a, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x75, 0x67, 0x48, 0x69, + 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x48, 0x0a, 0x0f, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x5f, 0x73, 0x75, 0x6d, 0x6d, 0x61, + 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, + 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x75, 0x6d, 0x65, 0x72, + 0x69, 0x63, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x0e, 0x6e, 0x75, 0x6d, 0x65, 0x72, + 0x69, 0x63, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x22, 0x8a, 0x02, 0x0a, 0x16, 0x43, 0x6f, + 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, + 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, + 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, + 0x27, 0x0a, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, + 0x6d, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, + 0x73, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x26, 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, + 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, + 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, + 0x12, 0x28, 0x0a, 0x0b, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0a, + 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, + 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, + 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x6a, 0x0a, 0x17, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, + 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x4f, 0x0a, 0x12, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x5f, + 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, + 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, + 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, + 0x52, 0x10, 0x74, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, + 0x72, 0x79, 0x22, 0xa8, 0x01, 0x0a, 0x10, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, + 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x2c, 0x0a, 0x03, 0x6d, 0x69, 0x6e, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x52, 0x03, 0x6d, 0x69, 0x6e, 0x12, 0x2c, 0x0a, 0x03, 0x6d, 0x61, 0x78, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x03, + 0x6d, 0x61, 0x78, 0x12, 0x38, 0x0a, 0x09, 0x77, 0x61, 0x74, 0x65, 0x72, 0x6d, 0x61, 0x72, 0x6b, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x52, 0x09, 0x77, 0x61, 0x74, 0x65, 0x72, 0x6d, 0x61, 0x72, 0x6b, 0x22, 0x8c, 0x02, + 0x0a, 0x18, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x43, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, + 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, + 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x63, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x61, 0x74, + 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x61, 0x74, + 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, + 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, + 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x26, + 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x09, 0x74, 0x61, 0x62, + 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x0b, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, + 0x72, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x61, 0x6d, 0x65, + 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x71, 0x0a, 0x19, + 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x43, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, + 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x13, 0x63, 0x61, 0x74, + 0x65, 0x67, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, + 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, + 0x69, 0x63, 0x61, 0x6c, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x12, 0x63, 0x61, 0x74, + 0x65, 0x67, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x22, + 0x8c, 0x05, 0x0a, 0x17, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, + 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, - 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x61, - 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x61, + 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, - 0x73, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x73, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x26, 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x09, 0x74, 0x61, - 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x0b, 0x63, 0x6f, 0x6c, 0x75, 0x6d, - 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, - 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x61, 0x6d, - 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x71, 0x0a, - 0x19, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x43, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, - 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x13, 0x63, 0x61, - 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, - 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, - 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, - 0x72, 0x69, 0x63, 0x61, 0x6c, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x12, 0x63, 0x61, - 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, - 0x22, 0x8c, 0x05, 0x0a, 0x17, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x53, - 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, + 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x5b, 0x0a, 0x08, 0x6d, 0x65, 0x61, 0x73, 0x75, + 0x72, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x72, 0x69, 0x6c, 0x6c, + 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, + 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x2e, 0x42, 0x61, 0x73, 0x69, 0x63, 0x4d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, + 0x42, 0x08, 0xfa, 0x42, 0x05, 0x92, 0x01, 0x02, 0x08, 0x01, 0x52, 0x08, 0x6d, 0x65, 0x61, 0x73, + 0x75, 0x72, 0x65, 0x73, 0x12, 0x3b, 0x0a, 0x15, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x5f, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x13, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x61, 0x6d, + 0x65, 0x12, 0x43, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, + 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, + 0x65, 0x73, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x09, 0x74, 0x69, 0x6d, + 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x1f, 0x0a, 0x06, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x73, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x1a, 0x02, 0x28, 0x00, 0x52, + 0x06, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x73, 0x12, 0x28, 0x0a, 0x0b, 0x73, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, 0x42, 0x07, 0xfa, 0x42, + 0x04, 0x1a, 0x02, 0x28, 0x00, 0x52, 0x0a, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x53, 0x69, 0x7a, + 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x09, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x1b, 0x0a, + 0x09, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x7a, 0x6f, 0x6e, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x5a, 0x6f, 0x6e, 0x65, 0x1a, 0x62, 0x0a, 0x0c, 0x42, 0x61, + 0x73, 0x69, 0x63, 0x4d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x27, 0x0a, 0x0a, 0x65, 0x78, + 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, + 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x71, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x71, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x57, + 0x0a, 0x18, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, + 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x06, 0x72, 0x6f, + 0x6c, 0x6c, 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x72, 0x69, 0x6c, + 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, + 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, + 0x06, 0x72, 0x6f, 0x6c, 0x6c, 0x75, 0x70, 0x22, 0xb7, 0x01, 0x0a, 0x13, 0x54, 0x69, 0x6d, 0x65, + 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, + 0x30, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, + 0x74, 0x12, 0x2c, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x12, + 0x40, 0x0a, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x1a, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x47, 0x72, 0x61, 0x69, 0x6e, 0x42, 0x08, 0xfa, + 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, + 0x6c, 0x22, 0xa9, 0x01, 0x0a, 0x12, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x69, 0x6c, 0x6c, + 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, + 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x07, 0x72, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x73, 0x12, 0x36, 0x0a, 0x05, 0x73, 0x70, 0x61, 0x72, 0x6b, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, + 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x73, 0x70, 0x61, 0x72, 0x6b, 0x12, 0x1f, 0x0a, 0x0b, + 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x0a, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x82, 0x01, + 0x0a, 0x0f, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x12, 0x2a, 0x0a, 0x02, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x02, 0x74, 0x73, 0x12, 0x10, 0x0a, + 0x03, 0x62, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x62, 0x69, 0x6e, 0x12, + 0x31, 0x0a, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, + 0x64, 0x73, 0x22, 0xe1, 0x01, 0x0a, 0x17, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x72, 0x64, + 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, + 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, + 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, + 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x61, 0x74, + 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x63, 0x68, 0x65, + 0x6d, 0x61, 0x12, 0x26, 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, + 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, + 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, + 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x3c, 0x0a, 0x18, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, + 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x63, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, + 0x6c, 0x69, 0x74, 0x79, 0x22, 0xdd, 0x01, 0x0a, 0x13, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, + 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, - 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, + 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x64, - 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, + 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x62, - 0x61, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, + 0x61, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x26, 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x09, 0x74, - 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x5b, 0x0a, 0x08, 0x6d, 0x65, 0x61, 0x73, - 0x75, 0x72, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x72, 0x69, 0x6c, - 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, - 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x2e, 0x42, 0x61, 0x73, 0x69, 0x63, 0x4d, 0x65, 0x61, 0x73, 0x75, 0x72, - 0x65, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x92, 0x01, 0x02, 0x08, 0x01, 0x52, 0x08, 0x6d, 0x65, 0x61, - 0x73, 0x75, 0x72, 0x65, 0x73, 0x12, 0x3b, 0x0a, 0x15, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x5f, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x13, 0x74, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x61, - 0x6d, 0x65, 0x12, 0x43, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, - 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, - 0x69, 0x65, 0x73, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x09, 0x74, 0x69, - 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x1f, 0x0a, 0x06, 0x70, 0x69, 0x78, 0x65, 0x6c, - 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x1a, 0x02, 0x28, 0x00, - 0x52, 0x06, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x73, 0x12, 0x28, 0x0a, 0x0b, 0x73, 0x61, 0x6d, 0x70, - 0x6c, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, 0x42, 0x07, 0xfa, - 0x42, 0x04, 0x1a, 0x02, 0x28, 0x00, 0x52, 0x0a, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x53, 0x69, - 0x7a, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x09, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x1b, - 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x7a, 0x6f, 0x6e, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x5a, 0x6f, 0x6e, 0x65, 0x1a, 0x62, 0x0a, 0x0c, 0x42, - 0x61, 0x73, 0x69, 0x63, 0x4d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x27, 0x0a, 0x0a, 0x65, - 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, - 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x71, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x71, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x22, - 0x57, 0x0a, 0x18, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, - 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x06, 0x72, - 0x6f, 0x6c, 0x6c, 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x72, 0x69, - 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, - 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x52, 0x06, 0x72, 0x6f, 0x6c, 0x6c, 0x75, 0x70, 0x22, 0xb7, 0x01, 0x0a, 0x13, 0x54, 0x69, 0x6d, - 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, - 0x12, 0x30, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x73, 0x74, 0x61, - 0x72, 0x74, 0x12, 0x2c, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x03, 0x65, 0x6e, 0x64, - 0x12, 0x40, 0x0a, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x47, 0x72, 0x61, 0x69, 0x6e, 0x42, 0x08, - 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, - 0x61, 0x6c, 0x22, 0xa9, 0x01, 0x0a, 0x12, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x72, 0x65, 0x73, - 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x69, 0x6c, - 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, - 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x07, 0x72, 0x65, - 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x36, 0x0a, 0x05, 0x73, 0x70, 0x61, 0x72, 0x6b, 0x18, 0x02, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, - 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, - 0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x73, 0x70, 0x61, 0x72, 0x6b, 0x12, 0x1f, 0x0a, - 0x0b, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x05, 0x52, 0x0a, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x82, - 0x01, 0x0a, 0x0f, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x56, 0x61, 0x6c, - 0x75, 0x65, 0x12, 0x2a, 0x0a, 0x02, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x02, 0x74, 0x73, 0x12, 0x10, - 0x0a, 0x03, 0x62, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x62, 0x69, 0x6e, - 0x12, 0x31, 0x0a, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x07, 0x72, 0x65, 0x63, 0x6f, - 0x72, 0x64, 0x73, 0x22, 0xe1, 0x01, 0x0a, 0x17, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x72, - 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, + 0x72, 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, + 0x72, 0x69, 0x74, 0x79, 0x22, 0x96, 0x02, 0x0a, 0x14, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, + 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, + 0x0f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, + 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, + 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x0e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x43, + 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x12, 0x6e, 0x0a, 0x13, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, + 0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, + 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, + 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x55, 0x6e, 0x73, 0x75, 0x70, + 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x12, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x43, + 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x1a, 0x45, 0x0a, 0x17, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, + 0x6f, 0x72, 0x74, 0x65, 0x64, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x6b, 0x0a, + 0x0d, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x12, 0x12, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x32, 0x0a, 0x15, 0x6c, 0x61, 0x72, 0x67, 0x65, 0x73, + 0x74, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x13, 0x6c, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x53, 0x74, + 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x22, 0xf9, 0x01, 0x0a, 0x10, 0x54, + 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x77, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, - 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x04, 0x20, + 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, - 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x61, - 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x06, 0x20, + 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x26, 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, - 0x52, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, - 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, - 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x3c, 0x0a, 0x18, 0x54, 0x61, 0x62, 0x6c, 0x65, - 0x43, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, - 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x63, 0x61, 0x72, 0x64, 0x69, 0x6e, - 0x61, 0x6c, 0x69, 0x74, 0x79, 0x22, 0xdd, 0x01, 0x0a, 0x13, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, - 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, - 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1c, - 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, - 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x61, 0x74, 0x61, - 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, - 0x61, 0x12, 0x26, 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x09, - 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, - 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, - 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x96, 0x02, 0x0a, 0x14, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, - 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, - 0x0a, 0x0f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, - 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, - 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x0e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, - 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x12, 0x6e, 0x0a, 0x13, 0x75, 0x6e, 0x73, 0x75, 0x70, - 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x18, 0x02, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, - 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, - 0x6d, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x55, 0x6e, 0x73, 0x75, - 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x52, 0x12, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, - 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x1a, 0x45, 0x0a, 0x17, 0x55, 0x6e, 0x73, 0x75, 0x70, - 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x6b, - 0x0a, 0x0d, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x12, - 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x32, 0x0a, 0x15, 0x6c, 0x61, 0x72, 0x67, 0x65, - 0x73, 0x74, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x13, 0x6c, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x53, - 0x74, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x22, 0xf9, 0x01, 0x0a, 0x10, - 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x77, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, - 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, - 0x1a, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x64, - 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x63, - 0x68, 0x65, 0x6d, 0x61, 0x12, 0x26, 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, - 0x01, 0x52, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x05, - 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x42, 0x07, 0xfa, 0x42, 0x04, - 0x1a, 0x02, 0x28, 0x00, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, - 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, - 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x40, 0x0a, 0x11, 0x54, 0x61, 0x62, 0x6c, 0x65, - 0x52, 0x6f, 0x77, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x04, - 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, - 0x75, 0x63, 0x74, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x2a, 0x70, 0x0a, 0x0e, 0x42, 0x75, 0x69, - 0x6c, 0x74, 0x69, 0x6e, 0x4d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x12, 0x1f, 0x0a, 0x1b, 0x42, - 0x55, 0x49, 0x4c, 0x54, 0x49, 0x4e, 0x5f, 0x4d, 0x45, 0x41, 0x53, 0x55, 0x52, 0x45, 0x5f, 0x55, - 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, - 0x42, 0x55, 0x49, 0x4c, 0x54, 0x49, 0x4e, 0x5f, 0x4d, 0x45, 0x41, 0x53, 0x55, 0x52, 0x45, 0x5f, - 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x10, 0x01, 0x12, 0x22, 0x0a, 0x1e, 0x42, 0x55, 0x49, 0x4c, 0x54, - 0x49, 0x4e, 0x5f, 0x4d, 0x45, 0x41, 0x53, 0x55, 0x52, 0x45, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, - 0x5f, 0x44, 0x49, 0x53, 0x54, 0x49, 0x4e, 0x43, 0x54, 0x10, 0x02, 0x2a, 0x9e, 0x02, 0x0a, 0x1d, - 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x43, 0x6f, 0x6d, 0x70, 0x61, - 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x53, 0x6f, 0x72, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x31, 0x0a, - 0x2d, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x53, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x43, 0x4f, - 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x54, 0x59, - 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, - 0x12, 0x30, 0x0a, 0x2c, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x53, 0x5f, 0x56, 0x49, 0x45, 0x57, - 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x53, 0x4f, 0x52, 0x54, - 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x56, 0x41, 0x4c, 0x55, 0x45, - 0x10, 0x01, 0x12, 0x36, 0x0a, 0x32, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x53, 0x5f, 0x56, 0x49, - 0x45, 0x57, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x53, 0x4f, - 0x52, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, - 0x4f, 0x4e, 0x5f, 0x56, 0x41, 0x4c, 0x55, 0x45, 0x10, 0x02, 0x12, 0x2f, 0x0a, 0x2b, 0x4d, 0x45, + 0x52, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x05, 0x6c, + 0x69, 0x6d, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x1a, + 0x02, 0x28, 0x00, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, + 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, + 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x40, 0x0a, 0x11, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, + 0x6f, 0x77, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x04, 0x64, + 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, + 0x63, 0x74, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x2a, 0x70, 0x0a, 0x0e, 0x42, 0x75, 0x69, 0x6c, + 0x74, 0x69, 0x6e, 0x4d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x12, 0x1f, 0x0a, 0x1b, 0x42, 0x55, + 0x49, 0x4c, 0x54, 0x49, 0x4e, 0x5f, 0x4d, 0x45, 0x41, 0x53, 0x55, 0x52, 0x45, 0x5f, 0x55, 0x4e, + 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x42, + 0x55, 0x49, 0x4c, 0x54, 0x49, 0x4e, 0x5f, 0x4d, 0x45, 0x41, 0x53, 0x55, 0x52, 0x45, 0x5f, 0x43, + 0x4f, 0x55, 0x4e, 0x54, 0x10, 0x01, 0x12, 0x22, 0x0a, 0x1e, 0x42, 0x55, 0x49, 0x4c, 0x54, 0x49, + 0x4e, 0x5f, 0x4d, 0x45, 0x41, 0x53, 0x55, 0x52, 0x45, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, + 0x44, 0x49, 0x53, 0x54, 0x49, 0x4e, 0x43, 0x54, 0x10, 0x02, 0x2a, 0x9e, 0x02, 0x0a, 0x1d, 0x4d, + 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, + 0x69, 0x73, 0x6f, 0x6e, 0x53, 0x6f, 0x72, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x31, 0x0a, 0x2d, + 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x53, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x43, 0x4f, 0x4d, + 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x54, 0x59, 0x50, + 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, + 0x30, 0x0a, 0x2c, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x53, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, + 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x53, 0x4f, 0x52, 0x54, 0x5f, + 0x54, 0x59, 0x50, 0x45, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x56, 0x41, 0x4c, 0x55, 0x45, 0x10, + 0x01, 0x12, 0x36, 0x0a, 0x32, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x53, 0x5f, 0x56, 0x49, 0x45, + 0x57, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x53, 0x4f, 0x52, + 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, + 0x4e, 0x5f, 0x56, 0x41, 0x4c, 0x55, 0x45, 0x10, 0x02, 0x12, 0x2f, 0x0a, 0x2b, 0x4d, 0x45, 0x54, + 0x52, 0x49, 0x43, 0x53, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, + 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x41, + 0x42, 0x53, 0x5f, 0x44, 0x45, 0x4c, 0x54, 0x41, 0x10, 0x03, 0x12, 0x2f, 0x0a, 0x2b, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x53, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, - 0x41, 0x42, 0x53, 0x5f, 0x44, 0x45, 0x4c, 0x54, 0x41, 0x10, 0x03, 0x12, 0x2f, 0x0a, 0x2b, 0x4d, - 0x45, 0x54, 0x52, 0x49, 0x43, 0x53, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x43, 0x4f, 0x4d, 0x50, - 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, - 0x5f, 0x52, 0x45, 0x4c, 0x5f, 0x44, 0x45, 0x4c, 0x54, 0x41, 0x10, 0x04, 0x2a, 0xb0, 0x02, 0x0a, - 0x20, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x43, 0x6f, 0x6d, 0x70, - 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x4d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x54, 0x79, 0x70, - 0x65, 0x12, 0x34, 0x0a, 0x30, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x53, 0x5f, 0x56, 0x49, 0x45, - 0x57, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x4d, 0x45, 0x41, - 0x53, 0x55, 0x52, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, - 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x33, 0x0a, 0x2f, 0x4d, 0x45, 0x54, 0x52, 0x49, - 0x43, 0x53, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, - 0x4f, 0x4e, 0x5f, 0x4d, 0x45, 0x41, 0x53, 0x55, 0x52, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, - 0x42, 0x41, 0x53, 0x45, 0x5f, 0x56, 0x41, 0x4c, 0x55, 0x45, 0x10, 0x01, 0x12, 0x39, 0x0a, 0x35, - 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x53, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x43, 0x4f, 0x4d, - 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x4d, 0x45, 0x41, 0x53, 0x55, 0x52, 0x45, 0x5f, - 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, - 0x56, 0x41, 0x4c, 0x55, 0x45, 0x10, 0x02, 0x12, 0x32, 0x0a, 0x2e, 0x4d, 0x45, 0x54, 0x52, 0x49, - 0x43, 0x53, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, - 0x4f, 0x4e, 0x5f, 0x4d, 0x45, 0x41, 0x53, 0x55, 0x52, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, - 0x41, 0x42, 0x53, 0x5f, 0x44, 0x45, 0x4c, 0x54, 0x41, 0x10, 0x03, 0x12, 0x32, 0x0a, 0x2e, 0x4d, + 0x52, 0x45, 0x4c, 0x5f, 0x44, 0x45, 0x4c, 0x54, 0x41, 0x10, 0x04, 0x2a, 0xb0, 0x02, 0x0a, 0x20, + 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x43, 0x6f, 0x6d, 0x70, 0x61, + 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x4d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x34, 0x0a, 0x30, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x53, 0x5f, 0x56, 0x49, 0x45, 0x57, + 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x4d, 0x45, 0x41, 0x53, + 0x55, 0x52, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, + 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x33, 0x0a, 0x2f, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, + 0x53, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, + 0x4e, 0x5f, 0x4d, 0x45, 0x41, 0x53, 0x55, 0x52, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x42, + 0x41, 0x53, 0x45, 0x5f, 0x56, 0x41, 0x4c, 0x55, 0x45, 0x10, 0x01, 0x12, 0x39, 0x0a, 0x35, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x53, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x4d, 0x45, 0x41, 0x53, 0x55, 0x52, 0x45, 0x5f, 0x54, - 0x59, 0x50, 0x45, 0x5f, 0x52, 0x45, 0x4c, 0x5f, 0x44, 0x45, 0x4c, 0x54, 0x41, 0x10, 0x04, 0x2a, - 0x6d, 0x0a, 0x0f, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x4d, 0x65, 0x74, 0x68, - 0x6f, 0x64, 0x12, 0x20, 0x0a, 0x1c, 0x48, 0x49, 0x53, 0x54, 0x4f, 0x47, 0x52, 0x41, 0x4d, 0x5f, - 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, - 0x45, 0x44, 0x10, 0x00, 0x12, 0x17, 0x0a, 0x13, 0x48, 0x49, 0x53, 0x54, 0x4f, 0x47, 0x52, 0x41, - 0x4d, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x46, 0x44, 0x10, 0x01, 0x12, 0x1f, 0x0a, - 0x1b, 0x48, 0x49, 0x53, 0x54, 0x4f, 0x47, 0x52, 0x41, 0x4d, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, - 0x44, 0x5f, 0x44, 0x49, 0x41, 0x47, 0x4e, 0x4f, 0x53, 0x54, 0x49, 0x43, 0x10, 0x02, 0x32, 0xba, - 0x2f, 0x0a, 0x0c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, - 0x74, 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x1d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, - 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, + 0x59, 0x50, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x56, + 0x41, 0x4c, 0x55, 0x45, 0x10, 0x02, 0x12, 0x32, 0x0a, 0x2e, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, + 0x53, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, + 0x4e, 0x5f, 0x4d, 0x45, 0x41, 0x53, 0x55, 0x52, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x41, + 0x42, 0x53, 0x5f, 0x44, 0x45, 0x4c, 0x54, 0x41, 0x10, 0x03, 0x12, 0x32, 0x0a, 0x2e, 0x4d, 0x45, + 0x54, 0x52, 0x49, 0x43, 0x53, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, + 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x4d, 0x45, 0x41, 0x53, 0x55, 0x52, 0x45, 0x5f, 0x54, 0x59, + 0x50, 0x45, 0x5f, 0x52, 0x45, 0x4c, 0x5f, 0x44, 0x45, 0x4c, 0x54, 0x41, 0x10, 0x04, 0x2a, 0x6d, + 0x0a, 0x0f, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x4d, 0x65, 0x74, 0x68, 0x6f, + 0x64, 0x12, 0x20, 0x0a, 0x1c, 0x48, 0x49, 0x53, 0x54, 0x4f, 0x47, 0x52, 0x41, 0x4d, 0x5f, 0x4d, + 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, + 0x44, 0x10, 0x00, 0x12, 0x17, 0x0a, 0x13, 0x48, 0x49, 0x53, 0x54, 0x4f, 0x47, 0x52, 0x41, 0x4d, + 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x46, 0x44, 0x10, 0x01, 0x12, 0x1f, 0x0a, 0x1b, + 0x48, 0x49, 0x53, 0x54, 0x4f, 0x47, 0x52, 0x41, 0x4d, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, + 0x5f, 0x44, 0x49, 0x41, 0x47, 0x4e, 0x4f, 0x53, 0x54, 0x49, 0x43, 0x10, 0x02, 0x32, 0xba, 0x2f, + 0x0a, 0x0c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x74, + 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x1d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x26, 0x3a, - 0x01, 0x2a, 0x22, 0x21, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, - 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, - 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x80, 0x01, 0x0a, 0x06, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, - 0x12, 0x1e, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x1f, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x35, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2f, 0x3a, 0x01, 0x2a, 0x22, 0x2a, 0x2f, 0x76, - 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, - 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, - 0x73, 0x2f, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x9b, 0x01, 0x0a, 0x0c, 0x45, 0x78, 0x70, - 0x6f, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x24, 0x2e, 0x72, 0x69, 0x6c, 0x6c, - 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, - 0x72, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x25, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x38, 0x3a, 0x01, - 0x2a, 0x22, 0x33, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, - 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x72, - 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x2f, 0x7b, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x7d, 0x2f, - 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x9e, 0x01, 0x0a, 0x0e, 0x50, 0x72, 0x6f, 0x6a, 0x65, - 0x63, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x26, 0x2e, 0x72, 0x69, 0x6c, 0x6c, - 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x6a, - 0x65, 0x63, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x27, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61, - 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3b, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x35, 0x12, 0x33, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, - 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, - 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2d, - 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0xd2, 0x01, 0x0a, 0x16, 0x4d, 0x65, 0x74, 0x72, - 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x2e, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, - 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, + 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x26, 0x3a, 0x01, + 0x2a, 0x22, 0x21, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, + 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, + 0x75, 0x65, 0x72, 0x79, 0x12, 0x80, 0x01, 0x0a, 0x06, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x12, + 0x1e, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x1f, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x35, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2f, 0x3a, 0x01, 0x2a, 0x22, 0x2a, 0x2f, 0x76, 0x31, + 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, + 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, + 0x2f, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x9b, 0x01, 0x0a, 0x0c, 0x45, 0x78, 0x70, 0x6f, + 0x72, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x24, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, + 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, + 0x74, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, + 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x38, 0x3a, 0x01, 0x2a, + 0x22, 0x33, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, + 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x72, 0x65, + 0x70, 0x6f, 0x72, 0x74, 0x73, 0x2f, 0x7b, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x7d, 0x2f, 0x65, + 0x78, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x9e, 0x01, 0x0a, 0x0e, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, + 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x26, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, + 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x27, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3b, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x35, 0x12, 0x33, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, + 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, + 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2d, 0x73, + 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0xd2, 0x01, 0x0a, 0x16, 0x4d, 0x65, 0x74, 0x72, 0x69, + 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x2e, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x41, + 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x2f, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x41, + 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x57, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x51, 0x3a, 0x01, 0x2a, 0x22, 0x4c, 0x2f, + 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, + 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, + 0x65, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2d, 0x76, 0x69, 0x65, 0x77, 0x73, + 0x2f, 0x7b, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x7d, 0x2f, + 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0xc7, 0x01, 0x0a, 0x12, + 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, 0x6f, 0x70, 0x6c, 0x69, + 0x73, 0x74, 0x12, 0x2a, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, - 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x57, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x51, 0x3a, 0x01, 0x2a, 0x22, 0x4c, - 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, - 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, - 0x69, 0x65, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2d, 0x76, 0x69, 0x65, 0x77, - 0x73, 0x2f, 0x7b, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x7d, - 0x2f, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0xc7, 0x01, 0x0a, - 0x12, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, 0x6f, 0x70, 0x6c, - 0x69, 0x73, 0x74, 0x12, 0x2a, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, - 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, - 0x77, 0x54, 0x6f, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x2b, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, 0x6f, 0x70, - 0x6c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x58, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x52, 0x3a, 0x01, 0x2a, 0x22, 0x4d, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, - 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, - 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x6d, 0x65, 0x74, - 0x72, 0x69, 0x63, 0x73, 0x2d, 0x76, 0x69, 0x65, 0x77, 0x73, 0x2f, 0x7b, 0x6d, 0x65, 0x74, 0x72, - 0x69, 0x63, 0x73, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x74, - 0x6f, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x12, 0xd8, 0x01, 0x0a, 0x15, 0x4d, 0x65, 0x74, 0x72, 0x69, - 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, - 0x12, 0x2d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x43, 0x6f, - 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x2e, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, + 0x54, 0x6f, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, + 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, 0x6f, 0x70, 0x6c, + 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x58, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x52, 0x3a, 0x01, 0x2a, 0x22, 0x4d, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, + 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, + 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, + 0x69, 0x63, 0x73, 0x2d, 0x76, 0x69, 0x65, 0x77, 0x73, 0x2f, 0x7b, 0x6d, 0x65, 0x74, 0x72, 0x69, + 0x63, 0x73, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x74, 0x6f, + 0x70, 0x6c, 0x69, 0x73, 0x74, 0x12, 0xd8, 0x01, 0x0a, 0x15, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, + 0x73, 0x56, 0x69, 0x65, 0x77, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x12, + 0x2d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x43, 0x6f, 0x6d, - 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x60, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x5a, 0x3a, 0x01, 0x2a, 0x22, 0x55, 0x2f, 0x76, 0x31, 0x2f, - 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, - 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, - 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2d, 0x76, 0x69, 0x65, 0x77, 0x73, 0x2f, 0x7b, 0x6d, - 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65, - 0x7d, 0x2f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x65, 0x2d, 0x74, 0x6f, 0x70, 0x6c, 0x69, 0x73, - 0x74, 0x12, 0xd3, 0x01, 0x0a, 0x15, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, - 0x77, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x12, 0x2d, 0x2e, 0x72, 0x69, - 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, - 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, - 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x72, 0x69, 0x6c, + 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, + 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x43, 0x6f, 0x6d, 0x70, + 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x60, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x5a, 0x3a, 0x01, 0x2a, 0x22, 0x55, 0x2f, 0x76, 0x31, 0x2f, 0x69, + 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, + 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x6d, + 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2d, 0x76, 0x69, 0x65, 0x77, 0x73, 0x2f, 0x7b, 0x6d, 0x65, + 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, + 0x2f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x65, 0x2d, 0x74, 0x6f, 0x70, 0x6c, 0x69, 0x73, 0x74, + 0x12, 0xd3, 0x01, 0x0a, 0x15, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, + 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x12, 0x2d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, - 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5b, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x55, 0x3a, 0x01, 0x2a, 0x22, 0x50, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, - 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, - 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, - 0x63, 0x73, 0x2d, 0x76, 0x69, 0x65, 0x77, 0x73, 0x2f, 0x7b, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, - 0x73, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x74, 0x69, 0x6d, - 0x65, 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, 0x12, 0xc3, 0x01, 0x0a, 0x11, 0x4d, 0x65, 0x74, 0x72, - 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x73, 0x12, 0x29, 0x2e, - 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, 0x6f, 0x74, 0x61, 0x6c, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, - 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, - 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x57, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x51, 0x3a, 0x01, 0x2a, 0x22, - 0x4c, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, - 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, - 0x72, 0x69, 0x65, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2d, 0x76, 0x69, 0x65, - 0x77, 0x73, 0x2f, 0x7b, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x76, 0x69, 0x65, 0x77, - 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x73, 0x12, 0xbb, 0x01, - 0x0a, 0x0f, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x52, 0x6f, 0x77, - 0x73, 0x12, 0x27, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x52, - 0x6f, 0x77, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x72, 0x69, 0x6c, - 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, - 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x52, 0x6f, 0x77, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x55, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x4f, 0x3a, 0x01, 0x2a, 0x22, - 0x4a, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, - 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, - 0x72, 0x69, 0x65, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2d, 0x76, 0x69, 0x65, - 0x77, 0x73, 0x2f, 0x7b, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x76, 0x69, 0x65, 0x77, - 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x72, 0x6f, 0x77, 0x73, 0x12, 0xd8, 0x01, 0x0a, 0x14, - 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, 0x69, 0x6d, 0x65, 0x52, - 0x61, 0x6e, 0x67, 0x65, 0x12, 0x2c, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, - 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, - 0x65, 0x77, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, - 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x63, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x5d, 0x3a, 0x01, 0x2a, 0x22, 0x58, 0x2f, 0x76, - 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, - 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, - 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2d, 0x76, 0x69, 0x65, 0x77, 0x73, 0x2f, - 0x7b, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x6e, 0x61, - 0x6d, 0x65, 0x7d, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x2d, 0x73, - 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0xc0, 0x01, 0x0a, 0x11, 0x4d, 0x65, 0x74, 0x72, 0x69, - 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x29, 0x2e, 0x72, + 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x72, 0x69, 0x6c, 0x6c, + 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, + 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5b, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x55, 0x3a, 0x01, 0x2a, 0x22, 0x50, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, + 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, + 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, + 0x73, 0x2d, 0x76, 0x69, 0x65, 0x77, 0x73, 0x2f, 0x7b, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, + 0x5f, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, 0x12, 0xc3, 0x01, 0x0a, 0x11, 0x4d, 0x65, 0x74, 0x72, 0x69, + 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x73, 0x12, 0x29, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, - 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, + 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, - 0x73, 0x56, 0x69, 0x65, 0x77, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x54, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x4e, 0x12, 0x4c, 0x2f, 0x76, 0x31, + 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x57, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x51, 0x3a, 0x01, 0x2a, 0x22, 0x4c, + 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, + 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, + 0x69, 0x65, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2d, 0x76, 0x69, 0x65, 0x77, + 0x73, 0x2f, 0x7b, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x73, 0x12, 0xbb, 0x01, 0x0a, + 0x0f, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x52, 0x6f, 0x77, 0x73, + 0x12, 0x27, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x52, 0x6f, + 0x77, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x72, 0x69, 0x6c, 0x6c, + 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, + 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x52, 0x6f, 0x77, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x55, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x4f, 0x3a, 0x01, 0x2a, 0x22, 0x4a, + 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, + 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, + 0x69, 0x65, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2d, 0x76, 0x69, 0x65, 0x77, + 0x73, 0x2f, 0x7b, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x72, 0x6f, 0x77, 0x73, 0x12, 0xd8, 0x01, 0x0a, 0x14, 0x4d, + 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, + 0x6e, 0x67, 0x65, 0x12, 0x2c, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, + 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, + 0x77, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x2d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, + 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x63, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x5d, 0x3a, 0x01, 0x2a, 0x22, 0x58, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2d, 0x76, 0x69, 0x65, 0x77, 0x73, 0x2f, 0x7b, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x6e, 0x61, 0x6d, - 0x65, 0x7d, 0x2f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0xc3, 0x01, 0x0a, 0x11, 0x4d, 0x65, - 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, - 0x29, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x53, 0x65, 0x61, - 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x72, 0x69, 0x6c, - 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, - 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x57, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x51, 0x3a, 0x01, - 0x2a, 0x22, 0x4c, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, - 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, - 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2d, 0x76, - 0x69, 0x65, 0x77, 0x73, 0x2f, 0x7b, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x76, 0x69, - 0x65, 0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, - 0xd4, 0x01, 0x0a, 0x15, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, - 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x2d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, + 0x65, 0x7d, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x2d, 0x73, 0x75, + 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0xc0, 0x01, 0x0a, 0x11, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, + 0x73, 0x56, 0x69, 0x65, 0x77, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x29, 0x2e, 0x72, 0x69, + 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, + 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, + 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, + 0x56, 0x69, 0x65, 0x77, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x54, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x4e, 0x12, 0x4c, 0x2f, 0x76, 0x31, 0x2f, + 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, + 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, + 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2d, 0x76, 0x69, 0x65, 0x77, 0x73, 0x2f, 0x7b, 0x6d, + 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x7d, 0x2f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0xc3, 0x01, 0x0a, 0x11, 0x4d, 0x65, 0x74, + 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x29, + 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x53, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, - 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, + 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x57, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x51, 0x3a, 0x01, 0x2a, + 0x22, 0x4c, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, + 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, + 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2d, 0x76, 0x69, + 0x65, 0x77, 0x73, 0x2f, 0x7b, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x76, 0x69, 0x65, + 0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0xd4, + 0x01, 0x0a, 0x15, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, 0x69, + 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x2d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x56, - 0x3a, 0x01, 0x2a, 0x22, 0x51, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, - 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, - 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, - 0x2d, 0x76, 0x69, 0x65, 0x77, 0x73, 0x2f, 0x7b, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, - 0x76, 0x69, 0x65, 0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x2d, - 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0xd7, 0x01, 0x0a, 0x16, 0x4d, 0x65, 0x74, 0x72, 0x69, - 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x12, 0x2e, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x41, - 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x2f, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x41, - 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x5c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x56, 0x3a, 0x01, 0x2a, 0x22, 0x51, 0x2f, - 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, - 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, - 0x65, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2d, 0x76, 0x69, 0x65, 0x77, 0x73, - 0x2f, 0x7b, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x12, 0xd8, 0x01, 0x0a, 0x1d, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x45, 0x78, 0x70, 0x72, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x53, - 0x51, 0x4c, 0x12, 0x35, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x45, 0x78, 0x70, 0x72, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x53, - 0x51, 0x4c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x72, 0x69, 0x6c, 0x6c, - 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x76, - 0x65, 0x72, 0x74, 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x4d, - 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x53, 0x51, 0x4c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x48, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x42, 0x3a, 0x01, 0x2a, 0x22, 0x3d, 0x2f, 0x76, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, + 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, + 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x56, 0x3a, + 0x01, 0x2a, 0x22, 0x51, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, + 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, + 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2d, + 0x76, 0x69, 0x65, 0x77, 0x73, 0x2f, 0x7b, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x76, + 0x69, 0x65, 0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x2d, 0x72, + 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0xd7, 0x01, 0x0a, 0x16, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, + 0x73, 0x56, 0x69, 0x65, 0x77, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x12, 0x2e, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x41, 0x6e, + 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x2f, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x41, 0x6e, + 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x5c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x56, 0x3a, 0x01, 0x2a, 0x22, 0x51, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, - 0x73, 0x2f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x2d, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x12, 0xa8, 0x01, 0x0a, 0x0d, - 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x12, 0x25, 0x2e, - 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, - 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x43, 0x61, - 0x6e, 0x76, 0x61, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x48, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x42, 0x3a, 0x01, 0x2a, 0x22, 0x3d, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, - 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, - 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x63, 0x61, 0x6e, - 0x76, 0x61, 0x73, 0x65, 0x73, 0x2f, 0x7b, 0x63, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x7d, 0x2f, 0x72, - 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x12, 0xb6, 0x01, 0x0a, 0x10, 0x52, 0x65, 0x73, 0x6f, 0x6c, - 0x76, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x12, 0x28, 0x2e, 0x72, 0x69, - 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, - 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, - 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x43, - 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x4d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x47, 0x3a, 0x01, 0x2a, 0x22, 0x42, 0x2f, 0x76, 0x31, + 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2d, 0x76, 0x69, 0x65, 0x77, 0x73, 0x2f, + 0x7b, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x7d, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, + 0xd8, 0x01, 0x0a, 0x1d, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x45, 0x78, 0x70, 0x72, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x53, 0x51, + 0x4c, 0x12, 0x35, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x45, 0x78, 0x70, 0x72, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x53, 0x51, + 0x4c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, + 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x76, 0x65, + 0x72, 0x74, 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x4d, 0x65, + 0x74, 0x72, 0x69, 0x63, 0x73, 0x53, 0x51, 0x4c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x48, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x42, 0x3a, 0x01, 0x2a, 0x22, 0x3d, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, - 0x2f, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x7b, 0x63, 0x6f, 0x6d, - 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x7d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x12, - 0xc2, 0x01, 0x0a, 0x16, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, - 0x61, 0x74, 0x65, 0x64, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x2e, 0x2e, 0x72, 0x69, 0x6c, - 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, - 0x6f, 0x6c, 0x76, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x53, 0x74, 0x72, - 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x72, 0x69, 0x6c, - 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, - 0x6f, 0x6c, 0x76, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x53, 0x74, 0x72, - 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x47, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x41, 0x3a, 0x01, 0x2a, 0x22, 0x3c, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, + 0x2f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x2d, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x12, 0xa8, 0x01, 0x0a, 0x0d, 0x52, + 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x12, 0x25, 0x2e, 0x72, + 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, + 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, + 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x43, 0x61, 0x6e, + 0x76, 0x61, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x48, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x42, 0x3a, 0x01, 0x2a, 0x22, 0x3d, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, - 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x72, 0x65, 0x73, 0x6f, - 0x6c, 0x76, 0x65, 0x2d, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x2d, 0x73, 0x74, - 0x72, 0x69, 0x6e, 0x67, 0x12, 0xc7, 0x01, 0x0a, 0x14, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, - 0x6f, 0x6c, 0x6c, 0x75, 0x70, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x2c, 0x2e, - 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x6f, 0x6c, 0x6c, 0x75, 0x70, 0x49, 0x6e, 0x74, 0x65, - 0x72, 0x76, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x72, 0x69, - 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, - 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x6f, 0x6c, 0x6c, 0x75, 0x70, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, - 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x52, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x4c, 0x3a, 0x01, 0x2a, 0x22, 0x47, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, + 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x63, 0x61, 0x6e, 0x76, + 0x61, 0x73, 0x65, 0x73, 0x2f, 0x7b, 0x63, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x7d, 0x2f, 0x72, 0x65, + 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x12, 0xb6, 0x01, 0x0a, 0x10, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, + 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x12, 0x28, 0x2e, 0x72, 0x69, 0x6c, + 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, + 0x6f, 0x6c, 0x76, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, + 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x43, 0x6f, + 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x4d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x47, 0x3a, 0x01, 0x2a, 0x22, 0x42, 0x2f, 0x76, 0x31, 0x2f, + 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, + 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, + 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x7b, 0x63, 0x6f, 0x6d, 0x70, + 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x7d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x12, 0xc2, + 0x01, 0x0a, 0x16, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, + 0x74, 0x65, 0x64, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x2e, 0x2e, 0x72, 0x69, 0x6c, 0x6c, + 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, + 0x6c, 0x76, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x53, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x72, 0x69, 0x6c, 0x6c, + 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, + 0x6c, 0x76, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x53, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x47, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x41, 0x3a, 0x01, 0x2a, 0x22, 0x3c, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, - 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x72, 0x6f, 0x6c, 0x6c, 0x75, - 0x70, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, - 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0x9e, - 0x01, 0x0a, 0x0a, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x6f, 0x70, 0x4b, 0x12, 0x22, 0x2e, - 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x6f, 0x70, 0x4b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x23, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x6f, 0x70, 0x4b, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x47, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x41, 0x3a, 0x01, - 0x2a, 0x22, 0x3c, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, - 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, - 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x74, 0x6f, 0x70, 0x6b, 0x2f, 0x74, 0x61, 0x62, 0x6c, - 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, - 0xb0, 0x01, 0x0a, 0x0f, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x75, 0x6c, 0x6c, 0x43, 0x6f, - 0x75, 0x6e, 0x74, 0x12, 0x27, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, - 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x75, 0x6c, 0x6c, - 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x72, + 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x6c, + 0x76, 0x65, 0x2d, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x2d, 0x73, 0x74, 0x72, + 0x69, 0x6e, 0x67, 0x12, 0xc7, 0x01, 0x0a, 0x14, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x6f, + 0x6c, 0x6c, 0x75, 0x70, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x2c, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, - 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x75, 0x6c, 0x6c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x44, 0x12, 0x42, - 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, - 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, - 0x69, 0x65, 0x73, 0x2f, 0x6e, 0x75, 0x6c, 0x6c, 0x2d, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2f, 0x74, - 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, - 0x65, 0x7d, 0x12, 0xe0, 0x01, 0x0a, 0x1b, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x44, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, - 0x63, 0x73, 0x12, 0x33, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x44, 0x65, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x34, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, - 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, - 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x69, - 0x73, 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x56, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x50, 0x12, 0x4e, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, - 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, - 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x76, 0x65, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, - 0x73, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0xb9, 0x01, 0x0a, 0x0f, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, - 0x54, 0x69, 0x6d, 0x65, 0x47, 0x72, 0x61, 0x69, 0x6e, 0x12, 0x27, 0x2e, 0x72, 0x69, 0x6c, 0x6c, - 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, - 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x47, 0x72, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x47, - 0x72, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x53, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x4d, 0x12, 0x4b, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, + 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x6f, 0x6c, 0x6c, 0x75, 0x70, 0x49, 0x6e, 0x74, 0x65, 0x72, + 0x76, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x72, 0x69, 0x6c, + 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, + 0x75, 0x6d, 0x6e, 0x52, 0x6f, 0x6c, 0x6c, 0x75, 0x70, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, + 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x52, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x4c, 0x3a, 0x01, 0x2a, 0x22, 0x47, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, - 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x73, 0x6d, 0x61, 0x6c, 0x6c, 0x65, - 0x73, 0x74, 0x2d, 0x74, 0x69, 0x6d, 0x65, 0x2d, 0x67, 0x72, 0x61, 0x69, 0x6e, 0x2f, 0x74, 0x61, - 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, - 0x7d, 0x12, 0xcc, 0x01, 0x0a, 0x16, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x75, 0x6d, 0x65, - 0x72, 0x69, 0x63, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x12, 0x2e, 0x2e, 0x72, - 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, - 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x48, 0x69, 0x73, 0x74, - 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x72, + 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x72, 0x6f, 0x6c, 0x6c, 0x75, 0x70, + 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, + 0x2f, 0x7b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0x9e, 0x01, + 0x0a, 0x0a, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x6f, 0x70, 0x4b, 0x12, 0x22, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, - 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x48, 0x69, 0x73, 0x74, - 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x51, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x4b, 0x12, 0x49, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, - 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, - 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x6e, 0x75, 0x6d, 0x65, 0x72, - 0x69, 0x63, 0x2d, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x2f, 0x74, 0x61, 0x62, + 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x6f, 0x70, 0x4b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x23, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x6f, 0x70, 0x4b, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x47, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x41, 0x3a, 0x01, 0x2a, + 0x22, 0x3c, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, + 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, + 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x74, 0x6f, 0x70, 0x6b, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, + 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0xb0, + 0x01, 0x0a, 0x0f, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x75, 0x6c, 0x6c, 0x43, 0x6f, 0x75, + 0x6e, 0x74, 0x12, 0x27, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, + 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x75, 0x6c, 0x6c, 0x43, + 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x72, 0x69, + 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, + 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x75, 0x6c, 0x6c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x44, 0x12, 0x42, 0x2f, + 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, + 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, + 0x65, 0x73, 0x2f, 0x6e, 0x75, 0x6c, 0x6c, 0x2d, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2f, 0x74, 0x61, + 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x7d, 0x12, 0xe0, 0x01, 0x0a, 0x1b, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x44, 0x65, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, + 0x73, 0x12, 0x33, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x34, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, + 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x44, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, + 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x56, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x50, 0x12, 0x4e, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, + 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, + 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x76, 0x65, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, + 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x7d, 0x12, 0xb9, 0x01, 0x0a, 0x0f, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, + 0x69, 0x6d, 0x65, 0x47, 0x72, 0x61, 0x69, 0x6e, 0x12, 0x27, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, + 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, + 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x47, 0x72, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x28, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x47, 0x72, + 0x61, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x53, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x4d, 0x12, 0x4b, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, + 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, + 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x73, 0x6d, 0x61, 0x6c, 0x6c, 0x65, 0x73, + 0x74, 0x2d, 0x74, 0x69, 0x6d, 0x65, 0x2d, 0x67, 0x72, 0x61, 0x69, 0x6e, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, - 0x12, 0xbc, 0x01, 0x0a, 0x12, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x75, 0x67, 0x48, 0x69, - 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x12, 0x2a, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, - 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, - 0x52, 0x75, 0x67, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, - 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x75, 0x67, 0x48, - 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x4d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x47, 0x12, 0x45, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, - 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, - 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x72, 0x75, - 0x67, 0x2d, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x2f, 0x74, 0x61, 0x62, 0x6c, + 0x12, 0xcc, 0x01, 0x0a, 0x16, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x75, 0x6d, 0x65, 0x72, + 0x69, 0x63, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x12, 0x2e, 0x2e, 0x72, 0x69, + 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, + 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x48, 0x69, 0x73, 0x74, 0x6f, + 0x67, 0x72, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x72, 0x69, + 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, + 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x48, 0x69, 0x73, 0x74, 0x6f, + 0x67, 0x72, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x51, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x4b, 0x12, 0x49, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, + 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, + 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, + 0x63, 0x2d, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, - 0xb8, 0x01, 0x0a, 0x0f, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, - 0x6e, 0x67, 0x65, 0x12, 0x27, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, - 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, - 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x72, - 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, - 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, + 0xbc, 0x01, 0x0a, 0x12, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x75, 0x67, 0x48, 0x69, 0x73, + 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x12, 0x2a, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, + 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, + 0x75, 0x67, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, + 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x75, 0x67, 0x48, 0x69, + 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x4d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x47, 0x12, 0x45, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, + 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, + 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x72, 0x75, 0x67, + 0x2d, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, + 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0xb8, + 0x01, 0x0a, 0x0f, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, + 0x67, 0x65, 0x12, 0x27, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, + 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x52, + 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x72, 0x69, + 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, + 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x52, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x4c, 0x12, 0x4a, 0x2f, + 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, + 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, + 0x65, 0x73, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x2d, 0x73, 0x75, + 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, + 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0xbe, 0x01, 0x0a, 0x11, 0x43, 0x6f, + 0x6c, 0x75, 0x6d, 0x6e, 0x43, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x12, + 0x29, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x43, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, + 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x72, 0x69, 0x6c, + 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, + 0x75, 0x6d, 0x6e, 0x43, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x52, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x4c, 0x12, 0x4a, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, - 0x69, 0x65, 0x73, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x2d, 0x73, - 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x74, - 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0xbe, 0x01, 0x0a, 0x11, 0x43, - 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x43, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, - 0x12, 0x29, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x43, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, - 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x72, 0x69, - 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, - 0x6c, 0x75, 0x6d, 0x6e, 0x43, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x52, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x4c, 0x12, - 0x4a, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, + 0x69, 0x65, 0x73, 0x2f, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x2d, 0x63, 0x61, 0x72, 0x64, 0x69, + 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x74, + 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0xb6, 0x01, 0x0a, 0x10, 0x43, + 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x12, + 0x28, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, + 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x72, 0x69, 0x6c, 0x6c, + 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, + 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x47, 0x3a, 0x01, 0x2a, 0x22, + 0x42, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, - 0x72, 0x69, 0x65, 0x73, 0x2f, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x2d, 0x63, 0x61, 0x72, 0x64, - 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, - 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0xb6, 0x01, 0x0a, 0x10, - 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, - 0x12, 0x28, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, - 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x72, 0x69, 0x6c, - 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, - 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x47, 0x3a, 0x01, 0x2a, - 0x22, 0x42, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, - 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, - 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, - 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x7d, 0x12, 0xba, 0x01, 0x0a, 0x10, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, - 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x28, 0x2e, 0x72, 0x69, 0x6c, 0x6c, - 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x62, 0x6c, - 0x65, 0x43, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, - 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x72, 0x64, 0x69, - 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x51, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x4b, 0x12, 0x49, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, - 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, - 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x74, 0x61, 0x62, 0x6c, - 0x65, 0x2d, 0x63, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x74, 0x61, - 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, - 0x7d, 0x12, 0xac, 0x01, 0x0a, 0x0c, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, - 0x6e, 0x73, 0x12, 0x24, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, + 0x72, 0x69, 0x65, 0x73, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, + 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x7d, 0x12, 0xba, 0x01, 0x0a, 0x10, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x72, + 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x28, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, - 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x4f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x49, 0x22, 0x47, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, - 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, - 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x63, 0x6f, 0x6c, - 0x75, 0x6d, 0x6e, 0x73, 0x2d, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2f, 0x74, 0x61, 0x62, + 0x43, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, + 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x72, 0x64, 0x69, 0x6e, + 0x61, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x51, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x4b, 0x12, 0x49, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, + 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, + 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, + 0x2d, 0x63, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, - 0x12, 0x98, 0x01, 0x0a, 0x09, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x77, 0x73, 0x12, 0x21, - 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x77, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x22, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x77, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x44, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x3e, 0x12, 0x3c, 0x2f, - 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, - 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, - 0x65, 0x73, 0x2f, 0x72, 0x6f, 0x77, 0x73, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, - 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x42, 0xbf, 0x01, 0x0a, 0x13, - 0x63, 0x6f, 0x6d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, - 0x2e, 0x76, 0x31, 0x42, 0x0c, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x74, - 0x6f, 0x50, 0x01, 0x5a, 0x3c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x72, 0x69, 0x6c, 0x6c, 0x64, 0x61, 0x74, 0x61, 0x2f, 0x72, 0x69, 0x6c, 0x6c, 0x2f, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x72, 0x69, 0x6c, 0x6c, 0x2f, 0x72, 0x75, 0x6e, - 0x74, 0x69, 0x6d, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x76, - 0x31, 0xa2, 0x02, 0x03, 0x52, 0x52, 0x58, 0xaa, 0x02, 0x0f, 0x52, 0x69, 0x6c, 0x6c, 0x2e, 0x52, - 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0f, 0x52, 0x69, 0x6c, 0x6c, - 0x5c, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1b, 0x52, 0x69, - 0x6c, 0x6c, 0x5c, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, - 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x11, 0x52, 0x69, 0x6c, 0x6c, - 0x3a, 0x3a, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x12, 0xac, 0x01, 0x0a, 0x0c, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, + 0x73, 0x12, 0x24, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, + 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, + 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4f, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x49, 0x22, 0x47, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, + 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, + 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x63, 0x6f, 0x6c, 0x75, + 0x6d, 0x6e, 0x73, 0x2d, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2f, 0x74, 0x61, 0x62, 0x6c, + 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, + 0x98, 0x01, 0x0a, 0x09, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x77, 0x73, 0x12, 0x21, 0x2e, + 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, + 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x77, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x22, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x77, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x44, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x3e, 0x12, 0x3c, 0x2f, 0x76, + 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, + 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, + 0x73, 0x2f, 0x72, 0x6f, 0x77, 0x73, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x74, + 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x42, 0xbf, 0x01, 0x0a, 0x13, 0x63, + 0x6f, 0x6d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, + 0x76, 0x31, 0x42, 0x0c, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x50, 0x01, 0x5a, 0x3c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, + 0x69, 0x6c, 0x6c, 0x64, 0x61, 0x74, 0x61, 0x2f, 0x72, 0x69, 0x6c, 0x6c, 0x2f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x72, 0x69, 0x6c, 0x6c, 0x2f, 0x72, 0x75, 0x6e, 0x74, + 0x69, 0x6d, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x76, 0x31, + 0xa2, 0x02, 0x03, 0x52, 0x52, 0x58, 0xaa, 0x02, 0x0f, 0x52, 0x69, 0x6c, 0x6c, 0x2e, 0x52, 0x75, + 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0f, 0x52, 0x69, 0x6c, 0x6c, 0x5c, + 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1b, 0x52, 0x69, 0x6c, + 0x6c, 0x5c, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x11, 0x52, 0x69, 0x6c, 0x6c, 0x3a, + 0x3a, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -11111,120 +11124,121 @@ var file_rill_runtime_v1_queries_proto_depIdxs = []int32{ 109, // 142: rill.runtime.v1.ResolveCanvasResponse.referenced_metrics_views:type_name -> rill.runtime.v1.ResolveCanvasResponse.ReferencedMetricsViewsEntry 118, // 143: rill.runtime.v1.ResolveComponentRequest.args:type_name -> google.protobuf.Struct 118, // 144: rill.runtime.v1.ResolveComponentResponse.renderer_properties:type_name -> google.protobuf.Struct - 110, // 145: rill.runtime.v1.ResolveTemplatedStringRequest.additional_where_by_metrics_view:type_name -> rill.runtime.v1.ResolveTemplatedStringRequest.AdditionalWhereByMetricsViewEntry - 33, // 146: rill.runtime.v1.ResolveTemplatedStringRequest.additional_time_range:type_name -> rill.runtime.v1.TimeRange - 121, // 147: rill.runtime.v1.ColumnRollupIntervalResponse.start:type_name -> google.protobuf.Timestamp - 121, // 148: rill.runtime.v1.ColumnRollupIntervalResponse.end:type_name -> google.protobuf.Timestamp - 123, // 149: rill.runtime.v1.ColumnRollupIntervalResponse.interval:type_name -> rill.runtime.v1.TimeGrain - 71, // 150: rill.runtime.v1.ColumnTopKResponse.categorical_summary:type_name -> rill.runtime.v1.CategoricalSummary - 72, // 151: rill.runtime.v1.CategoricalSummary.top_k:type_name -> rill.runtime.v1.TopK - 111, // 152: rill.runtime.v1.TopK.entries:type_name -> rill.runtime.v1.TopK.Entry - 77, // 153: rill.runtime.v1.ColumnDescriptiveStatisticsResponse.numeric_summary:type_name -> rill.runtime.v1.NumericSummary - 78, // 154: rill.runtime.v1.NumericSummary.numeric_histogram_bins:type_name -> rill.runtime.v1.NumericHistogramBins - 79, // 155: rill.runtime.v1.NumericSummary.numeric_statistics:type_name -> rill.runtime.v1.NumericStatistics - 80, // 156: rill.runtime.v1.NumericSummary.numeric_outliers:type_name -> rill.runtime.v1.NumericOutliers - 112, // 157: rill.runtime.v1.NumericHistogramBins.bins:type_name -> rill.runtime.v1.NumericHistogramBins.Bin - 113, // 158: rill.runtime.v1.NumericOutliers.outliers:type_name -> rill.runtime.v1.NumericOutliers.Outlier - 123, // 159: rill.runtime.v1.ColumnTimeGrainResponse.time_grain:type_name -> rill.runtime.v1.TimeGrain - 3, // 160: rill.runtime.v1.ColumnNumericHistogramRequest.histogram_method:type_name -> rill.runtime.v1.HistogramMethod - 77, // 161: rill.runtime.v1.ColumnNumericHistogramResponse.numeric_summary:type_name -> rill.runtime.v1.NumericSummary - 77, // 162: rill.runtime.v1.ColumnRugHistogramResponse.numeric_summary:type_name -> rill.runtime.v1.NumericSummary - 89, // 163: rill.runtime.v1.ColumnTimeRangeResponse.time_range_summary:type_name -> rill.runtime.v1.TimeRangeSummary - 121, // 164: rill.runtime.v1.TimeRangeSummary.min:type_name -> google.protobuf.Timestamp - 121, // 165: rill.runtime.v1.TimeRangeSummary.max:type_name -> google.protobuf.Timestamp - 121, // 166: rill.runtime.v1.TimeRangeSummary.watermark:type_name -> google.protobuf.Timestamp - 71, // 167: rill.runtime.v1.ColumnCardinalityResponse.categorical_summary:type_name -> rill.runtime.v1.CategoricalSummary - 114, // 168: rill.runtime.v1.ColumnTimeSeriesRequest.measures:type_name -> rill.runtime.v1.ColumnTimeSeriesRequest.BasicMeasure - 94, // 169: rill.runtime.v1.ColumnTimeSeriesRequest.time_range:type_name -> rill.runtime.v1.TimeSeriesTimeRange - 95, // 170: rill.runtime.v1.ColumnTimeSeriesResponse.rollup:type_name -> rill.runtime.v1.TimeSeriesResponse - 121, // 171: rill.runtime.v1.TimeSeriesTimeRange.start:type_name -> google.protobuf.Timestamp - 121, // 172: rill.runtime.v1.TimeSeriesTimeRange.end:type_name -> google.protobuf.Timestamp - 123, // 173: rill.runtime.v1.TimeSeriesTimeRange.interval:type_name -> rill.runtime.v1.TimeGrain - 96, // 174: rill.runtime.v1.TimeSeriesResponse.results:type_name -> rill.runtime.v1.TimeSeriesValue - 96, // 175: rill.runtime.v1.TimeSeriesResponse.spark:type_name -> rill.runtime.v1.TimeSeriesValue - 121, // 176: rill.runtime.v1.TimeSeriesValue.ts:type_name -> google.protobuf.Timestamp - 118, // 177: rill.runtime.v1.TimeSeriesValue.records:type_name -> google.protobuf.Struct - 101, // 178: rill.runtime.v1.TableColumnsResponse.profile_columns:type_name -> rill.runtime.v1.ProfileColumn - 115, // 179: rill.runtime.v1.TableColumnsResponse.unsupported_columns:type_name -> rill.runtime.v1.TableColumnsResponse.UnsupportedColumnsEntry - 118, // 180: rill.runtime.v1.TableRowsResponse.data:type_name -> google.protobuf.Struct - 116, // 181: rill.runtime.v1.MetricsViewFilter.Cond.in:type_name -> google.protobuf.Value - 116, // 182: rill.runtime.v1.MetricsViewSearchResponse.SearchResult.value:type_name -> google.protobuf.Value - 121, // 183: rill.runtime.v1.MetricsViewAnnotationsResponse.Annotation.time:type_name -> google.protobuf.Timestamp - 121, // 184: rill.runtime.v1.MetricsViewAnnotationsResponse.Annotation.time_end:type_name -> google.protobuf.Timestamp - 118, // 185: rill.runtime.v1.MetricsViewAnnotationsResponse.Annotation.additional_fields:type_name -> google.protobuf.Struct - 124, // 186: rill.runtime.v1.ResolveCanvasResponse.ResolvedComponentsEntry.value:type_name -> rill.runtime.v1.Resource - 124, // 187: rill.runtime.v1.ResolveCanvasResponse.ReferencedMetricsViewsEntry.value:type_name -> rill.runtime.v1.Resource - 122, // 188: rill.runtime.v1.ResolveTemplatedStringRequest.AdditionalWhereByMetricsViewEntry.value:type_name -> rill.runtime.v1.Expression - 116, // 189: rill.runtime.v1.TopK.Entry.value:type_name -> google.protobuf.Value - 4, // 190: rill.runtime.v1.QueryService.Query:input_type -> rill.runtime.v1.QueryRequest - 6, // 191: rill.runtime.v1.QueryService.Export:input_type -> rill.runtime.v1.ExportRequest - 8, // 192: rill.runtime.v1.QueryService.ExportReport:input_type -> rill.runtime.v1.ExportReportRequest - 13, // 193: rill.runtime.v1.QueryService.ProjectStorage:input_type -> rill.runtime.v1.ProjectStorageRequest - 16, // 194: rill.runtime.v1.QueryService.MetricsViewAggregation:input_type -> rill.runtime.v1.MetricsViewAggregationRequest - 29, // 195: rill.runtime.v1.QueryService.MetricsViewToplist:input_type -> rill.runtime.v1.MetricsViewToplistRequest - 31, // 196: rill.runtime.v1.QueryService.MetricsViewComparison:input_type -> rill.runtime.v1.MetricsViewComparisonRequest - 38, // 197: rill.runtime.v1.QueryService.MetricsViewTimeSeries:input_type -> rill.runtime.v1.MetricsViewTimeSeriesRequest - 40, // 198: rill.runtime.v1.QueryService.MetricsViewTotals:input_type -> rill.runtime.v1.MetricsViewTotalsRequest - 42, // 199: rill.runtime.v1.QueryService.MetricsViewRows:input_type -> rill.runtime.v1.MetricsViewRowsRequest - 48, // 200: rill.runtime.v1.QueryService.MetricsViewTimeRange:input_type -> rill.runtime.v1.MetricsViewTimeRangeRequest - 50, // 201: rill.runtime.v1.QueryService.MetricsViewSchema:input_type -> rill.runtime.v1.MetricsViewSchemaRequest - 52, // 202: rill.runtime.v1.QueryService.MetricsViewSearch:input_type -> rill.runtime.v1.MetricsViewSearchRequest - 54, // 203: rill.runtime.v1.QueryService.MetricsViewTimeRanges:input_type -> rill.runtime.v1.MetricsViewTimeRangesRequest - 57, // 204: rill.runtime.v1.QueryService.MetricsViewAnnotations:input_type -> rill.runtime.v1.MetricsViewAnnotationsRequest - 59, // 205: rill.runtime.v1.QueryService.ConvertExpressionToMetricsSQL:input_type -> rill.runtime.v1.ConvertExpressionToMetricsSQLRequest - 61, // 206: rill.runtime.v1.QueryService.ResolveCanvas:input_type -> rill.runtime.v1.ResolveCanvasRequest - 63, // 207: rill.runtime.v1.QueryService.ResolveComponent:input_type -> rill.runtime.v1.ResolveComponentRequest - 65, // 208: rill.runtime.v1.QueryService.ResolveTemplatedString:input_type -> rill.runtime.v1.ResolveTemplatedStringRequest - 67, // 209: rill.runtime.v1.QueryService.ColumnRollupInterval:input_type -> rill.runtime.v1.ColumnRollupIntervalRequest - 69, // 210: rill.runtime.v1.QueryService.ColumnTopK:input_type -> rill.runtime.v1.ColumnTopKRequest - 73, // 211: rill.runtime.v1.QueryService.ColumnNullCount:input_type -> rill.runtime.v1.ColumnNullCountRequest - 75, // 212: rill.runtime.v1.QueryService.ColumnDescriptiveStatistics:input_type -> rill.runtime.v1.ColumnDescriptiveStatisticsRequest - 81, // 213: rill.runtime.v1.QueryService.ColumnTimeGrain:input_type -> rill.runtime.v1.ColumnTimeGrainRequest - 83, // 214: rill.runtime.v1.QueryService.ColumnNumericHistogram:input_type -> rill.runtime.v1.ColumnNumericHistogramRequest - 85, // 215: rill.runtime.v1.QueryService.ColumnRugHistogram:input_type -> rill.runtime.v1.ColumnRugHistogramRequest - 87, // 216: rill.runtime.v1.QueryService.ColumnTimeRange:input_type -> rill.runtime.v1.ColumnTimeRangeRequest - 90, // 217: rill.runtime.v1.QueryService.ColumnCardinality:input_type -> rill.runtime.v1.ColumnCardinalityRequest - 92, // 218: rill.runtime.v1.QueryService.ColumnTimeSeries:input_type -> rill.runtime.v1.ColumnTimeSeriesRequest - 97, // 219: rill.runtime.v1.QueryService.TableCardinality:input_type -> rill.runtime.v1.TableCardinalityRequest - 99, // 220: rill.runtime.v1.QueryService.TableColumns:input_type -> rill.runtime.v1.TableColumnsRequest - 102, // 221: rill.runtime.v1.QueryService.TableRows:input_type -> rill.runtime.v1.TableRowsRequest - 5, // 222: rill.runtime.v1.QueryService.Query:output_type -> rill.runtime.v1.QueryResponse - 7, // 223: rill.runtime.v1.QueryService.Export:output_type -> rill.runtime.v1.ExportResponse - 9, // 224: rill.runtime.v1.QueryService.ExportReport:output_type -> rill.runtime.v1.ExportReportResponse - 14, // 225: rill.runtime.v1.QueryService.ProjectStorage:output_type -> rill.runtime.v1.ProjectStorageResponse - 17, // 226: rill.runtime.v1.QueryService.MetricsViewAggregation:output_type -> rill.runtime.v1.MetricsViewAggregationResponse - 30, // 227: rill.runtime.v1.QueryService.MetricsViewToplist:output_type -> rill.runtime.v1.MetricsViewToplistResponse - 32, // 228: rill.runtime.v1.QueryService.MetricsViewComparison:output_type -> rill.runtime.v1.MetricsViewComparisonResponse - 39, // 229: rill.runtime.v1.QueryService.MetricsViewTimeSeries:output_type -> rill.runtime.v1.MetricsViewTimeSeriesResponse - 41, // 230: rill.runtime.v1.QueryService.MetricsViewTotals:output_type -> rill.runtime.v1.MetricsViewTotalsResponse - 43, // 231: rill.runtime.v1.QueryService.MetricsViewRows:output_type -> rill.runtime.v1.MetricsViewRowsResponse - 49, // 232: rill.runtime.v1.QueryService.MetricsViewTimeRange:output_type -> rill.runtime.v1.MetricsViewTimeRangeResponse - 51, // 233: rill.runtime.v1.QueryService.MetricsViewSchema:output_type -> rill.runtime.v1.MetricsViewSchemaResponse - 53, // 234: rill.runtime.v1.QueryService.MetricsViewSearch:output_type -> rill.runtime.v1.MetricsViewSearchResponse - 55, // 235: rill.runtime.v1.QueryService.MetricsViewTimeRanges:output_type -> rill.runtime.v1.MetricsViewTimeRangesResponse - 58, // 236: rill.runtime.v1.QueryService.MetricsViewAnnotations:output_type -> rill.runtime.v1.MetricsViewAnnotationsResponse - 60, // 237: rill.runtime.v1.QueryService.ConvertExpressionToMetricsSQL:output_type -> rill.runtime.v1.ConvertExpressionToMetricsSQLResponse - 62, // 238: rill.runtime.v1.QueryService.ResolveCanvas:output_type -> rill.runtime.v1.ResolveCanvasResponse - 64, // 239: rill.runtime.v1.QueryService.ResolveComponent:output_type -> rill.runtime.v1.ResolveComponentResponse - 66, // 240: rill.runtime.v1.QueryService.ResolveTemplatedString:output_type -> rill.runtime.v1.ResolveTemplatedStringResponse - 68, // 241: rill.runtime.v1.QueryService.ColumnRollupInterval:output_type -> rill.runtime.v1.ColumnRollupIntervalResponse - 70, // 242: rill.runtime.v1.QueryService.ColumnTopK:output_type -> rill.runtime.v1.ColumnTopKResponse - 74, // 243: rill.runtime.v1.QueryService.ColumnNullCount:output_type -> rill.runtime.v1.ColumnNullCountResponse - 76, // 244: rill.runtime.v1.QueryService.ColumnDescriptiveStatistics:output_type -> rill.runtime.v1.ColumnDescriptiveStatisticsResponse - 82, // 245: rill.runtime.v1.QueryService.ColumnTimeGrain:output_type -> rill.runtime.v1.ColumnTimeGrainResponse - 84, // 246: rill.runtime.v1.QueryService.ColumnNumericHistogram:output_type -> rill.runtime.v1.ColumnNumericHistogramResponse - 86, // 247: rill.runtime.v1.QueryService.ColumnRugHistogram:output_type -> rill.runtime.v1.ColumnRugHistogramResponse - 88, // 248: rill.runtime.v1.QueryService.ColumnTimeRange:output_type -> rill.runtime.v1.ColumnTimeRangeResponse - 91, // 249: rill.runtime.v1.QueryService.ColumnCardinality:output_type -> rill.runtime.v1.ColumnCardinalityResponse - 93, // 250: rill.runtime.v1.QueryService.ColumnTimeSeries:output_type -> rill.runtime.v1.ColumnTimeSeriesResponse - 98, // 251: rill.runtime.v1.QueryService.TableCardinality:output_type -> rill.runtime.v1.TableCardinalityResponse - 100, // 252: rill.runtime.v1.QueryService.TableColumns:output_type -> rill.runtime.v1.TableColumnsResponse - 103, // 253: rill.runtime.v1.QueryService.TableRows:output_type -> rill.runtime.v1.TableRowsResponse - 222, // [222:254] is the sub-list for method output_type - 190, // [190:222] is the sub-list for method input_type - 190, // [190:190] is the sub-list for extension type_name - 190, // [190:190] is the sub-list for extension extendee - 0, // [0:190] is the sub-list for field type_name + 118, // 145: rill.runtime.v1.ResolveComponentResponse.resolved_args:type_name -> google.protobuf.Struct + 110, // 146: rill.runtime.v1.ResolveTemplatedStringRequest.additional_where_by_metrics_view:type_name -> rill.runtime.v1.ResolveTemplatedStringRequest.AdditionalWhereByMetricsViewEntry + 33, // 147: rill.runtime.v1.ResolveTemplatedStringRequest.additional_time_range:type_name -> rill.runtime.v1.TimeRange + 121, // 148: rill.runtime.v1.ColumnRollupIntervalResponse.start:type_name -> google.protobuf.Timestamp + 121, // 149: rill.runtime.v1.ColumnRollupIntervalResponse.end:type_name -> google.protobuf.Timestamp + 123, // 150: rill.runtime.v1.ColumnRollupIntervalResponse.interval:type_name -> rill.runtime.v1.TimeGrain + 71, // 151: rill.runtime.v1.ColumnTopKResponse.categorical_summary:type_name -> rill.runtime.v1.CategoricalSummary + 72, // 152: rill.runtime.v1.CategoricalSummary.top_k:type_name -> rill.runtime.v1.TopK + 111, // 153: rill.runtime.v1.TopK.entries:type_name -> rill.runtime.v1.TopK.Entry + 77, // 154: rill.runtime.v1.ColumnDescriptiveStatisticsResponse.numeric_summary:type_name -> rill.runtime.v1.NumericSummary + 78, // 155: rill.runtime.v1.NumericSummary.numeric_histogram_bins:type_name -> rill.runtime.v1.NumericHistogramBins + 79, // 156: rill.runtime.v1.NumericSummary.numeric_statistics:type_name -> rill.runtime.v1.NumericStatistics + 80, // 157: rill.runtime.v1.NumericSummary.numeric_outliers:type_name -> rill.runtime.v1.NumericOutliers + 112, // 158: rill.runtime.v1.NumericHistogramBins.bins:type_name -> rill.runtime.v1.NumericHistogramBins.Bin + 113, // 159: rill.runtime.v1.NumericOutliers.outliers:type_name -> rill.runtime.v1.NumericOutliers.Outlier + 123, // 160: rill.runtime.v1.ColumnTimeGrainResponse.time_grain:type_name -> rill.runtime.v1.TimeGrain + 3, // 161: rill.runtime.v1.ColumnNumericHistogramRequest.histogram_method:type_name -> rill.runtime.v1.HistogramMethod + 77, // 162: rill.runtime.v1.ColumnNumericHistogramResponse.numeric_summary:type_name -> rill.runtime.v1.NumericSummary + 77, // 163: rill.runtime.v1.ColumnRugHistogramResponse.numeric_summary:type_name -> rill.runtime.v1.NumericSummary + 89, // 164: rill.runtime.v1.ColumnTimeRangeResponse.time_range_summary:type_name -> rill.runtime.v1.TimeRangeSummary + 121, // 165: rill.runtime.v1.TimeRangeSummary.min:type_name -> google.protobuf.Timestamp + 121, // 166: rill.runtime.v1.TimeRangeSummary.max:type_name -> google.protobuf.Timestamp + 121, // 167: rill.runtime.v1.TimeRangeSummary.watermark:type_name -> google.protobuf.Timestamp + 71, // 168: rill.runtime.v1.ColumnCardinalityResponse.categorical_summary:type_name -> rill.runtime.v1.CategoricalSummary + 114, // 169: rill.runtime.v1.ColumnTimeSeriesRequest.measures:type_name -> rill.runtime.v1.ColumnTimeSeriesRequest.BasicMeasure + 94, // 170: rill.runtime.v1.ColumnTimeSeriesRequest.time_range:type_name -> rill.runtime.v1.TimeSeriesTimeRange + 95, // 171: rill.runtime.v1.ColumnTimeSeriesResponse.rollup:type_name -> rill.runtime.v1.TimeSeriesResponse + 121, // 172: rill.runtime.v1.TimeSeriesTimeRange.start:type_name -> google.protobuf.Timestamp + 121, // 173: rill.runtime.v1.TimeSeriesTimeRange.end:type_name -> google.protobuf.Timestamp + 123, // 174: rill.runtime.v1.TimeSeriesTimeRange.interval:type_name -> rill.runtime.v1.TimeGrain + 96, // 175: rill.runtime.v1.TimeSeriesResponse.results:type_name -> rill.runtime.v1.TimeSeriesValue + 96, // 176: rill.runtime.v1.TimeSeriesResponse.spark:type_name -> rill.runtime.v1.TimeSeriesValue + 121, // 177: rill.runtime.v1.TimeSeriesValue.ts:type_name -> google.protobuf.Timestamp + 118, // 178: rill.runtime.v1.TimeSeriesValue.records:type_name -> google.protobuf.Struct + 101, // 179: rill.runtime.v1.TableColumnsResponse.profile_columns:type_name -> rill.runtime.v1.ProfileColumn + 115, // 180: rill.runtime.v1.TableColumnsResponse.unsupported_columns:type_name -> rill.runtime.v1.TableColumnsResponse.UnsupportedColumnsEntry + 118, // 181: rill.runtime.v1.TableRowsResponse.data:type_name -> google.protobuf.Struct + 116, // 182: rill.runtime.v1.MetricsViewFilter.Cond.in:type_name -> google.protobuf.Value + 116, // 183: rill.runtime.v1.MetricsViewSearchResponse.SearchResult.value:type_name -> google.protobuf.Value + 121, // 184: rill.runtime.v1.MetricsViewAnnotationsResponse.Annotation.time:type_name -> google.protobuf.Timestamp + 121, // 185: rill.runtime.v1.MetricsViewAnnotationsResponse.Annotation.time_end:type_name -> google.protobuf.Timestamp + 118, // 186: rill.runtime.v1.MetricsViewAnnotationsResponse.Annotation.additional_fields:type_name -> google.protobuf.Struct + 124, // 187: rill.runtime.v1.ResolveCanvasResponse.ResolvedComponentsEntry.value:type_name -> rill.runtime.v1.Resource + 124, // 188: rill.runtime.v1.ResolveCanvasResponse.ReferencedMetricsViewsEntry.value:type_name -> rill.runtime.v1.Resource + 122, // 189: rill.runtime.v1.ResolveTemplatedStringRequest.AdditionalWhereByMetricsViewEntry.value:type_name -> rill.runtime.v1.Expression + 116, // 190: rill.runtime.v1.TopK.Entry.value:type_name -> google.protobuf.Value + 4, // 191: rill.runtime.v1.QueryService.Query:input_type -> rill.runtime.v1.QueryRequest + 6, // 192: rill.runtime.v1.QueryService.Export:input_type -> rill.runtime.v1.ExportRequest + 8, // 193: rill.runtime.v1.QueryService.ExportReport:input_type -> rill.runtime.v1.ExportReportRequest + 13, // 194: rill.runtime.v1.QueryService.ProjectStorage:input_type -> rill.runtime.v1.ProjectStorageRequest + 16, // 195: rill.runtime.v1.QueryService.MetricsViewAggregation:input_type -> rill.runtime.v1.MetricsViewAggregationRequest + 29, // 196: rill.runtime.v1.QueryService.MetricsViewToplist:input_type -> rill.runtime.v1.MetricsViewToplistRequest + 31, // 197: rill.runtime.v1.QueryService.MetricsViewComparison:input_type -> rill.runtime.v1.MetricsViewComparisonRequest + 38, // 198: rill.runtime.v1.QueryService.MetricsViewTimeSeries:input_type -> rill.runtime.v1.MetricsViewTimeSeriesRequest + 40, // 199: rill.runtime.v1.QueryService.MetricsViewTotals:input_type -> rill.runtime.v1.MetricsViewTotalsRequest + 42, // 200: rill.runtime.v1.QueryService.MetricsViewRows:input_type -> rill.runtime.v1.MetricsViewRowsRequest + 48, // 201: rill.runtime.v1.QueryService.MetricsViewTimeRange:input_type -> rill.runtime.v1.MetricsViewTimeRangeRequest + 50, // 202: rill.runtime.v1.QueryService.MetricsViewSchema:input_type -> rill.runtime.v1.MetricsViewSchemaRequest + 52, // 203: rill.runtime.v1.QueryService.MetricsViewSearch:input_type -> rill.runtime.v1.MetricsViewSearchRequest + 54, // 204: rill.runtime.v1.QueryService.MetricsViewTimeRanges:input_type -> rill.runtime.v1.MetricsViewTimeRangesRequest + 57, // 205: rill.runtime.v1.QueryService.MetricsViewAnnotations:input_type -> rill.runtime.v1.MetricsViewAnnotationsRequest + 59, // 206: rill.runtime.v1.QueryService.ConvertExpressionToMetricsSQL:input_type -> rill.runtime.v1.ConvertExpressionToMetricsSQLRequest + 61, // 207: rill.runtime.v1.QueryService.ResolveCanvas:input_type -> rill.runtime.v1.ResolveCanvasRequest + 63, // 208: rill.runtime.v1.QueryService.ResolveComponent:input_type -> rill.runtime.v1.ResolveComponentRequest + 65, // 209: rill.runtime.v1.QueryService.ResolveTemplatedString:input_type -> rill.runtime.v1.ResolveTemplatedStringRequest + 67, // 210: rill.runtime.v1.QueryService.ColumnRollupInterval:input_type -> rill.runtime.v1.ColumnRollupIntervalRequest + 69, // 211: rill.runtime.v1.QueryService.ColumnTopK:input_type -> rill.runtime.v1.ColumnTopKRequest + 73, // 212: rill.runtime.v1.QueryService.ColumnNullCount:input_type -> rill.runtime.v1.ColumnNullCountRequest + 75, // 213: rill.runtime.v1.QueryService.ColumnDescriptiveStatistics:input_type -> rill.runtime.v1.ColumnDescriptiveStatisticsRequest + 81, // 214: rill.runtime.v1.QueryService.ColumnTimeGrain:input_type -> rill.runtime.v1.ColumnTimeGrainRequest + 83, // 215: rill.runtime.v1.QueryService.ColumnNumericHistogram:input_type -> rill.runtime.v1.ColumnNumericHistogramRequest + 85, // 216: rill.runtime.v1.QueryService.ColumnRugHistogram:input_type -> rill.runtime.v1.ColumnRugHistogramRequest + 87, // 217: rill.runtime.v1.QueryService.ColumnTimeRange:input_type -> rill.runtime.v1.ColumnTimeRangeRequest + 90, // 218: rill.runtime.v1.QueryService.ColumnCardinality:input_type -> rill.runtime.v1.ColumnCardinalityRequest + 92, // 219: rill.runtime.v1.QueryService.ColumnTimeSeries:input_type -> rill.runtime.v1.ColumnTimeSeriesRequest + 97, // 220: rill.runtime.v1.QueryService.TableCardinality:input_type -> rill.runtime.v1.TableCardinalityRequest + 99, // 221: rill.runtime.v1.QueryService.TableColumns:input_type -> rill.runtime.v1.TableColumnsRequest + 102, // 222: rill.runtime.v1.QueryService.TableRows:input_type -> rill.runtime.v1.TableRowsRequest + 5, // 223: rill.runtime.v1.QueryService.Query:output_type -> rill.runtime.v1.QueryResponse + 7, // 224: rill.runtime.v1.QueryService.Export:output_type -> rill.runtime.v1.ExportResponse + 9, // 225: rill.runtime.v1.QueryService.ExportReport:output_type -> rill.runtime.v1.ExportReportResponse + 14, // 226: rill.runtime.v1.QueryService.ProjectStorage:output_type -> rill.runtime.v1.ProjectStorageResponse + 17, // 227: rill.runtime.v1.QueryService.MetricsViewAggregation:output_type -> rill.runtime.v1.MetricsViewAggregationResponse + 30, // 228: rill.runtime.v1.QueryService.MetricsViewToplist:output_type -> rill.runtime.v1.MetricsViewToplistResponse + 32, // 229: rill.runtime.v1.QueryService.MetricsViewComparison:output_type -> rill.runtime.v1.MetricsViewComparisonResponse + 39, // 230: rill.runtime.v1.QueryService.MetricsViewTimeSeries:output_type -> rill.runtime.v1.MetricsViewTimeSeriesResponse + 41, // 231: rill.runtime.v1.QueryService.MetricsViewTotals:output_type -> rill.runtime.v1.MetricsViewTotalsResponse + 43, // 232: rill.runtime.v1.QueryService.MetricsViewRows:output_type -> rill.runtime.v1.MetricsViewRowsResponse + 49, // 233: rill.runtime.v1.QueryService.MetricsViewTimeRange:output_type -> rill.runtime.v1.MetricsViewTimeRangeResponse + 51, // 234: rill.runtime.v1.QueryService.MetricsViewSchema:output_type -> rill.runtime.v1.MetricsViewSchemaResponse + 53, // 235: rill.runtime.v1.QueryService.MetricsViewSearch:output_type -> rill.runtime.v1.MetricsViewSearchResponse + 55, // 236: rill.runtime.v1.QueryService.MetricsViewTimeRanges:output_type -> rill.runtime.v1.MetricsViewTimeRangesResponse + 58, // 237: rill.runtime.v1.QueryService.MetricsViewAnnotations:output_type -> rill.runtime.v1.MetricsViewAnnotationsResponse + 60, // 238: rill.runtime.v1.QueryService.ConvertExpressionToMetricsSQL:output_type -> rill.runtime.v1.ConvertExpressionToMetricsSQLResponse + 62, // 239: rill.runtime.v1.QueryService.ResolveCanvas:output_type -> rill.runtime.v1.ResolveCanvasResponse + 64, // 240: rill.runtime.v1.QueryService.ResolveComponent:output_type -> rill.runtime.v1.ResolveComponentResponse + 66, // 241: rill.runtime.v1.QueryService.ResolveTemplatedString:output_type -> rill.runtime.v1.ResolveTemplatedStringResponse + 68, // 242: rill.runtime.v1.QueryService.ColumnRollupInterval:output_type -> rill.runtime.v1.ColumnRollupIntervalResponse + 70, // 243: rill.runtime.v1.QueryService.ColumnTopK:output_type -> rill.runtime.v1.ColumnTopKResponse + 74, // 244: rill.runtime.v1.QueryService.ColumnNullCount:output_type -> rill.runtime.v1.ColumnNullCountResponse + 76, // 245: rill.runtime.v1.QueryService.ColumnDescriptiveStatistics:output_type -> rill.runtime.v1.ColumnDescriptiveStatisticsResponse + 82, // 246: rill.runtime.v1.QueryService.ColumnTimeGrain:output_type -> rill.runtime.v1.ColumnTimeGrainResponse + 84, // 247: rill.runtime.v1.QueryService.ColumnNumericHistogram:output_type -> rill.runtime.v1.ColumnNumericHistogramResponse + 86, // 248: rill.runtime.v1.QueryService.ColumnRugHistogram:output_type -> rill.runtime.v1.ColumnRugHistogramResponse + 88, // 249: rill.runtime.v1.QueryService.ColumnTimeRange:output_type -> rill.runtime.v1.ColumnTimeRangeResponse + 91, // 250: rill.runtime.v1.QueryService.ColumnCardinality:output_type -> rill.runtime.v1.ColumnCardinalityResponse + 93, // 251: rill.runtime.v1.QueryService.ColumnTimeSeries:output_type -> rill.runtime.v1.ColumnTimeSeriesResponse + 98, // 252: rill.runtime.v1.QueryService.TableCardinality:output_type -> rill.runtime.v1.TableCardinalityResponse + 100, // 253: rill.runtime.v1.QueryService.TableColumns:output_type -> rill.runtime.v1.TableColumnsResponse + 103, // 254: rill.runtime.v1.QueryService.TableRows:output_type -> rill.runtime.v1.TableRowsResponse + 223, // [223:255] is the sub-list for method output_type + 191, // [191:223] is the sub-list for method input_type + 191, // [191:191] is the sub-list for extension type_name + 191, // [191:191] is the sub-list for extension extendee + 0, // [0:191] is the sub-list for field type_name } func init() { file_rill_runtime_v1_queries_proto_init() } diff --git a/proto/gen/rill/runtime/v1/queries.pb.validate.go b/proto/gen/rill/runtime/v1/queries.pb.validate.go index 6d5ca64cd039..014945f831f1 100644 --- a/proto/gen/rill/runtime/v1/queries.pb.validate.go +++ b/proto/gen/rill/runtime/v1/queries.pb.validate.go @@ -11297,6 +11297,35 @@ func (m *ResolveComponentResponse) validate(all bool) error { } } + if all { + switch v := interface{}(m.GetResolvedArgs()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, ResolveComponentResponseValidationError{ + field: "ResolvedArgs", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, ResolveComponentResponseValidationError{ + field: "ResolvedArgs", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetResolvedArgs()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return ResolveComponentResponseValidationError{ + field: "ResolvedArgs", + reason: "embedded message failed validation", + cause: err, + } + } + } + if len(errors) > 0 { return ResolveComponentResponseMultiError(errors) } diff --git a/proto/gen/rill/runtime/v1/resources.pb.go b/proto/gen/rill/runtime/v1/resources.pb.go index c7dccdb7e403..013e8bde7025 100644 --- a/proto/gen/rill/runtime/v1/resources.pb.go +++ b/proto/gen/rill/runtime/v1/resources.pb.go @@ -5404,13 +5404,16 @@ type ComponentSpec struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - DisplayName string `protobuf:"bytes,1,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` - Description string `protobuf:"bytes,7,opt,name=description,proto3" json:"description,omitempty"` - Renderer string `protobuf:"bytes,4,opt,name=renderer,proto3" json:"renderer,omitempty"` - RendererProperties *structpb.Struct `protobuf:"bytes,5,opt,name=renderer_properties,json=rendererProperties,proto3" json:"renderer_properties,omitempty"` - Input []*ComponentVariable `protobuf:"bytes,8,rep,name=input,proto3" json:"input,omitempty"` - Output *ComponentVariable `protobuf:"bytes,9,opt,name=output,proto3" json:"output,omitempty"` - DefinedInCanvas bool `protobuf:"varint,6,opt,name=defined_in_canvas,json=definedInCanvas,proto3" json:"defined_in_canvas,omitempty"` + DisplayName string `protobuf:"bytes,1,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` + Description string `protobuf:"bytes,7,opt,name=description,proto3" json:"description,omitempty"` + Renderer string `protobuf:"bytes,4,opt,name=renderer,proto3" json:"renderer,omitempty"` + RendererProperties *structpb.Struct `protobuf:"bytes,5,opt,name=renderer_properties,json=rendererProperties,proto3" json:"renderer_properties,omitempty"` + // Declared parameters that canvases can bind values to when referencing this component. + // Bound values are available in the renderer properties' templating as {{ .params. }}. + Params []*ComponentParam `protobuf:"bytes,10,rep,name=params,proto3" json:"params,omitempty"` + Input []*ComponentVariable `protobuf:"bytes,8,rep,name=input,proto3" json:"input,omitempty"` + Output *ComponentVariable `protobuf:"bytes,9,opt,name=output,proto3" json:"output,omitempty"` + DefinedInCanvas bool `protobuf:"varint,6,opt,name=defined_in_canvas,json=definedInCanvas,proto3" json:"defined_in_canvas,omitempty"` } func (x *ComponentSpec) Reset() { @@ -5473,6 +5476,13 @@ func (x *ComponentSpec) GetRendererProperties() *structpb.Struct { return nil } +func (x *ComponentSpec) GetParams() []*ComponentParam { + if x != nil { + return x.Params + } + return nil +} + func (x *ComponentSpec) GetInput() []*ComponentVariable { if x != nil { return x.Input @@ -5615,6 +5625,111 @@ func (x *ComponentVariable) GetDefaultValue() *structpb.Value { return nil } +// ComponentParam declares a typed, validated parameter of a component. +type ComponentParam struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Param name. Must be a valid identifier; referenced in templates as {{ .params. }}. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // Param type. One of: "string", "number", "boolean", "metrics_view", "measure", "dimension", "time_dimension". + Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` + // Human-facing description of the param. + Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` + // If true, a canvas item referencing this component must bind a value for the param. + Required bool `protobuf:"varint,4,opt,name=required,proto3" json:"required,omitempty"` + // Default value used when the param is not bound. Mutually exclusive with required=true. + Default *structpb.Value `protobuf:"bytes,5,opt,name=default,proto3" json:"default,omitempty"` + // For "measure", "dimension" and "time_dimension" params: + // the name of a sibling param of type "metrics_view" whose bound metrics view the field must belong to. + // May be omitted when exactly one "metrics_view" param is declared, in which case the parser fills it in. + MetricsViewParam string `protobuf:"bytes,6,opt,name=metrics_view_param,json=metricsViewParam,proto3" json:"metrics_view_param,omitempty"` + // For scalar params: allowed values. Renders as a select input in visual editors. + Options []*structpb.Value `protobuf:"bytes,7,rep,name=options,proto3" json:"options,omitempty"` +} + +func (x *ComponentParam) Reset() { + *x = ComponentParam{} + if protoimpl.UnsafeEnabled { + mi := &file_rill_runtime_v1_resources_proto_msgTypes[54] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ComponentParam) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ComponentParam) ProtoMessage() {} + +func (x *ComponentParam) ProtoReflect() protoreflect.Message { + mi := &file_rill_runtime_v1_resources_proto_msgTypes[54] + 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 ComponentParam.ProtoReflect.Descriptor instead. +func (*ComponentParam) Descriptor() ([]byte, []int) { + return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{54} +} + +func (x *ComponentParam) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *ComponentParam) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *ComponentParam) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *ComponentParam) GetRequired() bool { + if x != nil { + return x.Required + } + return false +} + +func (x *ComponentParam) GetDefault() *structpb.Value { + if x != nil { + return x.Default + } + return nil +} + +func (x *ComponentParam) GetMetricsViewParam() string { + if x != nil { + return x.MetricsViewParam + } + return "" +} + +func (x *ComponentParam) GetOptions() []*structpb.Value { + if x != nil { + return x.Options + } + return nil +} + type Canvas struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -5627,7 +5742,7 @@ type Canvas struct { func (x *Canvas) Reset() { *x = Canvas{} if protoimpl.UnsafeEnabled { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[54] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5640,7 +5755,7 @@ func (x *Canvas) String() string { func (*Canvas) ProtoMessage() {} func (x *Canvas) ProtoReflect() protoreflect.Message { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[54] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[55] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5653,7 +5768,7 @@ func (x *Canvas) ProtoReflect() protoreflect.Message { // Deprecated: Use Canvas.ProtoReflect.Descriptor instead. func (*Canvas) Descriptor() ([]byte, []int) { - return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{54} + return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{55} } func (x *Canvas) GetSpec() *CanvasSpec { @@ -5721,7 +5836,7 @@ type CanvasSpec struct { func (x *CanvasSpec) Reset() { *x = CanvasSpec{} if protoimpl.UnsafeEnabled { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[55] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5734,7 +5849,7 @@ func (x *CanvasSpec) String() string { func (*CanvasSpec) ProtoMessage() {} func (x *CanvasSpec) ProtoReflect() protoreflect.Message { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[55] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[56] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5747,7 +5862,7 @@ func (x *CanvasSpec) ProtoReflect() protoreflect.Message { // Deprecated: Use CanvasSpec.ProtoReflect.Descriptor instead. func (*CanvasSpec) Descriptor() ([]byte, []int) { - return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{55} + return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{56} } func (x *CanvasSpec) GetDisplayName() string { @@ -5891,7 +6006,7 @@ type CanvasState struct { func (x *CanvasState) Reset() { *x = CanvasState{} if protoimpl.UnsafeEnabled { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[56] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5904,7 +6019,7 @@ func (x *CanvasState) String() string { func (*CanvasState) ProtoMessage() {} func (x *CanvasState) ProtoReflect() protoreflect.Message { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[56] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[57] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5917,7 +6032,7 @@ func (x *CanvasState) ProtoReflect() protoreflect.Message { // Deprecated: Use CanvasState.ProtoReflect.Descriptor instead. func (*CanvasState) Descriptor() ([]byte, []int) { - return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{56} + return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{57} } func (x *CanvasState) GetValidSpec() *CanvasSpec { @@ -5953,7 +6068,7 @@ type CanvasRow struct { func (x *CanvasRow) Reset() { *x = CanvasRow{} if protoimpl.UnsafeEnabled { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[57] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[58] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5966,7 +6081,7 @@ func (x *CanvasRow) String() string { func (*CanvasRow) ProtoMessage() {} func (x *CanvasRow) ProtoReflect() protoreflect.Message { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[57] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[58] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5979,7 +6094,7 @@ func (x *CanvasRow) ProtoReflect() protoreflect.Message { // Deprecated: Use CanvasRow.ProtoReflect.Descriptor instead. func (*CanvasRow) Descriptor() ([]byte, []int) { - return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{57} + return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{58} } func (x *CanvasRow) GetHeight() uint32 { @@ -6025,7 +6140,7 @@ type CanvasTabGroup struct { func (x *CanvasTabGroup) Reset() { *x = CanvasTabGroup{} if protoimpl.UnsafeEnabled { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[58] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6038,7 +6153,7 @@ func (x *CanvasTabGroup) String() string { func (*CanvasTabGroup) ProtoMessage() {} func (x *CanvasTabGroup) ProtoReflect() protoreflect.Message { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[58] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[59] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6051,7 +6166,7 @@ func (x *CanvasTabGroup) ProtoReflect() protoreflect.Message { // Deprecated: Use CanvasTabGroup.ProtoReflect.Descriptor instead. func (*CanvasTabGroup) Descriptor() ([]byte, []int) { - return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{58} + return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{59} } func (x *CanvasTabGroup) GetName() string { @@ -6085,7 +6200,7 @@ type CanvasTab struct { func (x *CanvasTab) Reset() { *x = CanvasTab{} if protoimpl.UnsafeEnabled { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[59] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6098,7 +6213,7 @@ func (x *CanvasTab) String() string { func (*CanvasTab) ProtoMessage() {} func (x *CanvasTab) ProtoReflect() protoreflect.Message { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[59] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[60] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6111,7 +6226,7 @@ func (x *CanvasTab) ProtoReflect() protoreflect.Message { // Deprecated: Use CanvasTab.ProtoReflect.Descriptor instead. func (*CanvasTab) Descriptor() ([]byte, []int) { - return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{59} + return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{60} } func (x *CanvasTab) GetName() string { @@ -6144,6 +6259,9 @@ type CanvasItem struct { Component string `protobuf:"bytes,1,opt,name=component,proto3" json:"component,omitempty"` // Indicates if the component was defined inline as part of the canvas YAML. DefinedInCanvas bool `protobuf:"varint,8,opt,name=defined_in_canvas,json=definedInCanvas,proto3" json:"defined_in_canvas,omitempty"` + // Values bound to the referenced component's declared params. + // Only set for items that reference an externally defined component. + Params *structpb.Struct `protobuf:"bytes,11,opt,name=params,proto3" json:"params,omitempty"` // Width of the item. The unit is given in width_unit. Width *uint32 `protobuf:"varint,9,opt,name=width,proto3,oneof" json:"width,omitempty"` // Unit of the width. Current possible values: empty string. @@ -6153,7 +6271,7 @@ type CanvasItem struct { func (x *CanvasItem) Reset() { *x = CanvasItem{} if protoimpl.UnsafeEnabled { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[60] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6166,7 +6284,7 @@ func (x *CanvasItem) String() string { func (*CanvasItem) ProtoMessage() {} func (x *CanvasItem) ProtoReflect() protoreflect.Message { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[60] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[61] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6179,7 +6297,7 @@ func (x *CanvasItem) ProtoReflect() protoreflect.Message { // Deprecated: Use CanvasItem.ProtoReflect.Descriptor instead. func (*CanvasItem) Descriptor() ([]byte, []int) { - return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{60} + return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{61} } func (x *CanvasItem) GetComponent() string { @@ -6196,6 +6314,13 @@ func (x *CanvasItem) GetDefinedInCanvas() bool { return false } +func (x *CanvasItem) GetParams() *structpb.Struct { + if x != nil { + return x.Params + } + return nil +} + func (x *CanvasItem) GetWidth() uint32 { if x != nil && x.Width != nil { return *x.Width @@ -6233,7 +6358,7 @@ type CanvasPreset struct { func (x *CanvasPreset) Reset() { *x = CanvasPreset{} if protoimpl.UnsafeEnabled { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[61] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6246,7 +6371,7 @@ func (x *CanvasPreset) String() string { func (*CanvasPreset) ProtoMessage() {} func (x *CanvasPreset) ProtoReflect() protoreflect.Message { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[61] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[62] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6259,7 +6384,7 @@ func (x *CanvasPreset) ProtoReflect() protoreflect.Message { // Deprecated: Use CanvasPreset.ProtoReflect.Descriptor instead. func (*CanvasPreset) Descriptor() ([]byte, []int) { - return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{61} + return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{62} } func (x *CanvasPreset) GetTimeRange() string { @@ -6301,7 +6426,7 @@ type DefaultMetricsSQLFilter struct { func (x *DefaultMetricsSQLFilter) Reset() { *x = DefaultMetricsSQLFilter{} if protoimpl.UnsafeEnabled { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[62] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6314,7 +6439,7 @@ func (x *DefaultMetricsSQLFilter) String() string { func (*DefaultMetricsSQLFilter) ProtoMessage() {} func (x *DefaultMetricsSQLFilter) ProtoReflect() protoreflect.Message { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[62] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[63] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6327,7 +6452,7 @@ func (x *DefaultMetricsSQLFilter) ProtoReflect() protoreflect.Message { // Deprecated: Use DefaultMetricsSQLFilter.ProtoReflect.Descriptor instead. func (*DefaultMetricsSQLFilter) Descriptor() ([]byte, []int) { - return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{62} + return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{63} } func (x *DefaultMetricsSQLFilter) GetExpression() *Expression { @@ -6350,7 +6475,7 @@ type API struct { func (x *API) Reset() { *x = API{} if protoimpl.UnsafeEnabled { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[63] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6363,7 +6488,7 @@ func (x *API) String() string { func (*API) ProtoMessage() {} func (x *API) ProtoReflect() protoreflect.Message { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[63] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[64] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6376,7 +6501,7 @@ func (x *API) ProtoReflect() protoreflect.Message { // Deprecated: Use API.ProtoReflect.Descriptor instead. func (*API) Descriptor() ([]byte, []int) { - return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{63} + return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{64} } func (x *API) GetSpec() *APISpec { @@ -6412,7 +6537,7 @@ type APISpec struct { func (x *APISpec) Reset() { *x = APISpec{} if protoimpl.UnsafeEnabled { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[64] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6425,7 +6550,7 @@ func (x *APISpec) String() string { func (*APISpec) ProtoMessage() {} func (x *APISpec) ProtoReflect() protoreflect.Message { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[64] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[65] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6438,7 +6563,7 @@ func (x *APISpec) ProtoReflect() protoreflect.Message { // Deprecated: Use APISpec.ProtoReflect.Descriptor instead. func (*APISpec) Descriptor() ([]byte, []int) { - return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{64} + return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{65} } func (x *APISpec) GetResolver() string { @@ -6513,7 +6638,7 @@ type APIState struct { func (x *APIState) Reset() { *x = APIState{} if protoimpl.UnsafeEnabled { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[65] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6526,7 +6651,7 @@ func (x *APIState) String() string { func (*APIState) ProtoMessage() {} func (x *APIState) ProtoReflect() protoreflect.Message { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[65] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[66] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6539,7 +6664,7 @@ func (x *APIState) ProtoReflect() protoreflect.Message { // Deprecated: Use APIState.ProtoReflect.Descriptor instead. func (*APIState) Descriptor() ([]byte, []int) { - return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{65} + return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{66} } type Schedule struct { @@ -6557,7 +6682,7 @@ type Schedule struct { func (x *Schedule) Reset() { *x = Schedule{} if protoimpl.UnsafeEnabled { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[66] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6570,7 +6695,7 @@ func (x *Schedule) String() string { func (*Schedule) ProtoMessage() {} func (x *Schedule) ProtoReflect() protoreflect.Message { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[66] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[67] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6583,7 +6708,7 @@ func (x *Schedule) ProtoReflect() protoreflect.Message { // Deprecated: Use Schedule.ProtoReflect.Descriptor instead. func (*Schedule) Descriptor() ([]byte, []int) { - return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{66} + return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{67} } func (x *Schedule) GetRefUpdate() bool { @@ -6636,7 +6761,7 @@ type ParseError struct { func (x *ParseError) Reset() { *x = ParseError{} if protoimpl.UnsafeEnabled { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[67] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6649,7 +6774,7 @@ func (x *ParseError) String() string { func (*ParseError) ProtoMessage() {} func (x *ParseError) ProtoReflect() protoreflect.Message { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[67] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[68] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6662,7 +6787,7 @@ func (x *ParseError) ProtoReflect() protoreflect.Message { // Deprecated: Use ParseError.ProtoReflect.Descriptor instead. func (*ParseError) Descriptor() ([]byte, []int) { - return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{67} + return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{68} } func (x *ParseError) GetMessage() string { @@ -6712,7 +6837,7 @@ type ValidationError struct { func (x *ValidationError) Reset() { *x = ValidationError{} if protoimpl.UnsafeEnabled { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[68] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6725,7 +6850,7 @@ func (x *ValidationError) String() string { func (*ValidationError) ProtoMessage() {} func (x *ValidationError) ProtoReflect() protoreflect.Message { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[68] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[69] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6738,7 +6863,7 @@ func (x *ValidationError) ProtoReflect() protoreflect.Message { // Deprecated: Use ValidationError.ProtoReflect.Descriptor instead. func (*ValidationError) Descriptor() ([]byte, []int) { - return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{68} + return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{69} } func (x *ValidationError) GetMessage() string { @@ -6767,7 +6892,7 @@ type DependencyError struct { func (x *DependencyError) Reset() { *x = DependencyError{} if protoimpl.UnsafeEnabled { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[69] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6780,7 +6905,7 @@ func (x *DependencyError) String() string { func (*DependencyError) ProtoMessage() {} func (x *DependencyError) ProtoReflect() protoreflect.Message { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[69] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[70] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6793,7 +6918,7 @@ func (x *DependencyError) ProtoReflect() protoreflect.Message { // Deprecated: Use DependencyError.ProtoReflect.Descriptor instead. func (*DependencyError) Descriptor() ([]byte, []int) { - return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{69} + return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{70} } func (x *DependencyError) GetMessage() string { @@ -6821,7 +6946,7 @@ type ExecutionError struct { func (x *ExecutionError) Reset() { *x = ExecutionError{} if protoimpl.UnsafeEnabled { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[70] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6834,7 +6959,7 @@ func (x *ExecutionError) String() string { func (*ExecutionError) ProtoMessage() {} func (x *ExecutionError) ProtoReflect() protoreflect.Message { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[70] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[71] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6847,7 +6972,7 @@ func (x *ExecutionError) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecutionError.ProtoReflect.Descriptor instead. func (*ExecutionError) Descriptor() ([]byte, []int) { - return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{70} + return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{71} } func (x *ExecutionError) GetMessage() string { @@ -6868,7 +6993,7 @@ type CharLocation struct { func (x *CharLocation) Reset() { *x = CharLocation{} if protoimpl.UnsafeEnabled { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[71] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6881,7 +7006,7 @@ func (x *CharLocation) String() string { func (*CharLocation) ProtoMessage() {} func (x *CharLocation) ProtoReflect() protoreflect.Message { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[71] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[72] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6894,7 +7019,7 @@ func (x *CharLocation) ProtoReflect() protoreflect.Message { // Deprecated: Use CharLocation.ProtoReflect.Descriptor instead. func (*CharLocation) Descriptor() ([]byte, []int) { - return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{71} + return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{72} } func (x *CharLocation) GetLine() uint32 { @@ -6916,7 +7041,7 @@ type ConnectorV2 struct { func (x *ConnectorV2) Reset() { *x = ConnectorV2{} if protoimpl.UnsafeEnabled { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[72] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6929,7 +7054,7 @@ func (x *ConnectorV2) String() string { func (*ConnectorV2) ProtoMessage() {} func (x *ConnectorV2) ProtoReflect() protoreflect.Message { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[72] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[73] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6942,7 +7067,7 @@ func (x *ConnectorV2) ProtoReflect() protoreflect.Message { // Deprecated: Use ConnectorV2.ProtoReflect.Descriptor instead. func (*ConnectorV2) Descriptor() ([]byte, []int) { - return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{72} + return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{73} } func (x *ConnectorV2) GetSpec() *ConnectorSpec { @@ -6974,7 +7099,7 @@ type ConnectorSpec struct { func (x *ConnectorSpec) Reset() { *x = ConnectorSpec{} if protoimpl.UnsafeEnabled { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[73] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6987,7 +7112,7 @@ func (x *ConnectorSpec) String() string { func (*ConnectorSpec) ProtoMessage() {} func (x *ConnectorSpec) ProtoReflect() protoreflect.Message { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[73] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[74] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7000,7 +7125,7 @@ func (x *ConnectorSpec) ProtoReflect() protoreflect.Message { // Deprecated: Use ConnectorSpec.ProtoReflect.Descriptor instead. func (*ConnectorSpec) Descriptor() ([]byte, []int) { - return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{73} + return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{74} } func (x *ConnectorSpec) GetDriver() string { @@ -7049,7 +7174,7 @@ type ConnectorState struct { func (x *ConnectorState) Reset() { *x = ConnectorState{} if protoimpl.UnsafeEnabled { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[74] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7062,7 +7187,7 @@ func (x *ConnectorState) String() string { func (*ConnectorState) ProtoMessage() {} func (x *ConnectorState) ProtoReflect() protoreflect.Message { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[74] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[75] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7075,7 +7200,7 @@ func (x *ConnectorState) ProtoReflect() protoreflect.Message { // Deprecated: Use ConnectorState.ProtoReflect.Descriptor instead. func (*ConnectorState) Descriptor() ([]byte, []int) { - return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{74} + return file_rill_runtime_v1_resources_proto_rawDescGZIP(), []int{75} } func (x *ConnectorState) GetSpecHash() string { @@ -7115,7 +7240,7 @@ type MetricsViewSpec_Dimension struct { func (x *MetricsViewSpec_Dimension) Reset() { *x = MetricsViewSpec_Dimension{} if protoimpl.UnsafeEnabled { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[75] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7128,7 +7253,7 @@ func (x *MetricsViewSpec_Dimension) String() string { func (*MetricsViewSpec_Dimension) ProtoMessage() {} func (x *MetricsViewSpec_Dimension) ProtoReflect() protoreflect.Message { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[75] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[76] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7263,7 +7388,7 @@ type MetricsViewSpec_DimensionSelector struct { func (x *MetricsViewSpec_DimensionSelector) Reset() { *x = MetricsViewSpec_DimensionSelector{} if protoimpl.UnsafeEnabled { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[76] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7276,7 +7401,7 @@ func (x *MetricsViewSpec_DimensionSelector) String() string { func (*MetricsViewSpec_DimensionSelector) ProtoMessage() {} func (x *MetricsViewSpec_DimensionSelector) ProtoReflect() protoreflect.Message { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[76] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[77] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7330,7 +7455,7 @@ type MetricsViewSpec_MeasureWindow struct { func (x *MetricsViewSpec_MeasureWindow) Reset() { *x = MetricsViewSpec_MeasureWindow{} if protoimpl.UnsafeEnabled { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[77] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7343,7 +7468,7 @@ func (x *MetricsViewSpec_MeasureWindow) String() string { func (*MetricsViewSpec_MeasureWindow) ProtoMessage() {} func (x *MetricsViewSpec_MeasureWindow) ProtoReflect() protoreflect.Message { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[77] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[78] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7410,7 +7535,7 @@ type MetricsViewSpec_Measure struct { func (x *MetricsViewSpec_Measure) Reset() { *x = MetricsViewSpec_Measure{} if protoimpl.UnsafeEnabled { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[78] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7423,7 +7548,7 @@ func (x *MetricsViewSpec_Measure) String() string { func (*MetricsViewSpec_Measure) ProtoMessage() {} func (x *MetricsViewSpec_Measure) ProtoReflect() protoreflect.Message { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[78] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[79] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7591,7 +7716,7 @@ type MetricsViewSpec_Annotation struct { func (x *MetricsViewSpec_Annotation) Reset() { *x = MetricsViewSpec_Annotation{} if protoimpl.UnsafeEnabled { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[79] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7604,7 +7729,7 @@ func (x *MetricsViewSpec_Annotation) String() string { func (*MetricsViewSpec_Annotation) ProtoMessage() {} func (x *MetricsViewSpec_Annotation) ProtoReflect() protoreflect.Message { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[79] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[80] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7721,7 +7846,7 @@ type MetricsViewSpec_Rollup struct { func (x *MetricsViewSpec_Rollup) Reset() { *x = MetricsViewSpec_Rollup{} if protoimpl.UnsafeEnabled { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[80] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7734,7 +7859,7 @@ func (x *MetricsViewSpec_Rollup) String() string { func (*MetricsViewSpec_Rollup) ProtoMessage() {} func (x *MetricsViewSpec_Rollup) ProtoReflect() protoreflect.Message { - mi := &file_rill_runtime_v1_resources_proto_msgTypes[80] + mi := &file_rill_runtime_v1_resources_proto_msgTypes[81] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9169,7 +9294,7 @@ var file_rill_runtime_v1_resources_proto_rawDesc = []byte{ 0x70, 0x65, 0x63, 0x12, 0x35, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x53, 0x74, - 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0xdc, 0x02, 0x0a, 0x0d, 0x43, + 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x95, 0x03, 0x0a, 0x0d, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x53, 0x70, 0x65, 0x63, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, @@ -9181,350 +9306,373 @@ var file_rill_runtime_v1_resources_proto_rawDesc = []byte{ 0x74, 0x69, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x12, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x65, 0x72, 0x50, 0x72, 0x6f, - 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x38, 0x0a, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, - 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, - 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, - 0x6e, 0x74, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x05, 0x69, 0x6e, 0x70, 0x75, - 0x74, 0x12, 0x3a, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x72, - 0x69, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x2a, 0x0a, - 0x11, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x5f, 0x63, 0x61, 0x6e, 0x76, - 0x61, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, - 0x64, 0x49, 0x6e, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x22, 0x97, 0x01, 0x0a, 0x0e, 0x43, 0x6f, - 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x3d, 0x0a, 0x0a, - 0x76, 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1e, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x53, 0x70, 0x65, 0x63, - 0x52, 0x09, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x53, 0x70, 0x65, 0x63, 0x12, 0x46, 0x0a, 0x11, 0x64, - 0x61, 0x74, 0x61, 0x5f, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x65, 0x64, 0x5f, 0x6f, 0x6e, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x52, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x65, - 0x64, 0x4f, 0x6e, 0x22, 0x78, 0x0a, 0x11, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, - 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, - 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, - 0x12, 0x3b, 0x0a, 0x0d, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, - 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x6d, 0x0a, - 0x06, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x12, 0x2f, 0x0a, 0x04, 0x73, 0x70, 0x65, 0x63, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, - 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x53, 0x70, - 0x65, 0x63, 0x52, 0x04, 0x73, 0x70, 0x65, 0x63, 0x12, 0x32, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, - 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, - 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x8a, 0x07, 0x0a, - 0x0a, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x53, 0x70, 0x65, 0x63, 0x12, 0x21, 0x0a, 0x0c, 0x64, - 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x16, - 0x0a, 0x06, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x77, 0x69, - 0x64, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x57, 0x69, - 0x64, 0x74, 0x68, 0x12, 0x13, 0x0a, 0x05, 0x67, 0x61, 0x70, 0x5f, 0x78, 0x18, 0x09, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x04, 0x67, 0x61, 0x70, 0x58, 0x12, 0x13, 0x0a, 0x05, 0x67, 0x61, 0x70, 0x5f, - 0x79, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x67, 0x61, 0x70, 0x59, 0x12, 0x14, 0x0a, - 0x05, 0x74, 0x68, 0x65, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x68, - 0x65, 0x6d, 0x65, 0x12, 0x41, 0x0a, 0x0e, 0x65, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x5f, - 0x74, 0x68, 0x65, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x72, 0x69, - 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x68, - 0x65, 0x6d, 0x65, 0x53, 0x70, 0x65, 0x63, 0x52, 0x0d, 0x65, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, - 0x64, 0x54, 0x68, 0x65, 0x6d, 0x65, 0x12, 0x42, 0x0a, 0x0b, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x72, - 0x61, 0x6e, 0x67, 0x65, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x72, 0x69, - 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, - 0x70, 0x6c, 0x6f, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0a, - 0x74, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x35, 0x0a, 0x17, 0x61, 0x6c, - 0x6c, 0x6f, 0x77, 0x5f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, - 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x61, 0x6c, 0x6c, - 0x6f, 0x77, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, - 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x7a, 0x6f, 0x6e, 0x65, 0x73, 0x18, - 0x0c, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x5a, 0x6f, 0x6e, 0x65, 0x73, - 0x12, 0x27, 0x0a, 0x0f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x5f, 0x65, 0x6e, 0x61, 0x62, - 0x6c, 0x65, 0x64, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x66, 0x69, 0x6c, 0x74, 0x65, - 0x72, 0x73, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x44, 0x0a, 0x0e, 0x64, 0x65, 0x66, - 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x72, 0x65, 0x73, 0x65, 0x74, 0x18, 0x0f, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x50, 0x72, 0x65, 0x73, 0x65, 0x74, - 0x52, 0x0d, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x72, 0x65, 0x73, 0x65, 0x74, 0x12, - 0x40, 0x0a, 0x09, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x56, 0x61, - 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x09, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, - 0x73, 0x12, 0x2e, 0x0a, 0x04, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x12, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x37, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, + 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, + 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, + 0x65, 0x6e, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x52, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, + 0x12, 0x38, 0x0a, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x22, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x72, 0x69, 0x61, + 0x62, 0x6c, 0x65, 0x52, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x3a, 0x0a, 0x06, 0x6f, 0x75, + 0x74, 0x70, 0x75, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x69, 0x6c, + 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, + 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x06, + 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, + 0x64, 0x5f, 0x69, 0x6e, 0x5f, 0x63, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x0f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x49, 0x6e, 0x43, 0x61, 0x6e, 0x76, + 0x61, 0x73, 0x22, 0x97, 0x01, 0x0a, 0x0e, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x3d, 0x0a, 0x0a, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x73, + 0x70, 0x65, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x72, 0x69, 0x6c, 0x6c, + 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, + 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x53, 0x70, 0x65, 0x63, 0x52, 0x09, 0x76, 0x61, 0x6c, 0x69, 0x64, + 0x53, 0x70, 0x65, 0x63, 0x12, 0x46, 0x0a, 0x11, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x65, 0x66, + 0x72, 0x65, 0x73, 0x68, 0x65, 0x64, 0x5f, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0f, 0x64, 0x61, 0x74, + 0x61, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x65, 0x64, 0x4f, 0x6e, 0x22, 0x78, 0x0a, 0x11, + 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, + 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x3b, 0x0a, 0x0d, 0x64, 0x65, 0x66, + 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, + 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x88, 0x02, 0x0a, 0x0e, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x6e, 0x65, 0x6e, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, + 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, + 0x30, 0x0a, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, + 0x74, 0x12, 0x2c, 0x0a, 0x12, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x76, 0x69, 0x65, + 0x77, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x6d, + 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x12, + 0x30, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x22, 0x6d, 0x0a, 0x06, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x12, 0x2f, 0x0a, 0x04, 0x73, + 0x70, 0x65, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x72, 0x69, 0x6c, 0x6c, + 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x76, + 0x61, 0x73, 0x53, 0x70, 0x65, 0x63, 0x52, 0x04, 0x73, 0x70, 0x65, 0x63, 0x12, 0x32, 0x0a, 0x05, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x72, 0x69, + 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, + 0x6e, 0x76, 0x61, 0x73, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, + 0x22, 0x8a, 0x07, 0x0a, 0x0a, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x53, 0x70, 0x65, 0x63, 0x12, + 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x18, 0x11, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, + 0x78, 0x5f, 0x77, 0x69, 0x64, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x6d, + 0x61, 0x78, 0x57, 0x69, 0x64, 0x74, 0x68, 0x12, 0x13, 0x0a, 0x05, 0x67, 0x61, 0x70, 0x5f, 0x78, + 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x67, 0x61, 0x70, 0x58, 0x12, 0x13, 0x0a, 0x05, + 0x67, 0x61, 0x70, 0x5f, 0x79, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x67, 0x61, 0x70, + 0x59, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x68, 0x65, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x74, 0x68, 0x65, 0x6d, 0x65, 0x12, 0x41, 0x0a, 0x0e, 0x65, 0x6d, 0x62, 0x65, 0x64, + 0x64, 0x65, 0x64, 0x5f, 0x74, 0x68, 0x65, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x52, 0x6f, 0x77, 0x52, 0x04, 0x72, 0x6f, 0x77, - 0x73, 0x12, 0x44, 0x0a, 0x0e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x72, 0x75, + 0x31, 0x2e, 0x54, 0x68, 0x65, 0x6d, 0x65, 0x53, 0x70, 0x65, 0x63, 0x52, 0x0d, 0x65, 0x6d, 0x62, + 0x65, 0x64, 0x64, 0x65, 0x64, 0x54, 0x68, 0x65, 0x6d, 0x65, 0x12, 0x42, 0x0a, 0x0b, 0x74, 0x69, + 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x21, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6c, 0x6f, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, + 0x67, 0x65, 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x35, + 0x0a, 0x17, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x74, + 0x69, 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x14, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x54, 0x69, 0x6d, 0x65, + 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x7a, 0x6f, + 0x6e, 0x65, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x5a, + 0x6f, 0x6e, 0x65, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x5f, + 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x66, + 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x44, 0x0a, + 0x0e, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x72, 0x65, 0x73, 0x65, 0x74, 0x18, + 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, + 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x50, 0x72, + 0x65, 0x73, 0x65, 0x74, 0x52, 0x0d, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x72, 0x65, + 0x73, 0x65, 0x74, 0x12, 0x40, 0x0a, 0x09, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, + 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, + 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, + 0x6e, 0x74, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x09, 0x76, 0x61, 0x72, 0x69, + 0x61, 0x62, 0x6c, 0x65, 0x73, 0x12, 0x2e, 0x0a, 0x04, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x12, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, + 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x52, 0x6f, 0x77, 0x52, + 0x04, 0x72, 0x6f, 0x77, 0x73, 0x12, 0x44, 0x0a, 0x0e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, + 0x79, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, + 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, + 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x0d, 0x73, 0x65, + 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x70, + 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x18, 0x10, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, + 0x72, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x5f, 0x66, + 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x18, 0x13, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x72, 0x65, + 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x12, 0x4e, 0x0a, + 0x0b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x14, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, + 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x53, 0x70, 0x65, 0x63, 0x2e, + 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x0b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x3e, 0x0a, + 0x10, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x91, 0x01, + 0x0a, 0x0b, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x3a, 0x0a, + 0x0a, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1b, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x53, 0x70, 0x65, 0x63, 0x52, 0x09, + 0x76, 0x61, 0x6c, 0x69, 0x64, 0x53, 0x70, 0x65, 0x63, 0x12, 0x46, 0x0a, 0x11, 0x64, 0x61, 0x74, + 0x61, 0x5f, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x65, 0x64, 0x5f, 0x6f, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x52, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x65, 0x64, 0x4f, + 0x6e, 0x22, 0xc5, 0x01, 0x0a, 0x09, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x52, 0x6f, 0x77, 0x12, + 0x1b, 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x48, + 0x00, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x88, 0x01, 0x01, 0x12, 0x1f, 0x0a, 0x0b, + 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x5f, 0x75, 0x6e, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0a, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x55, 0x6e, 0x69, 0x74, 0x12, 0x31, 0x0a, + 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x72, + 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, + 0x61, 0x6e, 0x76, 0x61, 0x73, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, + 0x12, 0x3c, 0x0a, 0x09, 0x74, 0x61, 0x62, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, + 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x54, 0x61, 0x62, 0x47, + 0x72, 0x6f, 0x75, 0x70, 0x52, 0x08, 0x74, 0x61, 0x62, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x42, 0x09, + 0x0a, 0x07, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x22, 0x54, 0x0a, 0x0e, 0x43, 0x61, 0x6e, + 0x76, 0x61, 0x73, 0x54, 0x61, 0x62, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x2e, 0x0a, 0x04, 0x74, 0x61, 0x62, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, + 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x54, 0x61, 0x62, 0x52, 0x04, 0x74, 0x61, 0x62, 0x73, 0x22, + 0x72, 0x0a, 0x09, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x54, 0x61, 0x62, 0x12, 0x12, 0x0a, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, + 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x04, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x1a, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x52, 0x6f, 0x77, 0x52, 0x04, 0x72, + 0x6f, 0x77, 0x73, 0x22, 0xcb, 0x01, 0x0a, 0x0a, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x49, 0x74, + 0x65, 0x6d, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, + 0x12, 0x2a, 0x0a, 0x11, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x5f, 0x63, + 0x61, 0x6e, 0x76, 0x61, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x64, 0x65, 0x66, + 0x69, 0x6e, 0x65, 0x64, 0x49, 0x6e, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x12, 0x2f, 0x0a, 0x06, + 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, + 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x19, 0x0a, + 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x00, 0x52, 0x05, + 0x77, 0x69, 0x64, 0x74, 0x68, 0x88, 0x01, 0x01, 0x12, 0x1d, 0x0a, 0x0a, 0x77, 0x69, 0x64, 0x74, + 0x68, 0x5f, 0x75, 0x6e, 0x69, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x77, 0x69, + 0x64, 0x74, 0x68, 0x55, 0x6e, 0x69, 0x74, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x77, 0x69, 0x64, 0x74, + 0x68, 0x22, 0x9c, 0x03, 0x0a, 0x0c, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x50, 0x72, 0x65, 0x73, + 0x65, 0x74, 0x12, 0x22, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x52, 0x61, + 0x6e, 0x67, 0x65, 0x88, 0x01, 0x01, 0x12, 0x4f, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, + 0x69, 0x73, 0x6f, 0x6e, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x26, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6c, 0x6f, 0x72, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, + 0x73, 0x6f, 0x6e, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x0e, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, + 0x73, 0x6f, 0x6e, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x36, 0x0a, 0x14, 0x63, 0x6f, 0x6d, 0x70, 0x61, + 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x5f, 0x64, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x13, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, + 0x73, 0x6f, 0x6e, 0x44, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, + 0x4e, 0x0a, 0x0b, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x65, 0x78, 0x70, 0x72, 0x18, 0x13, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, + 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x50, 0x72, 0x65, + 0x73, 0x65, 0x74, 0x2e, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x45, 0x78, 0x70, 0x72, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x0a, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x45, 0x78, 0x70, 0x72, 0x1a, + 0x67, 0x0a, 0x0f, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x45, 0x78, 0x70, 0x72, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x6b, 0x65, 0x79, 0x12, 0x3e, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, + 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x4d, 0x65, 0x74, + 0x72, 0x69, 0x63, 0x73, 0x53, 0x51, 0x4c, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x74, 0x69, 0x6d, + 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x42, 0x17, 0x0a, 0x15, 0x5f, 0x63, 0x6f, 0x6d, 0x70, + 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x5f, 0x64, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, + 0x22, 0x56, 0x0a, 0x17, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x4d, 0x65, 0x74, 0x72, 0x69, + 0x63, 0x73, 0x53, 0x51, 0x4c, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x3b, 0x0a, 0x0a, 0x65, + 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1b, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x65, 0x78, + 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x64, 0x0a, 0x03, 0x41, 0x50, 0x49, 0x12, + 0x2c, 0x0a, 0x04, 0x73, 0x70, 0x65, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, + 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, + 0x41, 0x50, 0x49, 0x53, 0x70, 0x65, 0x63, 0x52, 0x04, 0x73, 0x70, 0x65, 0x63, 0x12, 0x2f, 0x0a, + 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x72, + 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, + 0x50, 0x49, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0xf8, + 0x03, 0x0a, 0x07, 0x41, 0x50, 0x49, 0x53, 0x70, 0x65, 0x63, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, + 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, + 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x12, 0x48, 0x0a, 0x13, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, + 0x65, 0x72, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x12, 0x72, 0x65, + 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, + 0x12, 0x27, 0x0a, 0x0f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x5f, 0x73, 0x75, 0x6d, 0x6d, + 0x61, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6f, 0x70, 0x65, 0x6e, 0x61, + 0x70, 0x69, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x36, 0x0a, 0x17, 0x6f, 0x70, 0x65, + 0x6e, 0x61, 0x70, 0x69, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x5f, + 0x6a, 0x73, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, 0x6f, 0x70, 0x65, 0x6e, + 0x61, 0x70, 0x69, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x4a, 0x73, 0x6f, + 0x6e, 0x12, 0x3d, 0x0a, 0x1b, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x5f, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x5f, 0x6a, 0x73, 0x6f, 0x6e, + 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x18, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x4a, 0x73, 0x6f, 0x6e, + 0x12, 0x3f, 0x0a, 0x1c, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x5f, 0x72, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x5f, 0x6a, 0x73, 0x6f, 0x6e, + 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x19, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x4a, 0x73, 0x6f, + 0x6e, 0x12, 0x2e, 0x0a, 0x13, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x5f, 0x64, 0x65, 0x66, + 0x73, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, + 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x44, 0x65, 0x66, 0x73, 0x50, 0x72, 0x65, 0x66, 0x69, + 0x78, 0x12, 0x44, 0x0a, 0x0e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x0d, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, - 0x74, 0x79, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x69, 0x6e, 0x6e, 0x65, - 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x18, 0x10, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x0d, 0x70, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x12, 0x29, - 0x0a, 0x10, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, - 0x72, 0x73, 0x18, 0x13, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, - 0x65, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x12, 0x4e, 0x0a, 0x0b, 0x61, 0x6e, 0x6e, - 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x14, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, - 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x53, 0x70, 0x65, 0x63, 0x2e, 0x41, 0x6e, 0x6e, 0x6f, - 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0b, 0x61, 0x6e, - 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x3e, 0x0a, 0x10, 0x41, 0x6e, 0x6e, - 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, - 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, - 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x91, 0x01, 0x0a, 0x0b, 0x43, 0x61, - 0x6e, 0x76, 0x61, 0x73, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x3a, 0x0a, 0x0a, 0x76, 0x61, 0x6c, - 0x69, 0x64, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, - 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x53, 0x70, 0x65, 0x63, 0x52, 0x09, 0x76, 0x61, 0x6c, 0x69, - 0x64, 0x53, 0x70, 0x65, 0x63, 0x12, 0x46, 0x0a, 0x11, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x65, - 0x66, 0x72, 0x65, 0x73, 0x68, 0x65, 0x64, 0x5f, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0f, 0x64, 0x61, - 0x74, 0x61, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x65, 0x64, 0x4f, 0x6e, 0x22, 0xc5, 0x01, - 0x0a, 0x09, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x52, 0x6f, 0x77, 0x12, 0x1b, 0x0a, 0x06, 0x68, - 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x00, 0x52, 0x06, 0x68, - 0x65, 0x69, 0x67, 0x68, 0x74, 0x88, 0x01, 0x01, 0x12, 0x1f, 0x0a, 0x0b, 0x68, 0x65, 0x69, 0x67, - 0x68, 0x74, 0x5f, 0x75, 0x6e, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x68, - 0x65, 0x69, 0x67, 0x68, 0x74, 0x55, 0x6e, 0x69, 0x74, 0x12, 0x31, 0x0a, 0x05, 0x69, 0x74, 0x65, - 0x6d, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, - 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x76, 0x61, - 0x73, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x3c, 0x0a, 0x09, - 0x74, 0x61, 0x62, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1f, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x54, 0x61, 0x62, 0x47, 0x72, 0x6f, 0x75, 0x70, - 0x52, 0x08, 0x74, 0x61, 0x62, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x68, - 0x65, 0x69, 0x67, 0x68, 0x74, 0x22, 0x54, 0x0a, 0x0e, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x54, - 0x61, 0x62, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x04, 0x74, - 0x61, 0x62, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x72, 0x69, 0x6c, 0x6c, - 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x76, - 0x61, 0x73, 0x54, 0x61, 0x62, 0x52, 0x04, 0x74, 0x61, 0x62, 0x73, 0x22, 0x72, 0x0a, 0x09, 0x43, - 0x61, 0x6e, 0x76, 0x61, 0x73, 0x54, 0x61, 0x62, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, - 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, - 0x2e, 0x0a, 0x04, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, - 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x52, 0x6f, 0x77, 0x52, 0x04, 0x72, 0x6f, 0x77, 0x73, 0x22, - 0x9a, 0x01, 0x0a, 0x0a, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x1c, - 0x0a, 0x09, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x12, 0x2a, 0x0a, 0x11, - 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x5f, 0x63, 0x61, 0x6e, 0x76, 0x61, - 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, - 0x49, 0x6e, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x12, 0x19, 0x0a, 0x05, 0x77, 0x69, 0x64, 0x74, - 0x68, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x00, 0x52, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, - 0x88, 0x01, 0x01, 0x12, 0x1d, 0x0a, 0x0a, 0x77, 0x69, 0x64, 0x74, 0x68, 0x5f, 0x75, 0x6e, 0x69, - 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x77, 0x69, 0x64, 0x74, 0x68, 0x55, 0x6e, - 0x69, 0x74, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x77, 0x69, 0x64, 0x74, 0x68, 0x22, 0x9c, 0x03, 0x0a, - 0x0c, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x50, 0x72, 0x65, 0x73, 0x65, 0x74, 0x12, 0x22, 0x0a, - 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x48, 0x00, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x88, 0x01, - 0x01, 0x12, 0x4f, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x5f, - 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x72, 0x69, 0x6c, - 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, - 0x6c, 0x6f, 0x72, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x4d, 0x6f, - 0x64, 0x65, 0x52, 0x0e, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x4d, 0x6f, - 0x64, 0x65, 0x12, 0x36, 0x0a, 0x14, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, - 0x5f, 0x64, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, - 0x48, 0x01, 0x52, 0x13, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x44, 0x69, - 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x4e, 0x0a, 0x0b, 0x66, 0x69, - 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x65, 0x78, 0x70, 0x72, 0x18, 0x13, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x2d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x50, 0x72, 0x65, 0x73, 0x65, 0x74, 0x2e, 0x46, - 0x69, 0x6c, 0x74, 0x65, 0x72, 0x45, 0x78, 0x70, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, - 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x45, 0x78, 0x70, 0x72, 0x1a, 0x67, 0x0a, 0x0f, 0x46, 0x69, - 0x6c, 0x74, 0x65, 0x72, 0x45, 0x78, 0x70, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, - 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, - 0x3e, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, - 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x53, - 0x51, 0x4c, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, - 0x02, 0x38, 0x01, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, - 0x67, 0x65, 0x42, 0x17, 0x0a, 0x15, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, - 0x6e, 0x5f, 0x64, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x56, 0x0a, 0x17, 0x44, - 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x53, 0x51, 0x4c, - 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x3b, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x72, 0x69, 0x6c, - 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, - 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x22, 0x64, 0x0a, 0x03, 0x41, 0x50, 0x49, 0x12, 0x2c, 0x0a, 0x04, 0x73, 0x70, - 0x65, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, - 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x50, 0x49, 0x53, 0x70, - 0x65, 0x63, 0x52, 0x04, 0x73, 0x70, 0x65, 0x63, 0x12, 0x2f, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, - 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x50, 0x49, 0x53, 0x74, 0x61, - 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0xf8, 0x03, 0x0a, 0x07, 0x41, 0x50, - 0x49, 0x53, 0x70, 0x65, 0x63, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, - 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, - 0x72, 0x12, 0x48, 0x0a, 0x13, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x5f, 0x70, 0x72, - 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, - 0x72, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x6f, - 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x5f, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x53, 0x75, 0x6d, - 0x6d, 0x61, 0x72, 0x79, 0x12, 0x36, 0x0a, 0x17, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x5f, - 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x5f, 0x6a, 0x73, 0x6f, 0x6e, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x50, 0x61, - 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x4a, 0x73, 0x6f, 0x6e, 0x12, 0x3d, 0x0a, 0x1b, - 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, - 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x5f, 0x6a, 0x73, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x18, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x4a, 0x73, 0x6f, 0x6e, 0x12, 0x3f, 0x0a, 0x1c, 0x6f, - 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, - 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x5f, 0x6a, 0x73, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x19, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x4a, 0x73, 0x6f, 0x6e, 0x12, 0x2e, 0x0a, 0x13, - 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x5f, 0x64, 0x65, 0x66, 0x73, 0x5f, 0x70, 0x72, 0x65, - 0x66, 0x69, 0x78, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x6f, 0x70, 0x65, 0x6e, 0x61, - 0x70, 0x69, 0x44, 0x65, 0x66, 0x73, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x44, 0x0a, 0x0e, - 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x06, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, - 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, - 0x75, 0x6c, 0x65, 0x52, 0x0d, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x75, 0x6c, - 0x65, 0x73, 0x12, 0x30, 0x0a, 0x14, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x6e, 0x65, 0x73, 0x74, 0x65, - 0x64, 0x5f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x12, 0x73, 0x6b, 0x69, 0x70, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x53, 0x65, 0x63, 0x75, - 0x72, 0x69, 0x74, 0x79, 0x22, 0x0a, 0x0a, 0x08, 0x41, 0x50, 0x49, 0x53, 0x74, 0x61, 0x74, 0x65, - 0x22, 0x9b, 0x01, 0x0a, 0x08, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x1d, 0x0a, - 0x0a, 0x72, 0x65, 0x66, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x09, 0x72, 0x65, 0x66, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, - 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, - 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x72, 0x6f, 0x6e, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x72, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x69, - 0x63, 0x6b, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x0d, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, - 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x7a, 0x6f, 0x6e, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x5a, 0x6f, 0x6e, 0x65, 0x22, 0xbf, - 0x01, 0x0a, 0x0a, 0x50, 0x61, 0x72, 0x73, 0x65, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, - 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, - 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, - 0x50, 0x61, 0x74, 0x68, 0x12, 0x44, 0x0a, 0x0e, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6c, 0x6f, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x72, - 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, - 0x68, 0x61, 0x72, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0d, 0x73, 0x74, 0x61, - 0x72, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x78, - 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x65, 0x78, - 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x77, 0x61, 0x72, 0x6e, 0x69, 0x6e, - 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x77, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, - 0x22, 0x50, 0x0a, 0x0f, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, - 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a, - 0x0d, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x50, 0x61, - 0x74, 0x68, 0x22, 0x4b, 0x0a, 0x0f, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, - 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, 0x22, - 0x2a, 0x0a, 0x0e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, - 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x22, 0x0a, 0x0c, 0x43, - 0x68, 0x61, 0x72, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6c, - 0x69, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x65, 0x22, - 0x78, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x56, 0x32, 0x12, 0x32, - 0x0a, 0x04, 0x73, 0x70, 0x65, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x72, - 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, - 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x53, 0x70, 0x65, 0x63, 0x52, 0x04, 0x73, 0x70, - 0x65, 0x63, 0x12, 0x35, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1f, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x53, 0x74, 0x61, - 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0xf1, 0x01, 0x0a, 0x0d, 0x43, 0x6f, - 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x53, 0x70, 0x65, 0x63, 0x12, 0x16, 0x0a, 0x06, 0x64, - 0x72, 0x69, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x72, 0x69, - 0x76, 0x65, 0x72, 0x12, 0x37, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, - 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, - 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x31, 0x0a, 0x14, - 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, - 0x74, 0x69, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x74, 0x65, 0x6d, 0x70, - 0x6c, 0x61, 0x74, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, - 0x1c, 0x0a, 0x09, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3e, 0x0a, - 0x0e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x72, 0x67, 0x73, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x0d, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x41, 0x72, 0x67, 0x73, 0x22, 0x2d, 0x0a, - 0x0e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, - 0x1b, 0x0a, 0x09, 0x73, 0x70, 0x65, 0x63, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x73, 0x70, 0x65, 0x63, 0x48, 0x61, 0x73, 0x68, 0x2a, 0x8a, 0x01, 0x0a, - 0x0f, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x63, 0x69, 0x6c, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x12, 0x20, 0x0a, 0x1c, 0x52, 0x45, 0x43, 0x4f, 0x4e, 0x43, 0x49, 0x4c, 0x45, 0x5f, 0x53, 0x54, - 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, - 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x52, 0x45, 0x43, 0x4f, 0x4e, 0x43, 0x49, 0x4c, 0x45, 0x5f, - 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x49, 0x44, 0x4c, 0x45, 0x10, 0x01, 0x12, 0x1c, 0x0a, - 0x18, 0x52, 0x45, 0x43, 0x4f, 0x4e, 0x43, 0x49, 0x4c, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, - 0x53, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x1c, 0x0a, 0x18, 0x52, - 0x45, 0x43, 0x4f, 0x4e, 0x43, 0x49, 0x4c, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, - 0x52, 0x55, 0x4e, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x03, 0x2a, 0x8c, 0x01, 0x0a, 0x0f, 0x4d, 0x6f, - 0x64, 0x65, 0x6c, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x21, 0x0a, - 0x1d, 0x4d, 0x4f, 0x44, 0x45, 0x4c, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x5f, 0x4d, 0x4f, - 0x44, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, + 0x74, 0x79, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x30, 0x0a, 0x14, 0x73, 0x6b, 0x69, 0x70, 0x5f, + 0x6e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x73, 0x6b, 0x69, 0x70, 0x4e, 0x65, 0x73, 0x74, 0x65, + 0x64, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x22, 0x0a, 0x0a, 0x08, 0x41, 0x50, 0x49, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0x9b, 0x01, 0x0a, 0x08, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, + 0x6c, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x66, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x72, 0x65, 0x66, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x07, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x63, + 0x72, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x72, 0x6f, 0x6e, 0x12, + 0x25, 0x0a, 0x0e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, + 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x53, + 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x7a, + 0x6f, 0x6e, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x5a, + 0x6f, 0x6e, 0x65, 0x22, 0xbf, 0x01, 0x0a, 0x0a, 0x50, 0x61, 0x72, 0x73, 0x65, 0x45, 0x72, 0x72, + 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1b, 0x0a, 0x09, + 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x44, 0x0a, 0x0e, 0x73, 0x74, 0x61, + 0x72, 0x74, 0x5f, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x61, 0x72, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x1a, 0x0a, 0x08, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x08, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x77, + 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x77, 0x61, + 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x22, 0x50, 0x0a, 0x0f, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x5f, 0x70, + 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x70, 0x65, + 0x72, 0x74, 0x79, 0x50, 0x61, 0x74, 0x68, 0x22, 0x4b, 0x0a, 0x0f, 0x44, 0x65, 0x70, 0x65, 0x6e, + 0x64, 0x65, 0x6e, 0x63, 0x79, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, + 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, + 0x65, 0x6e, 0x63, 0x79, 0x22, 0x2a, 0x0a, 0x0e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, + 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x22, 0x22, 0x0a, 0x0c, 0x43, 0x68, 0x61, 0x72, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, + 0x6c, 0x69, 0x6e, 0x65, 0x22, 0x78, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, + 0x72, 0x56, 0x32, 0x12, 0x32, 0x0a, 0x04, 0x73, 0x70, 0x65, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1e, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x53, 0x70, 0x65, + 0x63, 0x52, 0x04, 0x73, 0x70, 0x65, 0x63, 0x12, 0x35, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, + 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, + 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0xf1, + 0x01, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x53, 0x70, 0x65, 0x63, + 0x12, 0x16, 0x0a, 0x06, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x12, 0x37, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x70, + 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, + 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, + 0x73, 0x12, 0x31, 0x0a, 0x14, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x70, + 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x13, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, + 0x74, 0x69, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x3e, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x5f, + 0x61, 0x72, 0x67, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, + 0x75, 0x63, 0x74, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x41, 0x72, + 0x67, 0x73, 0x22, 0x2d, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x53, + 0x74, 0x61, 0x74, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x70, 0x65, 0x63, 0x5f, 0x68, 0x61, 0x73, + 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x70, 0x65, 0x63, 0x48, 0x61, 0x73, + 0x68, 0x2a, 0x8a, 0x01, 0x0a, 0x0f, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x63, 0x69, 0x6c, 0x65, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x20, 0x0a, 0x1c, 0x52, 0x45, 0x43, 0x4f, 0x4e, 0x43, 0x49, + 0x4c, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, + 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x52, 0x45, 0x43, 0x4f, 0x4e, + 0x43, 0x49, 0x4c, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x49, 0x44, 0x4c, 0x45, + 0x10, 0x01, 0x12, 0x1c, 0x0a, 0x18, 0x52, 0x45, 0x43, 0x4f, 0x4e, 0x43, 0x49, 0x4c, 0x45, 0x5f, + 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x02, + 0x12, 0x1c, 0x0a, 0x18, 0x52, 0x45, 0x43, 0x4f, 0x4e, 0x43, 0x49, 0x4c, 0x45, 0x5f, 0x53, 0x54, + 0x41, 0x54, 0x55, 0x53, 0x5f, 0x52, 0x55, 0x4e, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x03, 0x2a, 0x8c, + 0x01, 0x0a, 0x0f, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4d, 0x6f, + 0x64, 0x65, 0x12, 0x21, 0x0a, 0x1d, 0x4d, 0x4f, 0x44, 0x45, 0x4c, 0x5f, 0x43, 0x48, 0x41, 0x4e, + 0x47, 0x45, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, + 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x4d, 0x4f, 0x44, 0x45, 0x4c, 0x5f, 0x43, + 0x48, 0x41, 0x4e, 0x47, 0x45, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x52, 0x45, 0x53, 0x45, 0x54, + 0x10, 0x01, 0x12, 0x1c, 0x0a, 0x18, 0x4d, 0x4f, 0x44, 0x45, 0x4c, 0x5f, 0x43, 0x48, 0x41, 0x4e, + 0x47, 0x45, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x4d, 0x41, 0x4e, 0x55, 0x41, 0x4c, 0x10, 0x02, 0x12, 0x1b, 0x0a, 0x17, 0x4d, 0x4f, 0x44, 0x45, 0x4c, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, - 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x52, 0x45, 0x53, 0x45, 0x54, 0x10, 0x01, 0x12, 0x1c, 0x0a, - 0x18, 0x4d, 0x4f, 0x44, 0x45, 0x4c, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x5f, 0x4d, 0x4f, - 0x44, 0x45, 0x5f, 0x4d, 0x41, 0x4e, 0x55, 0x41, 0x4c, 0x10, 0x02, 0x12, 0x1b, 0x0a, 0x17, 0x4d, - 0x4f, 0x44, 0x45, 0x4c, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x5f, 0x4d, 0x4f, 0x44, 0x45, - 0x5f, 0x50, 0x41, 0x54, 0x43, 0x48, 0x10, 0x03, 0x2a, 0xab, 0x01, 0x0a, 0x15, 0x45, 0x78, 0x70, - 0x6c, 0x6f, 0x72, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x4d, 0x6f, - 0x64, 0x65, 0x12, 0x27, 0x0a, 0x23, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x43, 0x4f, - 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x55, 0x4e, - 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x20, 0x0a, 0x1c, 0x45, - 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, - 0x4e, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x01, 0x12, 0x20, 0x0a, - 0x1c, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, - 0x53, 0x4f, 0x4e, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x10, 0x02, 0x12, - 0x25, 0x0a, 0x21, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, - 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x44, 0x49, 0x4d, 0x45, 0x4e, - 0x53, 0x49, 0x4f, 0x4e, 0x10, 0x03, 0x2a, 0xae, 0x01, 0x0a, 0x0e, 0x45, 0x78, 0x70, 0x6c, 0x6f, - 0x72, 0x65, 0x57, 0x65, 0x62, 0x56, 0x69, 0x65, 0x77, 0x12, 0x20, 0x0a, 0x1c, 0x45, 0x58, 0x50, - 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x57, 0x45, 0x42, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x55, 0x4e, - 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1c, 0x0a, 0x18, 0x45, - 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x57, 0x45, 0x42, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, - 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x10, 0x01, 0x12, 0x23, 0x0a, 0x1f, 0x45, 0x58, 0x50, - 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x57, 0x45, 0x42, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x54, 0x49, - 0x4d, 0x45, 0x5f, 0x44, 0x49, 0x4d, 0x45, 0x4e, 0x53, 0x49, 0x4f, 0x4e, 0x10, 0x02, 0x12, 0x1a, - 0x0a, 0x16, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x57, 0x45, 0x42, 0x5f, 0x56, 0x49, - 0x45, 0x57, 0x5f, 0x50, 0x49, 0x56, 0x4f, 0x54, 0x10, 0x03, 0x12, 0x1b, 0x0a, 0x17, 0x45, 0x58, - 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x57, 0x45, 0x42, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x43, - 0x41, 0x4e, 0x56, 0x41, 0x53, 0x10, 0x04, 0x2a, 0xdc, 0x01, 0x0a, 0x0f, 0x45, 0x78, 0x70, 0x6c, - 0x6f, 0x72, 0x65, 0x53, 0x6f, 0x72, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x21, 0x0a, 0x1d, 0x45, - 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, - 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, - 0x0a, 0x17, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x54, - 0x59, 0x50, 0x45, 0x5f, 0x56, 0x41, 0x4c, 0x55, 0x45, 0x10, 0x01, 0x12, 0x1d, 0x0a, 0x19, 0x45, - 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, - 0x5f, 0x50, 0x45, 0x52, 0x43, 0x45, 0x4e, 0x54, 0x10, 0x02, 0x12, 0x23, 0x0a, 0x1f, 0x45, 0x58, + 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x50, 0x41, 0x54, 0x43, 0x48, 0x10, 0x03, 0x2a, 0xab, 0x01, + 0x0a, 0x15, 0x45, 0x78, 0x70, 0x6c, 0x6f, 0x72, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, + 0x73, 0x6f, 0x6e, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x27, 0x0a, 0x23, 0x45, 0x58, 0x50, 0x4c, 0x4f, + 0x52, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x4d, 0x4f, + 0x44, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, + 0x12, 0x20, 0x0a, 0x1c, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x50, + 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x4e, 0x4f, 0x4e, 0x45, + 0x10, 0x01, 0x12, 0x20, 0x0a, 0x1c, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x43, 0x4f, + 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x54, 0x49, + 0x4d, 0x45, 0x10, 0x02, 0x12, 0x25, 0x0a, 0x21, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, + 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, + 0x44, 0x49, 0x4d, 0x45, 0x4e, 0x53, 0x49, 0x4f, 0x4e, 0x10, 0x03, 0x2a, 0xae, 0x01, 0x0a, 0x0e, + 0x45, 0x78, 0x70, 0x6c, 0x6f, 0x72, 0x65, 0x57, 0x65, 0x62, 0x56, 0x69, 0x65, 0x77, 0x12, 0x20, + 0x0a, 0x1c, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x57, 0x45, 0x42, 0x5f, 0x56, 0x49, + 0x45, 0x57, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, + 0x12, 0x1c, 0x0a, 0x18, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x57, 0x45, 0x42, 0x5f, + 0x56, 0x49, 0x45, 0x57, 0x5f, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x10, 0x01, 0x12, 0x23, + 0x0a, 0x1f, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x57, 0x45, 0x42, 0x5f, 0x56, 0x49, + 0x45, 0x57, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x5f, 0x44, 0x49, 0x4d, 0x45, 0x4e, 0x53, 0x49, 0x4f, + 0x4e, 0x10, 0x02, 0x12, 0x1a, 0x0a, 0x16, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x57, + 0x45, 0x42, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x50, 0x49, 0x56, 0x4f, 0x54, 0x10, 0x03, 0x12, + 0x1b, 0x0a, 0x17, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x57, 0x45, 0x42, 0x5f, 0x56, + 0x49, 0x45, 0x57, 0x5f, 0x43, 0x41, 0x4e, 0x56, 0x41, 0x53, 0x10, 0x04, 0x2a, 0xdc, 0x01, 0x0a, + 0x0f, 0x45, 0x78, 0x70, 0x6c, 0x6f, 0x72, 0x65, 0x53, 0x6f, 0x72, 0x74, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x21, 0x0a, 0x1d, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x53, 0x4f, 0x52, 0x54, + 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, + 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x53, + 0x4f, 0x52, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x56, 0x41, 0x4c, 0x55, 0x45, 0x10, 0x01, + 0x12, 0x1d, 0x0a, 0x19, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x53, 0x4f, 0x52, 0x54, + 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x45, 0x52, 0x43, 0x45, 0x4e, 0x54, 0x10, 0x02, 0x12, + 0x23, 0x0a, 0x1f, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x53, 0x4f, 0x52, 0x54, 0x5f, + 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x45, 0x4c, 0x54, 0x41, 0x5f, 0x50, 0x45, 0x52, 0x43, 0x45, + 0x4e, 0x54, 0x10, 0x03, 0x12, 0x24, 0x0a, 0x20, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, + 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x45, 0x4c, 0x54, 0x41, 0x5f, + 0x41, 0x42, 0x53, 0x4f, 0x4c, 0x55, 0x54, 0x45, 0x10, 0x04, 0x12, 0x1f, 0x0a, 0x1b, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, - 0x44, 0x45, 0x4c, 0x54, 0x41, 0x5f, 0x50, 0x45, 0x52, 0x43, 0x45, 0x4e, 0x54, 0x10, 0x03, 0x12, - 0x24, 0x0a, 0x20, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x53, 0x4f, 0x52, 0x54, 0x5f, - 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x45, 0x4c, 0x54, 0x41, 0x5f, 0x41, 0x42, 0x53, 0x4f, 0x4c, - 0x55, 0x54, 0x45, 0x10, 0x04, 0x12, 0x1f, 0x0a, 0x1b, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, - 0x5f, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x49, 0x4d, 0x45, 0x4e, - 0x53, 0x49, 0x4f, 0x4e, 0x10, 0x05, 0x2a, 0x85, 0x01, 0x0a, 0x0f, 0x41, 0x73, 0x73, 0x65, 0x72, - 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x20, 0x0a, 0x1c, 0x41, 0x53, - 0x53, 0x45, 0x52, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, - 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, + 0x44, 0x49, 0x4d, 0x45, 0x4e, 0x53, 0x49, 0x4f, 0x4e, 0x10, 0x05, 0x2a, 0x85, 0x01, 0x0a, 0x0f, + 0x41, 0x73, 0x73, 0x65, 0x72, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, + 0x20, 0x0a, 0x1c, 0x41, 0x53, 0x53, 0x45, 0x52, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, + 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, + 0x00, 0x12, 0x19, 0x0a, 0x15, 0x41, 0x53, 0x53, 0x45, 0x52, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, + 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x50, 0x41, 0x53, 0x53, 0x10, 0x01, 0x12, 0x19, 0x0a, 0x15, 0x41, 0x53, 0x53, 0x45, 0x52, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, - 0x5f, 0x50, 0x41, 0x53, 0x53, 0x10, 0x01, 0x12, 0x19, 0x0a, 0x15, 0x41, 0x53, 0x53, 0x45, 0x52, - 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x46, 0x41, 0x49, 0x4c, - 0x10, 0x02, 0x12, 0x1a, 0x0a, 0x16, 0x41, 0x53, 0x53, 0x45, 0x52, 0x54, 0x49, 0x4f, 0x4e, 0x5f, - 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x42, 0xc1, - 0x01, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, - 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x42, 0x0e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x69, 0x6c, 0x6c, 0x64, 0x61, 0x74, 0x61, 0x2f, 0x72, 0x69, - 0x6c, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x72, 0x69, 0x6c, - 0x6c, 0x2f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x72, 0x75, 0x6e, - 0x74, 0x69, 0x6d, 0x65, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x52, 0x52, 0x58, 0xaa, 0x02, 0x0f, 0x52, - 0x69, 0x6c, 0x6c, 0x2e, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x56, 0x31, 0xca, 0x02, - 0x0f, 0x52, 0x69, 0x6c, 0x6c, 0x5c, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x5c, 0x56, 0x31, - 0xe2, 0x02, 0x1b, 0x52, 0x69, 0x6c, 0x6c, 0x5c, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x5c, - 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, - 0x11, 0x52, 0x69, 0x6c, 0x6c, 0x3a, 0x3a, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x3a, 0x3a, - 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x10, 0x02, 0x12, 0x1a, 0x0a, 0x16, 0x41, 0x53, 0x53, 0x45, 0x52, + 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x45, 0x52, 0x52, 0x4f, + 0x52, 0x10, 0x03, 0x42, 0xc1, 0x01, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, + 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x42, 0x0e, 0x52, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3c, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x69, 0x6c, 0x6c, 0x64, 0x61, + 0x74, 0x61, 0x2f, 0x72, 0x69, 0x6c, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, + 0x6e, 0x2f, 0x72, 0x69, 0x6c, 0x6c, 0x2f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2f, 0x76, + 0x31, 0x3b, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x52, 0x52, + 0x58, 0xaa, 0x02, 0x0f, 0x52, 0x69, 0x6c, 0x6c, 0x2e, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, + 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0f, 0x52, 0x69, 0x6c, 0x6c, 0x5c, 0x52, 0x75, 0x6e, 0x74, 0x69, + 0x6d, 0x65, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1b, 0x52, 0x69, 0x6c, 0x6c, 0x5c, 0x52, 0x75, 0x6e, + 0x74, 0x69, 0x6d, 0x65, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0xea, 0x02, 0x11, 0x52, 0x69, 0x6c, 0x6c, 0x3a, 0x3a, 0x52, 0x75, 0x6e, 0x74, + 0x69, 0x6d, 0x65, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -9540,7 +9688,7 @@ func file_rill_runtime_v1_resources_proto_rawDescGZIP() []byte { } var file_rill_runtime_v1_resources_proto_enumTypes = make([]protoimpl.EnumInfo, 8) -var file_rill_runtime_v1_resources_proto_msgTypes = make([]protoimpl.MessageInfo, 87) +var file_rill_runtime_v1_resources_proto_msgTypes = make([]protoimpl.MessageInfo, 88) var file_rill_runtime_v1_resources_proto_goTypes = []any{ (ReconcileStatus)(0), // 0: rill.runtime.v1.ReconcileStatus (ModelChangeMode)(0), // 1: rill.runtime.v1.ModelChangeMode @@ -9604,48 +9752,49 @@ var file_rill_runtime_v1_resources_proto_goTypes = []any{ (*ComponentSpec)(nil), // 59: rill.runtime.v1.ComponentSpec (*ComponentState)(nil), // 60: rill.runtime.v1.ComponentState (*ComponentVariable)(nil), // 61: rill.runtime.v1.ComponentVariable - (*Canvas)(nil), // 62: rill.runtime.v1.Canvas - (*CanvasSpec)(nil), // 63: rill.runtime.v1.CanvasSpec - (*CanvasState)(nil), // 64: rill.runtime.v1.CanvasState - (*CanvasRow)(nil), // 65: rill.runtime.v1.CanvasRow - (*CanvasTabGroup)(nil), // 66: rill.runtime.v1.CanvasTabGroup - (*CanvasTab)(nil), // 67: rill.runtime.v1.CanvasTab - (*CanvasItem)(nil), // 68: rill.runtime.v1.CanvasItem - (*CanvasPreset)(nil), // 69: rill.runtime.v1.CanvasPreset - (*DefaultMetricsSQLFilter)(nil), // 70: rill.runtime.v1.DefaultMetricsSQLFilter - (*API)(nil), // 71: rill.runtime.v1.API - (*APISpec)(nil), // 72: rill.runtime.v1.APISpec - (*APIState)(nil), // 73: rill.runtime.v1.APIState - (*Schedule)(nil), // 74: rill.runtime.v1.Schedule - (*ParseError)(nil), // 75: rill.runtime.v1.ParseError - (*ValidationError)(nil), // 76: rill.runtime.v1.ValidationError - (*DependencyError)(nil), // 77: rill.runtime.v1.DependencyError - (*ExecutionError)(nil), // 78: rill.runtime.v1.ExecutionError - (*CharLocation)(nil), // 79: rill.runtime.v1.CharLocation - (*ConnectorV2)(nil), // 80: rill.runtime.v1.ConnectorV2 - (*ConnectorSpec)(nil), // 81: rill.runtime.v1.ConnectorSpec - (*ConnectorState)(nil), // 82: rill.runtime.v1.ConnectorState - (*MetricsViewSpec_Dimension)(nil), // 83: rill.runtime.v1.MetricsViewSpec.Dimension - (*MetricsViewSpec_DimensionSelector)(nil), // 84: rill.runtime.v1.MetricsViewSpec.DimensionSelector - (*MetricsViewSpec_MeasureWindow)(nil), // 85: rill.runtime.v1.MetricsViewSpec.MeasureWindow - (*MetricsViewSpec_Measure)(nil), // 86: rill.runtime.v1.MetricsViewSpec.Measure - (*MetricsViewSpec_Annotation)(nil), // 87: rill.runtime.v1.MetricsViewSpec.Annotation - (*MetricsViewSpec_Rollup)(nil), // 88: rill.runtime.v1.MetricsViewSpec.Rollup - nil, // 89: rill.runtime.v1.MetricsViewSpec.QueryAttributesEntry - nil, // 90: rill.runtime.v1.ReportSpec.AnnotationsEntry - nil, // 91: rill.runtime.v1.AlertSpec.AnnotationsEntry - nil, // 92: rill.runtime.v1.ThemeColors.VariablesEntry - nil, // 93: rill.runtime.v1.CanvasSpec.AnnotationsEntry - nil, // 94: rill.runtime.v1.CanvasPreset.FilterExprEntry - (*timestamppb.Timestamp)(nil), // 95: google.protobuf.Timestamp - (*structpb.Struct)(nil), // 96: google.protobuf.Struct - (*StructType)(nil), // 97: rill.runtime.v1.StructType - (TimeGrain)(0), // 98: rill.runtime.v1.TimeGrain - (*Expression)(nil), // 99: rill.runtime.v1.Expression - (ExportFormat)(0), // 100: rill.runtime.v1.ExportFormat - (*Color)(nil), // 101: rill.runtime.v1.Color - (*structpb.Value)(nil), // 102: google.protobuf.Value - (*Type)(nil), // 103: rill.runtime.v1.Type + (*ComponentParam)(nil), // 62: rill.runtime.v1.ComponentParam + (*Canvas)(nil), // 63: rill.runtime.v1.Canvas + (*CanvasSpec)(nil), // 64: rill.runtime.v1.CanvasSpec + (*CanvasState)(nil), // 65: rill.runtime.v1.CanvasState + (*CanvasRow)(nil), // 66: rill.runtime.v1.CanvasRow + (*CanvasTabGroup)(nil), // 67: rill.runtime.v1.CanvasTabGroup + (*CanvasTab)(nil), // 68: rill.runtime.v1.CanvasTab + (*CanvasItem)(nil), // 69: rill.runtime.v1.CanvasItem + (*CanvasPreset)(nil), // 70: rill.runtime.v1.CanvasPreset + (*DefaultMetricsSQLFilter)(nil), // 71: rill.runtime.v1.DefaultMetricsSQLFilter + (*API)(nil), // 72: rill.runtime.v1.API + (*APISpec)(nil), // 73: rill.runtime.v1.APISpec + (*APIState)(nil), // 74: rill.runtime.v1.APIState + (*Schedule)(nil), // 75: rill.runtime.v1.Schedule + (*ParseError)(nil), // 76: rill.runtime.v1.ParseError + (*ValidationError)(nil), // 77: rill.runtime.v1.ValidationError + (*DependencyError)(nil), // 78: rill.runtime.v1.DependencyError + (*ExecutionError)(nil), // 79: rill.runtime.v1.ExecutionError + (*CharLocation)(nil), // 80: rill.runtime.v1.CharLocation + (*ConnectorV2)(nil), // 81: rill.runtime.v1.ConnectorV2 + (*ConnectorSpec)(nil), // 82: rill.runtime.v1.ConnectorSpec + (*ConnectorState)(nil), // 83: rill.runtime.v1.ConnectorState + (*MetricsViewSpec_Dimension)(nil), // 84: rill.runtime.v1.MetricsViewSpec.Dimension + (*MetricsViewSpec_DimensionSelector)(nil), // 85: rill.runtime.v1.MetricsViewSpec.DimensionSelector + (*MetricsViewSpec_MeasureWindow)(nil), // 86: rill.runtime.v1.MetricsViewSpec.MeasureWindow + (*MetricsViewSpec_Measure)(nil), // 87: rill.runtime.v1.MetricsViewSpec.Measure + (*MetricsViewSpec_Annotation)(nil), // 88: rill.runtime.v1.MetricsViewSpec.Annotation + (*MetricsViewSpec_Rollup)(nil), // 89: rill.runtime.v1.MetricsViewSpec.Rollup + nil, // 90: rill.runtime.v1.MetricsViewSpec.QueryAttributesEntry + nil, // 91: rill.runtime.v1.ReportSpec.AnnotationsEntry + nil, // 92: rill.runtime.v1.AlertSpec.AnnotationsEntry + nil, // 93: rill.runtime.v1.ThemeColors.VariablesEntry + nil, // 94: rill.runtime.v1.CanvasSpec.AnnotationsEntry + nil, // 95: rill.runtime.v1.CanvasPreset.FilterExprEntry + (*timestamppb.Timestamp)(nil), // 96: google.protobuf.Timestamp + (*structpb.Struct)(nil), // 97: google.protobuf.Struct + (*StructType)(nil), // 98: rill.runtime.v1.StructType + (TimeGrain)(0), // 99: rill.runtime.v1.TimeGrain + (*Expression)(nil), // 100: rill.runtime.v1.Expression + (ExportFormat)(0), // 101: rill.runtime.v1.ExportFormat + (*Color)(nil), // 102: rill.runtime.v1.Color + (*structpb.Value)(nil), // 103: google.protobuf.Value + (*Type)(nil), // 104: rill.runtime.v1.Type } var file_rill_runtime_v1_resources_proto_depIdxs = []int32{ 9, // 0: rill.runtime.v1.Resource.meta:type_name -> rill.runtime.v1.ResourceMeta @@ -9660,54 +9809,54 @@ var file_rill_runtime_v1_resources_proto_depIdxs = []int32{ 50, // 9: rill.runtime.v1.Resource.refresh_trigger:type_name -> rill.runtime.v1.RefreshTrigger 54, // 10: rill.runtime.v1.Resource.theme:type_name -> rill.runtime.v1.Theme 58, // 11: rill.runtime.v1.Resource.component:type_name -> rill.runtime.v1.Component - 62, // 12: rill.runtime.v1.Resource.canvas:type_name -> rill.runtime.v1.Canvas - 71, // 13: rill.runtime.v1.Resource.api:type_name -> rill.runtime.v1.API - 80, // 14: rill.runtime.v1.Resource.connector:type_name -> rill.runtime.v1.ConnectorV2 + 63, // 12: rill.runtime.v1.Resource.canvas:type_name -> rill.runtime.v1.Canvas + 72, // 13: rill.runtime.v1.Resource.api:type_name -> rill.runtime.v1.API + 81, // 14: rill.runtime.v1.Resource.connector:type_name -> rill.runtime.v1.ConnectorV2 10, // 15: rill.runtime.v1.ResourceMeta.name:type_name -> rill.runtime.v1.ResourceName 10, // 16: rill.runtime.v1.ResourceMeta.refs:type_name -> rill.runtime.v1.ResourceName 10, // 17: rill.runtime.v1.ResourceMeta.owner:type_name -> rill.runtime.v1.ResourceName - 95, // 18: rill.runtime.v1.ResourceMeta.created_on:type_name -> google.protobuf.Timestamp - 95, // 19: rill.runtime.v1.ResourceMeta.spec_updated_on:type_name -> google.protobuf.Timestamp - 95, // 20: rill.runtime.v1.ResourceMeta.state_updated_on:type_name -> google.protobuf.Timestamp - 95, // 21: rill.runtime.v1.ResourceMeta.deleted_on:type_name -> google.protobuf.Timestamp + 96, // 18: rill.runtime.v1.ResourceMeta.created_on:type_name -> google.protobuf.Timestamp + 96, // 19: rill.runtime.v1.ResourceMeta.spec_updated_on:type_name -> google.protobuf.Timestamp + 96, // 20: rill.runtime.v1.ResourceMeta.state_updated_on:type_name -> google.protobuf.Timestamp + 96, // 21: rill.runtime.v1.ResourceMeta.deleted_on:type_name -> google.protobuf.Timestamp 0, // 22: rill.runtime.v1.ResourceMeta.reconcile_status:type_name -> rill.runtime.v1.ReconcileStatus - 95, // 23: rill.runtime.v1.ResourceMeta.reconcile_on:type_name -> google.protobuf.Timestamp + 96, // 23: rill.runtime.v1.ResourceMeta.reconcile_on:type_name -> google.protobuf.Timestamp 10, // 24: rill.runtime.v1.ResourceMeta.renamed_from:type_name -> rill.runtime.v1.ResourceName 12, // 25: rill.runtime.v1.ProjectParser.spec:type_name -> rill.runtime.v1.ProjectParserSpec 13, // 26: rill.runtime.v1.ProjectParser.state:type_name -> rill.runtime.v1.ProjectParserState - 75, // 27: rill.runtime.v1.ProjectParserState.parse_errors:type_name -> rill.runtime.v1.ParseError - 95, // 28: rill.runtime.v1.ProjectParserState.current_commit_on:type_name -> google.protobuf.Timestamp + 76, // 27: rill.runtime.v1.ProjectParserState.parse_errors:type_name -> rill.runtime.v1.ParseError + 96, // 28: rill.runtime.v1.ProjectParserState.current_commit_on:type_name -> google.protobuf.Timestamp 15, // 29: rill.runtime.v1.Source.spec:type_name -> rill.runtime.v1.SourceSpec 16, // 30: rill.runtime.v1.Source.state:type_name -> rill.runtime.v1.SourceState - 96, // 31: rill.runtime.v1.SourceSpec.properties:type_name -> google.protobuf.Struct - 74, // 32: rill.runtime.v1.SourceSpec.refresh_schedule:type_name -> rill.runtime.v1.Schedule - 95, // 33: rill.runtime.v1.SourceState.refreshed_on:type_name -> google.protobuf.Timestamp + 97, // 31: rill.runtime.v1.SourceSpec.properties:type_name -> google.protobuf.Struct + 75, // 32: rill.runtime.v1.SourceSpec.refresh_schedule:type_name -> rill.runtime.v1.Schedule + 96, // 33: rill.runtime.v1.SourceState.refreshed_on:type_name -> google.protobuf.Timestamp 18, // 34: rill.runtime.v1.Model.spec:type_name -> rill.runtime.v1.ModelSpec 19, // 35: rill.runtime.v1.Model.state:type_name -> rill.runtime.v1.ModelState - 74, // 36: rill.runtime.v1.ModelSpec.refresh_schedule:type_name -> rill.runtime.v1.Schedule - 96, // 37: rill.runtime.v1.ModelSpec.incremental_state_resolver_properties:type_name -> google.protobuf.Struct - 96, // 38: rill.runtime.v1.ModelSpec.partitions_resolver_properties:type_name -> google.protobuf.Struct - 96, // 39: rill.runtime.v1.ModelSpec.input_properties:type_name -> google.protobuf.Struct - 96, // 40: rill.runtime.v1.ModelSpec.stage_properties:type_name -> google.protobuf.Struct - 96, // 41: rill.runtime.v1.ModelSpec.output_properties:type_name -> google.protobuf.Struct + 75, // 36: rill.runtime.v1.ModelSpec.refresh_schedule:type_name -> rill.runtime.v1.Schedule + 97, // 37: rill.runtime.v1.ModelSpec.incremental_state_resolver_properties:type_name -> google.protobuf.Struct + 97, // 38: rill.runtime.v1.ModelSpec.partitions_resolver_properties:type_name -> google.protobuf.Struct + 97, // 39: rill.runtime.v1.ModelSpec.input_properties:type_name -> google.protobuf.Struct + 97, // 40: rill.runtime.v1.ModelSpec.stage_properties:type_name -> google.protobuf.Struct + 97, // 41: rill.runtime.v1.ModelSpec.output_properties:type_name -> google.protobuf.Struct 1, // 42: rill.runtime.v1.ModelSpec.change_mode:type_name -> rill.runtime.v1.ModelChangeMode 20, // 43: rill.runtime.v1.ModelSpec.tests:type_name -> rill.runtime.v1.ModelTest - 96, // 44: rill.runtime.v1.ModelState.result_properties:type_name -> google.protobuf.Struct - 95, // 45: rill.runtime.v1.ModelState.refreshed_on:type_name -> google.protobuf.Timestamp - 96, // 46: rill.runtime.v1.ModelState.incremental_state:type_name -> google.protobuf.Struct - 97, // 47: rill.runtime.v1.ModelState.incremental_state_schema:type_name -> rill.runtime.v1.StructType - 96, // 48: rill.runtime.v1.ModelTest.resolver_properties:type_name -> google.protobuf.Struct + 97, // 44: rill.runtime.v1.ModelState.result_properties:type_name -> google.protobuf.Struct + 96, // 45: rill.runtime.v1.ModelState.refreshed_on:type_name -> google.protobuf.Timestamp + 97, // 46: rill.runtime.v1.ModelState.incremental_state:type_name -> google.protobuf.Struct + 98, // 47: rill.runtime.v1.ModelState.incremental_state_schema:type_name -> rill.runtime.v1.StructType + 97, // 48: rill.runtime.v1.ModelTest.resolver_properties:type_name -> google.protobuf.Struct 22, // 49: rill.runtime.v1.MetricsView.spec:type_name -> rill.runtime.v1.MetricsViewSpec 28, // 50: rill.runtime.v1.MetricsView.state:type_name -> rill.runtime.v1.MetricsViewState - 98, // 51: rill.runtime.v1.MetricsViewSpec.smallest_time_grain:type_name -> rill.runtime.v1.TimeGrain - 83, // 52: rill.runtime.v1.MetricsViewSpec.dimensions:type_name -> rill.runtime.v1.MetricsViewSpec.Dimension - 86, // 53: rill.runtime.v1.MetricsViewSpec.measures:type_name -> rill.runtime.v1.MetricsViewSpec.Measure + 99, // 51: rill.runtime.v1.MetricsViewSpec.smallest_time_grain:type_name -> rill.runtime.v1.TimeGrain + 84, // 52: rill.runtime.v1.MetricsViewSpec.dimensions:type_name -> rill.runtime.v1.MetricsViewSpec.Dimension + 87, // 53: rill.runtime.v1.MetricsViewSpec.measures:type_name -> rill.runtime.v1.MetricsViewSpec.Measure 35, // 54: rill.runtime.v1.MetricsViewSpec.parent_dimensions:type_name -> rill.runtime.v1.FieldSelector 35, // 55: rill.runtime.v1.MetricsViewSpec.parent_measures:type_name -> rill.runtime.v1.FieldSelector - 87, // 56: rill.runtime.v1.MetricsViewSpec.annotations:type_name -> rill.runtime.v1.MetricsViewSpec.Annotation + 88, // 56: rill.runtime.v1.MetricsViewSpec.annotations:type_name -> rill.runtime.v1.MetricsViewSpec.Annotation 23, // 57: rill.runtime.v1.MetricsViewSpec.security_rules:type_name -> rill.runtime.v1.SecurityRule - 89, // 58: rill.runtime.v1.MetricsViewSpec.query_attributes:type_name -> rill.runtime.v1.MetricsViewSpec.QueryAttributesEntry - 88, // 59: rill.runtime.v1.MetricsViewSpec.rollups:type_name -> rill.runtime.v1.MetricsViewSpec.Rollup + 90, // 58: rill.runtime.v1.MetricsViewSpec.query_attributes:type_name -> rill.runtime.v1.MetricsViewSpec.QueryAttributesEntry + 89, // 59: rill.runtime.v1.MetricsViewSpec.rollups:type_name -> rill.runtime.v1.MetricsViewSpec.Rollup 24, // 60: rill.runtime.v1.SecurityRule.access:type_name -> rill.runtime.v1.SecurityRuleAccess 25, // 61: rill.runtime.v1.SecurityRule.field_access:type_name -> rill.runtime.v1.SecurityRuleFieldAccess 26, // 62: rill.runtime.v1.SecurityRule.row_filter:type_name -> rill.runtime.v1.SecurityRuleRowFilter @@ -9715,10 +9864,10 @@ var file_rill_runtime_v1_resources_proto_depIdxs = []int32{ 10, // 64: rill.runtime.v1.SecurityRuleAccess.condition_resources:type_name -> rill.runtime.v1.ResourceName 10, // 65: rill.runtime.v1.SecurityRuleFieldAccess.condition_resources:type_name -> rill.runtime.v1.ResourceName 10, // 66: rill.runtime.v1.SecurityRuleRowFilter.condition_resources:type_name -> rill.runtime.v1.ResourceName - 99, // 67: rill.runtime.v1.SecurityRuleRowFilter.expression:type_name -> rill.runtime.v1.Expression + 100, // 67: rill.runtime.v1.SecurityRuleRowFilter.expression:type_name -> rill.runtime.v1.Expression 10, // 68: rill.runtime.v1.SecurityRuleTransitiveAccess.resource:type_name -> rill.runtime.v1.ResourceName 22, // 69: rill.runtime.v1.MetricsViewState.valid_spec:type_name -> rill.runtime.v1.MetricsViewSpec - 95, // 70: rill.runtime.v1.MetricsViewState.data_refreshed_on:type_name -> google.protobuf.Timestamp + 96, // 70: rill.runtime.v1.MetricsViewState.data_refreshed_on:type_name -> google.protobuf.Timestamp 30, // 71: rill.runtime.v1.Explore.spec:type_name -> rill.runtime.v1.ExploreSpec 31, // 72: rill.runtime.v1.Explore.state:type_name -> rill.runtime.v1.ExploreState 35, // 73: rill.runtime.v1.ExploreSpec.dimensions_selector:type_name -> rill.runtime.v1.FieldSelector @@ -9728,11 +9877,11 @@ var file_rill_runtime_v1_resources_proto_depIdxs = []int32{ 34, // 77: rill.runtime.v1.ExploreSpec.default_preset:type_name -> rill.runtime.v1.ExplorePreset 23, // 78: rill.runtime.v1.ExploreSpec.security_rules:type_name -> rill.runtime.v1.SecurityRule 30, // 79: rill.runtime.v1.ExploreState.valid_spec:type_name -> rill.runtime.v1.ExploreSpec - 95, // 80: rill.runtime.v1.ExploreState.data_refreshed_on:type_name -> google.protobuf.Timestamp + 96, // 80: rill.runtime.v1.ExploreState.data_refreshed_on:type_name -> google.protobuf.Timestamp 33, // 81: rill.runtime.v1.ExploreTimeRange.comparison_time_ranges:type_name -> rill.runtime.v1.ExploreComparisonTimeRange 35, // 82: rill.runtime.v1.ExplorePreset.dimensions_selector:type_name -> rill.runtime.v1.FieldSelector 35, // 83: rill.runtime.v1.ExplorePreset.measures_selector:type_name -> rill.runtime.v1.FieldSelector - 99, // 84: rill.runtime.v1.ExplorePreset.where:type_name -> rill.runtime.v1.Expression + 100, // 84: rill.runtime.v1.ExplorePreset.where:type_name -> rill.runtime.v1.Expression 2, // 85: rill.runtime.v1.ExplorePreset.comparison_mode:type_name -> rill.runtime.v1.ExploreComparisonMode 3, // 86: rill.runtime.v1.ExplorePreset.view:type_name -> rill.runtime.v1.ExploreWebView 4, // 87: rill.runtime.v1.ExplorePreset.explore_sort_type:type_name -> rill.runtime.v1.ExploreSortType @@ -9741,102 +9890,106 @@ var file_rill_runtime_v1_resources_proto_depIdxs = []int32{ 39, // 90: rill.runtime.v1.Migration.state:type_name -> rill.runtime.v1.MigrationState 41, // 91: rill.runtime.v1.Report.spec:type_name -> rill.runtime.v1.ReportSpec 42, // 92: rill.runtime.v1.Report.state:type_name -> rill.runtime.v1.ReportState - 74, // 93: rill.runtime.v1.ReportSpec.refresh_schedule:type_name -> rill.runtime.v1.Schedule - 96, // 94: rill.runtime.v1.ReportSpec.resolver_properties:type_name -> google.protobuf.Struct - 100, // 95: rill.runtime.v1.ReportSpec.export_format:type_name -> rill.runtime.v1.ExportFormat + 75, // 93: rill.runtime.v1.ReportSpec.refresh_schedule:type_name -> rill.runtime.v1.Schedule + 97, // 94: rill.runtime.v1.ReportSpec.resolver_properties:type_name -> google.protobuf.Struct + 101, // 95: rill.runtime.v1.ReportSpec.export_format:type_name -> rill.runtime.v1.ExportFormat 46, // 96: rill.runtime.v1.ReportSpec.notifiers:type_name -> rill.runtime.v1.Notifier - 90, // 97: rill.runtime.v1.ReportSpec.annotations:type_name -> rill.runtime.v1.ReportSpec.AnnotationsEntry - 95, // 98: rill.runtime.v1.ReportState.next_run_on:type_name -> google.protobuf.Timestamp + 91, // 97: rill.runtime.v1.ReportSpec.annotations:type_name -> rill.runtime.v1.ReportSpec.AnnotationsEntry + 96, // 98: rill.runtime.v1.ReportState.next_run_on:type_name -> google.protobuf.Timestamp 43, // 99: rill.runtime.v1.ReportState.current_execution:type_name -> rill.runtime.v1.ReportExecution 43, // 100: rill.runtime.v1.ReportState.execution_history:type_name -> rill.runtime.v1.ReportExecution - 95, // 101: rill.runtime.v1.ReportExecution.report_time:type_name -> google.protobuf.Timestamp - 95, // 102: rill.runtime.v1.ReportExecution.started_on:type_name -> google.protobuf.Timestamp - 95, // 103: rill.runtime.v1.ReportExecution.finished_on:type_name -> google.protobuf.Timestamp + 96, // 101: rill.runtime.v1.ReportExecution.report_time:type_name -> google.protobuf.Timestamp + 96, // 102: rill.runtime.v1.ReportExecution.started_on:type_name -> google.protobuf.Timestamp + 96, // 103: rill.runtime.v1.ReportExecution.finished_on:type_name -> google.protobuf.Timestamp 45, // 104: rill.runtime.v1.Alert.spec:type_name -> rill.runtime.v1.AlertSpec 47, // 105: rill.runtime.v1.Alert.state:type_name -> rill.runtime.v1.AlertState - 74, // 106: rill.runtime.v1.AlertSpec.refresh_schedule:type_name -> rill.runtime.v1.Schedule - 96, // 107: rill.runtime.v1.AlertSpec.resolver_properties:type_name -> google.protobuf.Struct - 96, // 108: rill.runtime.v1.AlertSpec.query_for_attributes:type_name -> google.protobuf.Struct + 75, // 106: rill.runtime.v1.AlertSpec.refresh_schedule:type_name -> rill.runtime.v1.Schedule + 97, // 107: rill.runtime.v1.AlertSpec.resolver_properties:type_name -> google.protobuf.Struct + 97, // 108: rill.runtime.v1.AlertSpec.query_for_attributes:type_name -> google.protobuf.Struct 46, // 109: rill.runtime.v1.AlertSpec.notifiers:type_name -> rill.runtime.v1.Notifier - 91, // 110: rill.runtime.v1.AlertSpec.annotations:type_name -> rill.runtime.v1.AlertSpec.AnnotationsEntry - 96, // 111: rill.runtime.v1.Notifier.properties:type_name -> google.protobuf.Struct - 95, // 112: rill.runtime.v1.AlertState.next_run_on:type_name -> google.protobuf.Timestamp + 92, // 110: rill.runtime.v1.AlertSpec.annotations:type_name -> rill.runtime.v1.AlertSpec.AnnotationsEntry + 97, // 111: rill.runtime.v1.Notifier.properties:type_name -> google.protobuf.Struct + 96, // 112: rill.runtime.v1.AlertState.next_run_on:type_name -> google.protobuf.Timestamp 48, // 113: rill.runtime.v1.AlertState.current_execution:type_name -> rill.runtime.v1.AlertExecution 48, // 114: rill.runtime.v1.AlertState.execution_history:type_name -> rill.runtime.v1.AlertExecution 49, // 115: rill.runtime.v1.AlertExecution.result:type_name -> rill.runtime.v1.AssertionResult - 95, // 116: rill.runtime.v1.AlertExecution.execution_time:type_name -> google.protobuf.Timestamp - 95, // 117: rill.runtime.v1.AlertExecution.started_on:type_name -> google.protobuf.Timestamp - 95, // 118: rill.runtime.v1.AlertExecution.finished_on:type_name -> google.protobuf.Timestamp - 95, // 119: rill.runtime.v1.AlertExecution.suppressed_since:type_name -> google.protobuf.Timestamp + 96, // 116: rill.runtime.v1.AlertExecution.execution_time:type_name -> google.protobuf.Timestamp + 96, // 117: rill.runtime.v1.AlertExecution.started_on:type_name -> google.protobuf.Timestamp + 96, // 118: rill.runtime.v1.AlertExecution.finished_on:type_name -> google.protobuf.Timestamp + 96, // 119: rill.runtime.v1.AlertExecution.suppressed_since:type_name -> google.protobuf.Timestamp 5, // 120: rill.runtime.v1.AssertionResult.status:type_name -> rill.runtime.v1.AssertionStatus - 96, // 121: rill.runtime.v1.AssertionResult.fail_row:type_name -> google.protobuf.Struct + 97, // 121: rill.runtime.v1.AssertionResult.fail_row:type_name -> google.protobuf.Struct 51, // 122: rill.runtime.v1.RefreshTrigger.spec:type_name -> rill.runtime.v1.RefreshTriggerSpec 52, // 123: rill.runtime.v1.RefreshTrigger.state:type_name -> rill.runtime.v1.RefreshTriggerState 10, // 124: rill.runtime.v1.RefreshTriggerSpec.resources:type_name -> rill.runtime.v1.ResourceName 53, // 125: rill.runtime.v1.RefreshTriggerSpec.models:type_name -> rill.runtime.v1.RefreshModelTrigger 55, // 126: rill.runtime.v1.Theme.spec:type_name -> rill.runtime.v1.ThemeSpec 56, // 127: rill.runtime.v1.Theme.state:type_name -> rill.runtime.v1.ThemeState - 101, // 128: rill.runtime.v1.ThemeSpec.primary_color:type_name -> rill.runtime.v1.Color - 101, // 129: rill.runtime.v1.ThemeSpec.secondary_color:type_name -> rill.runtime.v1.Color + 102, // 128: rill.runtime.v1.ThemeSpec.primary_color:type_name -> rill.runtime.v1.Color + 102, // 129: rill.runtime.v1.ThemeSpec.secondary_color:type_name -> rill.runtime.v1.Color 57, // 130: rill.runtime.v1.ThemeSpec.light:type_name -> rill.runtime.v1.ThemeColors 57, // 131: rill.runtime.v1.ThemeSpec.dark:type_name -> rill.runtime.v1.ThemeColors - 92, // 132: rill.runtime.v1.ThemeColors.variables:type_name -> rill.runtime.v1.ThemeColors.VariablesEntry + 93, // 132: rill.runtime.v1.ThemeColors.variables:type_name -> rill.runtime.v1.ThemeColors.VariablesEntry 59, // 133: rill.runtime.v1.Component.spec:type_name -> rill.runtime.v1.ComponentSpec 60, // 134: rill.runtime.v1.Component.state:type_name -> rill.runtime.v1.ComponentState - 96, // 135: rill.runtime.v1.ComponentSpec.renderer_properties:type_name -> google.protobuf.Struct - 61, // 136: rill.runtime.v1.ComponentSpec.input:type_name -> rill.runtime.v1.ComponentVariable - 61, // 137: rill.runtime.v1.ComponentSpec.output:type_name -> rill.runtime.v1.ComponentVariable - 59, // 138: rill.runtime.v1.ComponentState.valid_spec:type_name -> rill.runtime.v1.ComponentSpec - 95, // 139: rill.runtime.v1.ComponentState.data_refreshed_on:type_name -> google.protobuf.Timestamp - 102, // 140: rill.runtime.v1.ComponentVariable.default_value:type_name -> google.protobuf.Value - 63, // 141: rill.runtime.v1.Canvas.spec:type_name -> rill.runtime.v1.CanvasSpec - 64, // 142: rill.runtime.v1.Canvas.state:type_name -> rill.runtime.v1.CanvasState - 55, // 143: rill.runtime.v1.CanvasSpec.embedded_theme:type_name -> rill.runtime.v1.ThemeSpec - 32, // 144: rill.runtime.v1.CanvasSpec.time_ranges:type_name -> rill.runtime.v1.ExploreTimeRange - 69, // 145: rill.runtime.v1.CanvasSpec.default_preset:type_name -> rill.runtime.v1.CanvasPreset - 61, // 146: rill.runtime.v1.CanvasSpec.variables:type_name -> rill.runtime.v1.ComponentVariable - 65, // 147: rill.runtime.v1.CanvasSpec.rows:type_name -> rill.runtime.v1.CanvasRow - 23, // 148: rill.runtime.v1.CanvasSpec.security_rules:type_name -> rill.runtime.v1.SecurityRule - 93, // 149: rill.runtime.v1.CanvasSpec.annotations:type_name -> rill.runtime.v1.CanvasSpec.AnnotationsEntry - 63, // 150: rill.runtime.v1.CanvasState.valid_spec:type_name -> rill.runtime.v1.CanvasSpec - 95, // 151: rill.runtime.v1.CanvasState.data_refreshed_on:type_name -> google.protobuf.Timestamp - 68, // 152: rill.runtime.v1.CanvasRow.items:type_name -> rill.runtime.v1.CanvasItem - 66, // 153: rill.runtime.v1.CanvasRow.tab_group:type_name -> rill.runtime.v1.CanvasTabGroup - 67, // 154: rill.runtime.v1.CanvasTabGroup.tabs:type_name -> rill.runtime.v1.CanvasTab - 65, // 155: rill.runtime.v1.CanvasTab.rows:type_name -> rill.runtime.v1.CanvasRow - 2, // 156: rill.runtime.v1.CanvasPreset.comparison_mode:type_name -> rill.runtime.v1.ExploreComparisonMode - 94, // 157: rill.runtime.v1.CanvasPreset.filter_expr:type_name -> rill.runtime.v1.CanvasPreset.FilterExprEntry - 99, // 158: rill.runtime.v1.DefaultMetricsSQLFilter.expression:type_name -> rill.runtime.v1.Expression - 72, // 159: rill.runtime.v1.API.spec:type_name -> rill.runtime.v1.APISpec - 73, // 160: rill.runtime.v1.API.state:type_name -> rill.runtime.v1.APIState - 96, // 161: rill.runtime.v1.APISpec.resolver_properties:type_name -> google.protobuf.Struct - 23, // 162: rill.runtime.v1.APISpec.security_rules:type_name -> rill.runtime.v1.SecurityRule - 79, // 163: rill.runtime.v1.ParseError.start_location:type_name -> rill.runtime.v1.CharLocation - 81, // 164: rill.runtime.v1.ConnectorV2.spec:type_name -> rill.runtime.v1.ConnectorSpec - 82, // 165: rill.runtime.v1.ConnectorV2.state:type_name -> rill.runtime.v1.ConnectorState - 96, // 166: rill.runtime.v1.ConnectorSpec.properties:type_name -> google.protobuf.Struct - 96, // 167: rill.runtime.v1.ConnectorSpec.provision_args:type_name -> google.protobuf.Struct - 6, // 168: rill.runtime.v1.MetricsViewSpec.Dimension.type:type_name -> rill.runtime.v1.MetricsViewSpec.DimensionType - 98, // 169: rill.runtime.v1.MetricsViewSpec.Dimension.smallest_time_grain:type_name -> rill.runtime.v1.TimeGrain - 103, // 170: rill.runtime.v1.MetricsViewSpec.Dimension.data_type:type_name -> rill.runtime.v1.Type - 98, // 171: rill.runtime.v1.MetricsViewSpec.DimensionSelector.time_grain:type_name -> rill.runtime.v1.TimeGrain - 84, // 172: rill.runtime.v1.MetricsViewSpec.MeasureWindow.order_by:type_name -> rill.runtime.v1.MetricsViewSpec.DimensionSelector - 7, // 173: rill.runtime.v1.MetricsViewSpec.Measure.type:type_name -> rill.runtime.v1.MetricsViewSpec.MeasureType - 85, // 174: rill.runtime.v1.MetricsViewSpec.Measure.window:type_name -> rill.runtime.v1.MetricsViewSpec.MeasureWindow - 84, // 175: rill.runtime.v1.MetricsViewSpec.Measure.per_dimensions:type_name -> rill.runtime.v1.MetricsViewSpec.DimensionSelector - 84, // 176: rill.runtime.v1.MetricsViewSpec.Measure.required_dimensions:type_name -> rill.runtime.v1.MetricsViewSpec.DimensionSelector - 96, // 177: rill.runtime.v1.MetricsViewSpec.Measure.format_d3_locale:type_name -> google.protobuf.Struct - 103, // 178: rill.runtime.v1.MetricsViewSpec.Measure.data_type:type_name -> rill.runtime.v1.Type - 35, // 179: rill.runtime.v1.MetricsViewSpec.Annotation.measures_selector:type_name -> rill.runtime.v1.FieldSelector - 98, // 180: rill.runtime.v1.MetricsViewSpec.Rollup.time_grain:type_name -> rill.runtime.v1.TimeGrain - 35, // 181: rill.runtime.v1.MetricsViewSpec.Rollup.dimensions_selector:type_name -> rill.runtime.v1.FieldSelector - 35, // 182: rill.runtime.v1.MetricsViewSpec.Rollup.measures_selector:type_name -> rill.runtime.v1.FieldSelector - 70, // 183: rill.runtime.v1.CanvasPreset.FilterExprEntry.value:type_name -> rill.runtime.v1.DefaultMetricsSQLFilter - 184, // [184:184] is the sub-list for method output_type - 184, // [184:184] is the sub-list for method input_type - 184, // [184:184] is the sub-list for extension type_name - 184, // [184:184] is the sub-list for extension extendee - 0, // [0:184] is the sub-list for field type_name + 97, // 135: rill.runtime.v1.ComponentSpec.renderer_properties:type_name -> google.protobuf.Struct + 62, // 136: rill.runtime.v1.ComponentSpec.params:type_name -> rill.runtime.v1.ComponentParam + 61, // 137: rill.runtime.v1.ComponentSpec.input:type_name -> rill.runtime.v1.ComponentVariable + 61, // 138: rill.runtime.v1.ComponentSpec.output:type_name -> rill.runtime.v1.ComponentVariable + 59, // 139: rill.runtime.v1.ComponentState.valid_spec:type_name -> rill.runtime.v1.ComponentSpec + 96, // 140: rill.runtime.v1.ComponentState.data_refreshed_on:type_name -> google.protobuf.Timestamp + 103, // 141: rill.runtime.v1.ComponentVariable.default_value:type_name -> google.protobuf.Value + 103, // 142: rill.runtime.v1.ComponentParam.default:type_name -> google.protobuf.Value + 103, // 143: rill.runtime.v1.ComponentParam.options:type_name -> google.protobuf.Value + 64, // 144: rill.runtime.v1.Canvas.spec:type_name -> rill.runtime.v1.CanvasSpec + 65, // 145: rill.runtime.v1.Canvas.state:type_name -> rill.runtime.v1.CanvasState + 55, // 146: rill.runtime.v1.CanvasSpec.embedded_theme:type_name -> rill.runtime.v1.ThemeSpec + 32, // 147: rill.runtime.v1.CanvasSpec.time_ranges:type_name -> rill.runtime.v1.ExploreTimeRange + 70, // 148: rill.runtime.v1.CanvasSpec.default_preset:type_name -> rill.runtime.v1.CanvasPreset + 61, // 149: rill.runtime.v1.CanvasSpec.variables:type_name -> rill.runtime.v1.ComponentVariable + 66, // 150: rill.runtime.v1.CanvasSpec.rows:type_name -> rill.runtime.v1.CanvasRow + 23, // 151: rill.runtime.v1.CanvasSpec.security_rules:type_name -> rill.runtime.v1.SecurityRule + 94, // 152: rill.runtime.v1.CanvasSpec.annotations:type_name -> rill.runtime.v1.CanvasSpec.AnnotationsEntry + 64, // 153: rill.runtime.v1.CanvasState.valid_spec:type_name -> rill.runtime.v1.CanvasSpec + 96, // 154: rill.runtime.v1.CanvasState.data_refreshed_on:type_name -> google.protobuf.Timestamp + 69, // 155: rill.runtime.v1.CanvasRow.items:type_name -> rill.runtime.v1.CanvasItem + 67, // 156: rill.runtime.v1.CanvasRow.tab_group:type_name -> rill.runtime.v1.CanvasTabGroup + 68, // 157: rill.runtime.v1.CanvasTabGroup.tabs:type_name -> rill.runtime.v1.CanvasTab + 66, // 158: rill.runtime.v1.CanvasTab.rows:type_name -> rill.runtime.v1.CanvasRow + 97, // 159: rill.runtime.v1.CanvasItem.params:type_name -> google.protobuf.Struct + 2, // 160: rill.runtime.v1.CanvasPreset.comparison_mode:type_name -> rill.runtime.v1.ExploreComparisonMode + 95, // 161: rill.runtime.v1.CanvasPreset.filter_expr:type_name -> rill.runtime.v1.CanvasPreset.FilterExprEntry + 100, // 162: rill.runtime.v1.DefaultMetricsSQLFilter.expression:type_name -> rill.runtime.v1.Expression + 73, // 163: rill.runtime.v1.API.spec:type_name -> rill.runtime.v1.APISpec + 74, // 164: rill.runtime.v1.API.state:type_name -> rill.runtime.v1.APIState + 97, // 165: rill.runtime.v1.APISpec.resolver_properties:type_name -> google.protobuf.Struct + 23, // 166: rill.runtime.v1.APISpec.security_rules:type_name -> rill.runtime.v1.SecurityRule + 80, // 167: rill.runtime.v1.ParseError.start_location:type_name -> rill.runtime.v1.CharLocation + 82, // 168: rill.runtime.v1.ConnectorV2.spec:type_name -> rill.runtime.v1.ConnectorSpec + 83, // 169: rill.runtime.v1.ConnectorV2.state:type_name -> rill.runtime.v1.ConnectorState + 97, // 170: rill.runtime.v1.ConnectorSpec.properties:type_name -> google.protobuf.Struct + 97, // 171: rill.runtime.v1.ConnectorSpec.provision_args:type_name -> google.protobuf.Struct + 6, // 172: rill.runtime.v1.MetricsViewSpec.Dimension.type:type_name -> rill.runtime.v1.MetricsViewSpec.DimensionType + 99, // 173: rill.runtime.v1.MetricsViewSpec.Dimension.smallest_time_grain:type_name -> rill.runtime.v1.TimeGrain + 104, // 174: rill.runtime.v1.MetricsViewSpec.Dimension.data_type:type_name -> rill.runtime.v1.Type + 99, // 175: rill.runtime.v1.MetricsViewSpec.DimensionSelector.time_grain:type_name -> rill.runtime.v1.TimeGrain + 85, // 176: rill.runtime.v1.MetricsViewSpec.MeasureWindow.order_by:type_name -> rill.runtime.v1.MetricsViewSpec.DimensionSelector + 7, // 177: rill.runtime.v1.MetricsViewSpec.Measure.type:type_name -> rill.runtime.v1.MetricsViewSpec.MeasureType + 86, // 178: rill.runtime.v1.MetricsViewSpec.Measure.window:type_name -> rill.runtime.v1.MetricsViewSpec.MeasureWindow + 85, // 179: rill.runtime.v1.MetricsViewSpec.Measure.per_dimensions:type_name -> rill.runtime.v1.MetricsViewSpec.DimensionSelector + 85, // 180: rill.runtime.v1.MetricsViewSpec.Measure.required_dimensions:type_name -> rill.runtime.v1.MetricsViewSpec.DimensionSelector + 97, // 181: rill.runtime.v1.MetricsViewSpec.Measure.format_d3_locale:type_name -> google.protobuf.Struct + 104, // 182: rill.runtime.v1.MetricsViewSpec.Measure.data_type:type_name -> rill.runtime.v1.Type + 35, // 183: rill.runtime.v1.MetricsViewSpec.Annotation.measures_selector:type_name -> rill.runtime.v1.FieldSelector + 99, // 184: rill.runtime.v1.MetricsViewSpec.Rollup.time_grain:type_name -> rill.runtime.v1.TimeGrain + 35, // 185: rill.runtime.v1.MetricsViewSpec.Rollup.dimensions_selector:type_name -> rill.runtime.v1.FieldSelector + 35, // 186: rill.runtime.v1.MetricsViewSpec.Rollup.measures_selector:type_name -> rill.runtime.v1.FieldSelector + 71, // 187: rill.runtime.v1.CanvasPreset.FilterExprEntry.value:type_name -> rill.runtime.v1.DefaultMetricsSQLFilter + 188, // [188:188] is the sub-list for method output_type + 188, // [188:188] is the sub-list for method input_type + 188, // [188:188] is the sub-list for extension type_name + 188, // [188:188] is the sub-list for extension extendee + 0, // [0:188] is the sub-list for field type_name } func init() { file_rill_runtime_v1_resources_proto_init() } @@ -10499,7 +10652,7 @@ func file_rill_runtime_v1_resources_proto_init() { } } file_rill_runtime_v1_resources_proto_msgTypes[54].Exporter = func(v any, i int) any { - switch v := v.(*Canvas); i { + switch v := v.(*ComponentParam); i { case 0: return &v.state case 1: @@ -10511,7 +10664,7 @@ func file_rill_runtime_v1_resources_proto_init() { } } file_rill_runtime_v1_resources_proto_msgTypes[55].Exporter = func(v any, i int) any { - switch v := v.(*CanvasSpec); i { + switch v := v.(*Canvas); i { case 0: return &v.state case 1: @@ -10523,7 +10676,7 @@ func file_rill_runtime_v1_resources_proto_init() { } } file_rill_runtime_v1_resources_proto_msgTypes[56].Exporter = func(v any, i int) any { - switch v := v.(*CanvasState); i { + switch v := v.(*CanvasSpec); i { case 0: return &v.state case 1: @@ -10535,7 +10688,7 @@ func file_rill_runtime_v1_resources_proto_init() { } } file_rill_runtime_v1_resources_proto_msgTypes[57].Exporter = func(v any, i int) any { - switch v := v.(*CanvasRow); i { + switch v := v.(*CanvasState); i { case 0: return &v.state case 1: @@ -10547,7 +10700,7 @@ func file_rill_runtime_v1_resources_proto_init() { } } file_rill_runtime_v1_resources_proto_msgTypes[58].Exporter = func(v any, i int) any { - switch v := v.(*CanvasTabGroup); i { + switch v := v.(*CanvasRow); i { case 0: return &v.state case 1: @@ -10559,7 +10712,7 @@ func file_rill_runtime_v1_resources_proto_init() { } } file_rill_runtime_v1_resources_proto_msgTypes[59].Exporter = func(v any, i int) any { - switch v := v.(*CanvasTab); i { + switch v := v.(*CanvasTabGroup); i { case 0: return &v.state case 1: @@ -10571,7 +10724,7 @@ func file_rill_runtime_v1_resources_proto_init() { } } file_rill_runtime_v1_resources_proto_msgTypes[60].Exporter = func(v any, i int) any { - switch v := v.(*CanvasItem); i { + switch v := v.(*CanvasTab); i { case 0: return &v.state case 1: @@ -10583,7 +10736,7 @@ func file_rill_runtime_v1_resources_proto_init() { } } file_rill_runtime_v1_resources_proto_msgTypes[61].Exporter = func(v any, i int) any { - switch v := v.(*CanvasPreset); i { + switch v := v.(*CanvasItem); i { case 0: return &v.state case 1: @@ -10595,7 +10748,7 @@ func file_rill_runtime_v1_resources_proto_init() { } } file_rill_runtime_v1_resources_proto_msgTypes[62].Exporter = func(v any, i int) any { - switch v := v.(*DefaultMetricsSQLFilter); i { + switch v := v.(*CanvasPreset); i { case 0: return &v.state case 1: @@ -10607,7 +10760,7 @@ func file_rill_runtime_v1_resources_proto_init() { } } file_rill_runtime_v1_resources_proto_msgTypes[63].Exporter = func(v any, i int) any { - switch v := v.(*API); i { + switch v := v.(*DefaultMetricsSQLFilter); i { case 0: return &v.state case 1: @@ -10619,7 +10772,7 @@ func file_rill_runtime_v1_resources_proto_init() { } } file_rill_runtime_v1_resources_proto_msgTypes[64].Exporter = func(v any, i int) any { - switch v := v.(*APISpec); i { + switch v := v.(*API); i { case 0: return &v.state case 1: @@ -10631,7 +10784,7 @@ func file_rill_runtime_v1_resources_proto_init() { } } file_rill_runtime_v1_resources_proto_msgTypes[65].Exporter = func(v any, i int) any { - switch v := v.(*APIState); i { + switch v := v.(*APISpec); i { case 0: return &v.state case 1: @@ -10643,7 +10796,7 @@ func file_rill_runtime_v1_resources_proto_init() { } } file_rill_runtime_v1_resources_proto_msgTypes[66].Exporter = func(v any, i int) any { - switch v := v.(*Schedule); i { + switch v := v.(*APIState); i { case 0: return &v.state case 1: @@ -10655,7 +10808,7 @@ func file_rill_runtime_v1_resources_proto_init() { } } file_rill_runtime_v1_resources_proto_msgTypes[67].Exporter = func(v any, i int) any { - switch v := v.(*ParseError); i { + switch v := v.(*Schedule); i { case 0: return &v.state case 1: @@ -10667,7 +10820,7 @@ func file_rill_runtime_v1_resources_proto_init() { } } file_rill_runtime_v1_resources_proto_msgTypes[68].Exporter = func(v any, i int) any { - switch v := v.(*ValidationError); i { + switch v := v.(*ParseError); i { case 0: return &v.state case 1: @@ -10679,7 +10832,7 @@ func file_rill_runtime_v1_resources_proto_init() { } } file_rill_runtime_v1_resources_proto_msgTypes[69].Exporter = func(v any, i int) any { - switch v := v.(*DependencyError); i { + switch v := v.(*ValidationError); i { case 0: return &v.state case 1: @@ -10691,7 +10844,7 @@ func file_rill_runtime_v1_resources_proto_init() { } } file_rill_runtime_v1_resources_proto_msgTypes[70].Exporter = func(v any, i int) any { - switch v := v.(*ExecutionError); i { + switch v := v.(*DependencyError); i { case 0: return &v.state case 1: @@ -10703,7 +10856,7 @@ func file_rill_runtime_v1_resources_proto_init() { } } file_rill_runtime_v1_resources_proto_msgTypes[71].Exporter = func(v any, i int) any { - switch v := v.(*CharLocation); i { + switch v := v.(*ExecutionError); i { case 0: return &v.state case 1: @@ -10715,7 +10868,7 @@ func file_rill_runtime_v1_resources_proto_init() { } } file_rill_runtime_v1_resources_proto_msgTypes[72].Exporter = func(v any, i int) any { - switch v := v.(*ConnectorV2); i { + switch v := v.(*CharLocation); i { case 0: return &v.state case 1: @@ -10727,7 +10880,7 @@ func file_rill_runtime_v1_resources_proto_init() { } } file_rill_runtime_v1_resources_proto_msgTypes[73].Exporter = func(v any, i int) any { - switch v := v.(*ConnectorSpec); i { + switch v := v.(*ConnectorV2); i { case 0: return &v.state case 1: @@ -10739,7 +10892,7 @@ func file_rill_runtime_v1_resources_proto_init() { } } file_rill_runtime_v1_resources_proto_msgTypes[74].Exporter = func(v any, i int) any { - switch v := v.(*ConnectorState); i { + switch v := v.(*ConnectorSpec); i { case 0: return &v.state case 1: @@ -10751,7 +10904,7 @@ func file_rill_runtime_v1_resources_proto_init() { } } file_rill_runtime_v1_resources_proto_msgTypes[75].Exporter = func(v any, i int) any { - switch v := v.(*MetricsViewSpec_Dimension); i { + switch v := v.(*ConnectorState); i { case 0: return &v.state case 1: @@ -10763,7 +10916,7 @@ func file_rill_runtime_v1_resources_proto_init() { } } file_rill_runtime_v1_resources_proto_msgTypes[76].Exporter = func(v any, i int) any { - switch v := v.(*MetricsViewSpec_DimensionSelector); i { + switch v := v.(*MetricsViewSpec_Dimension); i { case 0: return &v.state case 1: @@ -10775,7 +10928,7 @@ func file_rill_runtime_v1_resources_proto_init() { } } file_rill_runtime_v1_resources_proto_msgTypes[77].Exporter = func(v any, i int) any { - switch v := v.(*MetricsViewSpec_MeasureWindow); i { + switch v := v.(*MetricsViewSpec_DimensionSelector); i { case 0: return &v.state case 1: @@ -10787,7 +10940,7 @@ func file_rill_runtime_v1_resources_proto_init() { } } file_rill_runtime_v1_resources_proto_msgTypes[78].Exporter = func(v any, i int) any { - switch v := v.(*MetricsViewSpec_Measure); i { + switch v := v.(*MetricsViewSpec_MeasureWindow); i { case 0: return &v.state case 1: @@ -10799,7 +10952,7 @@ func file_rill_runtime_v1_resources_proto_init() { } } file_rill_runtime_v1_resources_proto_msgTypes[79].Exporter = func(v any, i int) any { - switch v := v.(*MetricsViewSpec_Annotation); i { + switch v := v.(*MetricsViewSpec_Measure); i { case 0: return &v.state case 1: @@ -10811,6 +10964,18 @@ func file_rill_runtime_v1_resources_proto_init() { } } file_rill_runtime_v1_resources_proto_msgTypes[80].Exporter = func(v any, i int) any { + switch v := v.(*MetricsViewSpec_Annotation); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rill_runtime_v1_resources_proto_msgTypes[81].Exporter = func(v any, i int) any { switch v := v.(*MetricsViewSpec_Rollup); i { case 0: return &v.state @@ -10861,16 +11026,16 @@ func file_rill_runtime_v1_resources_proto_init() { (*AlertSpec_QueryForAttributes)(nil), } file_rill_runtime_v1_resources_proto_msgTypes[47].OneofWrappers = []any{} - file_rill_runtime_v1_resources_proto_msgTypes[57].OneofWrappers = []any{} - file_rill_runtime_v1_resources_proto_msgTypes[60].OneofWrappers = []any{} + file_rill_runtime_v1_resources_proto_msgTypes[58].OneofWrappers = []any{} file_rill_runtime_v1_resources_proto_msgTypes[61].OneofWrappers = []any{} + file_rill_runtime_v1_resources_proto_msgTypes[62].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_rill_runtime_v1_resources_proto_rawDesc, NumEnums: 8, - NumMessages: 87, + NumMessages: 88, NumExtensions: 0, NumServices: 0, }, diff --git a/proto/gen/rill/runtime/v1/resources.pb.validate.go b/proto/gen/rill/runtime/v1/resources.pb.validate.go index deb4bc8f013a..f84c5daabcda 100644 --- a/proto/gen/rill/runtime/v1/resources.pb.validate.go +++ b/proto/gen/rill/runtime/v1/resources.pb.validate.go @@ -9604,6 +9604,40 @@ func (m *ComponentSpec) validate(all bool) error { } } + for idx, item := range m.GetParams() { + _, _ = idx, item + + if all { + switch v := interface{}(item).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, ComponentSpecValidationError{ + field: fmt.Sprintf("Params[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, ComponentSpecValidationError{ + field: fmt.Sprintf("Params[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(item).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return ComponentSpecValidationError{ + field: fmt.Sprintf("Params[%v]", idx), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + for idx, item := range m.GetInput() { _, _ = idx, item @@ -10040,6 +10074,179 @@ var _ interface { ErrorName() string } = ComponentVariableValidationError{} +// Validate checks the field values on ComponentParam with the rules defined in +// the proto definition for this message. If any rules are violated, the first +// error encountered is returned, or nil if there are no violations. +func (m *ComponentParam) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on ComponentParam with the rules defined +// in the proto definition for this message. If any rules are violated, the +// result is a list of violation errors wrapped in ComponentParamMultiError, +// or nil if none found. +func (m *ComponentParam) ValidateAll() error { + return m.validate(true) +} + +func (m *ComponentParam) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for Name + + // no validation rules for Type + + // no validation rules for Description + + // no validation rules for Required + + if all { + switch v := interface{}(m.GetDefault()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, ComponentParamValidationError{ + field: "Default", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, ComponentParamValidationError{ + field: "Default", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetDefault()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return ComponentParamValidationError{ + field: "Default", + reason: "embedded message failed validation", + cause: err, + } + } + } + + // no validation rules for MetricsViewParam + + for idx, item := range m.GetOptions() { + _, _ = idx, item + + if all { + switch v := interface{}(item).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, ComponentParamValidationError{ + field: fmt.Sprintf("Options[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, ComponentParamValidationError{ + field: fmt.Sprintf("Options[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(item).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return ComponentParamValidationError{ + field: fmt.Sprintf("Options[%v]", idx), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + + if len(errors) > 0 { + return ComponentParamMultiError(errors) + } + + return nil +} + +// ComponentParamMultiError is an error wrapping multiple validation errors +// returned by ComponentParam.ValidateAll() if the designated constraints +// aren't met. +type ComponentParamMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m ComponentParamMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m ComponentParamMultiError) AllErrors() []error { return m } + +// ComponentParamValidationError is the validation error returned by +// ComponentParam.Validate if the designated constraints aren't met. +type ComponentParamValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e ComponentParamValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e ComponentParamValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e ComponentParamValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e ComponentParamValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e ComponentParamValidationError) ErrorName() string { return "ComponentParamValidationError" } + +// Error satisfies the builtin error interface +func (e ComponentParamValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sComponentParam.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = ComponentParamValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = ComponentParamValidationError{} + // Validate checks the field values on Canvas with the rules defined in the // proto definition for this message. If any rules are violated, the first // error encountered is returned, or nil if there are no violations. @@ -11131,6 +11338,35 @@ func (m *CanvasItem) validate(all bool) error { // no validation rules for DefinedInCanvas + if all { + switch v := interface{}(m.GetParams()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, CanvasItemValidationError{ + field: "Params", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, CanvasItemValidationError{ + field: "Params", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetParams()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return CanvasItemValidationError{ + field: "Params", + reason: "embedded message failed validation", + cause: err, + } + } + } + // no validation rules for WidthUnit if m.Width != nil { diff --git a/proto/gen/rill/runtime/v1/runtime.swagger.yaml b/proto/gen/rill/runtime/v1/runtime.swagger.yaml index 717e0d82e12c..d210a42818a7 100644 --- a/proto/gen/rill/runtime/v1/runtime.swagger.yaml +++ b/proto/gen/rill/runtime/v1/runtime.swagger.yaml @@ -4433,6 +4433,11 @@ definitions: definedInCanvas: type: boolean description: Indicates if the component was defined inline as part of the canvas YAML. + params: + type: object + description: |- + Values bound to the referenced component's declared params. + Only set for items that reference an externally defined component. width: type: integer format: int64 @@ -4958,6 +4963,34 @@ definitions: $ref: '#/definitions/v1ComponentSpec' state: $ref: '#/definitions/v1ComponentState' + v1ComponentParam: + type: object + properties: + name: + type: string + description: Param name. Must be a valid identifier; referenced in templates as {{ .params. }}. + type: + type: string + description: 'Param type. One of: "string", "number", "boolean", "metrics_view", "measure", "dimension", "time_dimension".' + description: + type: string + description: Human-facing description of the param. + required: + type: boolean + description: If true, a canvas item referencing this component must bind a value for the param. + default: + description: Default value used when the param is not bound. Mutually exclusive with required=true. + metricsViewParam: + type: string + description: |- + For "measure", "dimension" and "time_dimension" params: + the name of a sibling param of type "metrics_view" whose bound metrics view the field must belong to. + May be omitted when exactly one "metrics_view" param is declared, in which case the parser fills it in. + options: + type: array + items: {} + description: 'For scalar params: allowed values. Renders as a select input in visual editors.' + description: ComponentParam declares a typed, validated parameter of a component. v1ComponentSpec: type: object properties: @@ -4969,6 +5002,14 @@ definitions: type: string rendererProperties: type: object + params: + type: array + items: + type: object + $ref: '#/definitions/v1ComponentParam' + description: |- + Declared parameters that canvases can bind values to when referencing this component. + Bound values are available in the renderer properties' templating as {{ .params. }}. input: type: array items: @@ -7750,6 +7791,9 @@ definitions: rendererProperties: type: object title: Renderer properties with templating resolved for the provided args + resolvedArgs: + type: object + description: 'The effective args used for resolution: the component''s declared param defaults merged with the provided args.' v1ResolveTemplatedStringResponse: type: object properties: diff --git a/proto/rill/runtime/v1/queries.proto b/proto/rill/runtime/v1/queries.proto index e19fb32c6ba8..cbff554baef6 100644 --- a/proto/rill/runtime/v1/queries.proto +++ b/proto/rill/runtime/v1/queries.proto @@ -1047,6 +1047,8 @@ message ResolveComponentRequest { message ResolveComponentResponse { // Renderer properties with templating resolved for the provided args google.protobuf.Struct renderer_properties = 2; + // The effective args used for resolution: the component's declared param defaults merged with the provided args. + google.protobuf.Struct resolved_args = 3; } message ResolveTemplatedStringRequest { diff --git a/proto/rill/runtime/v1/resources.proto b/proto/rill/runtime/v1/resources.proto index 50e2547384b2..d04d116d1ad4 100644 --- a/proto/rill/runtime/v1/resources.proto +++ b/proto/rill/runtime/v1/resources.proto @@ -826,6 +826,9 @@ message ComponentSpec { string description = 7; string renderer = 4; google.protobuf.Struct renderer_properties = 5; + // Declared parameters that canvases can bind values to when referencing this component. + // Bound values are available in the renderer properties' templating as {{ .params. }}. + repeated ComponentParam params = 10; repeated ComponentVariable input = 8; ComponentVariable output = 9; bool defined_in_canvas = 6; @@ -845,6 +848,26 @@ message ComponentVariable { google.protobuf.Value default_value = 3; } +// ComponentParam declares a typed, validated parameter of a component. +message ComponentParam { + // Param name. Must be a valid identifier; referenced in templates as {{ .params. }}. + string name = 1; + // Param type. One of: "string", "number", "boolean", "metrics_view", "measure", "dimension", "time_dimension". + string type = 2; + // Human-facing description of the param. + string description = 3; + // If true, a canvas item referencing this component must bind a value for the param. + bool required = 4; + // Default value used when the param is not bound. Mutually exclusive with required=true. + google.protobuf.Value default = 5; + // For "measure", "dimension" and "time_dimension" params: + // the name of a sibling param of type "metrics_view" whose bound metrics view the field must belong to. + // May be omitted when exactly one "metrics_view" param is declared, in which case the parser fills it in. + string metrics_view_param = 6; + // For scalar params: allowed values. Renders as a select input in visual editors. + repeated google.protobuf.Value options = 7; +} + message Canvas { CanvasSpec spec = 1; CanvasState state = 2; @@ -937,6 +960,9 @@ message CanvasItem { string component = 1; // Indicates if the component was defined inline as part of the canvas YAML. bool defined_in_canvas = 8; + // Values bound to the referenced component's declared params. + // Only set for items that reference an externally defined component. + google.protobuf.Struct params = 11; // Width of the item. The unit is given in width_unit. optional uint32 width = 9; // Unit of the width. Current possible values: empty string. diff --git a/runtime/ai/develop_file.go b/runtime/ai/develop_file.go index 3616b1ab11df..041927b45f05 100644 --- a/runtime/ai/develop_file.go +++ b/runtime/ai/develop_file.go @@ -21,7 +21,7 @@ var _ Tool[*DevelopFileArgs, *DevelopFileResult] = (*DevelopFile)(nil) type DevelopFileArgs struct { Path string `json:"path" jsonschema:"The path of a .yaml or .sql file to create, update or delete."` - Type string `json:"type,omitempty" jsonschema:"Type of Rill file to develop (optional, but recommended if known). Options: rill.yaml, .env, connector, model, metrics_view, explore, canvas, theme, api, alert, report."` + Type string `json:"type,omitempty" jsonschema:"Type of Rill file to develop (optional, but recommended if known). Options: rill.yaml, .env, connector, model, metrics_view, explore, canvas, component, theme, api, alert, report."` Prompt string `json:"prompt" jsonschema:"A detailed description of how to develop the file. Include any relevant details assuming no prior context except the path's current content and status (if any)."` } @@ -74,7 +74,7 @@ func (t *DevelopFile) Handler(ctx context.Context, args *DevelopFileArgs) (*Deve if err != nil { return nil, fmt.Errorf("failed to load developer agent resource-specific system prompt: %w", err) } - case "connector", "model", "metrics_view", "explore", "canvas", "theme": + case "connector", "model", "metrics_view", "explore", "canvas", "component", "theme": resourceInstructions, err = instructions.Load(fmt.Sprintf("resources/%s.md", args.Type), instructions.Options{}) if err != nil { return nil, fmt.Errorf("failed to load developer agent resource-specific system prompt: %w", err) diff --git a/runtime/ai/instructions/data/resources/canvas.md b/runtime/ai/instructions/data/resources/canvas.md index 5f0fbbefbd62..65c6e876f684 100644 --- a/runtime/ai/instructions/data/resources/canvas.md +++ b/runtime/ai/instructions/data/resources/canvas.md @@ -873,6 +873,19 @@ image: Build fully custom visualizations using Metrics SQL queries and Vega-Lite specifications. Use this when the built-in chart types are insufficient and you need complete control over the visualization. +**Prefer a standalone component over an inline block.** Instead of embedding the `custom_chart` block in the canvas, create a `type: component` file under `viz_library/` that declares typed params, and reference it from the canvas item with `component: ` plus a `params:` map. This keeps canvas files small and makes the visualization reusable across dashboards. See the component resource instructions for the file format, param types, and templating conventions. Use an inline `custom_chart` block only for trivial one-off charts. Example reference: + +```yaml +rows: + - items: + - component: measure_trend + params: + metrics_view: bids_metrics + measure: total_bids + time_dim: __time + width: 8 +``` + Custom charts use `metrics_sql` to query data from metrics views and `vega_spec` to define the Vega-Lite visualization. The data from each query is available in the Vega-Lite spec as named datasets: `query1`, `query2`, etc. #### metrics_sql Query Language diff --git a/runtime/ai/instructions/data/resources/component.md b/runtime/ai/instructions/data/resources/component.md new file mode 100644 index 000000000000..919d5e37154a --- /dev/null +++ b/runtime/ai/instructions/data/resources/component.md @@ -0,0 +1,149 @@ +--- +description: Detailed instructions and examples for developing component (custom viz) resources in Rill +--- + +# Instructions for developing a component in Rill + +## Introduction + +Components are reusable visualizations ("custom viz") defined as standalone `type: component` files, conventionally under `viz_library/`. A component declares typed **params** and a **renderer**; canvas dashboards reference the component by name and bind values to its params. This makes one visualization reusable across many dashboards with different metrics views, measures, and dimensions. + +Prefer creating a standalone component over an inline `custom_chart` block in a canvas whenever the visualization is non-trivial or could plausibly be reused. Inline blocks bloat the canvas file and cannot be shared. + +## Anatomy + +A component file's only top-level keys are `type`, `display_name`, `description` (optional), `params`, and one renderer block such as `custom_chart` (which contains `metrics_sql` and `vega_spec`). Never place `metrics_sql` or `vega_spec` at the top level of the YAML, and never wrap the renderer under a `renderer:` key; a file without a proper renderer block parses as an empty draft and renders nothing. + +```yaml +# viz_library/measure_trend.yaml +type: component +display_name: Measure trend +description: Line chart of any measure over a time dimension. + +params: + - name: metrics_view + type: metrics_view + required: true + - name: measure + type: measure + required: true + - name: time_dim + type: time_dimension + required: true + - name: limit + type: number + default: 500 + - name: smooth + type: boolean + default: false + +custom_chart: + metrics_sql: | + SELECT {{ .params.time_dim }}, {{ .params.measure }} + FROM {{ .params.metrics_view }} + ORDER BY {{ .params.time_dim }} + LIMIT {{ .params.limit }} + vega_spec: | + { + "$schema": "https://vega.github.io/schema/vega-lite/v5.json", + "width": "container", + "height": "container", + "autosize": {"type": "fit"}, + "data": {"name": "query1"}, + "mark": {"type": "line", "interpolate": {"expr": "smooth ? 'monotone' : 'linear'"}}, + "encoding": { + "x": {"field": "{{ .params.time_dim }}", "type": "temporal"}, + "y": {"field": "{{ .params.measure }}", "type": "quantitative"} + } + } +``` + +The renderer block (`custom_chart:`) is a top-level key of the YAML, a sibling of `params` — never nest it under a `renderer:` key. Exactly one renderer block must be present. + +A canvas references it and binds values: + +```yaml +# dashboards/overview.yaml +type: canvas +rows: + - items: + - component: measure_trend + params: + metrics_view: bids_metrics + measure: total_bids + time_dim: __time + smooth: true + width: 8 +``` + +## Params + +Each param has: + +- `name` (required): a valid identifier, referenced in templates as `{{ .params. }}`. The names `title`, `description`, `datum`, `item`, `event`, and `parent` are reserved. +- `type` (required): one of `string`, `number`, `boolean`, `metrics_view`, `measure`, `dimension`, `time_dimension`. +- `required`: if true, every canvas item referencing the component must bind a value. Mutually exclusive with `default`. +- `default`: the value used when the param is not bound. Prefer defaults over `required` when evolving an existing component, so existing dashboards don't break. +- `description`: shown in the visual editor. +- `options`: for scalar params, the allowed values (renders as a select input). +- `metrics_view`: for `measure`/`dimension`/`time_dimension` params, the name of the sibling `metrics_view` param whose bound metrics view the field must belong to. Auto-inferred when exactly one `metrics_view` param is declared. + +Constraints enforced by the parser: + +- Params of type `metrics_view` must be named `metrics_view` or end with `_metrics_view`. +- Every `{{ .params.X }}` reference in the renderer properties must be a declared param. +- Canvas bindings are validated at reconcile time: unknown params, missing required params, type mismatches, and fields that don't exist in the bound metrics view are all errors. + +## Templating vs native Vega-Lite params + +There are two complementary mechanisms; use each for what it is for: + +1. **Field-shaped params** (`metrics_view`, `measure`, `dimension`, `time_dimension`) must be substituted through templating: `{{ .params.measure }}` inside `metrics_sql` and, where field names appear, inside `vega_spec`. Vega-Lite cannot parameterize field names natively. +2. **Scalar params** (`string`, `number`, `boolean`) are automatically injected as native [Vega-Lite params](https://vega.github.io/vega-lite/docs/parameter.html) at render time. Reference them directly by name in Vega expressions, predicates, and extents (e.g. `"expr": "smooth ? 'monotone' : 'linear'"`); no templating needed. If the `vega_spec` already declares a top-level param with the same name, only its `value` is overridden, so author-supplied `bind`/`expr` are preserved. Scalar params may additionally be templated when needed in SQL (e.g. `LIMIT {{ .params.limit }}`). + +## metrics_sql rules + +`metrics_sql` queries metrics views as virtual tables, and it is a deliberately restricted dialect — treat it as "pick columns", not general SQL: + +- Keep queries trivial: `SELECT FROM ` with an `ORDER BY` and `LIMIT`. For parameterized components that means `SELECT {{ .params. }}, {{ .params. }} FROM {{ .params.metrics_view }}`. +- Make the sort customizable: declare a required `string` param named `order_by` and write `ORDER BY {{ .params.order_by }} DESC`. The visual editor treats `order_by` specially by name: it renders a dropdown of the field values bound to the component's other params and defaults it to the measure. Time-series charts instead order by the time dimension ascending, without an `order_by` param. +- Declare a `number` param named `limit` (not required, with a default) and end the SQL with `LIMIT {{ .params.limit }}` so dashboards can tune the row count. Choose the default from the chart's visual density: around 10 where each row is a large mark (bars, arcs, text), up to 100 for charts that stay readable with many small marks (point/circle/square scatterplots, rect heatmaps, tick plots), and up to 2000 for time series. +- Every field param the `vega_spec` encodings or the `ORDER BY` reference must also appear in the `SELECT` list; ordering by an unselected field fails at query time, and encodings reading unselected fields render empty. +- NOT supported: CTEs (`WITH`), JOINs, subqueries, window functions, `CASE` expressions, and aggregate functions. Measures are already aggregated; never wrap them in `SUM()`/`AVG()`/`COUNT()`. Grouping by the selected dimensions is implicit. +- Column aliases (`AS x`) are not reflected in the output: result columns always keep the metrics view field names, so reference `{{ .params. }}` in the Vega encodings and `ORDER BY` the field itself, never an alias. +- `date_trunc('', )` is the one supported shaping function, for time bucketing. +- Query results are bound to the Vega spec as named datasets `query1`, `query2`, ... in order. + +If a visualization needs cross-row derivations (running sums, per-group offsets, rankings), they cannot be expressed here or in Vega: simplify the chart to what direct field encodings support instead of emulating the derivation. Row-local arithmetic on a row's own values (sign flips, ratios, differences) belongs in a Vega `calculate` transform, not in the SQL; see the transforms tip below. + +## Extracting an inline custom chart into a component + +To convert an existing inline `custom_chart` canvas item into a reusable component: + +1. Create `viz_library/.yaml` with `type: component` and move the `custom_chart` block into it verbatim. +2. Declare a `metrics_view` param and replace the metrics view name in each query's `FROM` clause with `{{ .params.metrics_view }}`. +3. For each field that should be configurable, declare a `measure`/`dimension`/`time_dimension` param and replace occurrences of the field name in both `metrics_sql` and `vega_spec` with `{{ .params. }}`. Leave visualization-specific fields hardcoded. +4. Replace the inline block in the canvas item with `component: ` plus a `params:` map binding the original values. The dashboard must render identically before and after. + +## Tips + +- Give the component a clear `display_name` and `description`; they are shown in the visual editor's widget picker. +- Remove Vega transforms that reshape or aggregate the dataset (`filter`, `aggregate`, `joinaggregate`, `window`, `stack`, `fold`, `pivot`, `lookup`, `bin`, `density`, `regression`, ...) and do not try to reproduce their derived values in `metrics_sql` (the dialect can't express them). Simplify the chart to direct field encodings, dropping encodings that depend on them; transforms written against specific data values do not survive rebinding the params to a different metrics view anyway. +- KEEP row-local `calculate` transforms whose derived values the chart's geometry needs: diverging sign flips (population pyramids, diverging stacked bars), ratios/percentages, differences, midpoints, absolute values. Rewrite their `datum` references against the params and keep the `as` name and the encodings that read it. Expose any literal category value the expression compares against as a required `string` param; scalar params are injected as native Vega-Lite params, so reference them directly in the expression. For example, a population pyramid declares `negate_when` (the dimension value plotted on the negative side) and uses: + + ```json + "transform": [{ + "calculate": "datum['{{ .params.color }}'] === negate_when ? -datum['{{ .params.measure }}'] : datum['{{ .params.measure }}']", + "as": "signed_value" + }] + ``` + + with the diverging axis encoded from `"signed_value"` (quantitative) and an axis `labelExpr` showing absolute values. +- `timeUnit` is an encoding property, not a transform: preserve it. When several channels derive from one temporal field via different `timeUnit`s (calendar heatmaps, punch cards, day/hour grids), declare a single `time_dimension` param and reference it from every such channel with its original `timeUnit` and `type`; select the field once in the SQL and order by it ascending with a time-series limit (up to 2000). +- Match every encoding's `type` to the param bound to it: `dimension` → `"nominal"`/`"ordinal"`, `time_dimension` → `"temporal"` (or the original ordinal + `timeUnit`), `measure` → `"quantitative"`. A `"temporal"` type on a plain dimension renders NaN axes. Remove `aggregate` from encodings (measures arrive pre-aggregated), except where a `timeUnit` groups several rows into one mark; keep the example's aggregate there so cells don't overplot. +- Never `bin` a dimension param or type it `"quantitative"`: metrics-view dimensions are categorical strings, so binning them renders a blank chart. When adapting a chart that bins raw numeric axis fields (histograms, binned scatterplots), make those channels nominal/ordinal dimension params without `bin` and keep count/size channels on measure params. +- When adapting an example, copy its `mark` and `config` blocks verbatim; do not invent config or sizing properties the example does not have (invalid config properties silently render a blank chart). +- When converting a Vega-Lite example or an existing chart, name params after their role in the chart (`x_axis`, `y_axis`, `color`, `size`, ...) rather than after the underlying column names, and set a `description` on each param. +- Do not alias templated fields in the SQL: Metrics SQL output columns always keep the metrics view field names, so `AS` aliases are not reflected in the query results. Reference the params in the Vega encodings too (e.g. `"field": "{{ .params.measure }}"`), and `ORDER BY` the field itself (e.g. `ORDER BY {{ .params.time_dim }}`). +- New params on an already-used component should be optional or have a default, otherwise existing dashboards break. +- Components are validated leniently while they contain unresolved `{{ .params.* }}` placeholders; the fully-bound instance is validated in each canvas that references it. diff --git a/runtime/canvas/component.go b/runtime/canvas/component.go index 090a31f11dd7..84193456815d 100644 --- a/runtime/canvas/component.go +++ b/runtime/canvas/component.go @@ -1,6 +1,7 @@ package canvas import ( + "encoding/json" "errors" "fmt" "strings" @@ -13,11 +14,26 @@ import ( // The provided metricsViews should contain every valid metrics view referenced by the component (as determined in the parser). // If the renderer properties reference a metrics view not in metricsViews, assume the metrics view is invalid or does not exist (don't look it up separately in the catalog). // +// allowTemplated should be true when the component declares params. In that case, properties may contain +// unresolved template placeholders (e.g. {{ .params.measure }}), which makes field-membership validation +// impossible here; only structural checks run, and the fully-bound instance is validated by the canvas +// reconciler (ValidateParamBindings) and at resolve time instead. +// // Note: metrics views referenced through markdown content cannot be validated here. // This is because the upstream parser can't extract refs from templates, so the metrics views cannot be passed through to here. // Warning: if you try to fix this, note that the refs must be added in the parser, not looked up dynamically here; // a dynamic lookup will have a race condition where the metrics view may not have been reconciled yet. -func ValidateRendererProperties(renderer string, props map[string]any, metricsViews map[string]*runtimev1.MetricsViewSpec) error { +func ValidateRendererProperties(renderer string, props map[string]any, metricsViews map[string]*runtimev1.MetricsViewSpec, allowTemplated bool) error { + if allowTemplated && hasTemplatedString(props) { + if renderer == "custom_chart" { + return validateCustomChart(props) + } + // Skip field-membership validation, but still reject unknown renderers. + if !knownRenderers[renderer] { + return fmt.Errorf("unsupported renderer %q", renderer) + } + return nil + } switch renderer { case "line_chart", "bar_chart", "area_chart", "stacked_bar", "stacked_bar_normalized": return validateCartesianChart(props, metricsViews) @@ -46,13 +62,92 @@ func ValidateRendererProperties(renderer string, props map[string]any, metricsVi case "leaderboard": return validateLeaderboard(props, metricsViews) case "custom_chart": - // TODO: Implement - return nil + return validateCustomChart(props) default: return fmt.Errorf("unsupported renderer %q", renderer) } } +// knownRenderers mirrors the cases of ValidateRendererProperties' switch; +// keep the two in sync when adding renderers. +var knownRenderers = map[string]bool{ + "line_chart": true, + "bar_chart": true, + "area_chart": true, + "stacked_bar": true, + "stacked_bar_normalized": true, + "donut_chart": true, + "pie_chart": true, + "scatter_plot": true, + "funnel_chart": true, + "heatmap": true, + "combo_chart": true, + "markdown": true, + "image": true, + "kpi": true, + "kpi_grid": true, + "table": true, + "pivot": true, + "leaderboard": true, + "custom_chart": true, +} + +// validateCustomChart validates properties for custom_chart. +// It only rejects malformed values, not incomplete ones: the visual editor persists draft custom +// charts with empty properties, so completeness is enforced at render time instead. +// metrics_sql queries are validated at query time, and vega_spec is validated as JSON only when +// it contains no template placeholders. +func validateCustomChart(props map[string]any) error { + if raw, ok := pathutil.GetPath(props, "metrics_sql"); ok { + switch v := raw.(type) { + case string: + // Nothing to check. + case []any: + for i, e := range v { + if _, ok := e.(string); !ok { + return fmt.Errorf("renderer property 'metrics_sql' entry at index %d must be a string", i) + } + } + default: + return errors.New("renderer property 'metrics_sql' must be a string or an array of strings") + } + } + + vegaSpec, ok, err := getOptionalPathString(props, "vega_spec") + if err != nil { + return err + } + if ok && strings.TrimSpace(vegaSpec) != "" && !strings.Contains(vegaSpec, "{{") { + var m map[string]any + if err := json.Unmarshal([]byte(vegaSpec), &m); err != nil { + return fmt.Errorf("renderer property 'vega_spec' is not a valid JSON object: %w", err) + } + } + + return nil +} + +// hasTemplatedString reports whether any string nested in the value contains template placeholders. +func hasTemplatedString(val any) bool { + switch val := val.(type) { + case string: + return strings.Contains(val, "{{") + case map[string]any: + for _, v := range val { + if hasTemplatedString(v) { + return true + } + } + case []any: + for _, v := range val { + if hasTemplatedString(v) { + return true + } + } + } + return false +} + // validateCartesianChart validates properties for line_chart, bar_chart, area_chart, stacked_bar, and stacked_bar_normalized. func validateCartesianChart(props map[string]any, metricsViews map[string]*runtimev1.MetricsViewSpec) error { mvn, mv, err := requireMetricsView(props, metricsViews) diff --git a/runtime/canvas/component_test.go b/runtime/canvas/component_test.go index 91e21d1e3109..da46c1a63df1 100644 --- a/runtime/canvas/component_test.go +++ b/runtime/canvas/component_test.go @@ -966,3 +966,127 @@ leaderboard: testruntime.RequireReconcileState(t, rt, id, 4, 1, 0) testruntime.RequireReconcileErrorContains(t, rt, id, runtime.ResourceKindComponent, "c1", "is not a dimension") } + +func TestValidateCustomChart(t *testing.T) { + rt, id := testruntime.NewInstanceWithOptions(t, testruntime.InstanceOptions{ + Files: metricsViewFiles(), + }) + + // Valid: static metrics_sql string and a JSON vega_spec. + testruntime.PutFiles(t, rt, id, map[string]string{ + "c1.yaml": ` +type: component +custom_chart: + metrics_sql: SELECT foo, y FROM mv1 + vega_spec: '{"mark": "bar"}' +`}) + testruntime.ReconcileParserAndWait(t, rt, id) + testruntime.RequireReconcileState(t, rt, id, 4, 0, 0) + + // Valid: metrics_sql as a list of queries. + testruntime.PutFiles(t, rt, id, map[string]string{ + "c1.yaml": ` +type: component +custom_chart: + metrics_sql: + - SELECT foo, y FROM mv1 + - SELECT bar, z FROM mv1 + vega_spec: '{"mark": "bar"}' +`}) + testruntime.ReconcileParserAndWait(t, rt, id) + testruntime.RequireReconcileState(t, rt, id, 4, 0, 0) + + // Valid: incomplete drafts are allowed; the visual editor persists custom charts with + // missing or empty properties while the user is still building them. + testruntime.PutFiles(t, rt, id, map[string]string{ + "c1.yaml": ` +type: component +custom_chart: + metrics_sql: SELECT foo, y FROM mv1 +`}) + testruntime.ReconcileParserAndWait(t, rt, id) + testruntime.RequireReconcileState(t, rt, id, 4, 0, 0) + + // Invalid: metrics_sql of the wrong type. + testruntime.PutFiles(t, rt, id, map[string]string{ + "c1.yaml": ` +type: component +custom_chart: + metrics_sql: 42 + vega_spec: '{"mark": "bar"}' +`}) + testruntime.ReconcileParserAndWait(t, rt, id) + testruntime.RequireReconcileState(t, rt, id, 4, 1, 0) + testruntime.RequireReconcileErrorContains(t, rt, id, runtime.ResourceKindComponent, "c1", "must be a string or an array of strings") + + // Invalid: untemplated vega_spec that is not valid JSON. + testruntime.PutFiles(t, rt, id, map[string]string{ + "c1.yaml": ` +type: component +custom_chart: + metrics_sql: SELECT foo, y FROM mv1 + vega_spec: 'not json' +`}) + testruntime.ReconcileParserAndWait(t, rt, id) + testruntime.RequireReconcileState(t, rt, id, 4, 1, 0) + testruntime.RequireReconcileErrorContains(t, rt, id, runtime.ResourceKindComponent, "c1", "not a valid JSON object") + + // Valid: a parameterized component with templated properties reconciles, + // including a vega_spec that only becomes valid JSON after templates resolve. + testruntime.PutFiles(t, rt, id, map[string]string{ + "c1.yaml": ` +type: component +params: + - name: metrics_view + type: metrics_view + required: true + - name: measure + type: measure + required: true +custom_chart: + metrics_sql: SELECT foo, {{ .params.measure }} AS value FROM {{ .params.metrics_view }} + vega_spec: '{"mark": "bar", "title": "{{ .params.measure }}"}' +`}) + testruntime.ReconcileParserAndWait(t, rt, id) + testruntime.RequireReconcileState(t, rt, id, 4, 0, 0) + + // Invalid: a parameterized component still gets structural checks despite templated properties. + testruntime.PutFiles(t, rt, id, map[string]string{ + "c1.yaml": ` +type: component +params: + - name: metrics_view + type: metrics_view + required: true +custom_chart: + metrics_sql: 42 + vega_spec: '{"mark": "bar", "title": "{{ .params.metrics_view }}"}' +`}) + testruntime.ReconcileParserAndWait(t, rt, id) + testruntime.RequireReconcileState(t, rt, id, 4, 1, 0) + testruntime.RequireReconcileErrorContains(t, rt, id, runtime.ResourceKindComponent, "c1", "must be a string or an array of strings") +} + +func TestValidateUnknownRendererWithParams(t *testing.T) { + rt, id := testruntime.NewInstanceWithOptions(t, testruntime.InstanceOptions{ + Files: metricsViewFiles(), + }) + + // A parameterized component skips field validation, but an unknown renderer + // (e.g. an erroneous `renderer:` wrapper around the real block) must still fail. + testruntime.PutFiles(t, rt, id, map[string]string{ + "c1.yaml": ` +type: component +params: + - name: metrics_view + type: metrics_view + required: true +renderer: + custom_chart: + metrics_sql: SELECT foo, y FROM {{ .params.metrics_view }} + vega_spec: '{"mark": "bar"}' +`}) + testruntime.ReconcileParserAndWait(t, rt, id) + testruntime.RequireReconcileState(t, rt, id, 4, 1, 0) + testruntime.RequireReconcileErrorContains(t, rt, id, runtime.ResourceKindComponent, "c1", `unsupported renderer "renderer"`) +} diff --git a/runtime/canvas/params.go b/runtime/canvas/params.go new file mode 100644 index 000000000000..d5aa453563f7 --- /dev/null +++ b/runtime/canvas/params.go @@ -0,0 +1,244 @@ +package canvas + +import ( + "encoding/json" + "fmt" + "strings" + + runtimev1 "github.com/rilldata/rill/proto/gen/rill/runtime/v1" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/structpb" +) + +// EffectiveArgs merges a component's declared param defaults with the provided args. +// Provided args take precedence over declared param defaults, +// which in turn take precedence over legacy input variable defaults. +func EffectiveArgs(spec *runtimev1.ComponentSpec, args map[string]any) map[string]any { + res := make(map[string]any, len(args)+len(spec.Params)+len(spec.Input)) + for _, v := range spec.Input { + if v.DefaultValue != nil { + res[v.Name] = v.DefaultValue.AsInterface() + } + } + for _, p := range spec.Params { + if p.Default != nil { + res[p.Name] = p.Default.AsInterface() + } + } + for k, v := range args { + res[k] = v + } + return res +} + +// ValidateParamBindings validates values bound to a component's declared params. +// It checks unknown keys, missing required params, scalar types and option membership. +// When metricsViews is non-nil, it additionally checks that params of type "metrics_view" name a valid metrics view +// and that field-typed params reference fields of their bound metrics view. +// The provided metricsViews should contain every valid metrics view bound to a param (as determined by refs in the parser); +// a bound metrics view missing from the map is reported as invalid (don't look it up separately in the catalog). +// Pass nil metricsViews to skip the metrics view checks (e.g. at resolve time, where they already ran at reconcile time). +// +// Bound string values containing template placeholders (e.g. {{ .env.name }}) are not validated; +// they resolve at render time. +func ValidateParamBindings(params []*runtimev1.ComponentParam, bound map[string]any, metricsViews map[string]*runtimev1.MetricsViewSpec) error { + declared := make(map[string]*runtimev1.ComponentParam, len(params)) + for _, p := range params { + declared[p.Name] = p + } + + for k := range bound { + if declared[k] == nil { + return fmt.Errorf("unknown param %q: it is not declared by the component", k) + } + } + + for _, p := range params { + v, err := effectiveParamValue(p, bound) + if err != nil { + return err + } + if v == nil { + // Optional and unbound with no default. + continue + } + if isTemplated(v) { + continue + } + + if err := validateParamValueType(p, v); err != nil { + return err + } + + if len(p.Options) > 0 { + val, err := structpb.NewValue(v) + if err != nil { + return fmt.Errorf("invalid value for param %q: %w", p.Name, err) + } + found := false + for _, opt := range p.Options { + if proto.Equal(val, opt) { + found = true + break + } + } + if !found { + return fmt.Errorf("value %v for param %q is not one of its options", v, p.Name) + } + } + + if metricsViews == nil { + continue + } + + switch p.Type { + case "metrics_view": + if metricsViews[v.(string)] == nil { + return fmt.Errorf("metrics view %q bound to param %q is invalid or does not exist", v, p.Name) + } + case "measure", "dimension", "time_dimension": + mvn, err := effectiveParamValue(declared[p.MetricsViewParam], bound) + if err != nil || mvn == nil || isTemplated(mvn) { + // The metrics view param is itself invalid or unresolvable; it reports its own error. + continue + } + mv := metricsViews[mvn.(string)] + if mv == nil { + continue + } + field := v.(string) + switch p.Type { + case "measure": + if !metricsViewHasMeasure(mv, field) { + return fmt.Errorf("value %q for param %q is not a measure in metrics view %q", field, p.Name, mvn) + } + case "dimension": + if !metricsViewHasDimension(mv, field) { + return fmt.Errorf("value %q for param %q is not a dimension in metrics view %q", field, p.Name, mvn) + } + case "time_dimension": + if !metricsViewHasTimeDimension(mv, field) { + return fmt.Errorf("value %q for param %q is not a time dimension in metrics view %q", field, p.Name, mvn) + } + } + } + } + + return nil +} + +// InjectVegaParams injects the values of a component's scalar params as native Vega-Lite params +// into a Vega-Lite spec (a JSON object), making them usable in Vega expressions, predicates and extents. +// If the spec already declares a top-level param with the same name, only its "value" is overridden +// so author-supplied properties like "bind" and "expr" are preserved. +// Field-typed params are not injected since Vega-Lite cannot parameterize field names; +// they are substituted through templating instead. +// Returns the spec unchanged if there is nothing to inject. +func InjectVegaParams(vegaSpec string, params []*runtimev1.ComponentParam, args map[string]any) (string, error) { + var names []string + values := make(map[string]any) + for _, p := range params { + switch p.Type { + case "string", "number", "boolean": + default: + continue + } + v, ok := args[p.Name] + if !ok || v == nil || isTemplated(v) { + continue + } + names = append(names, p.Name) + values[p.Name] = v + } + if len(names) == 0 || strings.TrimSpace(vegaSpec) == "" { + return vegaSpec, nil + } + + var spec map[string]any + if err := json.Unmarshal([]byte(vegaSpec), &spec); err != nil { + return "", fmt.Errorf("vega_spec is not a valid JSON object: %w", err) + } + + existing, _ := spec["params"].([]any) + for _, name := range names { + found := false + for _, e := range existing { + if m, ok := e.(map[string]any); ok && m["name"] == name { + m["value"] = values[name] + found = true + break + } + } + if !found { + existing = append(existing, map[string]any{"name": name, "value": values[name]}) + } + } + spec["params"] = existing + + out, err := json.Marshal(spec) + if err != nil { + return "", err + } + return string(out), nil +} + +// effectiveParamValue returns the value bound to a param, falling back to its default. +// It returns nil if the param is unbound and has no default, or an error if it is required and unbound. +func effectiveParamValue(p *runtimev1.ComponentParam, bound map[string]any) (any, error) { + if p == nil { + return nil, nil + } + if v, ok := bound[p.Name]; ok && v != nil { + return v, nil + } + if p.Default != nil { + return p.Default.AsInterface(), nil + } + if p.Required { + return nil, fmt.Errorf("missing value for required param %q", p.Name) + } + return nil, nil +} + +// validateParamValueType checks that a bound value conforms to the param's declared type. +func validateParamValueType(p *runtimev1.ComponentParam, v any) error { + switch p.Type { + case "number": + switch v.(type) { + case int, int32, int64, uint, uint32, uint64, float32, float64: + return nil + } + return fmt.Errorf("value for param %q must be a number, got %v", p.Name, v) + case "boolean": + if _, ok := v.(bool); !ok { + return fmt.Errorf("value for param %q must be a boolean, got %v", p.Name, v) + } + return nil + default: + // "string" and the metrics view field types hold string values. + if _, ok := v.(string); !ok { + return fmt.Errorf("value for param %q must be a string, got %v", p.Name, v) + } + return nil + } +} + +// metricsViewHasTimeDimension returns true if fieldName is the metrics view's primary time dimension +// or a declared dimension of the time type. +func metricsViewHasTimeDimension(mv *runtimev1.MetricsViewSpec, fieldName string) bool { + if mv.TimeDimension == fieldName { + return true + } + for _, d := range mv.Dimensions { + if d.Name == fieldName { + return d.Type == runtimev1.MetricsViewSpec_DIMENSION_TYPE_TIME + } + } + return false +} + +// isTemplated returns true if the value is a string containing template placeholders. +func isTemplated(v any) bool { + s, ok := v.(string) + return ok && strings.Contains(s, "{{") +} diff --git a/runtime/canvas/params_test.go b/runtime/canvas/params_test.go new file mode 100644 index 000000000000..2b62b0fc2cc8 --- /dev/null +++ b/runtime/canvas/params_test.go @@ -0,0 +1,128 @@ +package canvas_test + +import ( + "testing" + + runtimev1 "github.com/rilldata/rill/proto/gen/rill/runtime/v1" + "github.com/rilldata/rill/runtime/canvas" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/types/known/structpb" +) + +func testParams(t *testing.T) []*runtimev1.ComponentParam { + t.Helper() + return []*runtimev1.ComponentParam{ + {Name: "metrics_view", Type: "metrics_view", Required: true}, + {Name: "measure", Type: "measure", Required: true, MetricsViewParam: "metrics_view"}, + {Name: "dim", Type: "dimension", MetricsViewParam: "metrics_view"}, + {Name: "time_dim", Type: "time_dimension", MetricsViewParam: "metrics_view"}, + {Name: "limit", Type: "number", Default: structpb.NewNumberValue(500)}, + {Name: "shape", Type: "string", Default: structpb.NewStringValue("line"), Options: []*structpb.Value{structpb.NewStringValue("line"), structpb.NewStringValue("area")}}, + {Name: "smooth", Type: "boolean"}, + } +} + +func testMetricsViews(t *testing.T) map[string]*runtimev1.MetricsViewSpec { + t.Helper() + return map[string]*runtimev1.MetricsViewSpec{ + "mv1": { + TimeDimension: "ts", + Dimensions: []*runtimev1.MetricsViewSpec_Dimension{ + {Name: "country", Type: runtimev1.MetricsViewSpec_DIMENSION_TYPE_CATEGORICAL}, + {Name: "updated_at", Type: runtimev1.MetricsViewSpec_DIMENSION_TYPE_TIME}, + }, + Measures: []*runtimev1.MetricsViewSpec_Measure{ + {Name: "total"}, + }, + }, + } +} + +func TestEffectiveArgs(t *testing.T) { + spec := &runtimev1.ComponentSpec{ + Params: testParams(t), + Input: []*runtimev1.ComponentVariable{ + {Name: "legacy", DefaultValue: structpb.NewStringValue("x")}, + {Name: "limit", DefaultValue: structpb.NewNumberValue(1)}, // Overridden by the param default + }, + } + + args := canvas.EffectiveArgs(spec, map[string]any{"metrics_view": "mv1", "shape": "area"}) + require.Equal(t, map[string]any{ + "metrics_view": "mv1", + "limit": float64(500), + "shape": "area", + "legacy": "x", + }, args) +} + +func TestValidateParamBindings(t *testing.T) { + params := testParams(t) + mvs := testMetricsViews(t) + + valid := map[string]any{ + "metrics_view": "mv1", + "measure": "total", + "dim": "country", + "time_dim": "ts", + "limit": 100, + "shape": "area", + "smooth": true, + } + + cases := []struct { + name string + mutate func(m map[string]any) + mvs map[string]*runtimev1.MetricsViewSpec + wantErr string + }{ + {name: "valid", mutate: func(m map[string]any) {}}, + {name: "valid without metrics views", mutate: func(m map[string]any) { m["measure"] = "unknown" }, mvs: nil}, + {name: "unknown param", mutate: func(m map[string]any) { m["nope"] = 1 }, wantErr: `unknown param "nope"`}, + {name: "missing required", mutate: func(m map[string]any) { delete(m, "measure") }, wantErr: `missing value for required param "measure"`}, + {name: "type mismatch number", mutate: func(m map[string]any) { m["limit"] = "abc" }, wantErr: `param "limit" must be a number`}, + {name: "type mismatch boolean", mutate: func(m map[string]any) { m["smooth"] = "yes" }, wantErr: `param "smooth" must be a boolean`}, + {name: "type mismatch string", mutate: func(m map[string]any) { m["measure"] = 1 }, wantErr: `param "measure" must be a string`}, + {name: "value not in options", mutate: func(m map[string]any) { m["shape"] = "donut" }, wantErr: "not one of its options"}, + {name: "invalid metrics view", mutate: func(m map[string]any) { m["metrics_view"] = "mv2" }, wantErr: `metrics view "mv2" bound to param "metrics_view" is invalid or does not exist`}, + {name: "invalid measure", mutate: func(m map[string]any) { m["measure"] = "country" }, wantErr: `not a measure in metrics view "mv1"`}, + {name: "invalid dimension", mutate: func(m map[string]any) { m["dim"] = "total" }, wantErr: `not a dimension in metrics view "mv1"`}, + {name: "time dimension accepts time-typed dimension", mutate: func(m map[string]any) { m["time_dim"] = "updated_at" }}, + {name: "invalid time dimension", mutate: func(m map[string]any) { m["time_dim"] = "country" }, wantErr: `not a time dimension in metrics view "mv1"`}, + {name: "templated value skips validation", mutate: func(m map[string]any) { m["measure"] = "{{ .env.measure }}" }}, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + bound := make(map[string]any, len(valid)) + for k, v := range valid { + bound[k] = v + } + tc.mutate(bound) + + effectiveMVs := mvs + if tc.mvs == nil && tc.name == "valid without metrics views" { + effectiveMVs = nil + } + + err := canvas.ValidateParamBindings(params, bound, effectiveMVs) + if tc.wantErr == "" { + require.NoError(t, err) + } else { + require.ErrorContains(t, err, tc.wantErr) + } + }) + } + + // Optional params with no default can be omitted entirely. + err := canvas.ValidateParamBindings(params, map[string]any{"metrics_view": "mv1", "measure": "total"}, mvs) + require.NoError(t, err) + + // Defaults are validated too: a field param with a default referencing a missing field errors without a binding. + withDefault := []*runtimev1.ComponentParam{ + {Name: "metrics_view", Type: "metrics_view", Default: structpb.NewStringValue("mv1")}, + {Name: "measure", Type: "measure", MetricsViewParam: "metrics_view", Default: structpb.NewStringValue("missing")}, + } + err = canvas.ValidateParamBindings(withDefault, nil, mvs) + require.ErrorContains(t, err, `not a measure in metrics view "mv1"`) +} diff --git a/runtime/canvases.go b/runtime/canvases.go index e55ee01f4e41..a100d44b6b66 100644 --- a/runtime/canvases.go +++ b/runtime/canvases.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "strings" runtimev1 "github.com/rilldata/rill/proto/gen/rill/runtime/v1" "github.com/rilldata/rill/runtime/drivers" @@ -25,6 +26,19 @@ func CollectCanvasComponentNames(rows []*runtimev1.CanvasRow, out map[string]boo } } +// CollectCanvasItems collects all items in the given rows, +// descending into tab groups (one level deep, since tabs cannot be nested). +func CollectCanvasItems(rows []*runtimev1.CanvasRow, out *[]*runtimev1.CanvasItem) { + for _, row := range rows { + *out = append(*out, row.Items...) + if tg := row.GetTabGroup(); tg != nil { + for _, tab := range tg.Tabs { + CollectCanvasItems(tab.Rows, out) + } + } + } +} + type ResolveCanvasResult struct { Canvas *runtimev1.Resource ResolvedComponents map[string]*runtimev1.Resource @@ -99,7 +113,9 @@ func (r *Runtime) ResolveCanvas(ctx context.Context, instanceID, canvas string, for k, v := range validSpec.RendererProperties.Fields { switch k { case "metrics_view": - if name := v.GetStringValue(); name != "" { + // Skip templated values (e.g. {{ .params.metrics_view }}): + // metrics views bound to params are collected from the canvas items below. + if name := v.GetStringValue(); name != "" && !strings.Contains(name, "{{") { metricsViews[name] = true } case "metrics_sql": @@ -146,6 +162,39 @@ func (r *Runtime) ResolveCanvas(ctx context.Context, instanceID, canvas string, } } + // Extract metrics views bound to component params by canvas items. + var items []*runtimev1.CanvasItem + CollectCanvasItems(spec.Rows, &items) + for _, item := range items { + cmp := components[item.Component] + if cmp == nil { + continue + } + validSpec := cmp.GetComponent().State.ValidSpec + if validSpec == nil && unsafe { + validSpec = cmp.GetComponent().Spec + } + if validSpec == nil { + continue + } + var bound map[string]any + if item.Params != nil { + bound = item.Params.AsMap() + } + for _, p := range validSpec.Params { + if p.Type != "metrics_view" { + continue + } + v, ok := bound[p.Name] + if !ok && p.Default != nil { + v = p.Default.AsInterface() + } + if name, ok := v.(string); ok && name != "" && !strings.Contains(name, "{{") { + metricsViews[name] = true + } + } + } + // Lookup metrics view resources referencedMetricsViews := make(map[string]*runtimev1.Resource) for mvName := range metricsViews { diff --git a/runtime/feature_flags.go b/runtime/feature_flags.go index b153d1fc07db..1745e1acee33 100644 --- a/runtime/feature_flags.go +++ b/runtime/feature_flags.go @@ -66,6 +66,8 @@ var defaultFeatureFlags = map[string]string{ "cloud_editing": "false", // Controls visibility of the custom chart option in canvas dashboards "custom_charts": "false", + // Controls visibility of standalone custom viz components (creation, canvas references, extraction, examples gallery) + "custom_components": "false", // Controls visibility of the personal canvas feature (per-user owner-only canvases stored as virtual files) "personal_canvases": "false", } diff --git a/runtime/feature_flags_test.go b/runtime/feature_flags_test.go index 33d2f38ff074..f48bd0fb54cb 100644 --- a/runtime/feature_flags_test.go +++ b/runtime/feature_flags_test.go @@ -45,6 +45,7 @@ func Test_ResolveFeatureFlags(t *testing.T) { "stickyDashboardState": false, "cloudEditing": false, "customCharts": false, + "customComponents": false, "personalCanvases": false, "disablePersistentDashboardState": false, }, @@ -73,6 +74,7 @@ func Test_ResolveFeatureFlags(t *testing.T) { "stickyDashboardState": false, "cloudEditing": false, "customCharts": false, + "customComponents": false, "personalCanvases": false, "disablePersistentDashboardState": false, }, @@ -101,6 +103,7 @@ func Test_ResolveFeatureFlags(t *testing.T) { "stickyDashboardState": false, "cloudEditing": false, "customCharts": false, + "customComponents": false, "personalCanvases": false, "disablePersistentDashboardState": false, }, @@ -129,6 +132,7 @@ func Test_ResolveFeatureFlags(t *testing.T) { "stickyDashboardState": false, "cloudEditing": false, "customCharts": false, + "customComponents": false, "personalCanvases": false, "disablePersistentDashboardState": false, }, diff --git a/runtime/parser/parse_canvas.go b/runtime/parser/parse_canvas.go index 30b27b17044f..2cfbf7bd1e89 100644 --- a/runtime/parser/parse_canvas.go +++ b/runtime/parser/parse_canvas.go @@ -15,6 +15,7 @@ import ( "github.com/rilldata/rill/runtime/pkg/rilltime" "github.com/rilldata/rill/runtime/pkg/urlutils" "golang.org/x/exp/maps" + "google.golang.org/protobuf/types/known/structpb" "gopkg.in/yaml.v3" ) @@ -70,6 +71,7 @@ type canvasTabYAML struct { type canvasItemYAML struct { Width *string `yaml:"width"` Component string `yaml:"component"` // Name of an externally defined component + Params map[string]any `yaml:"params"` // Values bound to the referenced component's declared params InlineComponent map[string]yaml.Node `yaml:",inline"` // Any other properties are considered an inline component definition } @@ -326,6 +328,38 @@ func (p *Parser) parseCanvasRows(node *Node, rows []*canvasRowYAML, allowTabs bo return nil, fmt.Errorf("item %d in row %d has properties incompatible with 'component'", j, i) } + // Validate and convert param bindings. Bindings are only valid for items that reference + // an externally defined component; inline components can hardcode values directly. + var params *structpb.Struct + if len(item.Params) > 0 { + if len(item.InlineComponent) > 0 { + return nil, fmt.Errorf("item %d in row %d cannot pass 'params' to an inline component", j, i) + } + for k, v := range item.Params { + if !componentParamNameRegex.MatchString(k) { + return nil, fmt.Errorf("invalid param name %q for item %d in row %d", k, j, i) + } + switch v.(type) { + case string, bool, int, int32, int64, uint, uint32, uint64, float32, float64: + default: + return nil, fmt.Errorf("invalid value for param %q for item %d in row %d: only scalar values are supported", k, j, i) + } + // Register metrics views bound to params as refs of the canvas. + // The component parser enforces that params of type "metrics_view" are named + // "metrics_view" or end with "_metrics_view", which makes this extraction complete. + if k == "metrics_view" || strings.HasSuffix(k, "_metrics_view") { + if name, ok := v.(string); ok && name != "" && !strings.Contains(name, "{{") { + node.Refs = append(node.Refs, ResourceName{Kind: ResourceKindMetricsView, Name: name}) + } + } + } + var err error + params, err = structpb.NewStruct(item.Params) + if err != nil { + return nil, fmt.Errorf("invalid params for item %d in row %d: %w", j, i, err) + } + } + // Parse inline component definition if present and assign into item.Component var definedInCanvs bool if len(item.InlineComponent) > 0 { @@ -342,6 +376,7 @@ func (p *Parser) parseCanvasRows(node *Node, rows []*canvasRowYAML, allowTabs bo items = append(items, &runtimev1.CanvasItem{ Component: item.Component, DefinedInCanvas: definedInCanvs, + Params: params, Width: width, WidthUnit: widthUnit, }) @@ -449,6 +484,11 @@ func (p *Parser) parseCanvasInlineComponent(canvasName, posKey string, props map return "", nil, err } + // Param declarations only make sense on externally defined components, where canvas items can bind values to them. + if len(spec.Params) > 0 { + return "", nil, errors.New("inline components cannot declare params") + } + spec.DefinedInCanvas = true name := fmt.Sprintf("%s--component-%s", canvasName, posKey) diff --git a/runtime/parser/parse_component.go b/runtime/parser/parse_component.go index ae30e389a706..034262036579 100644 --- a/runtime/parser/parse_component.go +++ b/runtime/parser/parse_component.go @@ -3,6 +3,9 @@ package parser import ( "errors" "fmt" + "regexp" + "slices" + "strings" runtimev1 "github.com/rilldata/rill/proto/gen/rill/runtime/v1" "github.com/rilldata/rill/runtime/pkg/pbutil" @@ -15,11 +18,43 @@ type ComponentYAML struct { Title string `yaml:"title"` // Deprecated: use display_name Description string `yaml:"description"` Subtitle string `yaml:"subtitle"` // Deprecated: use description + Params []*ComponentParamYAML `yaml:"params"` Input []*ComponentVariableYAML `yaml:"input"` Output *ComponentVariableYAML `yaml:"output"` Other map[string]map[string]any `yaml:",inline" mapstructure:",remain"` // Generic renderer: can only have one key } +// ComponentParamYAML declares a typed parameter of a component. +// Canvases bind values to params when referencing the component; +// bound values are available in the renderer properties' templating as {{ .params. }}. +type ComponentParamYAML struct { + Name string `yaml:"name"` + Type string `yaml:"type"` + Description string `yaml:"description"` + Required bool `yaml:"required"` + Default any `yaml:"default"` + MetricsView string `yaml:"metrics_view"` // For field-typed params: back-reference to a sibling param of type "metrics_view" + Options []any `yaml:"options"` // For scalar params: allowed values +} + +// componentParamScalarTypes are the param types that hold plain values. +// Scalar params may declare options and are injected as native Vega-Lite params at resolve time. +var componentParamScalarTypes = []string{"string", "number", "boolean"} + +// componentParamFieldTypes are the param types that reference a field of a metrics view. +// They resolve their metrics view through a sibling param of type "metrics_view". +var componentParamFieldTypes = []string{"measure", "dimension", "time_dimension"} + +// componentParamNameRegex restricts param names to valid identifiers, +// since they are referenced as {{ .params. }} in Go templates and as signal names in Vega expressions. +var componentParamNameRegex = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_]*$`) + +// componentParamReservedNames are names that cannot be used for params: +// "title" and "description" collide with common component properties in visual editors, +// and "datum", "item", "event", "parent" are reserved in Vega expressions +// (scalar params are injected as native Vega-Lite params at resolve time). +var componentParamReservedNames = []string{"title", "description", "datum", "item", "event", "parent"} + type ComponentVariableYAML struct { Name string `yaml:"name"` Type string `yaml:"type"` @@ -95,10 +130,10 @@ func (p *Parser) parseComponentYAML(tmp *ComponentYAML) (*runtimev1.ComponentSpe // Discover and validate the renderer n := 0 var renderer string + var props map[string]any var rendererProps *structpb.Struct if len(tmp.Other) == 1 { n++ - var props map[string]any for renderer, props = range tmp.Other { break } @@ -128,7 +163,8 @@ func (p *Parser) parseComponentYAML(tmp *ComponentYAML) (*runtimev1.ComponentSpe for k, v := range rendererProps.Fields { if k == "metrics_view" { name := v.GetStringValue() - if name != "" { + // Skip templated values (e.g. {{ .params.metrics_view }}): refs must be static resource names. + if name != "" && !strings.Contains(name, "{{") { refs = append(refs, ResourceName{Kind: ResourceKindMetricsView, Name: name}) } break @@ -136,6 +172,50 @@ func (p *Parser) parseComponentYAML(tmp *ComponentYAML) (*runtimev1.ComponentSpe } } + // Parse declared params + params, err := parseComponentParams(tmp.Params) + if err != nil { + return nil, nil, err + } + + // Link metrics views set as defaults of metrics_view params: + // a component rendered with its defaults depends on the default metrics view + // even when no canvas binds the param, so it needs a ref for DAG ordering and invalidation. + for _, param := range params { + if param.Type != "metrics_view" || param.Default == nil { + continue + } + if name, ok := param.Default.AsInterface().(string); ok && name != "" && !strings.Contains(name, "{{") { + refs = append(refs, ResourceName{Kind: ResourceKindMetricsView, Name: name}) + } + } + + // When params are declared, require that all template references to .params (or its .args alias) + // in the renderer properties refer to declared params. This catches typos at parse time. + if len(params) > 0 { + declared := make(map[string]bool, len(params)) + for _, param := range params { + declared[param.Name] = true + } + vars := make(map[string]string) + if err := AnalyzeTemplateRecursively(props, vars); err != nil { + return nil, nil, fmt.Errorf("failed to analyze templating in renderer properties: %w", err) + } + for v := range vars { + rest, ok := strings.CutPrefix(v, "params.") + if !ok { + rest, ok = strings.CutPrefix(v, "args.") + } + if !ok { + continue + } + name, _, _ := strings.Cut(rest, ".") + if !declared[name] { + return nil, nil, fmt.Errorf("renderer properties reference undeclared param %q", name) + } + } + } + // Parse input variables var input []*runtimev1.ComponentVariable if len(tmp.Input) > 0 { @@ -165,9 +245,184 @@ func (p *Parser) parseComponentYAML(tmp *ComponentYAML) (*runtimev1.ComponentSpe Description: tmp.Description, Renderer: renderer, RendererProperties: rendererProps, + Params: params, Input: input, Output: output, } return spec, refs, nil } + +// parseComponentParams validates a component's declared params and converts them to protos. +func parseComponentParams(params []*ComponentParamYAML) ([]*runtimev1.ComponentParam, error) { + if len(params) == 0 { + return nil, nil + } + + // First pass: validate names and collect params of type "metrics_view" for back-reference resolution. + var mvParams []string + seen := make(map[string]bool, len(params)) + for i, param := range params { + if param == nil { + return nil, fmt.Errorf("param at index %d is empty", i) + } + if !componentParamNameRegex.MatchString(param.Name) { + return nil, fmt.Errorf("invalid param name %q: must be a valid identifier", param.Name) + } + if slices.Contains(componentParamReservedNames, param.Name) { + return nil, fmt.Errorf("param name %q is reserved", param.Name) + } + if seen[param.Name] { + return nil, fmt.Errorf("duplicate param name %q", param.Name) + } + seen[param.Name] = true + + if param.Type == "metrics_view" { + // The naming convention enables the canvas parser to extract metrics view refs from + // param bindings by key pattern without access to the component's declarations. + if param.Name != "metrics_view" && !strings.HasSuffix(param.Name, "_metrics_view") { + return nil, fmt.Errorf(`param %q of type "metrics_view" must be named "metrics_view" or end with "_metrics_view"`, param.Name) + } + mvParams = append(mvParams, param.Name) + } + } + + // Second pass: validate types, defaults, options and back-references, and convert to protos. + res := make([]*runtimev1.ComponentParam, len(params)) + for i, param := range params { + isScalar := slices.Contains(componentParamScalarTypes, param.Type) + isField := slices.Contains(componentParamFieldTypes, param.Type) + if !isScalar && !isField && param.Type != "metrics_view" { + return nil, fmt.Errorf("param %q has invalid type %q (options: %s)", param.Name, param.Type, strings.Join(slices.Concat(componentParamScalarTypes, []string{"metrics_view"}, componentParamFieldTypes), ", ")) + } + + if param.Required && param.Default != nil { + return nil, fmt.Errorf("param %q cannot both be required and have a default", param.Name) + } + if param.Default != nil { + if err := validateComponentParamValue(param.Type, param.Default); err != nil { + return nil, fmt.Errorf("invalid default for param %q: %w", param.Name, err) + } + } + + if len(param.Options) > 0 { + if !isScalar { + return nil, fmt.Errorf("param %q cannot have options: options are only supported for scalar types (%s)", param.Name, strings.Join(componentParamScalarTypes, ", ")) + } + defaultInOptions := param.Default == nil + for j, opt := range param.Options { + if err := validateComponentParamValue(param.Type, opt); err != nil { + return nil, fmt.Errorf("invalid option at index %d for param %q: %w", j, param.Name, err) + } + if param.Default != nil && scalarsEqual(param.Default, opt) { + defaultInOptions = true + } + } + if !defaultInOptions { + return nil, fmt.Errorf("default for param %q is not one of its options", param.Name) + } + } + + mvParam := param.MetricsView + if isField { + if mvParam == "" { + switch len(mvParams) { + case 1: + mvParam = mvParams[0] + case 0: + return nil, fmt.Errorf(`param %q of type %q requires a param of type "metrics_view" to be declared`, param.Name, param.Type) + default: + return nil, fmt.Errorf(`param %q of type %q must set "metrics_view" to disambiguate between multiple metrics_view params`, param.Name, param.Type) + } + } else if !slices.Contains(mvParams, mvParam) { + return nil, fmt.Errorf(`param %q references %q, which is not a declared param of type "metrics_view"`, param.Name, mvParam) + } + } else if mvParam != "" { + return nil, fmt.Errorf(`param %q of type %q cannot set "metrics_view"`, param.Name, param.Type) + } + + var defaultVal *structpb.Value + if param.Default != nil { + var err error + defaultVal, err = structpb.NewValue(param.Default) + if err != nil { + return nil, fmt.Errorf("invalid default for param %q: %w", param.Name, err) + } + } + var options []*structpb.Value + for j, opt := range param.Options { + val, err := structpb.NewValue(opt) + if err != nil { + return nil, fmt.Errorf("invalid option at index %d for param %q: %w", j, param.Name, err) + } + options = append(options, val) + } + + res[i] = &runtimev1.ComponentParam{ + Name: param.Name, + Type: param.Type, + Description: param.Description, + Required: param.Required, + Default: defaultVal, + MetricsViewParam: mvParam, + Options: options, + } + } + + return res, nil +} + +// validateComponentParamValue checks that a param's default or option value conforms to its declared type. +func validateComponentParamValue(typ string, v any) error { + switch typ { + case "number": + switch v.(type) { + case int, int32, int64, uint, uint32, uint64, float32, float64: + return nil + } + return fmt.Errorf("expected a number, got %v", v) + case "boolean": + if _, ok := v.(bool); !ok { + return fmt.Errorf("expected a boolean, got %v", v) + } + return nil + default: + // "string" and all metrics view field types hold string values. + if _, ok := v.(string); !ok { + return fmt.Errorf("expected a string, got %v", v) + } + return nil + } +} + +// scalarsEqual compares two scalar values, treating all numeric types as equal when their values match. +func scalarsEqual(a, b any) bool { + af, aok := asFloat(a) + bf, bok := asFloat(b) + if aok && bok { + return af == bf + } + return a == b +} + +func asFloat(v any) (float64, bool) { + switch v := v.(type) { + case int: + return float64(v), true + case int32: + return float64(v), true + case int64: + return float64(v), true + case uint: + return float64(v), true + case uint32: + return float64(v), true + case uint64: + return float64(v), true + case float32: + return float64(v), true + case float64: + return v, true + } + return 0, false +} diff --git a/runtime/parser/parser_test.go b/runtime/parser/parser_test.go index efbcc8e72b42..8617b5e22baa 100644 --- a/runtime/parser/parser_test.go +++ b/runtime/parser/parser_test.go @@ -1922,6 +1922,270 @@ input: requireResourcesAndErrors(t, p, resources, nil) } +func TestComponentParams(t *testing.T) { + ctx := context.Background() + repo := makeRepo(t, map[string]string{ + `rill.yaml`: ``, + `components/trend.yaml`: ` +type: component +params: + - name: metrics_view + type: metrics_view + required: true + - name: measure + type: measure + required: true + - name: time_dim + type: time_dimension + required: true + - name: limit + type: number + default: 500 + - name: shape + type: string + default: line + options: [line, area] +custom_chart: + metrics_sql: "SELECT {{ .params.time_dim }} AS ts, {{ .params.measure }} AS value FROM {{ .params.metrics_view }} LIMIT {{ .params.limit }}" + vega_spec: "{}" +`, + // Component with a templated metrics_view renderer property: it must not produce a ref. + `components/tpl.yaml`: ` +type: component +params: + - name: metrics_view + type: metrics_view + required: true +kpi: + metrics_view: "{{ .params.metrics_view }}" +`, + // Component with a defaulted metrics_view param: the default must produce a ref, + // since the component depends on it even when no canvas binds the param. + `components/defaulted.yaml`: ` +type: component +params: + - name: metrics_view + type: metrics_view + default: mv_default +kpi: + metrics_view: "{{ .params.metrics_view }}" +`, + `canvases/d1.yaml`: ` +type: canvas +rows: +- items: + - component: trend + params: + metrics_view: mv1 + measure: total + time_dim: __time + limit: 100 + width: 6 +`, + }) + + resources := []*Resource{ + { + Name: ResourceName{Kind: ResourceKindComponent, Name: "trend"}, + Paths: []string{"/components/trend.yaml"}, + ComponentSpec: &runtimev1.ComponentSpec{ + DisplayName: "Trend", + Renderer: "custom_chart", + RendererProperties: must(structpb.NewStruct(map[string]any{ + "metrics_sql": "SELECT {{ .params.time_dim }} AS ts, {{ .params.measure }} AS value FROM {{ .params.metrics_view }} LIMIT {{ .params.limit }}", + "vega_spec": "{}", + })), + Params: []*runtimev1.ComponentParam{ + {Name: "metrics_view", Type: "metrics_view", Required: true}, + {Name: "measure", Type: "measure", Required: true, MetricsViewParam: "metrics_view"}, + {Name: "time_dim", Type: "time_dimension", Required: true, MetricsViewParam: "metrics_view"}, + {Name: "limit", Type: "number", Default: structpb.NewNumberValue(500)}, + {Name: "shape", Type: "string", Default: structpb.NewStringValue("line"), Options: []*structpb.Value{structpb.NewStringValue("line"), structpb.NewStringValue("area")}}, + }, + }, + }, + { + Name: ResourceName{Kind: ResourceKindComponent, Name: "tpl"}, + Paths: []string{"/components/tpl.yaml"}, + ComponentSpec: &runtimev1.ComponentSpec{ + DisplayName: "Tpl", + Renderer: "kpi", + RendererProperties: must(structpb.NewStruct(map[string]any{"metrics_view": "{{ .params.metrics_view }}"})), + Params: []*runtimev1.ComponentParam{ + {Name: "metrics_view", Type: "metrics_view", Required: true}, + }, + }, + }, + { + Name: ResourceName{Kind: ResourceKindComponent, Name: "defaulted"}, + Paths: []string{"/components/defaulted.yaml"}, + Refs: []ResourceName{{Kind: ResourceKindMetricsView, Name: "mv_default"}}, + ComponentSpec: &runtimev1.ComponentSpec{ + DisplayName: "Defaulted", + Renderer: "kpi", + RendererProperties: must(structpb.NewStruct(map[string]any{"metrics_view": "{{ .params.metrics_view }}"})), + Params: []*runtimev1.ComponentParam{ + {Name: "metrics_view", Type: "metrics_view", Default: structpb.NewStringValue("mv_default")}, + }, + }, + }, + { + Name: ResourceName{Kind: ResourceKindCanvas, Name: "d1"}, + Paths: []string{"/canvases/d1.yaml"}, + Refs: []ResourceName{ + {Kind: ResourceKindComponent, Name: "trend"}, + {Kind: ResourceKindMetricsView, Name: "mv1"}, + }, + CanvasSpec: &runtimev1.CanvasSpec{ + DisplayName: "D1", + AllowCustomTimeRange: true, + FiltersEnabled: true, + Rows: []*runtimev1.CanvasRow{ + { + Items: []*runtimev1.CanvasItem{ + { + Component: "trend", + Params: must(structpb.NewStruct(map[string]any{ + "metrics_view": "mv1", + "measure": "total", + "time_dim": "__time", + "limit": 100, + })), + Width: asPtr(uint32(6)), + }, + }, + }, + }, + }, + }, + } + + p, err := Parse(ctx, repo, "", "", "duckdb", true) + require.NoError(t, err) + requireResourcesAndErrors(t, p, resources, nil) +} + +func TestComponentParamErrors(t *testing.T) { + ctx := context.Background() + + component := func(params string) string { + return fmt.Sprintf("type: component\nparams:\n%s\nkpi:\n metrics_view: foo\n", params) + } + + cases := []struct { + name string + files map[string]string + wantErr string + }{ + { + name: "duplicate param name", + files: map[string]string{`components/c.yaml`: component(" - name: a\n type: string\n - name: a\n type: number")}, + wantErr: `duplicate param name "a"`, + }, + { + name: "invalid type", + files: map[string]string{`components/c.yaml`: component(" - name: a\n type: widget")}, + wantErr: `invalid type "widget"`, + }, + { + name: "invalid name", + files: map[string]string{`components/c.yaml`: component(" - name: 1a\n type: string")}, + wantErr: `invalid param name "1a"`, + }, + { + name: "reserved name", + files: map[string]string{`components/c.yaml`: component(" - name: datum\n type: string")}, + wantErr: `param name "datum" is reserved`, + }, + { + name: "required with default", + files: map[string]string{`components/c.yaml`: component(" - name: a\n type: string\n required: true\n default: x")}, + wantErr: "cannot both be required and have a default", + }, + { + name: "default type mismatch", + files: map[string]string{`components/c.yaml`: component(" - name: a\n type: number\n default: x")}, + wantErr: "expected a number", + }, + { + name: "field param without metrics_view param", + files: map[string]string{`components/c.yaml`: component(" - name: a\n type: measure")}, + wantErr: `requires a param of type "metrics_view"`, + }, + { + name: "metrics_view param naming convention", + files: map[string]string{`components/c.yaml`: component(" - name: mv\n type: metrics_view")}, + wantErr: `must be named "metrics_view" or end with "_metrics_view"`, + }, + { + name: "back-reference to non-metrics_view param", + files: map[string]string{`components/c.yaml`: component(" - name: metrics_view\n type: metrics_view\n - name: a\n type: string\n - name: b\n type: measure\n metrics_view: a")}, + wantErr: `not a declared param of type "metrics_view"`, + }, + { + name: "options on field param", + files: map[string]string{`components/c.yaml`: component(" - name: metrics_view\n type: metrics_view\n - name: a\n type: measure\n options: [x, y]")}, + wantErr: "options are only supported for scalar types", + }, + { + name: "default not in options", + files: map[string]string{`components/c.yaml`: component(" - name: a\n type: string\n default: z\n options: [x, y]")}, + wantErr: "not one of its options", + }, + { + name: "undeclared param reference in renderer properties", + files: map[string]string{`components/c.yaml`: ` +type: component +params: + - name: a + type: string +kpi: + metrics_view: foo + measure: "{{ .params.b }}" +`}, + wantErr: `reference undeclared param "b"`, + }, + { + name: "params on inline component", + files: map[string]string{`canvases/d.yaml`: ` +type: canvas +rows: +- items: + - markdown: + content: Foo + params: + a: 1 +`}, + wantErr: "cannot pass 'params' to an inline component", + }, + { + name: "non-scalar param binding", + files: map[string]string{`canvases/d.yaml`: ` +type: canvas +rows: +- items: + - component: c + params: + a: [1, 2] +`}, + wantErr: "only scalar values are supported", + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + files := map[string]string{`rill.yaml`: ``} + for k, v := range tc.files { + files[k] = v + } + p, err := Parse(ctx, makeRepo(t, files), "", "", "duckdb", true) + require.NoError(t, err) + require.Len(t, p.Errors, 1) + require.Contains(t, p.Errors[0].Message, tc.wantErr) + }) + } +} + func TestCanvasTabGroups(t *testing.T) { ctx := context.Background() repo := makeRepo(t, map[string]string{ diff --git a/runtime/parser/schema/project.schema.yaml b/runtime/parser/schema/project.schema.yaml index 02dc12afdf4c..0d7c8e44e4a4 100644 --- a/runtime/parser/schema/project.schema.yaml +++ b/runtime/parser/schema/project.schema.yaml @@ -2406,6 +2406,14 @@ definitions: - **table** - Similar to Pivot table, add dimensions and measures to visualize your data - **heatmap** - Heat Map chart to visualize distribution of data - **donut_chart** - Donut or Pie chart to display sums of total + params: + type: object + description: Values bound to the referenced component's declared params. Only valid together with `component`. Values must be scalars. + additionalProperties: + type: + - string + - number + - boolean width: type: - string @@ -3156,6 +3164,11 @@ definitions: description: type: string description: Detailed description of the component's purpose and functionality + params: + type: array + description: List of typed parameters that canvases can bind values to when referencing this component. Bound values are available in the renderer properties' templating as `{{ .params. }}`. + items: + $ref: '#/definitions/component_param_properties' input: type: array description: List of input variables that can be passed to the component @@ -3396,6 +3409,50 @@ definitions: description: Overrides any properties in production environment. + component_param_properties: + type: object + properties: + name: + type: string + description: Param name. Must be a valid identifier; referenced in the renderer properties' templating as `{{ .params. }}`. + type: + type: string + enum: + - string + - number + - boolean + - metrics_view + - measure + - dimension + - time_dimension + description: Param type. Params of type `metrics_view` must be named `metrics_view` or end with `_metrics_view`. + description: + type: string + description: Human-facing description of the param + required: + type: boolean + description: If true, a canvas item referencing this component must bind a value for the param. Mutually exclusive with `default`. + default: + description: Default value used when the param is not bound + type: + - string + - number + - boolean + metrics_view: + type: string + description: For `measure`, `dimension` and `time_dimension` params, the name of a sibling param of type `metrics_view` whose bound metrics view the field must belong to. May be omitted when exactly one `metrics_view` param is declared. + options: + type: array + description: For scalar params, the allowed values. Renders as a select input in visual editors. + items: + type: + - string + - number + - boolean + required: + - name + - type + additionalProperties: false component_variable_properties: type: object properties: diff --git a/runtime/reconcilers/canvas.go b/runtime/reconcilers/canvas.go index 6962504b3705..f226e4bb6b7b 100644 --- a/runtime/reconcilers/canvas.go +++ b/runtime/reconcilers/canvas.go @@ -4,9 +4,11 @@ import ( "context" "errors" "fmt" + "strings" runtimev1 "github.com/rilldata/rill/proto/gen/rill/runtime/v1" "github.com/rilldata/rill/runtime" + "github.com/rilldata/rill/runtime/canvas" "github.com/rilldata/rill/runtime/drivers" "github.com/rilldata/rill/runtime/pkg/pathutil" "google.golang.org/protobuf/types/known/timestamppb" @@ -115,6 +117,9 @@ func (r *CanvasReconciler) Reconcile(ctx context.Context, n *runtimev1.ResourceN if validateErr == nil { validateErr = r.validateRequiredFilters(ctx, c.Spec, components) } + if validateErr == nil { + validateErr = r.validateItemParamBindings(ctx, c.Spec, components) + } // Capture the valid spec in the state if validateErr == nil { @@ -187,15 +192,34 @@ func (r *CanvasReconciler) ResolveTransitiveAccess(ctx context.Context, claims * return nil, fmt.Errorf("failed to get controller: %w", err) } - // Collect all component names referenced by the canvas (including those nested in tab groups) - componentNames := make(map[string]bool) - runtime.CollectCanvasComponentNames(spec.Rows, componentNames) + // Collect all items referenced by the canvas (including those nested in tab groups) + var items []*runtimev1.CanvasItem + runtime.CollectCanvasItems(spec.Rows, &items) + + // Process each item + seenComponents := make(map[string]bool, len(items)) + for _, item := range items { + // Track metrics views bound to the item's params. + // The component parser enforces that params of type "metrics_view" are named + // "metrics_view" or end with "_metrics_view", which makes this extraction complete. + if item.Params != nil { + for k, v := range item.Params.AsMap() { + if k == "metrics_view" || strings.HasSuffix(k, "_metrics_view") { + if name, ok := v.(string); ok && name != "" && !strings.Contains(name, "{{") { + refs.metricsViews[name] = true + } + } + } + } + + if seenComponents[item.Component] { + continue + } + seenComponents[item.Component] = true - // Process each component - for componentName := range componentNames { componentRef := &runtimev1.ResourceName{ Kind: runtime.ResourceKindComponent, - Name: componentName, + Name: item.Component, } // Allow access to the component itself conditionResources = append(conditionResources, componentRef) @@ -212,6 +236,16 @@ func (r *CanvasReconciler) ResolveTransitiveAccess(ctx context.Context, claims * if componentSpec == nil { componentSpec = componentRes.GetComponent().Spec } + + // Track metrics views set as defaults of the component's declared metrics_view params. + for _, p := range componentSpec.Params { + if p.Type == "metrics_view" && p.Default != nil { + if name, ok := p.Default.AsInterface().(string); ok && name != "" && !strings.Contains(name, "{{") { + refs.metricsViews[name] = true + } + } + } + if componentSpec.RendererProperties == nil { continue } @@ -365,6 +399,74 @@ func (r *CanvasReconciler) validateRequiredFilters(ctx context.Context, spec *ru return nil } +// validateItemParamBindings validates the param values that canvas items bind to their referenced +// components' declared params, including that field-typed params reference fields that exist in +// the bound metrics views. +func (r *CanvasReconciler) validateItemParamBindings(ctx context.Context, spec *runtimev1.CanvasSpec, components map[string]*runtimev1.Resource) error { + var items []*runtimev1.CanvasItem + runtime.CollectCanvasItems(spec.Rows, &items) + + // Cache of valid metrics view specs bound to params, shared across items. + mvs := make(map[string]*runtimev1.MetricsViewSpec) + + for _, item := range items { + cmp := components[item.Component] + if cmp == nil { + // Missing components are reported by checkRefs. + continue + } + componentSpec := cmp.GetComponent().State.ValidSpec + if componentSpec == nil { + componentSpec = cmp.GetComponent().Spec + } + + var bound map[string]any + if item.Params != nil { + bound = item.Params.AsMap() + } + if len(bound) == 0 && len(componentSpec.Params) == 0 { + continue + } + if len(bound) > 0 && len(componentSpec.Params) == 0 { + return fmt.Errorf("item passes params to component %q, which does not declare any params", item.Component) + } + + // Fetch the specs of the metrics views bound to params. + // It is safe to fetch them here because the parser added them as refs of the canvas, so DAG ordering holds. + for _, p := range componentSpec.Params { + if p.Type != "metrics_view" { + continue + } + v, ok := bound[p.Name] + if !ok && p.Default != nil { + v = p.Default.AsInterface() + } + name, ok := v.(string) + if !ok || name == "" || strings.Contains(name, "{{") { + continue + } + if _, ok := mvs[name]; ok { + continue + } + res, err := r.C.Get(ctx, &runtimev1.ResourceName{Kind: runtime.ResourceKindMetricsView, Name: name}, false) + if err != nil { + // Not found or invalid; ValidateParamBindings reports it as an invalid metrics view. + continue + } + if mvSpec := res.GetMetricsView().State.ValidSpec; mvSpec != nil { + mvs[name] = mvSpec + } + } + + err := canvas.ValidateParamBindings(componentSpec.Params, bound, mvs) + if err != nil { + return fmt.Errorf("invalid params for component %q: %w", item.Component, err) + } + } + + return nil +} + // rendererRefs tracks all metrics views found in canvas component renderer properties. // It currently only tracks metrics views, but in the future we may want to add an option to also track metrics view fields and filters. // We did that previously, but removed it since such granular security was considered too strict (it also impacts ability to filter by fields not present on the canvas). @@ -408,9 +510,13 @@ func (r *rendererRefs) populateRendererRefs(ctx context.Context, renderer string } // metricsView registers a metrics view reference. +// Templated values (e.g. {{ .params.metrics_view }}) are skipped; the metrics views bound to +// params are tracked from the canvas items' params instead. func (r *rendererRefs) metricsView(mv any) error { if mv, ok := mv.(string); ok { - r.metricsViews[mv] = true + if !strings.Contains(mv, "{{") { + r.metricsViews[mv] = true + } return nil } return fmt.Errorf("metrics view field is not a string") @@ -450,13 +556,31 @@ func (r *rendererRefs) text(ctx context.Context, content any) error { return nil } -// metricsSQL parses and registers metrics view references found in a metrics SQL string. +// metricsSQL parses and registers metrics view references found in a metrics_sql property, +// which holds either a single query string or a list of query strings. func (r *rendererRefs) metricsSQL(ctx context.Context, sql any) error { - sqlStr, ok := sql.(string) - if !ok { - return fmt.Errorf("metrics_sql field is not a string") + switch v := sql.(type) { + case string: + return r.metricsSQLString(ctx, v) + case []any: + // Multi-query custom charts: register refs per query, best-effort, + // so one malformed query doesn't drop refs from the others. + for _, e := range v { + if s, ok := e.(string); ok { + _ = r.metricsSQLString(ctx, s) + if ctx.Err() != nil { + return ctx.Err() + } + } + } + return nil + default: + return fmt.Errorf("metrics_sql field is not a string or a list of strings") } +} +// metricsSQLString parses and registers metrics view references found in a single metrics SQL query. +func (r *rendererRefs) metricsSQLString(ctx context.Context, sqlStr string) error { initializer, ok := runtime.ResolverInitializers["metrics_sql"] if !ok { return fmt.Errorf("metrics_sql resolver not registered") diff --git a/runtime/reconcilers/canvas_test.go b/runtime/reconcilers/canvas_test.go index f5cb9af1f876..aa862f6e52d5 100644 --- a/runtime/reconcilers/canvas_test.go +++ b/runtime/reconcilers/canvas_test.go @@ -308,6 +308,7 @@ func TestCanvasResolveTransitiveAccess(t *testing.T) { "m1.sql": `SELECT 'foo' as foo, 1 as x`, "m2.sql": `SELECT 'bar' as bar, 2 as y`, "m3.sql": `SELECT 'baz' as baz, 3 as z`, + "m4.sql": `SELECT 'qux' as qux, 4 as w`, "mv1.yaml": ` version: 1 type: metrics_view @@ -337,6 +338,16 @@ dimensions: measures: - name: z expression: sum(z) +`, + "mv4.yaml": ` +version: 1 +type: metrics_view +model: m4 +dimensions: +- column: qux +measures: +- name: w + expression: sum(w) `, "c1.yaml": ` type: canvas @@ -349,13 +360,18 @@ rows: - items: - custom_chart: metrics_sql: "SELECT bar, y FROM mv2" + - items: + - custom_chart: + metrics_sql: + - "SELECT bar, y FROM mv2" + - "SELECT qux, w FROM mv4" - items: - markdown: content: 'Total z: {{ metrics_sql "SELECT z FROM mv3" }}' `, }) testruntime.ReconcileParserAndWait(t, rt, id) - testruntime.RequireReconcileState(t, rt, id, 11, 0, 0) + testruntime.RequireReconcileState(t, rt, id, 14, 0, 0) // Build claims with a transitive access rule on the canvas ctx := t.Context() @@ -391,4 +407,163 @@ rows: sec, err = rt.ResolveSecurity(ctx, id, claims, mv3) require.NoError(t, err) require.True(t, sec.CanAccess()) + + // Resolve security for mv4 (referenced via a metrics_sql list in a multi-query custom chart); should be accessible + mv4 := testruntime.GetResource(t, rt, id, runtime.ResourceKindMetricsView, "mv4") + sec, err = rt.ResolveSecurity(ctx, id, claims, mv4) + require.NoError(t, err) + require.True(t, sec.CanAccess()) +} + +func TestCanvasItemParamBindings(t *testing.T) { + rt, id := testruntime.NewInstanceWithOptions(t, testruntime.InstanceOptions{ + Files: map[string]string{"rill.yaml": ""}, + }) + + // Create a model, a metrics view, a parameterized component, and a canvas binding values to its params. + testruntime.PutFiles(t, rt, id, map[string]string{ + "m1.sql": `SELECT '2025-01-01T00:00:00Z'::TIMESTAMP AS ts, 'foo' as foo, 1 as x`, + "mv1.yaml": ` +version: 1 +type: metrics_view +model: m1 +timeseries: ts +dimensions: +- column: foo +measures: +- name: x + expression: sum(x) +`, + "trend.yaml": ` +type: component +params: + - name: metrics_view + type: metrics_view + required: true + - name: measure + type: measure + required: true + - name: time_dim + type: time_dimension + required: true + - name: limit + type: number + default: 500 +custom_chart: + metrics_sql: SELECT {{ .params.time_dim }} AS ts, {{ .params.measure }} AS value FROM {{ .params.metrics_view }} LIMIT {{ .params.limit }} + vega_spec: '{"mark": "line"}' +`, + "c1.yaml": ` +type: canvas +rows: + - items: + - component: trend + params: + metrics_view: mv1 + measure: x + time_dim: ts +`, + }) + testruntime.ReconcileParserAndWait(t, rt, id) + testruntime.RequireReconcileState(t, rt, id, 5, 0, 0) + + // The canvas should be valid and have a parser-added ref to the param-bound metrics view. + c1 := testruntime.GetResource(t, rt, id, runtime.ResourceKindCanvas, "c1") + require.NotNil(t, c1.GetCanvas().State.ValidSpec) + var hasMVRef bool + for _, ref := range c1.Meta.Refs { + if ref.Kind == runtime.ResourceKindMetricsView && ref.Name == "mv1" { + hasMVRef = true + } + } + require.True(t, hasMVRef, "expected canvas to have a ref to the param-bound metrics view") + + // The param-bound metrics view should be accessible through transitive access on the canvas. + claims := &runtime.SecurityClaims{ + AdditionalRules: []*runtimev1.SecurityRule{ + { + Rule: &runtimev1.SecurityRule_TransitiveAccess{ + TransitiveAccess: &runtimev1.SecurityRuleTransitiveAccess{ + Resource: &runtimev1.ResourceName{Kind: runtime.ResourceKindCanvas, Name: "c1"}, + }, + }, + }, + }, + } + mv1 := testruntime.GetResource(t, rt, id, runtime.ResourceKindMetricsView, "mv1") + sec, err := rt.ResolveSecurity(t.Context(), id, claims, mv1) + require.NoError(t, err) + require.True(t, sec.CanAccess()) + + // Invalid: a bound measure that doesn't exist in the metrics view. + testruntime.PutFiles(t, rt, id, map[string]string{ + "c1.yaml": ` +type: canvas +rows: + - items: + - component: trend + params: + metrics_view: mv1 + measure: nonexistent + time_dim: ts +`, + }) + testruntime.ReconcileParserAndWait(t, rt, id) + testruntime.RequireReconcileState(t, rt, id, 5, 1, 0) + testruntime.RequireReconcileErrorContains(t, rt, id, runtime.ResourceKindCanvas, "c1", `not a measure in metrics view "mv1"`) + + // Invalid: a missing required param. + testruntime.PutFiles(t, rt, id, map[string]string{ + "c1.yaml": ` +type: canvas +rows: + - items: + - component: trend + params: + metrics_view: mv1 + time_dim: ts +`, + }) + testruntime.ReconcileParserAndWait(t, rt, id) + testruntime.RequireReconcileState(t, rt, id, 5, 1, 0) + testruntime.RequireReconcileErrorContains(t, rt, id, runtime.ResourceKindCanvas, "c1", `missing value for required param "measure"`) + + // Invalid: passing params to a component that doesn't declare any. + testruntime.PutFiles(t, rt, id, map[string]string{ + "plain.yaml": ` +type: component +kpi: + metrics_view: mv1 + measure: x +`, + "c1.yaml": ` +type: canvas +rows: + - items: + - component: plain + params: + foo: 1 +`, + }) + testruntime.ReconcileParserAndWait(t, rt, id) + testruntime.RequireReconcileState(t, rt, id, 6, 1, 0) + testruntime.RequireReconcileErrorContains(t, rt, id, runtime.ResourceKindCanvas, "c1", "does not declare any params") + + // Valid again: fix the canvas and check it recovers. + testruntime.PutFiles(t, rt, id, map[string]string{ + "c1.yaml": ` +type: canvas +rows: + - items: + - component: trend + params: + metrics_view: mv1 + measure: x + time_dim: ts + limit: 100 + - component: plain +`, + }) + testruntime.ReconcileParserAndWait(t, rt, id) + testruntime.RequireReconcileState(t, rt, id, 6, 0, 0) } diff --git a/runtime/reconcilers/component.go b/runtime/reconcilers/component.go index 9ade4bf8484e..243557eeee45 100644 --- a/runtime/reconcilers/component.go +++ b/runtime/reconcilers/component.go @@ -87,7 +87,7 @@ func (r *ComponentReconciler) Reconcile(ctx context.Context, n *runtimev1.Resour // Validate the renderer properties (only if all metrics view refs have a ValidSpec). var rendererErr error if allMetricsValid { - rendererErr = canvas.ValidateRendererProperties(c.Spec.Renderer, c.Spec.RendererProperties.AsMap(), mvs) + rendererErr = canvas.ValidateRendererProperties(c.Spec.Renderer, c.Spec.RendererProperties.AsMap(), mvs, len(c.Spec.Params) > 0) } else { rendererErr = errors.New("one or more referenced metrics views are invalid") } diff --git a/runtime/server/canvases.go b/runtime/server/canvases.go index 0b8677974d0a..6420b4942328 100644 --- a/runtime/server/canvases.go +++ b/runtime/server/canvases.go @@ -5,6 +5,7 @@ import ( runtimev1 "github.com/rilldata/rill/proto/gen/rill/runtime/v1" "github.com/rilldata/rill/runtime" + "github.com/rilldata/rill/runtime/canvas" "github.com/rilldata/rill/runtime/parser" "github.com/rilldata/rill/runtime/pkg/observability" "github.com/rilldata/rill/runtime/server/auth" @@ -74,16 +75,27 @@ func (s *Server) ResolveComponent(ctx context.Context, req *runtimev1.ResolveCom return nil, err } - // Parse args + // Parse args and validate them against the component's declared params. + // Components without declared params accept arbitrary args for backwards compatibility. args := req.Args.AsMap() + if len(spec.Params) > 0 { + if err := canvas.ValidateParamBindings(spec.Params, args, nil); err != nil { + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + } - // Setup templating data + // Merge the declared param defaults (and legacy input variable defaults) under the provided args. + effectiveArgs := canvas.EffectiveArgs(spec, args) + + // Setup templating data. + // The effective args are exposed both as .params (canonical, matching the YAML key) and .args (legacy alias). td := parser.TemplateData{ Environment: inst.Environment, User: claims.UserAttributes, Variables: inst.ResolveVariables(false), ExtraProps: map[string]any{ - "args": args, + "args": effectiveArgs, + "params": effectiveArgs, }, } @@ -100,14 +112,31 @@ func (s *Server) ResolveComponent(ctx context.Context, req *runtimev1.ResolveCom return nil, status.Errorf(codes.Internal, "failed to convert resolved renderer properties to map: %v", v) } + // For custom charts, inject scalar param values as native Vega-Lite params into the vega_spec. + if spec.Renderer == "custom_chart" { + if vegaSpec, ok := props["vega_spec"].(string); ok { + injected, err := canvas.InjectVegaParams(vegaSpec, spec.Params, effectiveArgs) + if err != nil { + return nil, status.Errorf(codes.InvalidArgument, "failed to inject params into vega_spec: %s", err.Error()) + } + props["vega_spec"] = injected + } + } + rendererProps, err = structpb.NewStruct(props) if err != nil { return nil, status.Errorf(codes.Internal, "failed to convert renderer properties to struct: %s", err.Error()) } } + resolvedArgs, err := structpb.NewStruct(effectiveArgs) + if err != nil { + return nil, status.Errorf(codes.Internal, "failed to convert resolved args to struct: %s", err.Error()) + } + // Return the response return &runtimev1.ResolveComponentResponse{ RendererProperties: rendererProps, + ResolvedArgs: resolvedArgs, }, nil } diff --git a/runtime/server/canvases_test.go b/runtime/server/canvases_test.go index 7bcdb7bbb5a6..e104308e0d48 100644 --- a/runtime/server/canvases_test.go +++ b/runtime/server/canvases_test.go @@ -2,6 +2,7 @@ package server_test import ( "context" + "encoding/json" "testing" runtimev1 "github.com/rilldata/rill/proto/gen/rill/runtime/v1" @@ -13,6 +14,8 @@ import ( "github.com/rilldata/rill/runtime/testruntime" "github.com/stretchr/testify/require" "go.uber.org/zap" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" "google.golang.org/protobuf/types/known/structpb" ) @@ -666,3 +669,187 @@ func must[T any](v T, err error) T { } return v } + +func TestResolveComponentWithParams(t *testing.T) { + rt, instanceID := testruntime.NewInstanceWithOptions(t, testruntime.InstanceOptions{ + Files: map[string]string{ + "rill.yaml": "", + "m1.sql": `SELECT 'US' AS country`, + "mv1.yaml": ` +type: metrics_view +version: 1 +model: m1 +dimensions: +- column: country +measures: +- name: count + expression: COUNT(*) +`, + "trend.yaml": ` +type: component +params: + - name: metrics_view + type: metrics_view + required: true + - name: measure + type: measure + required: true + - name: limit + type: number + default: 500 + - name: smooth + type: boolean + default: false +custom_chart: + metrics_sql: "SELECT country, {{ .params.measure }} AS value FROM {{ .params.metrics_view }} LIMIT {{ .params.limit }}" + vega_spec: '{"mark": "line", "params": [{"name": "smooth", "value": true, "bind": {"input": "checkbox"}}]}' +`, + }, + }) + testruntime.RequireReconcileState(t, rt, instanceID, 4, 0, 0) + + server, err := server.NewServer(context.Background(), &server.Options{}, rt, zap.NewNop(), ratelimit.NewNoop(), activity.NewNoopClient()) + require.NoError(t, err) + + args, err := structpb.NewStruct(map[string]any{ + "metrics_view": "mv1", + "measure": "count", + "smooth": false, + }) + require.NoError(t, err) + + res, err := server.ResolveComponent(testCtx(), &runtimev1.ResolveComponentRequest{ + InstanceId: instanceID, + Component: "trend", + Args: args, + }) + require.NoError(t, err) + + // Templating should resolve provided args and declared defaults. + props := res.RendererProperties.AsMap() + require.Equal(t, "SELECT country, count AS value FROM mv1 LIMIT 500", props["metrics_sql"]) + + // Scalar params should be injected as native Vega-Lite params: + // the author-declared "smooth" param keeps its bind but gets the bound value, + // and the "limit" param is appended with its default. + var vegaSpec map[string]any + require.NoError(t, json.Unmarshal([]byte(props["vega_spec"].(string)), &vegaSpec)) + vegaParams := vegaSpec["params"].([]any) + require.Len(t, vegaParams, 2) + smooth := vegaParams[0].(map[string]any) + require.Equal(t, "smooth", smooth["name"]) + require.Equal(t, false, smooth["value"]) + require.Equal(t, map[string]any{"input": "checkbox"}, smooth["bind"]) + limit := vegaParams[1].(map[string]any) + require.Equal(t, "limit", limit["name"]) + require.Equal(t, float64(500), limit["value"]) + + // The resolved args should contain the merged defaults and provided args. + require.Equal(t, map[string]any{ + "metrics_view": "mv1", + "measure": "count", + "limit": float64(500), + "smooth": false, + }, res.ResolvedArgs.AsMap()) + + // Missing required arg should return InvalidArgument. + args, err = structpb.NewStruct(map[string]any{"metrics_view": "mv1"}) + require.NoError(t, err) + _, err = server.ResolveComponent(testCtx(), &runtimev1.ResolveComponentRequest{ + InstanceId: instanceID, + Component: "trend", + Args: args, + }) + require.Error(t, err) + require.Equal(t, codes.InvalidArgument, status.Code(err)) + require.ErrorContains(t, err, `missing value for required param "measure"`) + + // Unknown arg should return InvalidArgument. + args, err = structpb.NewStruct(map[string]any{"metrics_view": "mv1", "measure": "count", "nope": 1}) + require.NoError(t, err) + _, err = server.ResolveComponent(testCtx(), &runtimev1.ResolveComponentRequest{ + InstanceId: instanceID, + Component: "trend", + Args: args, + }) + require.Error(t, err) + require.Equal(t, codes.InvalidArgument, status.Code(err)) + require.ErrorContains(t, err, `unknown param "nope"`) +} + +func TestResolveCanvasWithParamBoundMetricsView(t *testing.T) { + rt, instanceID := testruntime.NewInstanceWithOptions(t, testruntime.InstanceOptions{ + Files: map[string]string{ + "rill.yaml": "", + "m1.sql": `SELECT 'US' AS country`, + "mv1.yaml": ` +type: metrics_view +version: 1 +model: m1 +dimensions: +- column: country +measures: +- name: count + expression: COUNT(*) +`, + "trend.yaml": ` +type: component +params: + - name: metrics_view + type: metrics_view + required: true + - name: measure + type: measure + required: true +custom_chart: + metrics_sql: "SELECT country, {{ .params.measure }} AS value FROM {{ .params.metrics_view }}" + vega_spec: '{"mark": "line"}' +`, + // Built-in renderer with a templated metrics_view: ResolveCanvas must not + // treat the raw template string as a metrics view resource name. + "tplkpi.yaml": ` +type: component +params: + - name: metrics_view + type: metrics_view + required: true +kpi: + metrics_view: "{{ .params.metrics_view }}" +`, + "c1.yaml": ` +type: canvas +rows: +- items: + - component: trend + params: + metrics_view: mv1 + measure: count + - component: tplkpi + params: + metrics_view: mv1 +`, + }, + }) + testruntime.RequireReconcileState(t, rt, instanceID, 6, 0, 0) + + server, err := server.NewServer(context.Background(), &server.Options{}, rt, zap.NewNop(), ratelimit.NewNoop(), activity.NewNoopClient()) + require.NoError(t, err) + + res, err := server.ResolveCanvas(testCtx(), &runtimev1.ResolveCanvasRequest{ + InstanceId: instanceID, + Canvas: "c1", + }) + require.NoError(t, err) + + // The referenced components should be returned, and the param-bound metrics view + // should be included in the referenced metrics views. + require.Contains(t, res.ResolvedComponents, "trend") + require.Contains(t, res.ResolvedComponents, "tplkpi") + require.Contains(t, res.ReferencedMetricsViews, "mv1") + require.Len(t, res.ReferencedMetricsViews, 1) + + // The canvas items should carry the param bindings. + items := res.Canvas.GetCanvas().State.ValidSpec.Rows[0].Items + require.Len(t, items, 2) + require.Equal(t, map[string]any{"metrics_view": "mv1", "measure": "count"}, items[0].Params.AsMap()) +} diff --git a/web-common/scripts/snapshot-vega-examples.ts b/web-common/scripts/snapshot-vega-examples.ts new file mode 100644 index 000000000000..768bd047a45f --- /dev/null +++ b/web-common/scripts/snapshot-vega-examples.ts @@ -0,0 +1,244 @@ +/** + * Snapshots a curated subset of the Vega-Lite example gallery into + * src/features/custom-viz/examples/vega-examples.json. + * + * The snapshot is vendored (committed) so the "From Vega-Lite example" gallery works + * offline and without CSP exceptions. Each example's external data (data/*.json|csv|tsv) + * is fetched, sampled to at most MAX_ROWS rows, and inlined as data.values, so every + * gallery entry renders self-contained. + * + * Run manually when refreshing the gallery: + * npx tsx web-common/scripts/snapshot-vega-examples.ts + * + * The Vega-Lite examples are BSD-3-Clause licensed (University of Washington + * Interactive Data Lab); see the license field in the output file. + */ +import { csvParse, tsvParse, autoType } from "d3-dsv"; +import { mkdirSync, writeFileSync } from "node:fs"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; +import * as vega from "vega"; +import * as vegaLite from "vega-lite"; + +const INDEX_URL = + "https://raw.githubusercontent.com/vega/vega-lite/main/site/_data/examples.json"; +const EXAMPLES_BASE = "https://vega.github.io/vega-lite/examples/"; +const MAX_ROWS = 200; +const MAX_EXAMPLES = 90; + +// Categories to include, in gallery order. +const INCLUDED_CATEGORIES = new Set([ + "Single-View Plots", + "Composite Marks", + "Multi-View Displays", + "Interactive Charts", +]); + +// Examples containing these markers depend on features the import flow can't +// handle self-contained (geo projections, images, remote lookups at runtime). +const EXCLUDED_MARKERS = [ + '"projection"', + '"geoshape"', + "topojson", + '"graticule"', + '"sphere"', + '"image"', + ".png", + ".svg", +]; + +interface IndexEntry { + name: string; + title?: string; + description?: string; +} + +interface GalleryExample { + name: string; + title: string; + description?: string; + category: string; + subcategory: string; + spec: string; + // Static SVG thumbnail, pre-rendered at snapshot time so the gallery never + // runs a chart engine at runtime. Width/height attrs are stripped so it + // scales to its container via the viewBox. + thumbnail?: string; +} + +async function fetchJSON(url: string): Promise { + const res = await fetch(url); + if (!res.ok) throw new Error(`GET ${url}: ${res.status}`); + return res.json(); +} + +async function fetchText(url: string): Promise { + const res = await fetch(url); + if (!res.ok) throw new Error(`GET ${url}: ${res.status}`); + return res.text(); +} + +function sample(rows: unknown[]): unknown[] { + if (rows.length <= MAX_ROWS) return rows; + // Deterministic downsample: keep every nth row. + const step = rows.length / MAX_ROWS; + const out: unknown[] = []; + for (let i = 0; i < MAX_ROWS; i++) { + out.push(rows[Math.floor(i * step)]); + } + return out; +} + +async function loadDataset(url: string): Promise { + const absolute = new URL(url, EXAMPLES_BASE).toString(); + if (url.endsWith(".json")) { + const data = await fetchJSON(absolute); + return Array.isArray(data) ? sample(data) : null; + } + if (url.endsWith(".csv")) { + return sample(csvParse(await fetchText(absolute), autoType)); + } + if (url.endsWith(".tsv")) { + return sample(tsvParse(await fetchText(absolute), autoType)); + } + return null; +} + +/** + * Walks the spec and inlines every `data: {url}` as `data: {values}`. + * Returns false if any dataset can't be inlined (unsupported format). + */ +async function inlineData(node: unknown): Promise { + if (Array.isArray(node)) { + for (const child of node) { + if (!(await inlineData(child))) return false; + } + return true; + } + if (!node || typeof node !== "object") return true; + + const obj = node as Record; + const data = obj.data as Record | undefined; + if (data && typeof data.url === "string") { + const values = await loadDataset(data.url); + if (!values) return false; + const format = data.format as Record | undefined; + obj.data = { + values, + // Preserve parse-relevant format hints (e.g. {type: "json", property: ...}) + // are not needed once values are inlined; drop the format entirely except + // explicit field parses. + ...(format?.parse ? { format: { parse: format.parse } } : {}), + }; + } + + for (const [key, value] of Object.entries(obj)) { + if (key === "data") continue; + if (!(await inlineData(value))) return false; + } + return true; +} + +/** + * Renders a static SVG thumbnail for the example, headless. Returns undefined + * (and records why) when the spec can't render outside a browser. + */ +async function renderThumbnail( + spec: Record, + name: string, + skipped: string[], +): Promise { + try { + const compiled = vegaLite.compile( + spec as unknown as vegaLite.TopLevelSpec, + ).spec; + const view = new vega.View(vega.parse(compiled), { renderer: "none" }); + const svg = await view.toSVG(); + view.finalize(); + // Strip fixed dimensions so the SVG scales to its container via the viewBox. + return svg.replace( + /^]*?)\swidth="[^"]*"\sheight="[^"]*"/, + ' + >; + + const examples: GalleryExample[] = []; + const skipped: string[] = []; + // The upstream index lists some examples under multiple subcategories; + // keep only the first occurrence so names stay unique (they key UI lists). + const seen = new Set(); + + for (const [category, subcategories] of Object.entries(index)) { + if (!INCLUDED_CATEGORIES.has(category)) continue; + for (const [subcategory, entries] of Object.entries(subcategories)) { + for (const entry of entries) { + if (examples.length >= MAX_EXAMPLES) break; + if (seen.has(entry.name)) { + skipped.push(`${entry.name} (duplicate listing)`); + continue; + } + seen.add(entry.name); + try { + const rawSpec = await fetchText( + `${EXAMPLES_BASE}${entry.name}.vl.json`, + ); + if ( + EXCLUDED_MARKERS.some((marker) => + rawSpec.toLowerCase().includes(marker.toLowerCase()), + ) + ) { + skipped.push(`${entry.name} (excluded feature)`); + continue; + } + const spec = JSON.parse(rawSpec) as Record; + delete spec.description; + if (!(await inlineData(spec))) { + skipped.push(`${entry.name} (unsupported data format)`); + continue; + } + examples.push({ + name: entry.name, + title: entry.title ?? entry.name, + description: entry.description, + category, + subcategory, + spec: JSON.stringify(spec), + thumbnail: await renderThumbnail(spec, entry.name, skipped), + }); + } catch (error) { + skipped.push(`${entry.name} (${(error as Error).message})`); + } + } + } + } + + const out = { + license: + "Examples from the Vega-Lite project (https://vega.github.io/vega-lite/examples/), BSD-3-Clause, University of Washington Interactive Data Lab.", + snapshotSource: INDEX_URL, + examples, + }; + + const outPath = join( + dirname(fileURLToPath(import.meta.url)), + "../src/features/custom-viz/examples/vega-examples.json", + ); + mkdirSync(dirname(outPath), { recursive: true }); + writeFileSync(outPath, JSON.stringify(out, null, 2) + "\n"); + + console.log(`Wrote ${examples.length} examples to ${outPath}`); + console.log(`Skipped ${skipped.length}:`); + for (const reason of skipped) console.log(` - ${reason}`); +} + +void main(); diff --git a/web-common/src/features/canvas/AddComponentDropdown.svelte b/web-common/src/features/canvas/AddComponentDropdown.svelte index 449ff7d2ca6a..af002759413f 100644 --- a/web-common/src/features/canvas/AddComponentDropdown.svelte +++ b/web-common/src/features/canvas/AddComponentDropdown.svelte @@ -4,8 +4,13 @@ CHART_CONFIG, VISIBLE_CHART_TYPES, } from "@rilldata/web-common/features/components/charts/config"; + import { + ResourceKind, + useFilteredResources, + } from "@rilldata/web-common/features/entity-management/resource-selectors"; import { featureFlags } from "@rilldata/web-common/features/feature-flags"; import { m } from "@rilldata/web-common/lib/i18n/gen/messages"; + import { useRuntimeClient } from "@rilldata/web-common/runtime-client/v2"; import { Layers, Plus, PlusCircle } from "lucide-svelte"; import type { ComponentType, SvelteComponent } from "svelte"; import type { ChartType } from "../components/charts/types"; @@ -40,13 +45,28 @@ export let rowIndex: number | undefined = undefined; export let columnIndex: number | undefined = undefined; export let onItemClick: (type: CanvasComponentType) => void; + // When provided (and the customComponents flag is on), the menu lists the project's + // standalone components (custom viz) so they can be added as references. + export let onAddComponentRef: ((componentName: string) => void) | undefined = + undefined; export let onMouseEnter: () => void = () => {}; export let onOpenChange: (isOpen: boolean) => void = () => {}; // When provided, the menu offers "Tab group" as a final item. Only passed at the // top level (tab groups cannot be nested inside a tab or a column). export let onAddTabGroup: (() => void) | undefined = undefined; - const { customCharts } = featureFlags; + const { customCharts, customComponents } = featureFlags; + + const client = useRuntimeClient(); + + $: componentsQuery = useFilteredResources(client, ResourceKind.Component); + // Standalone (custom viz) components only: inline canvas components are excluded. + $: customVizComponents = ($componentsQuery?.data ?? []).filter( + (res) => + !res.component?.spec?.definedInCanvas && + !!res.meta?.name?.name && + !res.meta.name.name.includes("--component-"), + ); const ADD_DROPDOWN_CHART_TYPES = VISIBLE_CHART_TYPES.filter((type) => { return type !== "stacked_bar" && type !== "stacked_bar_normalized"; @@ -162,6 +182,31 @@ {/if} {/each} + {#if $customComponents && onAddComponentRef} + + + + + {m.canvas_your_components()} + + + {#each customVizComponents as res (res.meta?.name?.name)} + onAddComponentRef?.(res.meta?.name?.name ?? "")} + > + + {res.component?.spec?.displayName || res.meta?.name?.name} + + {:else} +
+ {m.canvas_no_components_yet()} +
+ {/each} +
+
+ {/if} + {#if onAddTabGroup} !!res.meta?.name?.name) + .map((res) => [res.meta!.name!.name as string, res]), + ); + $: ({ editorContent, updateEditorContent } = fileArtifact); $: contents = parseDocument($editorContent ?? ""); @@ -200,7 +217,9 @@ dragComponent = component; const id = component.id; - const element = document.querySelector("#" + id); + // getElementById, not querySelector: instance ids of referenced components + // contain "::", which is not valid in a CSS selector. + const element = document.getElementById(id); if (!element) return; const width = element.clientWidth; @@ -349,14 +368,17 @@ defaultMetrics, resolvedComponents, transaction, + componentResources: componentResourceMap, }); if (selectedId) { - const idsAtPositions = specRows.map((row) => { + // Selection ids are per-position instance ids (which for items that + // reference an external component differ from the item's component name). + const idsAtPositions = specRows.map((row, rowIdx) => { return { - items: row.items?.map((item) => { - return item.component ?? ""; - }), + items: row.items?.map((item, colIdx) => + canvasItemInstanceId(item, rowIdx, colIdx, namePrefix), + ), }; }); @@ -371,7 +393,9 @@ const colIndex = ids[rowIndex]?.items?.indexOf(selectedId); if (colIndex !== undefined && colIndex !== -1 && rowIndex !== -1) { - const newIdOfSelected = getId(rowIndex, colIndex, namePrefix); + const newIdOfSelected = selectedId.includes("::") + ? `${componentNameFromInstanceId(selectedId)}::${namePrefix}${rowIndex}-${colIndex}` + : getId(rowIndex, colIndex, namePrefix); if (selectedId && newIdOfSelected) setSelectedComponent(newIdOfSelected); @@ -386,16 +410,21 @@ function addItems( position: { row: number; column: number }, - items: CanvasComponentType[], + items: AddableItem[], target?: EditTarget, ) { if (!defaultMetrics) return; performTransaction( { - operations: items.map((type, i) => ({ + operations: items.map((item, i) => ({ type: "add", - componentType: type, + ...(typeof item === "string" + ? { componentType: item } + : { + componentType: "component_ref" as const, + componentName: item.componentName, + }), destination: { row: position.row, col: position.column + i, @@ -407,12 +436,31 @@ ); const { namePrefix } = resolveTarget(target); - const id = getId(position.row, position.column, namePrefix); + const id = getInstanceId( + items[0], + position.row, + position.column, + namePrefix, + ); setSelectedComponent(id); openSidebar(); } + // The client-side instance id an added item will get: the generated resource name + // for inline components, or the positional reference id for component references. + function getInstanceId( + item: AddableItem | undefined, + row: number, + column: number, + namePrefix = "", + ) { + if (item && typeof item !== "string") { + return `${item.componentName}::${namePrefix}${row}-${column}`; + } + return getId(row, column, namePrefix); + } + function updateContents() { const newContent = contents.toString(); if (newContent === $editorContent) { @@ -502,15 +550,11 @@ if (convertRowToTabGroup(contents, rowIndex)) updateContents(); } - function initializeRow( - row: number, - type: CanvasComponentType, - target?: EditTarget, - ) { + function initializeRow(row: number, item: AddableItem, target?: EditTarget) { if (!defaultMetrics) return; const { namePrefix } = resolveTarget(target); - const id = getId(row, 0, namePrefix); + const id = getInstanceId(item, row, 0, namePrefix); performTransaction( { @@ -518,7 +562,12 @@ { type: "add", insertRow: true, - componentType: type, + ...(typeof item === "string" + ? { componentType: item } + : { + componentType: "component_ref" as const, + componentName: item.componentName, + }), destination: { row, col: 0, @@ -865,6 +914,9 @@ onItemClick={(type) => { initializeRow(specCanvasRows.length, type); }} + onAddComponentRef={(componentName) => { + initializeRow(specCanvasRows.length, { componentName }); + }} onAddTabGroup={addTabGroupAction} /> {:else if canvasData} @@ -884,6 +936,10 @@ initializeRow(specCanvasRows.length, type); setTimeout(() => scrollToBottom(), 500); }} + onAddComponentRef={(componentName) => { + initializeRow(specCanvasRows.length, { componentName }); + setTimeout(() => scrollToBottom(), 500); + }} onAddTabGroup={addTabGroupAction} /> {/if} diff --git a/web-common/src/features/canvas/EditableCanvasRow.svelte b/web-common/src/features/canvas/EditableCanvasRow.svelte index 420d02a8a913..53d60209e121 100644 --- a/web-common/src/features/canvas/EditableCanvasRow.svelte +++ b/web-common/src/features/canvas/EditableCanvasRow.svelte @@ -6,7 +6,6 @@ import CanvasComponent from "./CanvasComponent.svelte"; import type { BaseCanvasComponent } from "./components/BaseCanvasComponent"; import DropZone from "./components/DropZone.svelte"; - import type { CanvasComponentType } from "./components/types"; import ElementDivider from "./ElementDivider.svelte"; import ItemWrapper from "./ItemWrapper.svelte"; import { @@ -15,6 +14,7 @@ MIN_WIDTH, mousePosition, normalizeSizeArray, + type AddableItem, } from "./layout-util"; import RowDropZone from "./RowDropZone.svelte"; import RowWrapper from "./RowWrapper.svelte"; @@ -33,7 +33,7 @@ export let selectedComponent: Writable; export let addItems: ( position: { row: number; column: number }, - items: CanvasComponentType[], + items: AddableItem[], ) => void; export let spreadEvenly: (index: number) => void; export let onComponentMouseDown: (params: { @@ -47,7 +47,7 @@ // Optional: insert a tab group at a given top-level index (top-level rows only). export let onAddTabGroup: ((index: number) => void) | undefined = undefined; export let onDrop: (row: number, column: number | null) => void; - export let initializeRow: (row: number, type: CanvasComponentType) => void; + export let initializeRow: (row: number, type: AddableItem) => void; export let updateRowHeight: (newHeight: number, index: number) => void; export let updateComponentWidths: ( index: number, diff --git a/web-common/src/features/canvas/EditableCanvasTabGroup.svelte b/web-common/src/features/canvas/EditableCanvasTabGroup.svelte index 0532391adae5..87be2f40bd6a 100644 --- a/web-common/src/features/canvas/EditableCanvasTabGroup.svelte +++ b/web-common/src/features/canvas/EditableCanvasTabGroup.svelte @@ -5,10 +5,9 @@ import AddComponentDropdown from "./AddComponentDropdown.svelte"; import CanvasTabStrip from "./CanvasTabStrip.svelte"; import type { BaseCanvasComponent } from "./components/BaseCanvasComponent"; - import type { CanvasComponentType } from "./components/types"; import EditableCanvasRow from "./EditableCanvasRow.svelte"; import ItemWrapper from "./ItemWrapper.svelte"; - import type { EditTarget } from "./layout-util"; + import type { AddableItem, EditTarget } from "./layout-util"; import RowDropZone from "./RowDropZone.svelte"; import RowWrapper from "./RowWrapper.svelte"; import type { TabGroup } from "./stores/tab-group"; @@ -39,13 +38,13 @@ ) => void; export let addItems: ( position: { row: number; column: number }, - items: CanvasComponentType[], + items: AddableItem[], target?: EditTarget, ) => void; export let spreadEvenly: (index: number, target?: EditTarget) => void; export let initializeRow: ( row: number, - type: CanvasComponentType, + type: AddableItem, target?: EditTarget, ) => void; export let updateRowHeight: ( @@ -186,6 +185,8 @@ label={m.canvas_add_widget_to_tab()} onItemClick={(type) => initializeRow($grid.length, type, target)} + onAddComponentRef={(componentName) => + initializeRow($grid.length, { componentName }, target)} /> @@ -235,6 +236,8 @@ componentForm label={m.canvas_add_widget_below_tabs()} onItemClick={(type) => initializeRow(blockIndex + 1, type)} + onAddComponentRef={(componentName) => + initializeRow(blockIndex + 1, { componentName })} onAddTabGroup={() => onAddTabGroup(blockIndex + 1)} /> diff --git a/web-common/src/features/canvas/ElementDivider.svelte b/web-common/src/features/canvas/ElementDivider.svelte index 4b3e3f535699..5b4b8cc2bb02 100644 --- a/web-common/src/features/canvas/ElementDivider.svelte +++ b/web-common/src/features/canvas/ElementDivider.svelte @@ -3,6 +3,7 @@ import { ArrowLeftRight } from "lucide-svelte"; import AddComponentDropdown from "./AddComponentDropdown.svelte"; import type { CanvasComponentType } from "./components/types"; + import type { AddableItem } from "./layout-util"; import { dropZone, activeDivider } from "./stores/ui-stores"; import Tooltip from "@rilldata/web-common/components/tooltip/Tooltip.svelte"; import TooltipContent from "@rilldata/web-common/components/tooltip/TooltipContent.svelte"; @@ -18,7 +19,7 @@ export let dragging: boolean; export let addItems: ( position: { row: number; column: number }, - item: CanvasComponentType[], + item: AddableItem[], ) => void; export let onColumnResizeStart: ((columnIndex: number) => void) | undefined = undefined; @@ -56,6 +57,12 @@ addItems({ row: rowIndex, column: addIndex }, [type]); } } + + function onAddComponentRef(componentName: string) { + if (componentName) { + addItems({ row: rowIndex, column: addIndex }, [{ componentName }]); + } + }
{ if (!isOpen) { activeDivider.set(null); diff --git a/web-common/src/features/canvas/LocalFiltersHeader.svelte b/web-common/src/features/canvas/LocalFiltersHeader.svelte index 46df3e8bbeae..40caaf495f16 100644 --- a/web-common/src/features/canvas/LocalFiltersHeader.svelte +++ b/web-common/src/features/canvas/LocalFiltersHeader.svelte @@ -25,7 +25,9 @@ } = component); $: metricsViewName = - "metrics_view" in $specStore ? ($specStore.metrics_view ?? null) : null; + "metrics_view" in $specStore + ? (($specStore.metrics_view as string | undefined) ?? null) + : null; $: if (metricsViewName) { measures = getMeasuresForMetricView(metricsViewName); @@ -93,9 +95,7 @@ import AddComponentDropdown from "./AddComponentDropdown.svelte"; - import type { CanvasComponentType } from "./components/types"; + import type { AddableItem } from "./layout-util"; import Divider from "./Divider.svelte"; import { activeDivider, dropZone } from "./stores/ui-stores"; @@ -11,7 +11,7 @@ export let position: "top" | "bottom" | undefined = undefined; export let onDrop: (row: number, column: number | null) => void; export let onRowResizeStart: (e: MouseEvent) => void = () => {}; - export let addItem: (type: CanvasComponentType) => void; + export let addItem: (item: AddableItem) => void; // When provided, the add menu offers inserting a tab group at this position. export let onAddTabGroup: (() => void) | undefined = undefined; @@ -93,6 +93,7 @@ } }} onItemClick={addItem} + onAddComponentRef={(componentName) => addItem({ componentName })} {onAddTabGroup} /> diff --git a/web-common/src/features/canvas/Toolbar.svelte b/web-common/src/features/canvas/Toolbar.svelte index da0f6380b2cc..7b200ab3801d 100644 --- a/web-common/src/features/canvas/Toolbar.svelte +++ b/web-common/src/features/canvas/Toolbar.svelte @@ -2,8 +2,14 @@ import * as DropdownMenu from "@rilldata/web-common/components/dropdown-menu/"; import ThreeDot from "@rilldata/web-common/components/icons/ThreeDot.svelte"; import Trash from "@rilldata/web-common/components/icons/Trash.svelte"; - import { Copy, Columns } from "lucide-svelte"; + import { Copy, Columns, PackageOpen, Save } from "lucide-svelte"; + import { m } from "@rilldata/web-common/lib/i18n/gen/messages"; + import { featureFlags } from "@rilldata/web-common/features/feature-flags"; + import SaveAsComponentDialog from "@rilldata/web-common/features/custom-viz/extract/SaveAsComponentDialog.svelte"; + import { detachComponentRef } from "@rilldata/web-common/features/custom-viz/extract/extract-component"; import type { BaseCanvasComponent } from "./components/BaseCanvasComponent"; + import { CustomChartComponent } from "./components/charts/custom-chart"; + import { ComponentRefComponent } from "./components/component-ref"; import type { ComponentWithMetricsView } from "./components/types"; import ExploreLink from "./explore-link/ExploreLink.svelte"; @@ -17,6 +23,15 @@ export let component: BaseCanvasComponent; export let navigationEnabled: boolean = true; + const { customComponents } = featureFlags; + + let saveAsComponentOpen = false; + + $: canSaveAsComponent = + $customComponents && component instanceof CustomChartComponent; + $: canDetach = + $customComponents && component instanceof ComponentRefComponent; + // Component types that support link to explore functionality const EXPLORE_SUPPORTED_TYPES = [ "kpi_grid", @@ -66,6 +81,21 @@ Duplicate + {#if canSaveAsComponent} + (saveAsComponentOpen = true)}> + + {m.component_extract_menu_item()} + + {/if} + {#if canDetach} + + detachComponentRef(component as ComponentRefComponent)} + > + + {m.component_detach_menu_item()} + + {/if} {#if onConvertToTabGroup} @@ -91,3 +121,10 @@ {/if}
+ +{#if canSaveAsComponent} + +{/if} diff --git a/web-common/src/features/canvas/components/BaseCanvasComponent.ts b/web-common/src/features/canvas/components/BaseCanvasComponent.ts index 9f6620d36042..002e66100357 100644 --- a/web-common/src/features/canvas/components/BaseCanvasComponent.ts +++ b/web-common/src/features/canvas/components/BaseCanvasComponent.ts @@ -10,6 +10,7 @@ import type { import { getFiltersFromText } from "@rilldata/web-common/features/dashboards/filters/dimension-filters/dimension-search-text-utils"; import type { ExploreState } from "@rilldata/web-common/features/dashboards/stores/explore-state"; import type { + V1CanvasItem, V1Expression, V1Resource, V1TimeRange, @@ -169,7 +170,10 @@ export abstract class BaseCanvasComponent { this.unsubscribeSpec?.(); } - update(resource: V1Resource, path: ComponentPath) { + // item is the canvas item this instance renders; only used by components whose + // editable state lives on the item rather than the resource (see ComponentRefComponent). + update(resource: V1Resource, path: ComponentPath, item?: V1CanvasItem) { + void item; const yamlSpec = (resource.component?.state?.validSpec ?.rendererProperties ?? (this.parent.allowUnvalidatedSpec diff --git a/web-common/src/features/canvas/components/component-ref/CanvasComponentRef.svelte b/web-common/src/features/canvas/components/component-ref/CanvasComponentRef.svelte new file mode 100644 index 000000000000..a41109da1969 --- /dev/null +++ b/web-common/src/features/canvas/components/component-ref/CanvasComponentRef.svelte @@ -0,0 +1,97 @@ + + +{#if !componentSpec} + +{:else if renderer !== "custom_chart"} + +{:else if $resolvedQuery.error && !optimisticProps} + +{:else} + +{/if} diff --git a/web-common/src/features/canvas/components/component-ref/index.ts b/web-common/src/features/canvas/components/component-ref/index.ts new file mode 100644 index 000000000000..1f3a976b14ff --- /dev/null +++ b/web-common/src/features/canvas/components/component-ref/index.ts @@ -0,0 +1,216 @@ +import { BaseCanvasComponent } from "@rilldata/web-common/features/canvas/components/BaseCanvasComponent"; +import type { CanvasComponentType } from "@rilldata/web-common/features/canvas/components/types"; +import type { + AllKeys, + InputParams, +} from "@rilldata/web-common/features/canvas/inspector/types"; +import type { + CanvasEntity, + ComponentPath, +} from "@rilldata/web-common/features/canvas/stores/canvas-entity"; +import { + getDeclaredParams, + isOrderByParam, + orderByOptions, + paramToInputParam, + prettyParamLabel, + reconcileOrderByArg, +} from "@rilldata/web-common/features/custom-viz/params"; +import type { + V1CanvasItem, + V1ComponentParam, + V1Resource, +} from "@rilldata/web-common/runtime-client"; +import { get } from "svelte/store"; +import CanvasComponentRef from "./CanvasComponentRef.svelte"; + +/** + * The flattened spec of a canvas item that references an externally defined component: + * the component name plus the values bound to its declared params spread at the top + * level, so the generated inspector inputs can bind to them like ordinary spec keys. + * Param bindings are scalars only (enforced by the canvas parser), which also keeps + * indexed access on the ComponentSpec union usable by the shared inspector widgets. + */ +export interface ComponentRefSpec { + component: string; + [param: string]: string | number | boolean | undefined; +} + +/** + * Canvas component for items that reference an externally defined component + * (`component: ` + `params:` in the canvas YAML). Unlike other canvas + * components, its editable state is the canvas item's param bindings, not the + * component's renderer properties, and its inspector inputs are generated from + * the referenced component's declared params. + */ +export class ComponentRefComponent extends BaseCanvasComponent { + minSize = { width: 4, height: 4 }; + defaultSize = { width: 6, height: 4 }; + resetParams = []; + type: CanvasComponentType = "component_ref"; + component = CanvasComponentRef; + + componentName: string; + + constructor( + resource: V1Resource, + parent: CanvasEntity, + path: ComponentPath, + item?: V1CanvasItem, + ) { + super(resource, parent, path, { component: item?.component ?? "" }); + this.componentName = item?.component ?? ""; + this.specStore.set(this.specFromItem(item)); + this.syncMetricsViewName(); + } + + override update( + resource: V1Resource, + path: ComponentPath, + item?: V1CanvasItem, + ) { + super.update(resource, path); + if (item?.component) this.componentName = item.component; + this.specStore.set(this.specFromItem(item)); + this.syncMetricsViewName(); + } + + /** The referenced component's declared params. */ + get declaredParams(): V1ComponentParam[] { + return getDeclaredParams( + get(this.resource), + this.parent.allowUnvalidatedSpec, + ); + } + + /** + * The values currently bound to the declared params. + * Filters to declared names, since the spec may carry derived keys + * (e.g. the metrics_view surfaced for the canvas filter system). + */ + args(spec: ComponentRefSpec = get(this.specStore)): Record { + const declared = new Set(this.declaredParams.map((p) => p.name)); + return Object.fromEntries( + Object.entries(spec).filter( + ([key, value]) => declared.has(key) && value !== undefined, + ), + ); + } + + isValid(spec: ComponentRefSpec): boolean { + return !!spec.component; + } + + inputParams(): InputParams { + const options: Record> = {}; + const args = this.args(); + for (const param of this.declaredParams) { + if (!param.name) continue; + // The by-convention order_by param selects among the currently bound + // field values instead of a free-text input. + if (isOrderByParam(param)) { + options[param.name] = { + type: "select", + label: prettyParamLabel(param.name), + optional: !param.required, + description: param.description, + meta: { options: orderByOptions(this.declaredParams, args) }, + }; + continue; + } + options[param.name] = paramToInputParam(param); + } + return { options, filter: {} }; + } + + override updateProperty( + key: AllKeys, + value: ComponentRefSpec[AllKeys], + ) { + const currentSpec = get(this.specStore); + const newSpec = { ...currentSpec, [key]: value }; + if (value === undefined || value === "") { + delete newSpec[key]; + } + + // When the bound metrics view changes, clear the bound field params that + // depend on it: they referenced fields of the previous metrics view. + for (const param of this.declaredParams) { + if (param.type === "metrics_view" && param.name === key) { + for (const dependent of this.declaredParams) { + if (dependent.metricsViewParam === key && dependent.name) { + delete newSpec[dependent.name]; + } + } + } + } + + // Keep the by-convention order_by binding in step: it follows a re-bound + // field it pointed at, and is re-seeded from the measure when it no longer + // matches any bound field (e.g. after a metrics view change). + reconcileOrderByArg(this.declaredParams, newSpec, { + name: String(key), + previousValue: currentSpec[key], + }); + + this.writeParamsToYAML(this.args(newSpec)); + this.specStore.set(newSpec); + this.syncMetricsViewName(); + } + + override setSpec(newSpec: ComponentRefSpec) { + this.writeParamsToYAML(this.args(newSpec)); + this.specStore.set(newSpec); + this.syncMetricsViewName(); + } + + static newComponentSpec(): ComponentRefSpec { + return { component: "" }; + } + + private specFromItem(item: V1CanvasItem | undefined): ComponentRefSpec { + return { + component: item?.component ?? this.componentName, + ...(item?.params ?? {}), + }; + } + + /** + * Persists the param bindings to the canvas YAML at the item's `params:` key. + * Only the params map is written; the item's other keys (component, width) stay untouched. + */ + private writeParamsToYAML(params: Record) { + if (!this.parent.fileArtifact) return; + const parsedDocument = get(this.parent.parsedContent); + const { updateEditorContent } = this.parent.fileArtifact; + + // pathInYAML ends with the component type segment; the item map is its parent. + const itemPath = this.pathInYAML.slice(0, -1); + if (Object.keys(params).length > 0) { + parsedDocument.setIn([...itemPath, "params"], params); + } else { + parsedDocument.deleteIn([...itemPath, "params"]); + } + + updateEditorContent(parsedDocument.toString(), false, true); + } + + /** + * Tracks the metrics view bound to the first metrics_view-typed param so the + * canvas filter and time systems know which metrics view this item uses. + */ + private syncMetricsViewName() { + const spec = get(this.specStore); + const mvParam = this.declaredParams.find((p) => p.type === "metrics_view"); + const name = mvParam?.name + ? (spec[mvParam.name] ?? mvParam.default) + : undefined; + if (typeof name !== "string" || !name || name === this.metricsViewName) { + return; + } + this.metricsViewName = name; + this.localFilters = this.parent.filterManager.createLocalFilterStore(name); + // Surface the metrics view under the key the shared canvas systems read. + this.specStore.update((s) => ({ ...s, metrics_view: name })); + } +} diff --git a/web-common/src/features/canvas/components/types.ts b/web-common/src/features/canvas/components/types.ts index feca61fb4c93..5fec7aebc97d 100644 --- a/web-common/src/features/canvas/components/types.ts +++ b/web-common/src/features/canvas/components/types.ts @@ -3,6 +3,7 @@ import type { CircularCanvasChartSpec } from "@rilldata/web-common/features/canv import type { ScatterPlotCanvasChartSpec } from "@rilldata/web-common/features/canvas/components/charts/variants/ScatterPlotChart"; import type { KPIGridSpec } from "@rilldata/web-common/features/canvas/components/kpi-grid"; import type { ChartType } from "../../components/charts/types"; +import type { ComponentRefSpec } from "./component-ref"; import type { ImageSpec } from "./image"; import type { KPISpec } from "./kpi"; import type { LeaderboardSpec } from "./leaderboard"; @@ -21,7 +22,11 @@ export type ComponentWithMetricsView = | LeaderboardSpec | CustomChart; -export type ComponentSpec = ComponentWithMetricsView | ImageSpec | MarkdownSpec; +export type ComponentSpec = + | ComponentWithMetricsView + | ImageSpec + | MarkdownSpec + | ComponentRefSpec; export interface ComponentCommonProperties { title?: string; @@ -59,7 +64,8 @@ export type CanvasComponentType = | "pivot" | "table" | "leaderboard" - | "custom_chart"; + | "custom_chart" + | "component_ref"; interface LineChart { line_chart: CartesianCanvasChartSpec; diff --git a/web-common/src/features/canvas/components/util.ts b/web-common/src/features/canvas/components/util.ts index 688659310e16..33b9ce0e2803 100644 --- a/web-common/src/features/canvas/components/util.ts +++ b/web-common/src/features/canvas/components/util.ts @@ -11,6 +11,7 @@ import type { FilterInputTypes, } from "@rilldata/web-common/features/canvas/inspector/types"; import { + type V1CanvasItem, type V1ComponentSpec, type V1MetricsViewSpec, type V1ResolveCanvasResponseResolvedComponents, @@ -18,6 +19,7 @@ import { } from "@rilldata/web-common/runtime-client"; import type { CanvasEntity, ComponentPath } from "../stores/canvas-entity"; import type { BaseCanvasComponent } from "./BaseCanvasComponent"; +import { ComponentRefComponent } from "./component-ref"; import { ImageComponent } from "./image"; import { LeaderboardComponent } from "./leaderboard"; import { MarkdownCanvasComponent } from "./markdown"; @@ -120,6 +122,7 @@ const NON_CHART_TYPES = [ "pivot", "leaderboard", "custom_chart", + "component_ref", ] as const; const ALL_COMPONENT_TYPES = [...CHART_TYPES, ...NON_CHART_TYPES] as const; @@ -152,6 +155,7 @@ const baseComponentMap = { table: PivotCanvasComponent, pivot: PivotCanvasComponent, custom_chart: CustomChartComponent, + component_ref: ComponentRefComponent, } as const; const IconMap = { markdown: TextIcon, @@ -178,6 +182,7 @@ const baseDisplayMap = { image: "Image", leaderboard: "Leaderboard", custom_chart: "Custom Chart", + component_ref: "Custom viz", } as const; const chartDisplayMap = Object.fromEntries( @@ -193,8 +198,19 @@ export function createComponent( resource: V1Resource, parent: CanvasEntity, path: ComponentPath, + item?: V1CanvasItem, + instanceId?: string, ): BaseCanvasComponent { - const type = resource.component?.spec?.renderer as CanvasComponentType; + const type = getComponentInstanceType(resource, item); + if (type === "component_ref") { + const component = new ComponentRefComponent(resource, parent, path, item); + // Items referencing an external component share one resource, so the + // resource name can't identify the instance: use the positional instance id + // (also the components-store key and the selection id) so two references to + // the same component get distinct DOM ids and selection/cleanup state. + if (instanceId) component.id = instanceId; + return component; + } const ComponentClass = COMPONENT_CLASS_MAP[type as keyof typeof COMPONENT_CLASS_MAP]; if (ComponentClass) { @@ -203,6 +219,26 @@ export function createComponent( return new CartesianChartComponent(resource, parent, path); } +/** + * Determines the component class type for a canvas item. + * Items that reference an externally defined component render through the + * component_ref wrapper regardless of the referenced component's renderer; + * everything else keys off the renderer. + */ +export function getComponentInstanceType( + resource: V1Resource | undefined, + item?: V1CanvasItem, + allowUnvalidatedSpec = true, +): CanvasComponentType { + if (item && !item.definedInCanvas && item.component) { + return "component_ref"; + } + return (resource?.component?.state?.validSpec?.renderer ?? + (allowUnvalidatedSpec + ? resource?.component?.spec?.renderer + : undefined)) as CanvasComponentType; +} + export function isCanvasComponentType( value: string | undefined, ): value is CanvasComponentType { diff --git a/web-common/src/features/canvas/inspector/ComponentsEditor.svelte b/web-common/src/features/canvas/inspector/ComponentsEditor.svelte index aa83dd6129c7..6c26dc3d057f 100644 --- a/web-common/src/features/canvas/inspector/ComponentsEditor.svelte +++ b/web-common/src/features/canvas/inspector/ComponentsEditor.svelte @@ -1,11 +1,15 @@ {#if componentType} @@ -41,6 +53,23 @@ {/if} + {#if isRef} +
+ {#if refFilePath} + + {m.canvas_edit_component()} + + + {/if} + + {m.canvas_component_ref_edit_note()} + +
+ {/if} + {#if componentType && component && rendererProperties && currentTab} {#if currentTab === "options"} {#key component} diff --git a/web-common/src/features/canvas/inspector/MetricSelectorDropdown.svelte b/web-common/src/features/canvas/inspector/MetricSelectorDropdown.svelte index 02bdee014957..41a6b3481231 100644 --- a/web-common/src/features/canvas/inspector/MetricSelectorDropdown.svelte +++ b/web-common/src/features/canvas/inspector/MetricSelectorDropdown.svelte @@ -29,7 +29,10 @@ .filter(isString); $: metricsView = - "metrics_view" in $spec ? $spec.metrics_view : metricsViewNames[0]; + (key in $spec ? ($spec[key] as string | undefined) : undefined) ?? + ("metrics_view" in $spec + ? ($spec.metrics_view as string | undefined) + : metricsViewNames[0]); + + {#if fields.length > 0} +
+
+ {m.component_extract_fields_label()} +
+
+ {m.component_extract_fields_note()} +
+ {#each fields as field (field.name)} + + {/each} +
+ {/if} + + + + {#snippet child({ props })} + + {/snippet} + + + + {#snippet child({ props })} + + {/snippet} + + + + diff --git a/web-common/src/features/custom-viz/extract/extract-component.spec.ts b/web-common/src/features/custom-viz/extract/extract-component.spec.ts new file mode 100644 index 000000000000..2321930f1491 --- /dev/null +++ b/web-common/src/features/custom-viz/extract/extract-component.spec.ts @@ -0,0 +1,129 @@ +import { describe, expect, it } from "vitest"; +import { parseDocument } from "yaml"; +import { extractedComponentYAML } from "./extract-component"; + +const spec = { + metrics_sql: [ + "SELECT country, total_bids FROM auction_metrics WHERE country != 'US' ORDER BY total_bids DESC", + ], + vega_spec: + '{"data": {"name": "query1"}, "mark": "bar", "encoding": {"x": {"field": "country"}, "y": {"field": "total_bids"}}}', +}; + +describe("extractedComponentYAML", () => { + it("always lifts the metrics view via the FROM clause", () => { + const { yaml, bindings } = extractedComponentYAML( + spec, + "auction_metrics", + "My Viz", + [], + ); + + const parsed = parseDocument(yaml).toJSON(); + expect(parsed.type).toBe("component"); + expect(parsed.display_name).toBe("My Viz"); + expect(parsed.params).toEqual([ + { name: "metrics_view", type: "metrics_view", required: true }, + ]); + expect(parsed.custom_chart.metrics_sql[0]).toContain( + "FROM {{ .params.metrics_view }}", + ); + // Field names stay hardcoded when not lifted. + expect(parsed.custom_chart.metrics_sql[0]).toContain("total_bids"); + expect(parsed.custom_chart.vega_spec).toContain('"field": "country"'); + + expect(bindings).toEqual({ metrics_view: "auction_metrics" }); + }); + + it("lifts checked fields in both the metrics SQL and the vega spec", () => { + const { yaml, bindings } = extractedComponentYAML( + spec, + "auction_metrics", + "My Viz", + [ + { name: "total_bids", type: "measure" }, + { name: "country", type: "dimension" }, + ], + ); + + const parsed = parseDocument(yaml).toJSON(); + expect(parsed.params).toEqual([ + { name: "metrics_view", type: "metrics_view", required: true }, + { name: "total_bids", type: "measure", required: true }, + { name: "country", type: "dimension", required: true }, + ]); + + const sql = parsed.custom_chart.metrics_sql[0]; + expect(sql).toContain("SELECT {{ .params.country }}"); + expect(sql).toContain("{{ .params.total_bids }} DESC"); + expect(parsed.custom_chart.vega_spec).toContain( + '"field": "{{ .params.country }}"', + ); + expect(parsed.custom_chart.vega_spec).toContain( + '"field": "{{ .params.total_bids }}"', + ); + + expect(bindings).toEqual({ + metrics_view: "auction_metrics", + total_bids: "total_bids", + country: "country", + }); + }); + + it("declares time dimensions as time_dimension params", () => { + const timeSpec = { + metrics_sql: ["SELECT ts, total_bids FROM auction_metrics"], + vega_spec: '{"encoding": {"x": {"field": "ts", "type": "temporal"}}}', + }; + const { yaml } = extractedComponentYAML(timeSpec, "auction_metrics", "V", [ + { name: "ts", type: "dimension", isTimeDimension: true }, + ]); + const parsed = parseDocument(yaml).toJSON(); + expect(parsed.params).toContainEqual({ + name: "ts", + type: "time_dimension", + required: true, + }); + }); + + it("does not replace substrings of other tokens", () => { + const trickySpec = { + metrics_sql: ["SELECT bid, total_bid FROM mv"], + vega_spec: '{"field": "total_bid"}', + }; + const { yaml } = extractedComponentYAML(trickySpec, "mv", "V", [ + { name: "bid", type: "measure" }, + ]); + const parsed = parseDocument(yaml).toJSON(); + // "bid" was lifted, but "total_bid" (which contains "bid" as a substring + // separated by an underscore, i.e. no word boundary) stays untouched. + expect(parsed.custom_chart.metrics_sql[0]).toBe( + "SELECT {{ .params.bid }}, total_bid FROM {{ .params.metrics_view }}", + ); + expect(parsed.custom_chart.vega_spec).toBe('{"field": "total_bid"}'); + }); + + it("sanitizes and dedupes generated param names", () => { + const trickySpec = { + metrics_sql: ["SELECT `weird field`, metrics_view FROM mv"], + vega_spec: "{}", + }; + const { yaml } = extractedComponentYAML(trickySpec, "mv", "V", [ + { name: "weird field", type: "dimension" }, + { name: "metrics_view", type: "measure" }, + ]); + const parsed = parseDocument(yaml).toJSON(); + const names = parsed.params.map((p: { name: string }) => p.name); + expect(names).toContain("weird_field"); + // Collides with the always-present metrics_view param, so it gets a suffix. + expect(names).toContain("metrics_view_2"); + }); + + it("produces YAML that round-trips through a parser", () => { + const { yaml } = extractedComponentYAML(spec, "auction_metrics", "V", [ + { name: "country", type: "dimension" }, + ]); + const doc = parseDocument(yaml); + expect(doc.errors).toEqual([]); + }); +}); diff --git a/web-common/src/features/custom-viz/extract/extract-component.ts b/web-common/src/features/custom-viz/extract/extract-component.ts new file mode 100644 index 000000000000..2bb90d5f18c3 --- /dev/null +++ b/web-common/src/features/custom-viz/extract/extract-component.ts @@ -0,0 +1,202 @@ +import type { ComponentRefComponent } from "@rilldata/web-common/features/canvas/components/component-ref"; +import type { + CustomChartComponent, + QueryFieldMeta, +} from "@rilldata/web-common/features/canvas/components/charts/custom-chart"; +import { + CUSTOM_VIZ_FOLDER, + getDeclaredParams, + substituteArgsRecursively, +} from "@rilldata/web-common/features/custom-viz/params"; +import { runtimeServicePutFile } from "@rilldata/web-common/runtime-client"; +import type { RuntimeClient } from "@rilldata/web-common/runtime-client/v2"; +import { get } from "svelte/store"; +import { Document } from "yaml"; + +/** + * Extraction and its inverse: converting an inline custom chart into a standalone, + * parameterized component ("Save as custom viz"), and materializing a component + * reference back into an inline custom chart ("Detach copy"). + * + * Extraction lifts params at the string level: the metrics view is templated by + * rewriting the FROM clause, and lifted fields by word-boundary replacement in both + * the metrics SQL and the Vega spec (Vega encodings reference the SQL output columns, + * so one replacement rule covers both). Anything ambiguous stays hardcoded and can be + * refined later in the component workspace. + */ + +export interface ExtractResult { + filePath: string; + componentName: string; +} + +export interface LiftedField extends QueryFieldMeta { + // Whether the field is the metrics view's time dimension. + isTimeDimension?: boolean; +} + +export function extractedComponentYAML( + spec: { metrics_sql?: string[]; vega_spec?: string }, + metricsViewName: string | undefined, + displayName: string, + liftedFields: LiftedField[], +): { yaml: string; bindings: Record } { + let metricsSQL = [...(spec.metrics_sql ?? [])]; + let vegaSpec = spec.vega_spec ?? ""; + + const params: Record[] = [ + { name: "metrics_view", type: "metrics_view", required: true }, + ]; + const bindings: Record = { metrics_view: metricsViewName }; + + if (metricsViewName) { + const fromClause = new RegExp( + `\\bFROM\\s+${escapeRegExp(metricsViewName)}\\b`, + "gi", + ); + metricsSQL = metricsSQL.map((sql) => + sql.replace(fromClause, "FROM {{ .params.metrics_view }}"), + ); + } + + const usedNames = new Set(["metrics_view"]); + for (const field of liftedFields) { + const paramName = uniqueParamName(sanitizeParamName(field.name), usedNames); + usedNames.add(paramName); + + params.push({ + name: paramName, + type: + field.type === "measure" + ? "measure" + : field.isTimeDimension + ? "time_dimension" + : "dimension", + required: true, + }); + bindings[paramName] = field.name; + + const token = new RegExp(`\\b${escapeRegExp(field.name)}\\b`, "g"); + const placeholder = `{{ .params.${paramName} }}`; + metricsSQL = metricsSQL.map((sql) => sql.replace(token, placeholder)); + vegaSpec = vegaSpec.replace(token, placeholder); + } + + const doc = new Document({ + type: "component", + display_name: displayName, + params, + custom_chart: { + metrics_sql: metricsSQL, + vega_spec: vegaSpec, + }, + }); + + return { yaml: doc.toString(), bindings }; +} + +/** + * Writes the extracted component to viz_library/.yaml and replaces the inline + * canvas item with a reference to it, preserving the item's width. + */ +export async function extractCustomChart( + client: RuntimeClient, + component: CustomChartComponent, + componentName: string, + displayName: string, + liftedFields: LiftedField[], +): Promise { + const { yaml, bindings } = extractedComponentYAML( + get(component.specStore), + component.metricsViewName, + displayName, + liftedFields, + ); + + const filePath = `/${CUSTOM_VIZ_FOLDER}/${componentName}.yaml`; + await runtimeServicePutFile(client, { + path: filePath, + blob: yaml, + create: true, + createOnly: true, + }); + + replaceItem(component, { component: componentName, params: bindings }); + + return { filePath, componentName }; +} + +/** + * The inverse of extraction: replaces a component reference with an inline custom + * chart whose param placeholders are materialized with the item's current bindings + * (declared defaults included). Other template namespaces (.env, .user) are preserved. + */ +export function detachComponentRef(component: ComponentRefComponent) { + const resource = get(component.resource); + const componentSpec = + resource?.component?.state?.validSpec ?? resource?.component?.spec; + if (!componentSpec?.rendererProperties) return; + + // Merge declared defaults under the bound values. + const args: Record = {}; + for (const param of getDeclaredParams(resource, true)) { + if (!param.name) continue; + if (param.default !== undefined && param.default !== null) { + args[param.name] = param.default; + } + } + Object.assign(args, component.args()); + + const inlineProps = substituteArgsRecursively( + componentSpec.rendererProperties, + args, + ) as Record; + + replaceItem(component, { + [componentSpec.renderer ?? "custom_chart"]: inlineProps, + }); +} + +/** + * Replaces the canvas item at the component's YAML path with the given item map, + * preserving its width. + */ +function replaceItem( + component: CustomChartComponent | ComponentRefComponent, + item: Record, +) { + const parent = component.parent; + if (!parent.fileArtifact) return; + const parsedDocument = get(parent.parsedContent); + + const itemPath = component.pathInYAML.slice(0, -1); + const width = parsedDocument.getIn([...itemPath, "width"]); + + parsedDocument.setIn(itemPath, { + ...item, + ...(width !== undefined ? { width } : {}), + }); + + parent.fileArtifact.updateEditorContent( + parsedDocument.toString(), + false, + true, + ); +} + +function sanitizeParamName(name: string): string { + const sanitized = name.replace(/\W/g, "_").replace(/^(\d)/, "_$1"); + return sanitized || "field"; +} + +function uniqueParamName(name: string, used: Set): string { + if (!used.has(name)) return name; + for (let i = 2; ; i++) { + const candidate = `${name}_${i}`; + if (!used.has(candidate)) return candidate; + } +} + +function escapeRegExp(value: string): string { + return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); +} diff --git a/web-common/src/features/custom-viz/params.spec.ts b/web-common/src/features/custom-viz/params.spec.ts new file mode 100644 index 000000000000..34264e48d5ff --- /dev/null +++ b/web-common/src/features/custom-viz/params.spec.ts @@ -0,0 +1,334 @@ +import type { + V1ComponentParam, + V1MetricsViewSpec, +} from "@rilldata/web-common/runtime-client"; +import { describe, expect, it } from "vitest"; +import { + buildDefaultArgs, + getDeclaredParams, + orderByOptions, + paramToInputParam, + prettyParamLabel, + reconcileOrderByArg, + substituteArgs, + substituteArgsRecursively, +} from "./params"; + +const params: V1ComponentParam[] = [ + { name: "metrics_view", type: "metrics_view", required: true }, + { + name: "measure", + type: "measure", + required: true, + metricsViewParam: "metrics_view", + }, + { + name: "dim", + type: "dimension", + metricsViewParam: "metrics_view", + }, + { + name: "time_dim", + type: "time_dimension", + required: true, + metricsViewParam: "metrics_view", + }, + { name: "limit", type: "number", default: 500 }, + { + name: "shape", + type: "string", + default: "line", + options: ["line", "area"], + }, + { name: "smooth", type: "boolean" }, +]; + +const metricsViewSpec: V1MetricsViewSpec = { + timeDimension: "ts", + dimensions: [ + { name: "country", type: "DIMENSION_TYPE_CATEGORICAL" }, + { name: "updated_at", type: "DIMENSION_TYPE_TIME" }, + { name: "device", type: "DIMENSION_TYPE_CATEGORICAL" }, + ], + measures: [{ name: "total" }, { name: "avg_price" }], +}; + +describe("paramToInputParam", () => { + it("maps param types to inspector input types", () => { + expect(paramToInputParam(params[0]).type).toBe("metrics"); + expect(paramToInputParam(params[1]).type).toBe("measure"); + expect(paramToInputParam(params[2]).type).toBe("dimension"); + expect(paramToInputParam(params[4]).type).toBe("number"); + expect(paramToInputParam(params[6]).type).toBe("boolean"); + }); + + it("maps time_dimension params to a time-constrained dimension picker", () => { + const input = paramToInputParam(params[3]); + expect(input.type).toBe("dimension"); + expect(input.meta?.includeTime).toBe(true); + expect(input.meta?.searchableItems).toEqual([]); + }); + + it("maps scalar params with options to a select", () => { + const input = paramToInputParam(params[5]); + expect(input.type).toBe("select"); + expect(input.meta?.options).toEqual([ + { value: "line", label: "line" }, + { value: "area", label: "area" }, + ]); + expect(input.meta?.default).toBe("line"); + }); + + it("marks required params as non-optional", () => { + expect(paramToInputParam(params[0]).optional).toBe(false); + expect(paramToInputParam(params[4]).optional).toBe(true); + }); +}); + +describe("buildDefaultArgs", () => { + it("computes smart defaults for each param type", () => { + const args = buildDefaultArgs(params, "mv1", metricsViewSpec); + expect(args).toEqual({ + metrics_view: "mv1", + measure: "total", + dim: "country", + time_dim: "ts", + limit: 500, + shape: "line", + // smooth has no default and stays unset + }); + }); + + it("does not reuse the same field for two params of the same type", () => { + const twoMeasures: V1ComponentParam[] = [ + { name: "m1", type: "measure", metricsViewParam: "metrics_view" }, + { name: "m2", type: "measure", metricsViewParam: "metrics_view" }, + ]; + const args = buildDefaultArgs(twoMeasures, "mv1", metricsViewSpec); + expect(args).toEqual({ m1: "total", m2: "avg_price" }); + }); + + it("skips time-typed dimensions for plain dimension params", () => { + const spec: V1MetricsViewSpec = { + dimensions: [ + { name: "updated_at", type: "DIMENSION_TYPE_TIME" }, + { name: "country", type: "DIMENSION_TYPE_CATEGORICAL" }, + ], + measures: [], + }; + const args = buildDefaultArgs( + [{ name: "dim", type: "dimension" }], + "mv1", + spec, + ); + expect(args).toEqual({ dim: "country" }); + }); + + it("leaves field params unset when the metrics view has no matching field", () => { + const args = buildDefaultArgs( + [ + { name: "metrics_view", type: "metrics_view" }, + { name: "time_dim", type: "time_dimension" }, + ], + "mv1", + { dimensions: [], measures: [] }, + ); + expect(args).toEqual({ metrics_view: "mv1" }); + }); + + it("defaults the order_by param to the bound measure", () => { + const args = buildDefaultArgs( + [ + { name: "metrics_view", type: "metrics_view", required: true }, + { name: "x_axis", type: "dimension", required: true }, + { name: "y_axis", type: "measure", required: true }, + { name: "order_by", type: "string", required: true }, + ], + "mv1", + metricsViewSpec, + ); + expect(args.order_by).toBe(args.y_axis); + expect(args.order_by).toBe("total"); + }); + + it("falls back to a bound dimension for order_by when there is no measure", () => { + const args = buildDefaultArgs( + [ + { name: "x_axis", type: "dimension", required: true }, + { name: "order_by", type: "string", required: true }, + ], + "mv1", + metricsViewSpec, + ); + expect(args.order_by).toBe("country"); + }); +}); + +describe("orderByOptions", () => { + it("offers the field values currently bound to the field params, deduped", () => { + const declared: V1ComponentParam[] = [ + { name: "metrics_view", type: "metrics_view" }, + { name: "x_axis", type: "dimension" }, + { name: "y_axis", type: "measure" }, + { name: "color", type: "measure" }, + { name: "order_by", type: "string" }, + { name: "limit", type: "number" }, + ]; + const options = orderByOptions(declared, { + metrics_view: "mv1", + x_axis: "country", + y_axis: "total", + color: "total", // duplicate value: appears once + order_by: "total", + limit: 10, + }); + expect(options.map((option) => option.value)).toEqual(["country", "total"]); + expect(options[0].label).toContain("X Axis"); + }); + + it("skips unbound field params", () => { + const options = orderByOptions([{ name: "x_axis", type: "dimension" }], {}); + expect(options).toEqual([]); + }); +}); + +describe("reconcileOrderByArg", () => { + const declared: V1ComponentParam[] = [ + { name: "metrics_view", type: "metrics_view", required: true }, + { name: "x_axis", type: "dimension", required: true }, + { name: "y_axis", type: "measure", required: true }, + { name: "order_by", type: "string", required: true }, + ]; + + it("follows a re-bound field that order_by pointed at", () => { + const args = { + x_axis: "country", + y_axis: "avg_price", // re-bound from "total" + order_by: "total", + }; + reconcileOrderByArg(declared, args, { + name: "y_axis", + previousValue: "total", + }); + expect(args.order_by).toBe("avg_price"); + }); + + it("follows a re-bound dimension too", () => { + const args = { x_axis: "device", y_axis: "total", order_by: "country" }; + reconcileOrderByArg(declared, args, { + name: "x_axis", + previousValue: "country", + }); + expect(args.order_by).toBe("device"); + }); + + it("keeps order_by when it points at a different, still-bound field", () => { + const args = { x_axis: "device", y_axis: "total", order_by: "total" }; + reconcileOrderByArg(declared, args, { + name: "x_axis", + previousValue: "country", + }); + expect(args.order_by).toBe("total"); + }); + + it("re-seeds from the measure when order_by no longer matches any bound field", () => { + // e.g. the metrics view changed and dependents were cleared around it. + const args: Record = { + x_axis: "device", + y_axis: "total", + order_by: "stale_field", + }; + reconcileOrderByArg(declared, args); + expect(args.order_by).toBe("total"); + }); + + it("does not override an explicit order_by change", () => { + const args = { x_axis: "country", y_axis: "total", order_by: "country" }; + reconcileOrderByArg(declared, args, { + name: "order_by", + previousValue: "total", + }); + expect(args.order_by).toBe("country"); + }); + + it("unsets order_by when no field is bound at all", () => { + const args: Record = { order_by: "total" }; + reconcileOrderByArg(declared, args); + expect(args.order_by).toBeUndefined(); + }); +}); + +describe("substituteArgs", () => { + it("substitutes .params and .args placeholders", () => { + expect( + substituteArgs( + "SELECT {{ .params.measure }} FROM {{ .args.metrics_view }} LIMIT {{.params.limit}}", + { measure: "total", metrics_view: "mv1", limit: 100 }, + ), + ).toBe("SELECT total FROM mv1 LIMIT 100"); + }); + + it("leaves unknown placeholders untouched", () => { + expect(substituteArgs("{{ .params.missing }}", {})).toBe( + "{{ .params.missing }}", + ); + }); + + it("does not substitute other template namespaces", () => { + expect(substituteArgs("{{ .env.name }}", { name: "x" })).toBe( + "{{ .env.name }}", + ); + }); + + it("substitutes repeated placeholders", () => { + expect( + substituteArgs("{{ .params.m }} + {{ .params.m }}", { m: "x" }), + ).toBe("x + x"); + }); +}); + +describe("substituteArgsRecursively", () => { + it("substitutes strings nested in maps and arrays", () => { + expect( + substituteArgsRecursively( + { + metrics_sql: ["SELECT {{ .params.m }} FROM mv"], + vega_spec: '{"title": "{{ .params.m }}"}', + count: 1, + }, + { m: "total" }, + ), + ).toEqual({ + metrics_sql: ["SELECT total FROM mv"], + vega_spec: '{"title": "total"}', + count: 1, + }); + }); +}); + +describe("getDeclaredParams", () => { + it("prefers the valid spec and falls back to the draft spec only when allowed", () => { + const resource = { + component: { + state: { validSpec: { params: [{ name: "a" }] } }, + spec: { params: [{ name: "b" }] }, + }, + }; + expect(getDeclaredParams(resource).map((p) => p.name)).toEqual(["a"]); + + const draftOnly = { + component: { spec: { params: [{ name: "b" }] } }, + }; + expect(getDeclaredParams(draftOnly)).toEqual([]); + expect(getDeclaredParams(draftOnly, true).map((p) => p.name)).toEqual([ + "b", + ]); + }); +}); + +describe("prettyParamLabel", () => { + it("converts snake_case to title case", () => { + expect(prettyParamLabel("metrics_view")).toBe("Metrics View"); + expect(prettyParamLabel("time_dim")).toBe("Time Dim"); + }); +}); diff --git a/web-common/src/features/custom-viz/params.ts b/web-common/src/features/custom-viz/params.ts new file mode 100644 index 000000000000..3ae2c4365705 --- /dev/null +++ b/web-common/src/features/custom-viz/params.ts @@ -0,0 +1,330 @@ +import type { ComponentInputParam } from "@rilldata/web-common/features/canvas/inspector/types"; +import { + MetricsViewSpecDimensionType, + type V1ComponentParam, + type V1MetricsViewSpec, + type V1Resource, +} from "@rilldata/web-common/runtime-client"; + +/** + * Utilities for working with the declared params of standalone (custom viz) components. + * A component declares typed params in its YAML (`params:`), and canvas items bind values + * to them (`params:` on the item). See runtime/parser/parse_component.go for the source + * of truth on param types and validation. + */ + +/** Project folder where custom viz component files are created by convention. */ +export const CUSTOM_VIZ_FOLDER = "viz_library"; + +export type ComponentParamType = + | "string" + | "number" + | "boolean" + | "metrics_view" + | "measure" + | "dimension" + | "time_dimension"; + +/** + * Reads the declared params from a component resource. + * This is the single accessor for the generated-client field so consumers stay + * insulated from the resource shape. + */ +export function getDeclaredParams( + resource: V1Resource | null | undefined, + allowUnvalidatedSpec = false, +): V1ComponentParam[] { + const component = resource?.component; + const spec = + component?.state?.validSpec ?? + (allowUnvalidatedSpec ? component?.spec : undefined); + return spec?.params ?? []; +} + +/** Whether a component resource declares params (i.e. is a parameterized custom viz). */ +export function hasDeclaredParams( + resource: V1Resource | null | undefined, + allowUnvalidatedSpec = false, +): boolean { + return getDeclaredParams(resource, allowUnvalidatedSpec).length > 0; +} + +/** Converts a snake_case param name into a human-friendly label. */ +export function prettyParamLabel(name = ""): string { + return name.replace(/_/g, " ").replace(/(^|\s)\w/g, (c) => c.toUpperCase()); +} + +/** + * Name convention for the sort-field param that generated components declare: + * a string param named "order_by" is rendered as a dropdown of the field values + * currently bound to the component's other params, and defaults to the measure. + */ +export const ORDER_BY_PARAM_NAME = "order_by"; + +const FIELD_PARAM_TYPES = new Set([ + "measure", + "dimension", + "time_dimension", +]); + +/** Whether a declared param is the by-convention sort-field selector. */ +export function isOrderByParam(param: V1ComponentParam): boolean { + return ( + param.name === ORDER_BY_PARAM_NAME && + (!param.type || param.type === "string") + ); +} + +/** + * Choices for the order_by param: the field values currently bound to the + * component's dimension/measure/time_dimension params. + */ +export function orderByOptions( + params: V1ComponentParam[], + args: Record, +): { value: string; label: string }[] { + const options: { value: string; label: string }[] = []; + const seen = new Set(); + for (const param of params) { + if (!param.name || !FIELD_PARAM_TYPES.has(param.type as ComponentParamType)) + continue; + const value = args[param.name]; + if (typeof value !== "string" || !value || seen.has(value)) continue; + seen.add(value); + options.push({ + value, + label: `${value} (${prettyParamLabel(param.name)})`, + }); + } + return options; +} + +/** + * Maps a declared param to the inspector input widget that edits it. + * The mapping targets the existing ParamMapper switchboard, so generated + * param forms render with the same widgets as built-in components. + */ +export function paramToInputParam( + param: V1ComponentParam, +): ComponentInputParam { + const common = { + label: prettyParamLabel(param.name), + optional: !param.required, + description: param.description, + }; + switch (param.type as ComponentParamType) { + case "metrics_view": + return { type: "metrics", ...common }; + case "measure": + return { type: "measure", ...common }; + case "dimension": + return { type: "dimension", ...common }; + case "time_dimension": + // A dimension picker restricted to the metrics view's time dimension. + return { + type: "dimension", + ...common, + meta: { includeTime: true, searchableItems: [] }, + }; + case "boolean": + return { + type: "boolean", + ...common, + meta: { defaultValue: param.default ?? false }, + }; + case "string": + case "number": + if (param.options?.length) { + return { + type: "select", + ...common, + meta: { + options: param.options.map((option) => ({ + value: option, + label: String(option), + })), + default: param.default, + }, + }; + } + return { type: param.type === "number" ? "number" : "text", ...common }; + default: + return { type: "text", ...common }; + } +} + +/** + * Computes best-guess default bindings for a component's declared params against a + * metrics view, mirroring the smart defaults used when adding built-in widgets: + * metrics_view params get the given metrics view, time_dimension params its time + * dimension, measure/dimension params the first unused field, and scalar params + * their declared default. + */ +export function buildDefaultArgs( + params: V1ComponentParam[], + metricsViewName: string | undefined, + metricsViewSpec: V1MetricsViewSpec | undefined, +): Record { + const args: Record = {}; + const usedFields = new Set(); + const timeDimension = metricsViewSpec?.timeDimension; + const dimensions = metricsViewSpec?.dimensions ?? []; + const measures = metricsViewSpec?.measures ?? []; + + for (const param of params) { + if (!param.name) continue; + if (param.default !== undefined && param.default !== null) { + args[param.name] = param.default; + continue; + } + switch (param.type as ComponentParamType) { + case "metrics_view": + if (metricsViewName) args[param.name] = metricsViewName; + break; + case "measure": { + const measure = measures.find( + (candidate) => candidate.name && !usedFields.has(candidate.name), + ); + if (measure?.name) { + args[param.name] = measure.name; + usedFields.add(measure.name); + } + break; + } + case "dimension": { + const dimension = dimensions.find( + (candidate) => + candidate.name && + !usedFields.has(candidate.name) && + candidate.name !== timeDimension && + candidate.type !== MetricsViewSpecDimensionType.DIMENSION_TYPE_TIME, + ); + if (dimension?.name) { + args[param.name] = dimension.name; + usedFields.add(dimension.name); + } + break; + } + case "time_dimension": + if (timeDimension) args[param.name] = timeDimension; + break; + default: + // Scalar params without a default stay unset. + break; + } + } + + // The by-convention order_by param defaults to the bound measure (falling + // back to any bound field) so generated Top-N queries sort sensibly. + const orderBy = params.find(isOrderByParam); + if (orderBy?.name && args[orderBy.name] === undefined) { + const value = defaultOrderByValue(params, args); + if (value) args[orderBy.name] = value; + } + + return args; +} + +/** + * Keeps the by-convention order_by binding in step when another param is + * re-bound: order_by follows the changed field when it pointed at its previous + * value, and otherwise is re-seeded from the measure when it no longer matches + * any bound field. Mutates and returns args. + */ +export function reconcileOrderByArg( + params: V1ComponentParam[], + args: Record, + changed?: { name: string; previousValue: unknown }, +): Record { + const orderBy = params.find(isOrderByParam); + if (!orderBy?.name) return args; + // The user picked order_by explicitly; nothing to reconcile. + if (changed?.name === orderBy.name) return args; + const current = args[orderBy.name]; + + // Follow a re-bound field param whose previous value order_by pointed at. + if (changed) { + const changedParam = params.find((param) => param.name === changed.name); + if ( + changedParam && + FIELD_PARAM_TYPES.has(changedParam.type as ComponentParamType) && + current !== undefined && + current === changed.previousValue && + typeof args[changed.name] === "string" + ) { + args[orderBy.name] = args[changed.name]; + return args; + } + } + + // Otherwise make sure it still matches a bound field; re-seed from the measure. + const valid = orderByOptions(params, args).map((option) => option.value); + if (typeof current !== "string" || !valid.includes(current)) { + const reseeded = defaultOrderByValue(params, args); + if (reseeded) args[orderBy.name] = reseeded; + else delete args[orderBy.name]; + } + return args; +} + +/** + * The default value for the order_by param given the currently bound field + * params: the measure's value, falling back to any other bound field. + */ +export function defaultOrderByValue( + params: V1ComponentParam[], + args: Record, +): string | undefined { + const boundFieldOf = (type: ComponentParamType) => + params.find( + (param) => + param.type === type && + param.name && + typeof args[param.name] === "string", + ); + const source = + boundFieldOf("measure") ?? + boundFieldOf("time_dimension") ?? + boundFieldOf("dimension"); + return source?.name ? (args[source.name] as string) : undefined; +} + +const TEMPLATE_ARG_REGEX = /\{\{\s*\.(?:params|args)\.(\w+)\s*\}\}/g; + +/** + * Client-side substitution of `{{ .params.x }}` (and its `.args.x` alias) placeholders. + * Only used for optimistic rendering before the server-resolved properties arrive; + * ResolveComponent is the authoritative resolution path. + */ +export function substituteArgs( + template: string, + args: Record, +): string { + return template.replace(TEMPLATE_ARG_REGEX, (match, name: string) => { + const value = args[name]; + return value === undefined || value === null ? match : String(value); + }); +} + +/** + * Applies substituteArgs to every string nested in the given value. + * Used to optimistically resolve a component's renderer properties client-side. + */ +export function substituteArgsRecursively( + value: unknown, + args: Record, +): unknown { + if (typeof value === "string") return substituteArgs(value, args); + if (Array.isArray(value)) { + return value.map((entry) => substituteArgsRecursively(entry, args)); + } + if (value && typeof value === "object") { + return Object.fromEntries( + Object.entries(value).map(([k, v]) => [ + k, + substituteArgsRecursively(v, args), + ]), + ); + } + return value; +} diff --git a/web-common/src/features/custom-viz/workspace/ComponentPreview.svelte b/web-common/src/features/custom-viz/workspace/ComponentPreview.svelte new file mode 100644 index 000000000000..a2a7646aab13 --- /dev/null +++ b/web-common/src/features/custom-viz/workspace/ComponentPreview.svelte @@ -0,0 +1,173 @@ + + +
+ {#if !componentSpec} + + {:else if renderer !== "custom_chart"} + + {:else if inlineSpec} +
+ {m.component_preview_sample_data()} + {#if $developerChat && filePath} + + {/if} +
+
+ +
+ {:else if $resolvedQuery.error && !optimisticProps} +
+ + {#if $developerChat && filePath} + + {/if} +
+ {:else} + +
+ +
+ {/if} +
diff --git a/web-common/src/features/custom-viz/workspace/ParamValueInput.svelte b/web-common/src/features/custom-viz/workspace/ParamValueInput.svelte new file mode 100644 index 000000000000..314ade2b405f --- /dev/null +++ b/web-common/src/features/custom-viz/workspace/ParamValueInput.svelte @@ -0,0 +1,170 @@ + + +{#if param.type === "metrics_view"} + onChange(next)} + /> +{:else if param.type === "boolean"} +
+ + onChange(next)} + /> +
+{:else if valueOptions?.length} + ({ + value: option as string, + label: String(option), + }))} + onChange={(next) => onChange(param.type === "number" ? Number(next) : next)} + /> +{:else} + +{/if} diff --git a/web-common/src/features/custom-viz/workspace/TestBindingsPanel.svelte b/web-common/src/features/custom-viz/workspace/TestBindingsPanel.svelte new file mode 100644 index 000000000000..aabbd9b0a9dd --- /dev/null +++ b/web-common/src/features/custom-viz/workspace/TestBindingsPanel.svelte @@ -0,0 +1,137 @@ + + +
+ {#if params.length === 0} +
+ {m.component_no_params()} +
+ {:else} +
+ {m.component_test_values()} +
+
+ {m.component_test_values_note()} +
+ {#each params as param (param.name)} +
+ setArg(param.name, value)} + /> + {#if param.description} +
+ {param.description} +
+ {/if} +
+ {/each} + {/if} +
diff --git a/web-common/src/features/custom-viz/workspace/UsedByPanel.svelte b/web-common/src/features/custom-viz/workspace/UsedByPanel.svelte new file mode 100644 index 000000000000..a7f5ef701327 --- /dev/null +++ b/web-common/src/features/custom-viz/workspace/UsedByPanel.svelte @@ -0,0 +1,95 @@ + + +
+
+ {m.component_used_by()} +
+ {#if usedBy.length === 0} +
+ {m.component_not_used()} +
+ {:else} + {#each usedBy as { resource, items } (resource.meta?.name?.name)} + {@const canvasName = resource.meta?.name?.name} + {@const filePath = resource.meta?.filePaths?.[0]} +
+
+ + {resource.canvas?.state?.validSpec?.displayName || canvasName} + + {#if items.length > 1} + ×{items.length} + {/if} +
+ {#each items as item, i (i)} + {#if item.params && Object.keys(item.params).length > 0} + + {/if} + {/each} +
+ {/each} + {/if} +
diff --git a/web-common/src/features/custom-viz/workspace/preview-state.ts b/web-common/src/features/custom-viz/workspace/preview-state.ts new file mode 100644 index 000000000000..ce9468b28e67 --- /dev/null +++ b/web-common/src/features/custom-viz/workspace/preview-state.ts @@ -0,0 +1,19 @@ +import { writable, type Writable } from "svelte/store"; + +/** + * Session-scoped test bindings for the component workspace preview, keyed by file path. + * These are dev-time values used to render the preview; they are never persisted to + * the component's YAML. + */ +const stores = new Map>>(); + +export function getPreviewArgsStore( + filePath: string, +): Writable> { + let store = stores.get(filePath); + if (!store) { + store = writable({}); + stores.set(filePath, store); + } + return store; +} diff --git a/web-common/src/features/entity-management/add/AddAssetButton.svelte b/web-common/src/features/entity-management/add/AddAssetButton.svelte index cb13eab6e678..0b62188443a2 100644 --- a/web-common/src/features/entity-management/add/AddAssetButton.svelte +++ b/web-common/src/features/entity-management/add/AddAssetButton.svelte @@ -27,6 +27,7 @@ import { useRuntimeClient } from "../../../runtime-client/v2"; import { useIsModelingSupportedForDefaultOlapDriverOLAP as useIsModelingSupportedForDefaultOlapDriver } from "../../connectors/selectors.ts"; import { directoryState } from "../../file-explorer/directory-store.ts"; + import VegaExamplesDialog from "@rilldata/web-common/features/custom-viz/examples/VegaExamplesDialog.svelte"; import { createResourceAndNavigate } from "./new-files.ts"; import AddAiConnectorDialog from "../../connectors/ai/AddAiConnectorDialog.svelte"; import CreateExploreDialog from "./CreateExploreDialog.svelte"; @@ -46,6 +47,7 @@ let showExploreDialog = false; let generateDataDialog = false; let showAiConnectorDialog = false; + let showVegaExamplesDialog = false; let addDataModalOpen = false; let addDataConnector = ""; let addDataTargetResource: ResourceKind | undefined; @@ -57,7 +59,7 @@ const createFile = createRuntimeServicePutFileMutation(runtimeClient); const createFolder = createRuntimeServiceCreateDirectoryMutation(runtimeClient); - const { developerChat } = featureFlags; + const { developerChat, customComponents } = featureFlags; $: currentFile = $page.params.file; $: currentDirectory = currentFile @@ -243,6 +245,18 @@
+ {#if $customComponents} + (showVegaExamplesDialog = true)} + > + + Custom viz + + {/if} More @@ -324,6 +338,10 @@ +{#if $customComponents} + +{/if} + + import { goto } from "$app/navigation"; + import { customYAMLwithJSONandSQL } from "@rilldata/web-common/components/editor/presets/yamlWithJsonAndSql"; + import Editor from "@rilldata/web-common/features/editor/Editor.svelte"; + import type { EditorView } from "@codemirror/view"; + import { handleEntityRename } from "@rilldata/web-common/features/entity-management/actions/ui-actions.ts"; + import { getNameFromFile } from "@rilldata/web-common/features/entity-management/entity-mappers"; + import type { FileArtifact } from "@rilldata/web-common/features/entity-management/file-artifact"; + import { + ResourceKind, + useFilteredResources, + } from "@rilldata/web-common/features/entity-management/resource-selectors"; + import ReconcileWarningPanel from "@rilldata/web-common/features/entity-management/ReconcileWarningPanel.svelte"; + import { sendComponentFilePrompt } from "@rilldata/web-common/features/custom-viz/component-ai-agent"; + import ComponentPreview from "@rilldata/web-common/features/custom-viz/workspace/ComponentPreview.svelte"; + import TestBindingsPanel from "@rilldata/web-common/features/custom-viz/workspace/TestBindingsPanel.svelte"; + import UsedByPanel from "@rilldata/web-common/features/custom-viz/workspace/UsedByPanel.svelte"; + import { featureFlags } from "@rilldata/web-common/features/feature-flags"; + import { getPreviewArgsStore } from "@rilldata/web-common/features/custom-viz/workspace/preview-state"; + import { getDeclaredParams } from "@rilldata/web-common/features/custom-viz/params"; + import SidebarWrapper from "@rilldata/web-common/features/visual-editing/SidebarWrapper.svelte"; + import { + Inspector, + WorkspaceContainer, + WorkspaceHeader, + } from "@rilldata/web-common/layout/workspace"; + import { workspaces } from "@rilldata/web-common/layout/workspace/workspace-stores"; + import WorkspaceEditorContainer from "@rilldata/web-common/layout/workspace/WorkspaceEditorContainer.svelte"; + import { m } from "@rilldata/web-common/lib/i18n/gen/messages"; + import { queryClient } from "@rilldata/web-common/lib/svelte-query/globalQueryClient"; + import type { V1ComponentParam } from "@rilldata/web-common/runtime-client"; + import { useRuntimeClient } from "@rilldata/web-common/runtime-client/v2"; + + export let fileArtifact: FileArtifact; + + const runtimeClient = useRuntimeClient(); + + const { developerChat } = featureFlags; + + let aiPrompt = ""; + let editor: EditorView | null = null; + + function askAI() { + const prompt = aiPrompt.trim(); + if (!prompt) return; + sendComponentFilePrompt(runtimeClient, filePath, prompt); + aiPrompt = ""; + } + + $: ({ + autoSave, + path: filePath, + fileName, + getResource, + remoteContent, + hasUnsavedChanges, + } = fileArtifact); + + $: resourceQuery = getResource(queryClient); + $: ({ data: resource } = $resourceQuery); + + $: componentName = getNameFromFile(filePath); + + $: workspace = workspaces.get(filePath); + $: selectedViewStore = workspace.view; + $: selectedView = $selectedViewStore ?? "code"; + + $: parseErrorQuery = fileArtifact.getParseError(queryClient); + $: parseError = $parseErrorQuery; + + $: argsStore = getPreviewArgsStore(filePath); + + // Breaking-change warning: the component is used by dashboards, and the draft + // spec removes, retypes, or adds a required param compared to the valid spec. + $: canvasesQuery = useFilteredResources(runtimeClient, ResourceKind.Canvas); + $: usedByCount = ($canvasesQuery?.data ?? []).filter((res) => + (res.meta?.refs ?? []).some( + (ref) => + ref.kind === ResourceKind.Component && ref.name === componentName, + ), + ).length; + $: validParams = resource?.component?.state?.validSpec?.params ?? []; + $: draftParams = getDeclaredParams(resource, true); + $: showBreakingWarning = + usedByCount > 0 && + validParams.length > 0 && + isBreakingChange(validParams, draftParams); + + function isBreakingChange( + valid: V1ComponentParam[], + draft: V1ComponentParam[], + ): boolean { + const draftByName = new Map(draft.map((p) => [p.name, p])); + for (const param of valid) { + const draftParam = draftByName.get(param.name); + if (!draftParam || draftParam.type !== param.type) return true; + } + for (const param of draft) { + const isNew = !valid.some((v) => v.name === param.name); + if (isNew && param.required) return true; + } + return false; + } + + async function onChangeCallback(newTitle: string) { + const newRoute = await handleEntityRename( + runtimeClient, + newTitle, + filePath, + fileName, + ); + if (newRoute) await goto(newRoute); + } + + + + + + +
+ {#if showBreakingWarning} +
+ {m.component_breaking_warning({ count: String(usedByCount) })} +
+ {/if} +
+ + + {#if selectedView === "code"} + + {:else} + + {/if} + +
+ +
+
+ + + + + {#if $developerChat} +
+ +
+ {/if} + + +
+
+
+
diff --git a/web-common/src/features/workspaces/WorkspaceDispatcher.svelte b/web-common/src/features/workspaces/WorkspaceDispatcher.svelte index b625f965687c..93c2c7de416f 100644 --- a/web-common/src/features/workspaces/WorkspaceDispatcher.svelte +++ b/web-common/src/features/workspaces/WorkspaceDispatcher.svelte @@ -4,13 +4,16 @@ import { customYAMLwithJSONandSQL } from "@rilldata/web-common/components/editor/presets/yamlWithJsonAndSql"; import { GeneratingMessage } from "@rilldata/web-common/components/generating-message"; import { generatingCanvasFilePath } from "@rilldata/web-common/features/canvas/ai-generation/generateCanvas"; + import { generatingComponentFilePath } from "@rilldata/web-common/features/custom-viz/examples/import-with-ai"; import Editor from "@rilldata/web-common/features/editor/Editor.svelte"; import FileWorkspaceHeader from "@rilldata/web-common/features/editor/FileWorkspaceHeader.svelte"; import { getExtensionsForFile } from "@rilldata/web-common/features/editor/getExtensionsForFile"; import { ResourceKind } from "@rilldata/web-common/features/entity-management/resource-selectors"; import { directoryState } from "@rilldata/web-common/features/file-explorer/directory-store"; import type { FileArtifact } from "@rilldata/web-common/features/entity-management/file-artifact"; + import { featureFlags } from "@rilldata/web-common/features/feature-flags"; import CanvasWorkspace from "@rilldata/web-common/features/workspaces/CanvasWorkspace.svelte"; + import ComponentWorkspace from "@rilldata/web-common/features/workspaces/ComponentWorkspace.svelte"; import ExploreWorkspace from "@rilldata/web-common/features/workspaces/ExploreWorkspace.svelte"; import MetricsWorkspace from "@rilldata/web-common/features/workspaces/MetricsWorkspace.svelte"; import ModelWorkspace from "@rilldata/web-common/features/workspaces/ModelWorkspace.svelte"; @@ -52,8 +55,13 @@ let resourceKind = $derived($resourceName?.kind as ResourceKind | undefined); + const { customComponents } = featureFlags; + let WorkspaceComponent = $derived( - workspaces.get(resourceKind ?? $inferredResourceKind), + (resourceKind ?? $inferredResourceKind) === ResourceKind.Component && + $customComponents + ? ComponentWorkspace + : workspaces.get(resourceKind ?? $inferredResourceKind), ); let resourceQuery = $derived(getResource(queryClient)); @@ -69,6 +77,9 @@ let parseError = $derived($parseErrorQuery); let isGeneratingThisFile = $derived($generatingCanvasFilePath === path); + let isImportingThisComponent = $derived( + $generatingComponentFilePath === path, + ); onMount(() => { expandDirectory(path); @@ -92,6 +103,8 @@
{#if isGeneratingThisFile} + {:else if isImportingThisComponent} + {:else if fileArtifact.isPreviewableDataFile} {:else if WorkspaceComponent} diff --git a/web-common/src/layout/workspace/WorkspaceEditorContainer.svelte b/web-common/src/layout/workspace/WorkspaceEditorContainer.svelte index adc00456d95a..672d0820aaa5 100644 --- a/web-common/src/layout/workspace/WorkspaceEditorContainer.svelte +++ b/web-common/src/layout/workspace/WorkspaceEditorContainer.svelte @@ -56,10 +56,12 @@ >
-
- {effectiveError} +
+ {effectiveError} {#if filePath} - + + + {/if}
diff --git a/web-common/src/lib/i18n/messages/en.json b/web-common/src/lib/i18n/messages/en.json index 5df177470ab4..43680a49a5b5 100644 --- a/web-common/src/lib/i18n/messages/en.json +++ b/web-common/src/lib/i18n/messages/en.json @@ -362,9 +362,47 @@ "canvas_column_dimensions_label": "Column dimensions", "canvas_columns_label": "Columns", "canvas_comparison_values_label": "Comparison values", + "component_ai_placeholder": "Describe a change and press Enter to edit with AI…", + "component_connect_with_ai": "Connect to your data with AI", + "component_example_imported": "Imported example as {path}", + "component_examples_all": "All examples", + "component_examples_description": "Import an example as a starting point, then connect it to your data in the component editor.", + "component_examples_empty": "No examples match your search", + "component_examples_start_blank": "Start blank", + "component_examples_title": "Vega-Lite examples", + "component_breaking_warning": "Used by {count} dashboard(s) — removing, retyping, or adding required params will break their bindings.", + "component_detach_menu_item": "Detach copy", + "component_extract_cta": "Save component", + "component_extract_description": "Creates a reusable component file and replaces this widget with a reference to it. The dashboard will render identically.", + "component_extract_fields_label": "Parameterize fields", + "component_extract_fields_note": "Checked fields become params that each dashboard can bind to its own fields. Unchecked fields stay hardcoded.", + "component_extract_menu_item": "Save as custom viz…", + "component_extract_name_invalid": "Use only letters, numbers, dashes and underscores", + "component_extract_name_label": "Component name", + "component_extract_name_required": "Name is required", + "component_extract_name_taken": "A component with this name already exists", + "component_extract_success": "Saved as viz_library/{name}.yaml", + "component_extract_title": "Save as custom viz", + "component_fix_with_ai": "Fix with AI", + "component_copy_bindings": "Use this dashboard's values", + "component_no_params": "Declare params to make this component reusable across dashboards.", + "component_not_used": "Not used by any dashboards yet", + "component_preview_no_spec": "Add a renderer (e.g. custom_chart) to preview this component", + "component_preview_sample_data": "Previewing with the spec's inline sample data", + "component_preview_title": "Preview", + "component_test_values": "Test values", + "component_test_values_note": "Preview-only bindings; dashboards set their own values.", + "component_used_by": "Used by", + "canvas_component_ref_edit_note": "Edits affect all dashboards using this component.", + "canvas_component_ref_missing": "Component \"{name}\" not found", + "canvas_component_ref_unsupported_renderer": "Components with renderer \"{renderer}\" cannot be referenced on a canvas yet", "canvas_configuration": "{label} Configuration", "canvas_configurations": "Canvas configurations", "canvas_custom_chart": "Custom Chart", + "canvas_custom_viz": "Custom viz", + "canvas_edit_component": "Edit component", + "canvas_no_components_yet": "No custom viz in this project yet", + "canvas_your_components": "Your components", "canvas_data_labels_label": "Data labels", "canvas_delete": "Delete", "canvas_delete_dashboard_desc": "The dashboard \"{name}\" will be permanently deleted. This action cannot be undone.", diff --git a/web-common/src/lib/i18n/messages/es.json b/web-common/src/lib/i18n/messages/es.json index 089440a67a01..4c57df9a0bf4 100644 --- a/web-common/src/lib/i18n/messages/es.json +++ b/web-common/src/lib/i18n/messages/es.json @@ -362,9 +362,47 @@ "canvas_column_dimensions_label": "Dimensiones de columna", "canvas_columns_label": "Columnas", "canvas_comparison_values_label": "Valores de comparación", + "component_ai_placeholder": "Describe un cambio y pulsa Enter para editar con IA…", + "component_connect_with_ai": "Conecta tus datos con IA", + "component_example_imported": "Ejemplo importado como {path}", + "component_examples_all": "Todos los ejemplos", + "component_examples_description": "Importa un ejemplo como punto de partida y luego conéctalo a tus datos en el editor de componentes.", + "component_examples_empty": "Ningún ejemplo coincide con tu búsqueda", + "component_examples_start_blank": "Empezar en blanco", + "component_examples_title": "Ejemplos de Vega-Lite", + "component_breaking_warning": "Usado por {count} dashboard(s) — eliminar, cambiar el tipo o añadir params obligatorios romperá sus vinculaciones.", + "component_detach_menu_item": "Separar copia", + "component_extract_cta": "Guardar componente", + "component_extract_description": "Crea un archivo de componente reutilizable y reemplaza este widget por una referencia. El dashboard se renderizará igual.", + "component_extract_fields_label": "Parametrizar campos", + "component_extract_fields_note": "Los campos marcados se convierten en params que cada dashboard puede vincular a sus propios campos. Los no marcados quedan fijos.", + "component_extract_menu_item": "Guardar como visualización personalizada…", + "component_extract_name_invalid": "Usa solo letras, números, guiones y guiones bajos", + "component_extract_name_label": "Nombre del componente", + "component_extract_name_required": "El nombre es obligatorio", + "component_extract_name_taken": "Ya existe un componente con este nombre", + "component_extract_success": "Guardado como viz_library/{name}.yaml", + "component_extract_title": "Guardar como visualización personalizada", + "component_fix_with_ai": "Corregir con IA", + "component_copy_bindings": "Usar los valores de este dashboard", + "component_no_params": "Declara params para que este componente sea reutilizable en dashboards.", + "component_not_used": "Aún no se usa en ningún dashboard", + "component_preview_no_spec": "Añade un renderizador (p. ej. custom_chart) para previsualizar este componente", + "component_preview_sample_data": "Vista previa con los datos de ejemplo del spec", + "component_preview_title": "Vista previa", + "component_test_values": "Valores de prueba", + "component_test_values_note": "Vinculaciones solo para la vista previa; los dashboards definen sus propios valores.", + "component_used_by": "Usado por", + "canvas_component_ref_edit_note": "Los cambios afectan a todos los dashboards que usan este componente.", + "canvas_component_ref_missing": "Componente \"{name}\" no encontrado", + "canvas_component_ref_unsupported_renderer": "Los componentes con renderizador \"{renderer}\" aún no se pueden referenciar en un canvas", "canvas_configuration": "Configuración de {label}", "canvas_configurations": "Configuraciones del canvas", "canvas_custom_chart": "Gráfico personalizado", + "canvas_custom_viz": "Visualización personalizada", + "canvas_edit_component": "Editar componente", + "canvas_no_components_yet": "Todavía no hay visualizaciones personalizadas en este proyecto", + "canvas_your_components": "Tus componentes", "canvas_data_labels_label": "Etiquetas de datos", "canvas_delete": "Eliminar", "canvas_delete_dashboard_desc": "El dashboard \"{name}\" será eliminado permanentemente. Esta acción no se puede deshacer.", diff --git a/web-common/src/proto/gen/rill/runtime/v1/queries_pb.ts b/web-common/src/proto/gen/rill/runtime/v1/queries_pb.ts index 2f0d7234ed4c..39470eceac7e 100644 --- a/web-common/src/proto/gen/rill/runtime/v1/queries_pb.ts +++ b/web-common/src/proto/gen/rill/runtime/v1/queries_pb.ts @@ -4445,6 +4445,13 @@ export class ResolveComponentResponse extends Message */ rendererProperties?: Struct; + /** + * The effective args used for resolution: the component's declared param defaults merged with the provided args. + * + * @generated from field: google.protobuf.Struct resolved_args = 3; + */ + resolvedArgs?: Struct; + constructor(data?: PartialMessage) { super(); proto3.util.initPartial(data, this); @@ -4454,6 +4461,7 @@ export class ResolveComponentResponse extends Message static readonly typeName = "rill.runtime.v1.ResolveComponentResponse"; static readonly fields: FieldList = proto3.util.newFieldList(() => [ { no: 2, name: "renderer_properties", kind: "message", T: Struct }, + { no: 3, name: "resolved_args", kind: "message", T: Struct }, ]); static fromBinary(bytes: Uint8Array, options?: Partial): ResolveComponentResponse { diff --git a/web-common/src/proto/gen/rill/runtime/v1/resources_pb.ts b/web-common/src/proto/gen/rill/runtime/v1/resources_pb.ts index f184c32bbdad..6c7bb6caae85 100644 --- a/web-common/src/proto/gen/rill/runtime/v1/resources_pb.ts +++ b/web-common/src/proto/gen/rill/runtime/v1/resources_pb.ts @@ -4786,6 +4786,14 @@ export class ComponentSpec extends Message { */ rendererProperties?: Struct; + /** + * Declared parameters that canvases can bind values to when referencing this component. + * Bound values are available in the renderer properties' templating as {{ .params. }}. + * + * @generated from field: repeated rill.runtime.v1.ComponentParam params = 10; + */ + params: ComponentParam[] = []; + /** * @generated from field: repeated rill.runtime.v1.ComponentVariable input = 8; */ @@ -4813,6 +4821,7 @@ export class ComponentSpec extends Message { { no: 7, name: "description", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 4, name: "renderer", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 5, name: "renderer_properties", kind: "message", T: Struct }, + { no: 10, name: "params", kind: "message", T: ComponentParam, repeated: true }, { no: 8, name: "input", kind: "message", T: ComponentVariable, repeated: true }, { no: 9, name: "output", kind: "message", T: ComponentVariable }, { no: 6, name: "defined_in_canvas", kind: "scalar", T: 8 /* ScalarType.BOOL */ }, @@ -4932,6 +4941,97 @@ export class ComponentVariable extends Message { } } +/** + * ComponentParam declares a typed, validated parameter of a component. + * + * @generated from message rill.runtime.v1.ComponentParam + */ +export class ComponentParam extends Message { + /** + * Param name. Must be a valid identifier; referenced in templates as {{ .params. }}. + * + * @generated from field: string name = 1; + */ + name = ""; + + /** + * Param type. One of: "string", "number", "boolean", "metrics_view", "measure", "dimension", "time_dimension". + * + * @generated from field: string type = 2; + */ + type = ""; + + /** + * Human-facing description of the param. + * + * @generated from field: string description = 3; + */ + description = ""; + + /** + * If true, a canvas item referencing this component must bind a value for the param. + * + * @generated from field: bool required = 4; + */ + required = false; + + /** + * Default value used when the param is not bound. Mutually exclusive with required=true. + * + * @generated from field: google.protobuf.Value default = 5; + */ + default?: Value; + + /** + * For "measure", "dimension" and "time_dimension" params: + * the name of a sibling param of type "metrics_view" whose bound metrics view the field must belong to. + * May be omitted when exactly one "metrics_view" param is declared, in which case the parser fills it in. + * + * @generated from field: string metrics_view_param = 6; + */ + metricsViewParam = ""; + + /** + * For scalar params: allowed values. Renders as a select input in visual editors. + * + * @generated from field: repeated google.protobuf.Value options = 7; + */ + options: Value[] = []; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "rill.runtime.v1.ComponentParam"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "name", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "type", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 3, name: "description", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 4, name: "required", kind: "scalar", T: 8 /* ScalarType.BOOL */ }, + { no: 5, name: "default", kind: "message", T: Value }, + { no: 6, name: "metrics_view_param", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 7, name: "options", kind: "message", T: Value, repeated: true }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): ComponentParam { + return new ComponentParam().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): ComponentParam { + return new ComponentParam().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): ComponentParam { + return new ComponentParam().fromJsonString(jsonString, options); + } + + static equals(a: ComponentParam | PlainMessage | undefined, b: ComponentParam | PlainMessage | undefined): boolean { + return proto3.util.equals(ComponentParam, a, b); + } +} + /** * @generated from message rill.runtime.v1.Canvas */ @@ -5389,6 +5489,14 @@ export class CanvasItem extends Message { */ definedInCanvas = false; + /** + * Values bound to the referenced component's declared params. + * Only set for items that reference an externally defined component. + * + * @generated from field: google.protobuf.Struct params = 11; + */ + params?: Struct; + /** * Width of the item. The unit is given in width_unit. * @@ -5413,6 +5521,7 @@ export class CanvasItem extends Message { static readonly fields: FieldList = proto3.util.newFieldList(() => [ { no: 1, name: "component", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 8, name: "defined_in_canvas", kind: "scalar", T: 8 /* ScalarType.BOOL */ }, + { no: 11, name: "params", kind: "message", T: Struct }, { no: 9, name: "width", kind: "scalar", T: 13 /* ScalarType.UINT32 */, opt: true }, { no: 10, name: "width_unit", kind: "scalar", T: 9 /* ScalarType.STRING */ }, ]); diff --git a/web-common/src/runtime-client/gen/index.schemas.ts b/web-common/src/runtime-client/gen/index.schemas.ts index d88198f6949b..365a05c4226b 100644 --- a/web-common/src/runtime-client/gen/index.schemas.ts +++ b/web-common/src/runtime-client/gen/index.schemas.ts @@ -414,11 +414,16 @@ export interface V1Canvas { state?: V1CanvasState; } +export type V1CanvasItemParams = { [key: string]: unknown }; + export interface V1CanvasItem { /** Name of the component to render. */ component?: string; /** Indicates if the component was defined inline as part of the canvas YAML. */ definedInCanvas?: boolean; + /** Values bound to the referenced component's declared params. +Only set for items that reference an externally defined component. */ + params?: V1CanvasItemParams; /** Width of the item. The unit is given in width_unit. */ width?: number; /** Unit of the width. Current possible values: empty string. */ @@ -699,11 +704,31 @@ export interface V1ComponentSpec { description?: string; renderer?: string; rendererProperties?: V1ComponentSpecRendererProperties; + /** Declared parameters that canvases can bind values to when referencing this component. */ + params?: V1ComponentParam[]; input?: V1ComponentVariable[]; output?: V1ComponentVariable; definedInCanvas?: boolean; } +/** ComponentParam declares a typed, validated parameter of a component. */ +export interface V1ComponentParam { + /** Param name. Must be a valid identifier; referenced in templates as {{ .params. }}. */ + name?: string; + /** Param type. One of: "string", "number", "boolean", "metrics_view", "measure", "dimension", "time_dimension". */ + type?: string; + /** Human-facing description of the param. */ + description?: string; + /** If true, a canvas item referencing this component must bind a value. */ + required?: boolean; + /** Default value used when the param is not bound. Mutually exclusive with required=true. */ + default?: unknown; + /** For field-typed params: the name of a sibling param of type "metrics_view" whose bound metrics view the field must belong to. */ + metricsViewParam?: string; + /** For scalar params: allowed values. Renders as a select input in visual editors. */ + options?: unknown[]; +} + export interface V1ComponentState { validSpec?: V1ComponentSpec; /** The last time any underlying metrics view(s)'s data was refreshed. @@ -2305,8 +2330,14 @@ export type V1ResolveComponentResponseRendererProperties = { [key: string]: unknown; }; +export type V1ResolveComponentResponseResolvedArgs = { + [key: string]: unknown; +}; + export interface V1ResolveComponentResponse { rendererProperties?: V1ResolveComponentResponseRendererProperties; + /** The effective args used for resolution: the component's declared param defaults merged with the provided args. */ + resolvedArgs?: V1ResolveComponentResponseResolvedArgs; } export interface V1ResolveTemplatedStringResponse { diff --git a/web-common/tests/projects/AdBidsComponents/.gitignore b/web-common/tests/projects/AdBidsComponents/.gitignore new file mode 100644 index 000000000000..b527f7f86b09 --- /dev/null +++ b/web-common/tests/projects/AdBidsComponents/.gitignore @@ -0,0 +1,5 @@ +.DS_Store + +# Rill +.env +tmp diff --git a/web-common/tests/projects/AdBidsComponents/dashboards/AdBids_metrics_canvas.yaml b/web-common/tests/projects/AdBidsComponents/dashboards/AdBids_metrics_canvas.yaml new file mode 100644 index 000000000000..c5b199c7ed56 --- /dev/null +++ b/web-common/tests/projects/AdBidsComponents/dashboards/AdBids_metrics_canvas.yaml @@ -0,0 +1,65 @@ +# Explore YAML +# Reference documentation: https://docs.rilldata.com/reference/project-files/canvas-dashboards + +type: canvas +display_name: "Adbids Canvas Dashboard" +defaults: + time_range: PT24H + comparison_mode: time +rows: + - items: + - kpi_grid: + metrics_view: AdBids_metrics + measures: + - total_records + - bid_price_sum + comparison: + - delta + - percent_change + width: 12 + height: 128px + - items: + - stacked_bar: + metrics_view: AdBids_metrics + x: + type: temporal + field: timestamp + sort: -y + limit: 20 + y: + type: quantitative + field: total_records + zeroBasedOrigin: true + color: hsl(240,100%,67%) + width: 12 + height: 320px + - items: + - stacked_bar: + metrics_view: AdBids_metrics + title: "" + description: "" + color: + field: domain + type: nominal + x: + field: publisher + limit: 20 + sort: -y + type: nominal + y: + field: bid_price_sum + type: quantitative + zeroBasedOrigin: true + width: 12 + height: 394px + - items: + - table: + metrics_view: AdBids_metrics + columns: + - publisher + - domain + - total_records + - bid_price_sum + title: Table component + width: 12 + height: 300px diff --git a/web-common/tests/projects/AdBidsComponents/dashboards/AdBids_metrics_explore.yaml b/web-common/tests/projects/AdBidsComponents/dashboards/AdBids_metrics_explore.yaml new file mode 100644 index 000000000000..34369cf3bf91 --- /dev/null +++ b/web-common/tests/projects/AdBidsComponents/dashboards/AdBids_metrics_explore.yaml @@ -0,0 +1,29 @@ +# Explore YAML +# Reference documentation: https://docs.rilldata.com/reference/project-files/explore-dashboards + +type: explore + +title: "Adbids dashboard" +metrics_view: AdBids_metrics + +dimensions: '*' +measures: '*' + +time_ranges: + - PT6H + - PT24H + - P7D + - P14D + - P4W + - P12M + - rill-TD + - rill-WTD + - rill-MTD + - rill-QTD + - rill-YTD + - rill-PDC + - rill-PWC + - rill-PMC + - rill-PQC + - rill-PYC + - inf \ No newline at end of file diff --git a/web-common/tests/projects/AdBidsComponents/data/AdBids.csv.gz b/web-common/tests/projects/AdBidsComponents/data/AdBids.csv.gz new file mode 100644 index 000000000000..da5ba5845b1e Binary files /dev/null and b/web-common/tests/projects/AdBidsComponents/data/AdBids.csv.gz differ diff --git a/web-common/tests/projects/AdBidsComponents/metrics/AdBids_metrics.yaml b/web-common/tests/projects/AdBidsComponents/metrics/AdBids_metrics.yaml new file mode 100644 index 000000000000..9f33fe700bfe --- /dev/null +++ b/web-common/tests/projects/AdBidsComponents/metrics/AdBids_metrics.yaml @@ -0,0 +1,37 @@ +# Metrics view YAML +# Reference documentation: https://docs.rilldata.com/reference/project-files/metrics-views + +version: 1 +type: metrics_view + +display_name: Adbids +table: AdBids_model +timeseries: timestamp + +dimensions: + - name: publisher + display_name: Publisher + column: publisher + - name: domain + display_name: Domain + column: domain + - name: timestamp + display_name: Timestamp + column: timestamp + type: time + - name: offset_timestamp + display_name: Offset Timestamp + column: offset_timestamp + type: time + +measures: + - name: total_records + display_name: Total records + expression: COUNT(*) + description: "" + format_preset: humanize + - name: bid_price_sum + display_name: Sum of Bid Price + expression: SUM(bid_price) + description: "" + format_preset: humanize diff --git a/web-common/tests/projects/AdBidsComponents/models/AdBids_model.sql b/web-common/tests/projects/AdBidsComponents/models/AdBids_model.sql new file mode 100644 index 000000000000..48acb6a05777 --- /dev/null +++ b/web-common/tests/projects/AdBidsComponents/models/AdBids_model.sql @@ -0,0 +1,5 @@ +select + *, + -- Add an offset timestamp that is 7 days earlier than the primary timestamp + "timestamp" - INTERVAL '7 days' as offset_timestamp +from AdBids diff --git a/web-common/tests/projects/AdBidsComponents/rill.yaml b/web-common/tests/projects/AdBidsComponents/rill.yaml new file mode 100644 index 000000000000..5db3a395b884 --- /dev/null +++ b/web-common/tests/projects/AdBidsComponents/rill.yaml @@ -0,0 +1,7 @@ +compiler: rillv1 + +display_name: "Untitled Rill Project" + +features: + chat: false + customComponents: true diff --git a/web-common/tests/projects/AdBidsComponents/sources/AdBids.yaml b/web-common/tests/projects/AdBidsComponents/sources/AdBids.yaml new file mode 100644 index 000000000000..070e7d310c09 --- /dev/null +++ b/web-common/tests/projects/AdBidsComponents/sources/AdBids.yaml @@ -0,0 +1,8 @@ +# Model YAML +# Reference documentation: https://docs.rilldata.com/reference/project-files/models + +type: model +materialize: true + +connector: "duckdb" +sql: "select * from read_csv('data/AdBids.csv.gz', auto_detect=true, ignore_errors=1, header=true)" \ No newline at end of file diff --git a/web-common/tests/projects/AdBidsComponents/viz_library/measure_trend.yaml b/web-common/tests/projects/AdBidsComponents/viz_library/measure_trend.yaml new file mode 100644 index 000000000000..008dcb090f3e --- /dev/null +++ b/web-common/tests/projects/AdBidsComponents/viz_library/measure_trend.yaml @@ -0,0 +1,33 @@ +type: component +display_name: Measure trend +description: Line chart of any measure over a time dimension. + +params: + - name: metrics_view + type: metrics_view + required: true + - name: measure + type: measure + required: true + - name: time_dim + type: time_dimension + required: true + +custom_chart: + metrics_sql: | + SELECT {{ .params.time_dim }}, {{ .params.measure }} + FROM {{ .params.metrics_view }} + ORDER BY {{ .params.time_dim }} + vega_spec: | + { + "$schema": "https://vega.github.io/schema/vega-lite/v5.json", + "width": "container", + "height": "container", + "autosize": {"type": "fit"}, + "data": {"name": "query1"}, + "mark": "line", + "encoding": { + "x": {"field": "{{ .params.time_dim }}", "type": "temporal"}, + "y": {"field": "{{ .params.measure }}", "type": "quantitative"} + } + } diff --git a/web-local/tests/components/custom-viz.spec.ts b/web-local/tests/components/custom-viz.spec.ts new file mode 100644 index 000000000000..ccb1406f648f --- /dev/null +++ b/web-local/tests/components/custom-viz.spec.ts @@ -0,0 +1,141 @@ +import { expect } from "@playwright/test"; +import { test } from "../setup/base"; + +test.describe("custom viz components", () => { + test.use({ project: "AdBidsComponents" }); + + test("can create a blank custom viz with a workspace and test bindings", async ({ + page, + }) => { + await page.getByLabel("Add asset").waitFor({ state: "visible" }); + await page.getByLabel("Add asset").click(); + + // "Custom viz" opens the examples gallery directly; "Start blank" sits in + // its header for the from-scratch path. + await page.getByRole("menuitem", { name: "Custom viz" }).click(); + await page.getByRole("button", { name: "Start blank" }).click(); + + // Lands on the new component file in the component workspace. + await expect(page).toHaveURL(/viz_library\/component\.yaml/); + + // The inspector shows the declared params as test bindings. + await expect(page.getByText("Test values")).toBeVisible(); + await expect(page.getByText("Metrics View", { exact: true })).toBeVisible(); + await expect(page.getByText("Measure", { exact: true })).toBeVisible(); + await expect(page.getByText("Dimension", { exact: true })).toBeVisible(); + + // The pre-existing component is not used by any dashboards yet. + await expect(page.getByText("Used by", { exact: true })).toBeVisible(); + + // The workspace opens in the visual view by default; the preview renders a + // chart against the auto-selected metrics view and test bindings. + await expect( + page.locator(".vega-embed svg, .vega-embed canvas"), + ).toBeVisible({ timeout: 15_000 }); + + // Switching to the code view shows the starter YAML. + await page.getByLabel("Switch to code editor").click(); + await expect(page.getByText("type: component")).toBeVisible(); + }); + + test("can add a custom viz to a canvas with generated param inputs", async ({ + page, + }) => { + await page.getByLabel("Add asset").waitFor({ state: "visible" }); + await page.getByLabel("Add asset").click(); + await page.getByRole("menuitem", { name: "Canvas dashboard" }).click(); + + await page + .getByRole("button", { name: "Add widget" }) + .waitFor({ state: "visible" }); + await page.getByRole("button", { name: "Add widget" }).click(); + + // The project's standalone components are listed in their own section. + await page.getByRole("menuitem", { name: "Your components" }).hover(); + await page.getByRole("menuitem", { name: "Measure trend" }).click(); + + // The inspector shows the generated param form with smart defaults bound. + await expect(page.getByText("Metrics View", { exact: true })).toBeVisible(); + await expect(page.getByText("Measure", { exact: true })).toBeVisible(); + await expect(page.getByText("Time Dim", { exact: true })).toBeVisible(); + + // The referenced component's header links to editing the component file. + await expect(page.getByText("Edit component")).toBeVisible(); + await expect( + page.getByText("Edits affect all dashboards using this component."), + ).toBeVisible(); + + // The referenced chart renders. + await expect( + page.locator(".vega-embed svg, .vega-embed canvas").first(), + ).toBeVisible({ timeout: 15_000 }); + }); + + test("can reference the same component twice with different bindings", async ({ + page, + }) => { + await page.getByLabel("Add asset").waitFor({ state: "visible" }); + await page.getByLabel("Add asset").click(); + await page.getByRole("menuitem", { name: "Canvas dashboard" }).click(); + + await page + .getByRole("button", { name: "Add widget" }) + .waitFor({ state: "visible" }); + await page.getByRole("button", { name: "Add widget" }).click(); + await page.getByRole("menuitem", { name: "Your components" }).hover(); + await page.getByRole("menuitem", { name: "Measure trend" }).click(); + + // Wait for the first instance to render before inserting the second. + await expect(page.locator(".vega-embed").first()).toBeVisible({ + timeout: 15_000, + }); + + await page + .getByRole("button", { name: "Resize row 1 column 1" }) + .hover({ force: true }); + await page + .getByRole("button", { + name: "Insert widget in row 1 at column 2", + exact: true, + }) + .click(); + await page.getByRole("menuitem", { name: "Your components" }).click(); + await page + .getByRole("menuitem", { name: "Measure trend" }) + .click({ timeout: 10_000 }); + + // Both instances render independently, each with a positional instance id + // as its DOM id (never the shared component resource name, which would + // produce duplicate ids and confuse drag geometry and selection). + await expect(page.locator(".vega-embed")).toHaveCount(2, { + timeout: 15_000, + }); + await expect(page.locator('[id="measure_trend"]')).toHaveCount(0); + await expect(page.locator('[id^="measure_trend::"]')).toHaveCount(2); + }); +}); + +test.describe("custom viz flag off", () => { + test.use({ project: "AdBids" }); + + test("menus do not offer custom viz when the flag is off", async ({ + page, + }) => { + await page.getByLabel("Add asset").waitFor({ state: "visible" }); + await page.getByLabel("Add asset").click(); + await expect( + page.getByRole("menuitem", { name: "Custom viz" }), + ).toHaveCount(0); + await page.keyboard.press("Escape"); + + await page.getByLabel("Add asset").click(); + await page.getByRole("menuitem", { name: "Canvas dashboard" }).click(); + await page + .getByRole("button", { name: "Add widget" }) + .waitFor({ state: "visible" }); + await page.getByRole("button", { name: "Add widget" }).click(); + await expect( + page.getByRole("menuitem", { name: "Your components" }), + ).toHaveCount(0); + }); +});