diff --git a/.golangci.yml b/.golangci.yml index cbd0fc46f8..445e35f88e 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,7 +1,3 @@ -run: - skip-dirs: - - node_modules - linters: disable-all: true enable: @@ -113,3 +109,6 @@ issues: - linters: - paralleltest text: 'does not use range value in test Run' + exclude-dirs: + - node_modules + diff --git a/CHANGELOG.md b/CHANGELOG.md index 767872c016..5d997f5763 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,18 +11,44 @@ For details about compatibility between different releases, see the **Commitment ### Added +- Add recvTime field to the decodeUplink input in payload formatters +- Add the latest battery percentage of the end device in the `ApplicationUplink` message. +- Add live data split view tutorial to the Console. +- Add end device attributes to ApplicationUp messages. + - Add the locations, version_ids, network_ids fields to the following ApplicationUp messages: + - ApplicationJoinAccept + - ApplicationDownlink + - ApplicationDownlinkFailed + - ApplicationInvalidatedDownlinks + - ApplicationServiceData + - Add Timeout and Cache fields in the EndDeviceMetadataStorageConfig of the AS. + ### Changed ### Deprecated +- Deprecate the Location field (and its subfields) in the EndDeviceMetadataStorageConfig of AS. + ### Removed ### Fixed +### Security + +## [3.33.1] - unreleased + +### Added + +- Add recvTime field to the decodeUplink input in payload formatters +- Add the latest battery percentage of the end device in the `ApplicationUplink` message. +- Add live data split view tutorial to the Console. + +### Fixed + - Enforce default page limit on AS and NS List RPCs if a value is not provided in the request. - Swapped field order in `RelayNotifyNewEndDeviceReq` MAC command. - -### Security +- `LinkADRAns` MAC command verification when the end device does not support ADR. +- Being able to remove all attributes in general settings. ## [3.34.0] - unreleased @@ -2936,7 +2962,8 @@ For details about compatibility between different releases, see the **Commitment NOTE: These links should respect backports. See https://github.com/TheThingsNetwork/lorawan-stack/pull/1444/files#r333379706. --> -[unreleased]: https://github.com/TheThingsNetwork/lorawan-stack/compare/v3.33.0...v3.33 +[unreleased]: https://github.com/TheThingsNetwork/lorawan-stack/compare/v3.33.1...v3.33 +[3.33.1]: https://github.com/TheThingsNetwork/lorawan-stack/compare/v3.33.0...v3.33.1 [3.33.0]: https://github.com/TheThingsNetwork/lorawan-stack/compare/v3.32.3...v3.33.0 [3.32.2]: https://github.com/TheThingsNetwork/lorawan-stack/compare/v3.32.2...v3.32.3 [3.32.2]: https://github.com/TheThingsNetwork/lorawan-stack/compare/v3.32.1...v3.32.2 diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index fd25b70398..1f0aa0443d 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -79,17 +79,11 @@ This creates a database, migrates tables and creates a user `admin` with passwor $ go run ./cmd/ttn-lw-stack -c ./config/stack/ttn-lw-stack.yml start ``` -5. Run the Frontend with - -```bash -$ tools/bin/mage js:serve -``` - -6. Login to The Things Stack via the Console +5. Login to The Things Stack via the Console In a web browser, navigate to `http://localhost:1885/` and login using credentials from step 3. -7. Customizing configuration +6. Customizing configuration To customize the configuration, copy the configuration file `/config/stack/ttn-lw-stack.yml` to a different location (ex: the `.env` folder in your repo). The configuration is documented in the [Configuration Reference](https://thethingsstack.io/reference/configuration/). @@ -251,123 +245,39 @@ The folder structure of the frontend looks as follows: ├── template.go go template module used to render the frontend HTML ``` -#### Development Configuration - -> To use a convenient interactive launcher for the development environments without any further setup required, please see the (interactive development stack launcher tool)[#interactive-development-stack-launcher-tool] - -In order to set up The Things Stack to support running the frontend via `webpack-dev-server`, the following environment setup is needed: - -```bash -# .dev.env -export NODE_ENV="development" -export TTN_LW_LOG_LEVEL="debug" -export TTN_LW_IS_OAUTH_UI_JS_FILE="libs.bundle.js account.js" -export TTN_LW_CONSOLE_UI_JS_FILE="libs.bundle.js console.js" -export TTN_LW_CONSOLE_UI_CANONICAL_URL="http://localhost:8080/console" -export TTN_LW_CONSOLE_OAUTH_AUTHORIZE_URL="http://localhost:8080/oauth/authorize" -export TTN_LW_CONSOLE_OAUTH_LOGOUT_URL="http://localhost:8080/oauth/logout" -export TTN_LW_CONSOLE_OAUTH_TOKEN_URL="http://localhost:8080/oauth/token" -export TTN_LW_IS_OAUTH_UI_CANONICAL_URL="http://localhost:8080/oauth" -export TTN_LW_IS_EMAIL_NETWORK_IDENTITY_SERVER_URL="http://localhost:8080/oauth.js" -export TTN_LW_CONSOLE_UI_ASSETS_BASE_URL="http://localhost:8080/assets" -export TTN_LW_IS_EMAIL_PROVIDER="dir" -export TTN_LW_IS_EMAIL_DIR=".dev/email" - -export TTN_LW_CONSOLE_UI_IS_BASE_URL="http://localhost:8080/api/v3" -export TTN_LW_CONSOLE_UI_AS_BASE_URL="http://localhost:8080/api/v3" -export TTN_LW_CONSOLE_UI_NS_BASE_URL="http://localhost:8080/api/v3" -export TTN_LW_CONSOLE_UI_JS_BASE_URL="http://localhost:8080/api/v3" -export TTN_LW_CONSOLE_UI_GS_BASE_URL="http://localhost:8080/api/v3" -export TTN_LW_CONSOLE_UI_EDTC_BASE_URL="http://localhost:8080/api/v3" -export TTN_LW_CONSOLE_UI_GCS_BASE_URL="http://localhost:8080/api/v3" -export TTN_LW_CONSOLE_UI_QRG_BASE_URL="http://localhost:8080/api/v3" - -export TTN_LW_IS_OAUTH_UI_IS_BASE_URL="http://localhost:8080/api/v3" -``` - -We recommend saving this configuration as an `.dev.env` file and sourcing it like `source .dev.env`. This allows you to easily apply development configuration when needed. - -The development server can also be run with a staging environment (`.staging.env`) with the following set up: - -```bash -# .staging.env -export NODE_ENV="development" -export TTN_LW_LOG_LEVEL="debug" - -export TTN_LW_AS_WEBHOOKS_TEMPLATES_DIRECTORY="/src/github.com/TheThingsNetwork/webhook-templates" -export TTN_LW_CONSOLE_OAUTH_AUTHORIZE_URL="https://tti.staging1.cloud.thethings.industries/oauth/authorize" -export TTN_LW_CONSOLE_OAUTH_LOGOUT_URL="https://tti.staging1.cloud.thethings.industries/oauth/logout" -export TTN_LW_CONSOLE_OAUTH_TOKEN_URL="https://tti.staging1.cloud.thethings.industries/oauth/token" -export TTN_LW_CONSOLE_UI_ASSETS_BASE_URL="http://localhost:8080/assets" -export TTN_LW_CONSOLE_UI_CANONICAL_URL="http://localhost:8080/console" -export TTN_LW_CONSOLE_UI_JS_FILE="libs.bundle.js console.js paint.js" -export TTN_LW_IS_OAUTH_UI_CANONICAL_URL="http://localhost:8080/oauth" -export TTN_LW_IS_OAUTH_UI_JS_FILE="libs.bundle.js oauth.js" - -export TTN_LW_CONSOLE_UI_SUPPORT_LINK="https://thethingsstack.io" - -export TTN_LW_CONSOLE_UI_IS_BASE_URL="https://tti.staging1.cloud.thethings.industries/api/v3" -export TTN_LW_CONSOLE_UI_AS_BASE_URL="https://tti.staging1.cloud.thethings.industries/api/v3" -export TTN_LW_CONSOLE_UI_NS_BASE_URL="https://tti.staging1.cloud.thethings.industries/api/v3" -export TTN_LW_CONSOLE_UI_GS_BASE_URL="https://tti.staging1.cloud.thethings.industries/api/v3" -export TTN_LW_CONSOLE_UI_JS_BASE_URL="https://tti.staging1.cloud.thethings.industries/api/v3" -export TTN_LW_CONSOLE_UI_QRG_BASE_URL="https://tti.staging1.cloud.thethings.industries/api/v3" -export TTN_LW_CONSOLE_UI_EDTC_BASE_URL="https://tti.staging1.cloud.thethings.industries/api/v3" - -export TTN_LW_CONSOLE_OAUTH_CLIENT_ID="localhost-console" -export TTN_LW_CONSOLE_OAUTH_CLIENT_SECRET="console" - -export TTN_LW_TLS_CERTIFICATE=/src/github.com/TheThingsNetwork/lorawan-stack/cert.pem -export TTN_LW_TLS_KEY=/src/github.com/TheThingsNetwork/lorawan-stack/key.pem -export TTN_LW_TLS_ROOT_CA=/src/github.com/TheThingsNetwork/lorawan-stack/cert.pem -export TTN_LW_TLS_SOURCE="file" -export TTN_LW_TLS_INSECURE_SKIP_VERIFY="true" -``` - -> Note: It is important to **source these environment variables in all terminal sessions** that run The Things Stack or the `tools/bin/mage` commands. Failing to do so will result in erros such as blank page renders. See also [troubleshooting](#troubleshooting). - -#### Optional Configuration - -##### Disable [Hot Module Replacement](https://webpack.js.org/concepts/hot-module-replacement/) - -If you experience trouble seeing the WebUIs updated after a code change, you can also disable hot module replacement and enforce a hard reload on code changes instead. This method is a bit slower but more robust. To do so apply the following variable: - -```bash -WEBPACK_DEV_SERVER_DISABLE_HMR="true" -``` - -> Note: Webpack-related configuration can be loaded from environment variables only. It cannot be sourced from a config file. +#### Interactive development stack launcher tool -##### Enable TLS in `webpack-dev-server` +In order to easily launch development environments in different deployment contexts, this mage target configures and starts a development environment for The Things Stack, allowing users to choose between local and staging environments, enable branding, and configure cloud-hosted mock setups. You can launch it via: ```bash -WEBPACK_DEV_SERVER_USE_TLS="true" +$ tools/bin/mage dev:serveDevWebui ``` -This option uses the key and certificate set via `TTN_LW_TLS_KEY` and `TTN_LW_TLS_CERTIFICATE` environment variables. Useful when developing functionalities that rely on TLS. -> Note: To use this option, The Things Stack for LoRaWAN must be properly setup for TLS. You can obtain more information about this in the **Getting Started** section of the The Things Stack for LoRaWAN documentation. - -#### Serving +It will interactively guide you through the desired setup and launches the The Things Stack as well as a frontend development server wia webpack. -For development purposes, the frontend can be run using `webpack-dev-server`. After following the [Getting Started](#getting-started) section to initialize The Things Stack and doing an initial build of the frontend via `tools/bin/mage js:build`, and setting up the correct environment, it can be served using: +The Things Stack can be accessed at `http://localhost:8080`. The frontend is ready when you see: ```bash -$ export NODE_ENV=development -$ tools/bin/mage js:serve +[js:serve] [webpack-dev-server] Project is running at: +[js:serve] [webpack-dev-server] Loopback: http://localhost:8080/, http://[::1]:8080/ ``` -The development server runs on `http://localhost:8080` and will proxy all API calls to port `1885`. The serve command watches any changes inside `pkg/webui` and refreshes automatically. - -#### Interactive development stack launcher tool - -In order to easily launch development environments in different deployment contexts, this mage target configures and starts a development environment for The Things Stack, allowing users to choose between local and staging environments, enable branding, and configure cloud-hosted mock setups. You can launch it via: +The backend is ready when you see: ```bash -$ tools/bin/mage dev:serveDevWebui +[stack] DEBUG Creating listener {"address": ":8887"} +[stack] DEBUG Creating listener {"address": ":1889"} +DEBUG Creating listener {"address": ":1887"} +DEBUG Creating listener {"address": ":8881"} +INFO New patch version available {"current": "3.32.2-dev", "docs_url": "https://www.thethingsindustries.com/docs/getting-started/upgrading/", "latest": "3.32.3"} +DEBUG Creating listener {"address": ":8883"} +DEBUG Creating listener {"address": ":8889"} +DEBUG Creating listener {"address": ":1881"} +DEBUG Creating listener {"address": ":8882"} +DEBUG Creating listener {"address": ":1883"} +DEBUG Creating listener {"address": ":1882"} ``` -It will interactively guide you through the desired setup and launches the The Things Stack Enterprise as well as a frontend development server wia webpack. - ## Code Style ### Code Formatting @@ -808,7 +718,33 @@ We use [Cypress](https://cypress.io) for running frontend-based end-to-end tests #### Running frontend end-to-end tests locally -Make sure to [build the frontend assets](#building-the-frontend) and run `tools/bin/mage dev:initStack dev:sqlDump` to create a seed database which the tests can reset the database to in between runs. To run the stack when working on end-to-end tests, use the `tools/bin/mage dev:startDevStack` command. This will run the runs The Things Stack with proper configuration for the end-to-end tests. Note: this command does not output anything, but logs are written to `.cache/devStack.log`. +The preferred way to run the end-to-end tests is to use the [interactive launcher tool](#interactive-development-stack-launcher-tool). + +1. Make sure to run `tools/bin/mage dev:dbStop dev:dbErase dev:dbCreate dev:initStack dev:sqlDump` to create a seed database which the tests can reset the database to in between runs. +2. Run `tools/bin/mage dev:serveDevWebui` +3. Select "Cypress" in the launcher tool +4. In a separate terminal, add the following environment variables: + +```bash + export NODE_ENV="development" + export CYPRESS_BASE_URL="http://localhost:8080" +``` + +5. And run the end-to-end tests (`tools/bin/mage js:cypressInteractive`) + +#### Optional: testing in development environment + +Make sure to [build the frontend assets](#building-the-frontend) and run `tools/bin/mage dev:dbStop dev:dbErase dev:dbCreate dev:initStack dev:sqlDump` to create a seed database which the tests can reset the database to in between runs. + +To run the stack when working on end-to-end tests, use the `tools/bin/mage dev:startDevStack` command. This will run the runs The Things Stack with proper configuration for the end-to-end tests. Note: this command does not output anything, but logs are written to `.cache/devStack.log`. + +It is possible to run the tests while using the development environment. To do so, follow the guide on setting up the [development environment](#development-configuration). Once configured, do the following: + +1. Run the stack with (`tools/bin/mage dev:startDevStack`) +2. Serve the frontend (`tools/bin/mage js:serve`) +3. Run the end-to-end tests (`tools/bin/mage js:cypressInteractive`) + +##### Running the tests [Cypress](https://www.cypress.io/) provides two modes for running tests: headless and interactive. - **Headless mode** will not display any browser GUI and output test progress into your terminal instead. This is helpful when one just needs see the results of the tests. @@ -1095,6 +1031,115 @@ $ go run ./cmd/ttn-lw-stack start It is also possible to use `go build`, or release snapshots, as described below. +### Advanced Development Configuration + +> The preffered way to set up the development environment is to use the [interactive development stack launcher tool](#interactive-development-stack-launcher-tool). + +In order to set up The Things Stack to support running the frontend via `webpack-dev-server`, the following environment setup is needed: + +```bash +# .dev.env +export NODE_ENV="development" +export TTN_LW_IS_ADMIN_RIGHTS_ALL="true" +export TTN_LW_IS_EMAIL_DIR=".dev/email" +export TTN_LW_IS_EMAIL_PROVIDER="dir" +export TTN_LW_LOG_LEVEL="debug" +export TTN_LW_NOC_ACCESS_EXTENDED="true" +export TTN_LW_PLUGINS_SOURCE="directory" +export TTN_LW_CONSOLE_UI_CANONICAL_URL="http://localhost:8080/console" + +export TTN_LW_CONSOLE_OAUTH_AUTHORIZE_URL="http://localhost:8080/oauth/authorize" +export TTN_LW_CONSOLE_OAUTH_LOGOUT_URL="http://localhost:8080/oauth/logout" +export TTN_LW_CONSOLE_OAUTH_TOKEN_URL="http://localhost:8080/oauth/token" +export TTN_LW_CONSOLE_UI_ASSETS_BASE_URL="http://localhost:8080/assets" +export TTN_LW_CONSOLE_UI_AS_BASE_URL="http://localhost:8080/api/v3" +export TTN_LW_CONSOLE_UI_EDTC_BASE_URL="http://localhost:8080/api/v3" +export TTN_LW_CONSOLE_UI_GCS_BASE_URL="http://localhost:8080/api/v3" +export TTN_LW_CONSOLE_UI_GS_BASE_URL="http://localhost:8080/api/v3" +export TTN_LW_CONSOLE_UI_IS_BASE_URL="http://localhost:8080/api/v3" +export TTN_LW_CONSOLE_UI_JS_BASE_URL="http://localhost:8080/api/v3" +export TTN_LW_CONSOLE_UI_JS_FILE="libs.bundle.js console.js" +export TTN_LW_CONSOLE_UI_NS_BASE_URL="http://localhost:8080/api/v3" +export TTN_LW_CONSOLE_UI_QRG_BASE_URL="http://localhost:8080/api/v3" +export TTN_LW_IS_OAUTH_UI_IS_BASE_URL="http://localhost:8080/api/v3" +export TTN_LW_IS_OAUTH_UI_JS_FILE="libs.bundle.js account.js" +export WEBPACK_DEV_BACKEND_API_PROXY_URL="http://localhost:1885" +export TTN_LW_CONSOLE_UI_ACCOUNT_URL="http://localhost:8080/oauth" +export TTN_LW_IS_EMAIL_NETWORK_IDENTITY_SERVER_URL="http://localhost:8080/oauth" +export TTN_LW_IS_OAUTH_UI_CANONICAL_URL="http://localhost:8080/oauth" +export CYPRESS_BASE_URL="http://localhost:8080" +``` + +We recommend saving this configuration as an `.dev.env` file and sourcing it like `source .dev.env`. This allows you to easily apply development configuration when needed. + +The development server can also be run with a staging environment (`.staging.env`) with the following set up: + +```bash +# .staging.env +export STAGING_URL="" + +export NODE_ENV="development" +export TTN_LW_IS_ADMIN_RIGHTS_ALL="true" +export TTN_LW_IS_EMAIL_DIR=".dev/email" +export TTN_LW_IS_EMAIL_PROVIDER="dir" +export TTN_LW_LOG_LEVEL="debug" +export TTN_LW_NOC_ACCESS_EXTENDED="true" +export TTN_LW_PLUGINS_SOURCE="directory" +export TTN_LW_CONSOLE_UI_CANONICAL_URL="http://localhost:8080/console" + +export TTN_LW_CONSOLE_OAUTH_AUTHORIZE_URL="${STAGING_URL}/oauth/authorize" +export TTN_LW_CONSOLE_OAUTH_CLIENT_ID="localhost-console" +export TTN_LW_CONSOLE_OAUTH_CLIENT_SECRET="console" +export TTN_LW_CONSOLE_OAUTH_LOGOUT_URL="${STAGING_URL}/oauth/logout" +export TTN_LW_CONSOLE_OAUTH_TOKEN_URL="${STAGING_URL}/oauth/token" +export TTN_LW_CONSOLE_UI_AS_BASE_URL="http://localhost:8080/api/v3" +export TTN_LW_CONSOLE_UI_EDTC_BASE_URL="http://localhost:8080/api/v3" +export TTN_LW_CONSOLE_UI_GCS_BASE_URL="http://localhost:8080/api/v3" +export TTN_LW_CONSOLE_UI_GS_BASE_URL="http://localhost:8080/api/v3" +export TTN_LW_CONSOLE_UI_IS_BASE_URL="http://localhost:8080/api/v3" +export TTN_LW_CONSOLE_UI_JS_BASE_URL="http://localhost:8080/api/v3" +export TTN_LW_CONSOLE_UI_NS_BASE_URL="http://localhost:8080/api/v3" +export TTN_LW_CONSOLE_UI_QRG_BASE_URL="http://localhost:8080/api/v3" +export TTN_LW_CONSOLE_UI_NOC_BASE_URL="http://localhost:8080/api/v3" +export TTN_LW_CONSOLE_UI_NOC_URL="${STAGING_URL}/noc" +export WEBPACK_DEV_BACKEND_API_PROXY_URL="${STAGING_URL}" +export TTN_LW_CONSOLE_UI_ACCOUNT_URL="${STAGING_URL}/oauth" +export TTN_LW_IS_OAUTH_UI_CANONICAL_URL="${STAGING_URL}/oauth" +``` + +> Note: It is important to **source these environment variables in all terminal sessions** that run The Things Stack or the `tools/bin/mage` commands. Failing to do so will result in erros such as blank page renders. See also [troubleshooting](#troubleshooting). + +#### Optional Configuration + +##### Disable [Hot Module Replacement](https://webpack.js.org/concepts/hot-module-replacement/) + +If you experience trouble seeing the WebUIs updated after a code change, you can also disable hot module replacement and enforce a hard reload on code changes instead. This method is a bit slower but more robust. To do so apply the following variable: + +```bash +WEBPACK_DEV_SERVER_DISABLE_HMR="true" +``` + +> Note: Webpack-related configuration can be loaded from environment variables only. It cannot be sourced from a config file. + +##### Enable TLS in `webpack-dev-server` + +```bash +WEBPACK_DEV_SERVER_USE_TLS="true" +``` +This option uses the key and certificate set via `TTN_LW_TLS_KEY` and `TTN_LW_TLS_CERTIFICATE` environment variables. Useful when developing functionalities that rely on TLS. + +> Note: To use this option, The Things Stack for LoRaWAN must be properly setup for TLS. You can obtain more information about this in the **Getting Started** section of the The Things Stack for LoRaWAN documentation. + +#### Serving + +For development purposes, the frontend can be run using `webpack-dev-server`. After following the [Getting Started](#getting-started) section to initialize The Things Stack and doing an initial build of the frontend via `tools/bin/mage js:build`, and [setting up the correct environment](#development-configuration), it can be served using: + +```bash +$ tools/bin/mage js:serve +``` + +The development server runs on `http://localhost:8080` and will proxy all API calls to port `1885`. The serve command watches any changes inside `pkg/webui` and refreshes automatically. + ## Releasing The Things Stack uses [GoReleaser](https://goreleaser.com/) for releases. If you want to build a release (snapshot), you first need to install GoReleaser: diff --git a/api/ttn/lorawan/v3/api.md b/api/ttn/lorawan/v3/api.md index 196bc6e43a..568fcc96e0 100644 --- a/api/ttn/lorawan/v3/api.md +++ b/api/ttn/lorawan/v3/api.md @@ -596,25 +596,38 @@ - [Enum `TxSchedulePriority`](#ttn.lorawan.v3.TxSchedulePriority) - [File `ttn/lorawan/v3/messages.proto`](#ttn/lorawan/v3/messages.proto) - [Message `ApplicationDownlink`](#ttn.lorawan.v3.ApplicationDownlink) + - [Message `ApplicationDownlink.AttributesEntry`](#ttn.lorawan.v3.ApplicationDownlink.AttributesEntry) - [Message `ApplicationDownlink.ClassBC`](#ttn.lorawan.v3.ApplicationDownlink.ClassBC) - [Message `ApplicationDownlink.ConfirmedRetry`](#ttn.lorawan.v3.ApplicationDownlink.ConfirmedRetry) + - [Message `ApplicationDownlink.LocationsEntry`](#ttn.lorawan.v3.ApplicationDownlink.LocationsEntry) - [Message `ApplicationDownlinkFailed`](#ttn.lorawan.v3.ApplicationDownlinkFailed) + - [Message `ApplicationDownlinkFailed.AttributesEntry`](#ttn.lorawan.v3.ApplicationDownlinkFailed.AttributesEntry) + - [Message `ApplicationDownlinkFailed.LocationsEntry`](#ttn.lorawan.v3.ApplicationDownlinkFailed.LocationsEntry) - [Message `ApplicationDownlinks`](#ttn.lorawan.v3.ApplicationDownlinks) - [Message `ApplicationInvalidatedDownlinks`](#ttn.lorawan.v3.ApplicationInvalidatedDownlinks) + - [Message `ApplicationInvalidatedDownlinks.AttributesEntry`](#ttn.lorawan.v3.ApplicationInvalidatedDownlinks.AttributesEntry) + - [Message `ApplicationInvalidatedDownlinks.LocationsEntry`](#ttn.lorawan.v3.ApplicationInvalidatedDownlinks.LocationsEntry) - [Message `ApplicationJoinAccept`](#ttn.lorawan.v3.ApplicationJoinAccept) + - [Message `ApplicationJoinAccept.AttributesEntry`](#ttn.lorawan.v3.ApplicationJoinAccept.AttributesEntry) + - [Message `ApplicationJoinAccept.LocationsEntry`](#ttn.lorawan.v3.ApplicationJoinAccept.LocationsEntry) - [Message `ApplicationLocation`](#ttn.lorawan.v3.ApplicationLocation) - [Message `ApplicationLocation.AttributesEntry`](#ttn.lorawan.v3.ApplicationLocation.AttributesEntry) - [Message `ApplicationServiceData`](#ttn.lorawan.v3.ApplicationServiceData) + - [Message `ApplicationServiceData.AttributesEntry`](#ttn.lorawan.v3.ApplicationServiceData.AttributesEntry) + - [Message `ApplicationServiceData.LocationsEntry`](#ttn.lorawan.v3.ApplicationServiceData.LocationsEntry) - [Message `ApplicationUp`](#ttn.lorawan.v3.ApplicationUp) - [Message `ApplicationUplink`](#ttn.lorawan.v3.ApplicationUplink) + - [Message `ApplicationUplink.AttributesEntry`](#ttn.lorawan.v3.ApplicationUplink.AttributesEntry) - [Message `ApplicationUplink.LocationsEntry`](#ttn.lorawan.v3.ApplicationUplink.LocationsEntry) - [Message `ApplicationUplinkNormalized`](#ttn.lorawan.v3.ApplicationUplinkNormalized) + - [Message `ApplicationUplinkNormalized.AttributesEntry`](#ttn.lorawan.v3.ApplicationUplinkNormalized.AttributesEntry) - [Message `ApplicationUplinkNormalized.LocationsEntry`](#ttn.lorawan.v3.ApplicationUplinkNormalized.LocationsEntry) - [Message `DownlinkMessage`](#ttn.lorawan.v3.DownlinkMessage) - [Message `DownlinkQueueOperationErrorDetails`](#ttn.lorawan.v3.DownlinkQueueOperationErrorDetails) - [Message `DownlinkQueueRequest`](#ttn.lorawan.v3.DownlinkQueueRequest) - [Message `GatewayTxAcknowledgment`](#ttn.lorawan.v3.GatewayTxAcknowledgment) - [Message `GatewayUplinkMessage`](#ttn.lorawan.v3.GatewayUplinkMessage) + - [Message `LastBatteryPercentage`](#ttn.lorawan.v3.LastBatteryPercentage) - [Message `MessagePayloadFormatters`](#ttn.lorawan.v3.MessagePayloadFormatters) - [Message `TxAcknowledgment`](#ttn.lorawan.v3.TxAcknowledgment) - [Message `UplinkMessage`](#ttn.lorawan.v3.UplinkMessage) @@ -8632,6 +8645,10 @@ Transmission settings for downlink. | `priority` | [`TxSchedulePriority`](#ttn.lorawan.v3.TxSchedulePriority) | | Priority for scheduling the downlink message. | | `correlation_ids` | [`string`](#string) | repeated | | | `confirmed_retry` | [`ApplicationDownlink.ConfirmedRetry`](#ttn.lorawan.v3.ApplicationDownlink.ConfirmedRetry) | | | +| `locations` | [`ApplicationDownlink.LocationsEntry`](#ttn.lorawan.v3.ApplicationDownlink.LocationsEntry) | repeated | End device location metadata, set by the Application Server while handling the message. | +| `version_ids` | [`EndDeviceVersionIdentifiers`](#ttn.lorawan.v3.EndDeviceVersionIdentifiers) | | End device version identifiers, set by the Application Server while handling the message. | +| `network_ids` | [`NetworkIdentifiers`](#ttn.lorawan.v3.NetworkIdentifiers) | | Network identifiers, set by the Network Server that handles the message. | +| `attributes` | [`ApplicationDownlink.AttributesEntry`](#ttn.lorawan.v3.ApplicationDownlink.AttributesEntry) | repeated | Attributes for devices, set by the Application Server while handling the message. | #### Field Rules @@ -8642,6 +8659,14 @@ Transmission settings for downlink. | `frm_payload` |

`bytes.max_len`: `255`

| | `priority` |

`enum.defined_only`: `true`

| | `correlation_ids` |

`repeated.items.string.max_len`: `100`

| +| `attributes` |

`map.max_pairs`: `10`

`map.keys.string.max_len`: `36`

`map.keys.string.pattern`: `^[a-z0-9](?:[-]?[a-z0-9]){2,}$`

`map.values.string.max_len`: `200`

| + +### Message `ApplicationDownlink.AttributesEntry` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `key` | [`string`](#string) | | | +| `value` | [`string`](#string) | | | ### Message `ApplicationDownlink.ClassBC` @@ -8663,12 +8688,23 @@ Transmission settings for downlink. | ----- | ----------- | | `max_attempts` |

`uint32.lte`: `100`

`uint32.gt`: `0`

| +### Message `ApplicationDownlink.LocationsEntry` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `key` | [`string`](#string) | | | +| `value` | [`Location`](#ttn.lorawan.v3.Location) | | | + ### Message `ApplicationDownlinkFailed` | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | `downlink` | [`ApplicationDownlink`](#ttn.lorawan.v3.ApplicationDownlink) | | | | `error` | [`ErrorDetails`](#ttn.lorawan.v3.ErrorDetails) | | | +| `locations` | [`ApplicationDownlinkFailed.LocationsEntry`](#ttn.lorawan.v3.ApplicationDownlinkFailed.LocationsEntry) | repeated | End device location metadata, set by the Application Server while handling the message. | +| `version_ids` | [`EndDeviceVersionIdentifiers`](#ttn.lorawan.v3.EndDeviceVersionIdentifiers) | | End device version identifiers, set by the Application Server while handling the message. | +| `network_ids` | [`NetworkIdentifiers`](#ttn.lorawan.v3.NetworkIdentifiers) | | Network identifiers, set by the Network Server that handles the message. | +| `attributes` | [`ApplicationDownlinkFailed.AttributesEntry`](#ttn.lorawan.v3.ApplicationDownlinkFailed.AttributesEntry) | repeated | Attributes for devices, set by the Application Server while handling the message. | #### Field Rules @@ -8676,6 +8712,21 @@ Transmission settings for downlink. | ----- | ----------- | | `downlink` |

`message.required`: `true`

| | `error` |

`message.required`: `true`

| +| `attributes` |

`map.max_pairs`: `10`

`map.keys.string.max_len`: `36`

`map.keys.string.pattern`: `^[a-z0-9](?:[-]?[a-z0-9]){2,}$`

`map.values.string.max_len`: `200`

| + +### Message `ApplicationDownlinkFailed.AttributesEntry` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `key` | [`string`](#string) | | | +| `value` | [`string`](#string) | | | + +### Message `ApplicationDownlinkFailed.LocationsEntry` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `key` | [`string`](#string) | | | +| `value` | [`Location`](#ttn.lorawan.v3.Location) | | | ### Message `ApplicationDownlinks` @@ -8690,12 +8741,31 @@ Transmission settings for downlink. | `downlinks` | [`ApplicationDownlink`](#ttn.lorawan.v3.ApplicationDownlink) | repeated | | | `last_f_cnt_down` | [`uint32`](#uint32) | | | | `session_key_id` | [`bytes`](#bytes) | | | +| `locations` | [`ApplicationInvalidatedDownlinks.LocationsEntry`](#ttn.lorawan.v3.ApplicationInvalidatedDownlinks.LocationsEntry) | repeated | End device location metadata, set by the Application Server while handling the message. | +| `version_ids` | [`EndDeviceVersionIdentifiers`](#ttn.lorawan.v3.EndDeviceVersionIdentifiers) | | End device version identifiers, set by the Application Server while handling the message. | +| `network_ids` | [`NetworkIdentifiers`](#ttn.lorawan.v3.NetworkIdentifiers) | | Network identifiers, set by the Network Server that handles the message. | +| `attributes` | [`ApplicationInvalidatedDownlinks.AttributesEntry`](#ttn.lorawan.v3.ApplicationInvalidatedDownlinks.AttributesEntry) | repeated | Attributes for devices, set by the Application Server while handling the message. | #### Field Rules | Field | Validations | | ----- | ----------- | | `session_key_id` |

`bytes.max_len`: `2048`

| +| `attributes` |

`map.max_pairs`: `10`

`map.keys.string.max_len`: `36`

`map.keys.string.pattern`: `^[a-z0-9](?:[-]?[a-z0-9]){2,}$`

`map.values.string.max_len`: `200`

| + +### Message `ApplicationInvalidatedDownlinks.AttributesEntry` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `key` | [`string`](#string) | | | +| `value` | [`string`](#string) | | | + +### Message `ApplicationInvalidatedDownlinks.LocationsEntry` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `key` | [`string`](#string) | | | +| `value` | [`Location`](#ttn.lorawan.v3.Location) | | | ### Message `ApplicationJoinAccept` @@ -8706,6 +8776,10 @@ Transmission settings for downlink. | `invalidated_downlinks` | [`ApplicationDownlink`](#ttn.lorawan.v3.ApplicationDownlink) | repeated | Downlink messages in the queue that got invalidated because of the session change. | | `pending_session` | [`bool`](#bool) | | Indicates whether the security context refers to the pending session, i.e. when this join-accept is an answer to a rejoin-request. | | `received_at` | [`google.protobuf.Timestamp`](#google.protobuf.Timestamp) | | Server time when the Network Server received the message. | +| `locations` | [`ApplicationJoinAccept.LocationsEntry`](#ttn.lorawan.v3.ApplicationJoinAccept.LocationsEntry) | repeated | End device location metadata, set by the Application Server while handling the message. | +| `version_ids` | [`EndDeviceVersionIdentifiers`](#ttn.lorawan.v3.EndDeviceVersionIdentifiers) | | End device version identifiers, set by the Application Server while handling the message. | +| `network_ids` | [`NetworkIdentifiers`](#ttn.lorawan.v3.NetworkIdentifiers) | | Network identifiers, set by the Network Server that handles the message. | +| `attributes` | [`ApplicationJoinAccept.AttributesEntry`](#ttn.lorawan.v3.ApplicationJoinAccept.AttributesEntry) | repeated | Attributes for devices, set by the Application Server while handling the message. | #### Field Rules @@ -8713,6 +8787,21 @@ Transmission settings for downlink. | ----- | ----------- | | `session_key_id` |

`bytes.max_len`: `2048`

| | `received_at` |

`timestamp.required`: `true`

| +| `attributes` |

`map.max_pairs`: `10`

`map.keys.string.max_len`: `36`

`map.keys.string.pattern`: `^[a-z0-9](?:[-]?[a-z0-9]){2,}$`

`map.values.string.max_len`: `200`

| + +### Message `ApplicationJoinAccept.AttributesEntry` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `key` | [`string`](#string) | | | +| `value` | [`string`](#string) | | | + +### Message `ApplicationJoinAccept.LocationsEntry` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `key` | [`string`](#string) | | | +| `value` | [`Location`](#ttn.lorawan.v3.Location) | | | ### Message `ApplicationLocation` @@ -8742,6 +8831,30 @@ Transmission settings for downlink. | ----- | ---- | ----- | ----------- | | `service` | [`string`](#string) | | | | `data` | [`google.protobuf.Struct`](#google.protobuf.Struct) | | | +| `locations` | [`ApplicationServiceData.LocationsEntry`](#ttn.lorawan.v3.ApplicationServiceData.LocationsEntry) | repeated | End device location metadata, set by the Application Server while handling the message. | +| `version_ids` | [`EndDeviceVersionIdentifiers`](#ttn.lorawan.v3.EndDeviceVersionIdentifiers) | | End device version identifiers, set by the Application Server while handling the message. | +| `network_ids` | [`NetworkIdentifiers`](#ttn.lorawan.v3.NetworkIdentifiers) | | Network identifiers, set by the Network Server that handles the message. | +| `attributes` | [`ApplicationServiceData.AttributesEntry`](#ttn.lorawan.v3.ApplicationServiceData.AttributesEntry) | repeated | Attributes for devices, set by the Application Server while handling the message. | + +#### Field Rules + +| Field | Validations | +| ----- | ----------- | +| `attributes` |

`map.max_pairs`: `10`

`map.keys.string.max_len`: `36`

`map.keys.string.pattern`: `^[a-z0-9](?:[-]?[a-z0-9]){2,}$`

`map.values.string.max_len`: `200`

| + +### Message `ApplicationServiceData.AttributesEntry` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `key` | [`string`](#string) | | | +| `value` | [`string`](#string) | | | + +### Message `ApplicationServiceData.LocationsEntry` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `key` | [`string`](#string) | | | +| `value` | [`Location`](#ttn.lorawan.v3.Location) | | | ### Message `ApplicationUp` @@ -8795,6 +8908,8 @@ Application uplink message. | `locations` | [`ApplicationUplink.LocationsEntry`](#ttn.lorawan.v3.ApplicationUplink.LocationsEntry) | repeated | End device location metadata, set by the Application Server while handling the message. | | `version_ids` | [`EndDeviceVersionIdentifiers`](#ttn.lorawan.v3.EndDeviceVersionIdentifiers) | | End device version identifiers, set by the Application Server while handling the message. | | `network_ids` | [`NetworkIdentifiers`](#ttn.lorawan.v3.NetworkIdentifiers) | | Network identifiers, set by the Network Server that handles the message. | +| `last_battery_percentage` | [`LastBatteryPercentage`](#ttn.lorawan.v3.LastBatteryPercentage) | | Last battery percentage of the end device. Received via the DevStatus MAC command at last_dev_status_received_at or earlier. Set by the Network Server while handling the message. | +| `attributes` | [`ApplicationUplink.AttributesEntry`](#ttn.lorawan.v3.ApplicationUplink.AttributesEntry) | repeated | Attributes for devices, set by the Application Server while handling the message. | #### Field Rules @@ -8803,6 +8918,14 @@ Application uplink message. | `session_key_id` |

`bytes.max_len`: `2048`

| | `f_port` |

`uint32.lte`: `255`

`uint32.not_in`: `[224]`

| | `settings` |

`message.required`: `true`

| +| `attributes` |

`map.max_pairs`: `10`

`map.keys.string.max_len`: `36`

`map.keys.string.pattern`: `^[a-z0-9](?:[-]?[a-z0-9]){2,}$`

`map.values.string.max_len`: `200`

| + +### Message `ApplicationUplink.AttributesEntry` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `key` | [`string`](#string) | | | +| `value` | [`string`](#string) | | | ### Message `ApplicationUplink.LocationsEntry` @@ -8829,6 +8952,7 @@ Application uplink message. | `locations` | [`ApplicationUplinkNormalized.LocationsEntry`](#ttn.lorawan.v3.ApplicationUplinkNormalized.LocationsEntry) | repeated | End device location metadata, set by the Application Server while handling the message. | | `version_ids` | [`EndDeviceVersionIdentifiers`](#ttn.lorawan.v3.EndDeviceVersionIdentifiers) | | End device version identifiers, set by the Application Server while handling the message. | | `network_ids` | [`NetworkIdentifiers`](#ttn.lorawan.v3.NetworkIdentifiers) | | Network identifiers, set by the Network Server that handles the message. | +| `attributes` | [`ApplicationUplinkNormalized.AttributesEntry`](#ttn.lorawan.v3.ApplicationUplinkNormalized.AttributesEntry) | repeated | Attributes for devices, set by the Application Server while handling the message. | #### Field Rules @@ -8839,6 +8963,14 @@ Application uplink message. | `normalized_payload` |

`message.required`: `true`

| | `settings` |

`message.required`: `true`

| | `received_at` |

`timestamp.required`: `true`

| +| `attributes` |

`map.max_pairs`: `10`

`map.keys.string.max_len`: `36`

`map.keys.string.pattern`: `^[a-z0-9](?:[-]?[a-z0-9]){2,}$`

`map.values.string.max_len`: `200`

| + +### Message `ApplicationUplinkNormalized.AttributesEntry` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `key` | [`string`](#string) | | | +| `value` | [`string`](#string) | | | ### Message `ApplicationUplinkNormalized.LocationsEntry` @@ -8940,6 +9072,20 @@ ncrc: [scheduled.advanced] | ----- | ----------- | | `message` |

`message.required`: `true`

| +### Message `LastBatteryPercentage` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `f_cnt` | [`uint32`](#uint32) | | Frame counter value of last uplink containing DevStatusAns. | +| `value` | [`google.protobuf.FloatValue`](#google.protobuf.FloatValue) | | The battery percentage of the end device. The value is defined in the [0, 100] interval. | +| `received_at` | [`google.protobuf.Timestamp`](#google.protobuf.Timestamp) | | Time when last DevStatus MAC command was received. | + +#### Field Rules + +| Field | Validations | +| ----- | ----------- | +| `value` |

`float.lte`: `100`

`float.gte`: `0`

| + ### Message `MessagePayloadFormatters` | Field | Type | Label | Description | diff --git a/api/ttn/lorawan/v3/api.swagger.json b/api/ttn/lorawan/v3/api.swagger.json index d9eb432aee..626f161912 100644 --- a/api/ttn/lorawan/v3/api.swagger.json +++ b/api/ttn/lorawan/v3/api.swagger.json @@ -20326,6 +20326,28 @@ }, "confirmed_retry": { "$ref": "#/definitions/ApplicationDownlinkConfirmedRetry" + }, + "locations": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/lorawanv3Location" + }, + "description": "End device location metadata, set by the Application Server while handling the message." + }, + "version_ids": { + "$ref": "#/definitions/v3EndDeviceVersionIdentifiers", + "description": "End device version identifiers, set by the Application Server while handling the message." + }, + "network_ids": { + "$ref": "#/definitions/v3NetworkIdentifiers", + "description": "Network identifiers, set by the Network Server that handles the message." + }, + "attributes": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Attributes for devices, set by the Application Server while handling the message." } } }, @@ -20337,6 +20359,28 @@ }, "error": { "$ref": "#/definitions/v3ErrorDetails" + }, + "locations": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/lorawanv3Location" + }, + "description": "End device location metadata, set by the Application Server while handling the message." + }, + "version_ids": { + "$ref": "#/definitions/v3EndDeviceVersionIdentifiers", + "description": "End device version identifiers, set by the Application Server while handling the message." + }, + "network_ids": { + "$ref": "#/definitions/v3NetworkIdentifiers", + "description": "Network identifiers, set by the Network Server that handles the message." + }, + "attributes": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Attributes for devices, set by the Application Server while handling the message." } } }, @@ -20377,6 +20421,28 @@ "session_key_id": { "type": "string", "format": "byte" + }, + "locations": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/lorawanv3Location" + }, + "description": "End device location metadata, set by the Application Server while handling the message." + }, + "version_ids": { + "$ref": "#/definitions/v3EndDeviceVersionIdentifiers", + "description": "End device version identifiers, set by the Application Server while handling the message." + }, + "network_ids": { + "$ref": "#/definitions/v3NetworkIdentifiers", + "description": "Network identifiers, set by the Network Server that handles the message." + }, + "attributes": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Attributes for devices, set by the Application Server while handling the message." } } }, @@ -20408,6 +20474,28 @@ "type": "string", "format": "date-time", "description": "Server time when the Network Server received the message." + }, + "locations": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/lorawanv3Location" + }, + "description": "End device location metadata, set by the Application Server while handling the message." + }, + "version_ids": { + "$ref": "#/definitions/v3EndDeviceVersionIdentifiers", + "description": "End device version identifiers, set by the Application Server while handling the message." + }, + "network_ids": { + "$ref": "#/definitions/v3NetworkIdentifiers", + "description": "Network identifiers, set by the Network Server that handles the message." + }, + "attributes": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Attributes for devices, set by the Application Server while handling the message." } } }, @@ -20907,6 +20995,28 @@ }, "data": { "type": "object" + }, + "locations": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/lorawanv3Location" + }, + "description": "End device location metadata, set by the Application Server while handling the message." + }, + "version_ids": { + "$ref": "#/definitions/v3EndDeviceVersionIdentifiers", + "description": "End device version identifiers, set by the Application Server while handling the message." + }, + "network_ids": { + "$ref": "#/definitions/v3NetworkIdentifiers", + "description": "Network identifiers, set by the Network Server that handles the message." + }, + "attributes": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Attributes for devices, set by the Application Server while handling the message." } } }, @@ -21068,6 +21178,17 @@ "network_ids": { "$ref": "#/definitions/v3NetworkIdentifiers", "description": "Network identifiers, set by the Network Server that handles the message." + }, + "last_battery_percentage": { + "$ref": "#/definitions/v3LastBatteryPercentage", + "description": "Last battery percentage of the end device.\nReceived via the DevStatus MAC command at last_dev_status_received_at or earlier.\nSet by the Network Server while handling the message." + }, + "attributes": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Attributes for devices, set by the Application Server while handling the message." } } }, @@ -21144,6 +21265,13 @@ "network_ids": { "$ref": "#/definitions/v3NetworkIdentifiers", "description": "Network identifiers, set by the Network Server that handles the message." + }, + "attributes": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Attributes for devices, set by the Application Server while handling the message." } } }, @@ -25802,6 +25930,26 @@ } } }, + "v3LastBatteryPercentage": { + "type": "object", + "properties": { + "f_cnt": { + "type": "integer", + "format": "int64", + "description": "Frame counter value of last uplink containing DevStatusAns." + }, + "value": { + "type": "number", + "format": "float", + "description": "The battery percentage of the end device.\nThe value is defined in the [0, 100] interval." + }, + "received_at": { + "type": "string", + "format": "date-time", + "description": "Time when last DevStatus MAC command was received." + } + } + }, "v3ListBandsResponse": { "type": "object", "properties": { diff --git a/api/ttn/lorawan/v3/messages.proto b/api/ttn/lorawan/v3/messages.proto index 043bca2328..0d09cff9ee 100644 --- a/api/ttn/lorawan/v3/messages.proto +++ b/api/ttn/lorawan/v3/messages.proto @@ -186,6 +186,19 @@ message GatewayUplinkMessage { string band_id = 2; } +message LastBatteryPercentage { + // Frame counter value of last uplink containing DevStatusAns. + uint32 f_cnt = 1; + // The battery percentage of the end device. + // The value is defined in the [0, 100] interval. + google.protobuf.FloatValue value = 2 [(validate.rules).float = { + gte: 0, + lte: 100 + }]; + // Time when last DevStatus MAC command was received. + google.protobuf.Timestamp received_at = 3; +} + message ApplicationUplink { option (thethings.flags.message) = { select: true, @@ -259,7 +272,26 @@ message ApplicationUplink { // Network identifiers, set by the Network Server that handles the message. NetworkIdentifiers network_ids = 16; - // next: 20 + // Last battery percentage of the end device. + // Received via the DevStatus MAC command at last_dev_status_received_at or earlier. + // Set by the Network Server while handling the message. + LastBatteryPercentage last_battery_percentage = 20; + + // Attributes for devices, set by the Application Server while handling the message. + map attributes = 21 [(validate.rules).map = { + max_pairs: 10, + keys: { + string: { + pattern: "^[a-z0-9](?:[-]?[a-z0-9]){2,}$", + max_len: 36 + } + }, + values: { + string: {max_len: 200} + } + }]; + + // next: 22 } message ApplicationUplinkNormalized { @@ -312,7 +344,21 @@ message ApplicationUplinkNormalized { // Network identifiers, set by the Network Server that handles the message. NetworkIdentifiers network_ids = 14; - // next: 15 + // Attributes for devices, set by the Application Server while handling the message. + map attributes = 15 [(validate.rules).map = { + max_pairs: 10, + keys: { + string: { + pattern: "^[a-z0-9](?:[-]?[a-z0-9]){2,}$", + max_len: 36 + } + }, + values: { + string: {max_len: 200} + } + }]; + + // next: 16 } message ApplicationLocation { @@ -352,6 +398,31 @@ message ApplicationJoinAccept { bool pending_session = 4; // Server time when the Network Server received the message. google.protobuf.Timestamp received_at = 8 [(validate.rules).timestamp.required = true]; + + // End device location metadata, set by the Application Server while handling the message. + map locations = 9; + + // End device version identifiers, set by the Application Server while handling the message. + EndDeviceVersionIdentifiers version_ids = 10; + + // Network identifiers, set by the Network Server that handles the message. + NetworkIdentifiers network_ids = 11; + + // Attributes for devices, set by the Application Server while handling the message. + map attributes = 12 [(validate.rules).map = { + max_pairs: 10, + keys: { + string: { + pattern: "^[a-z0-9](?:[-]?[a-z0-9]){2,}$", + max_len: 36 + } + }, + values: { + string: {max_len: 200} + } + }]; + + // next: 13 } message ApplicationDownlink { @@ -438,7 +509,30 @@ message ApplicationDownlink { ConfirmedRetry confirmed_retry = 11; - // next: 12 + // End device location metadata, set by the Application Server while handling the message. + map locations = 12; + + // End device version identifiers, set by the Application Server while handling the message. + EndDeviceVersionIdentifiers version_ids = 13; + + // Network identifiers, set by the Network Server that handles the message. + NetworkIdentifiers network_ids = 14; + + // Attributes for devices, set by the Application Server while handling the message. + map attributes = 15 [(validate.rules).map = { + max_pairs: 10, + keys: { + string: { + pattern: "^[a-z0-9](?:[-]?[a-z0-9]){2,}$", + max_len: 36 + } + }, + values: { + string: {max_len: 200} + } + }]; + + // next: 16 } message ApplicationDownlinks { @@ -452,6 +546,31 @@ message ApplicationDownlinkFailed { }; ApplicationDownlink downlink = 1 [(validate.rules).message.required = true]; ErrorDetails error = 2 [(validate.rules).message.required = true]; + + // End device location metadata, set by the Application Server while handling the message. + map locations = 3; + + // End device version identifiers, set by the Application Server while handling the message. + EndDeviceVersionIdentifiers version_ids = 4; + + // Network identifiers, set by the Network Server that handles the message. + NetworkIdentifiers network_ids = 5; + + // Attributes for devices, set by the Application Server while handling the message. + map attributes = 6 [(validate.rules).map = { + max_pairs: 10, + keys: { + string: { + pattern: "^[a-z0-9](?:[-]?[a-z0-9]){2,}$", + max_len: 36 + } + }, + values: { + string: {max_len: 200} + } + }]; + + // next: 7 } message ApplicationInvalidatedDownlinks { @@ -462,6 +581,31 @@ message ApplicationInvalidatedDownlinks { repeated ApplicationDownlink downlinks = 1; uint32 last_f_cnt_down = 2; bytes session_key_id = 3 [(validate.rules).bytes.max_len = 2048]; + + // End device location metadata, set by the Application Server while handling the message. + map locations = 4; + + // End device version identifiers, set by the Application Server while handling the message. + EndDeviceVersionIdentifiers version_ids = 5; + + // Network identifiers, set by the Network Server that handles the message. + NetworkIdentifiers network_ids = 6; + + // Attributes for devices, set by the Application Server while handling the message. + map attributes = 7 [(validate.rules).map = { + max_pairs: 10, + keys: { + string: { + pattern: "^[a-z0-9](?:[-]?[a-z0-9]){2,}$", + max_len: 36 + } + }, + values: { + string: {max_len: 200} + } + }]; + + // next: 8 } message DownlinkQueueOperationErrorDetails { @@ -509,6 +653,31 @@ message ApplicationServiceData { }; string service = 1; google.protobuf.Struct data = 2; + + // End device location metadata, set by the Application Server while handling the message. + map locations = 3; + + // End device version identifiers, set by the Application Server while handling the message. + EndDeviceVersionIdentifiers version_ids = 4; + + // Network identifiers, set by the Network Server that handles the message. + NetworkIdentifiers network_ids = 5; + + // Attributes for devices, set by the Application Server while handling the message. + map attributes = 6 [(validate.rules).map = { + max_pairs: 10, + keys: { + string: { + pattern: "^[a-z0-9](?:[-]?[a-z0-9]){2,}$", + max_len: 36 + } + }, + values: { + string: {max_len: 200} + } + }]; + + // next: 7 } // Application uplink message. diff --git a/api/ttn/lorawan/v3/user.proto b/api/ttn/lorawan/v3/user.proto index 7663cb151a..15b7bafffb 100644 --- a/api/ttn/lorawan/v3/user.proto +++ b/api/ttn/lorawan/v3/user.proto @@ -192,6 +192,10 @@ message UserConsolePreferences { SortBy sort_by = 3; message Tutorials { + option (thethings.flags.message) = { + select: true, + set: true + }; repeated Tutorial seen = 1 [(validate.rules).repeated = { unique: true, items: { diff --git a/cmd/internal/shared/applicationserver/config.go b/cmd/internal/shared/applicationserver/config.go index 0a680a3819..b420608610 100644 --- a/cmd/internal/shared/applicationserver/config.go +++ b/cmd/internal/shared/applicationserver/config.go @@ -49,15 +49,7 @@ var DefaultApplicationServerConfig = applicationserver.Config{ Downlinks: web.DownlinksConfig{PublicAddress: shared.DefaultPublicURL + "/api/v3"}, }, EndDeviceMetadataStorage: applicationserver.EndDeviceMetadataStorageConfig{ - Location: applicationserver.EndDeviceLocationStorageConfig{ - Timeout: 5 * time.Second, - Cache: applicationserver.EndDeviceLocationStorageCacheConfig{ - Enable: true, - MinRefreshInterval: 15 * time.Minute, - MaxRefreshInterval: 4 * time.Hour, - TTL: 14 * 24 * time.Hour, - }, - }, + Timeout: 5 * time.Second, }, Distribution: applicationserver.DistributionConfig{ Timeout: time.Minute, diff --git a/cmd/ttn-lw-stack/commands/start.go b/cmd/ttn-lw-stack/commands/start.go index ec3eaf7b09..8a8820fd31 100644 --- a/cmd/ttn-lw-stack/commands/start.go +++ b/cmd/ttn-lw-stack/commands/start.go @@ -27,7 +27,6 @@ import ( asioapredis "go.thethings.network/lorawan-stack/v3/pkg/applicationserver/io/packages/redis" asiopsredis "go.thethings.network/lorawan-stack/v3/pkg/applicationserver/io/pubsub/redis" asiowebredis "go.thethings.network/lorawan-stack/v3/pkg/applicationserver/io/web/redis" - asmetaredis "go.thethings.network/lorawan-stack/v3/pkg/applicationserver/metadata/redis" asredis "go.thethings.network/lorawan-stack/v3/pkg/applicationserver/redis" "go.thethings.network/lorawan-stack/v3/pkg/component" "go.thethings.network/lorawan-stack/v3/pkg/console" @@ -445,21 +444,11 @@ var startCommand = &cobra.Command{ } config.AS.Webhooks.Registry = webhookRegistry } - if cache := &config.AS.EndDeviceMetadataStorage.Location.Cache; cache.Enable { - switch config.Cache.Service { - case "redis": - cache.Cache = &asmetaredis.EndDeviceLocationCache{ - Redis: redis.New(config.Cache.Redis.WithNamespace("as", "metadata", "locations")), - } - default: - cache.Enable = false - } - } - locationRegistry, err := config.AS.EndDeviceMetadataStorage.Location.NewRegistry(ctx, c) + endDeviceRegistry, err := config.AS.EndDeviceMetadataStorage.NewRegistry(ctx, c) if err != nil { return shared.ErrInitializeApplicationServer.WithCause(err) } - config.AS.EndDeviceMetadataStorage.Location.Registry = locationRegistry + config.AS.EndDeviceMetadataStorage.Registry = endDeviceRegistry as, err := applicationserver.New(c, &config.AS) if err != nil { return shared.ErrInitializeApplicationServer.WithCause(err) diff --git a/config/messages.json b/config/messages.json index 8df261ae60..1563754468 100644 --- a/config/messages.json +++ b/config/messages.json @@ -2861,13 +2861,13 @@ "file": "io.go" } }, - "error:pkg/applicationserver/metadata/redis:cache_miss": { + "error:pkg/applicationserver/metadata:field_mask_path_not_supported": { "translations": { - "en": "cache miss" + "en": "field mask path `{path}` is not supported" }, "description": { - "package": "pkg/applicationserver/metadata/redis", - "file": "location_cache.go" + "package": "pkg/applicationserver/metadata", + "file": "metadata.go" } }, "error:pkg/applicationserver/redis:application_uid": { @@ -2978,15 +2978,6 @@ "file": "config.go" } }, - "error:pkg/applicationserver:invalid_ttl": { - "translations": { - "en": "invalid TTL `{ttl}`" - }, - "description": { - "package": "pkg/applicationserver", - "file": "config.go" - } - }, "error:pkg/applicationserver:join_server_unavailable": { "translations": { "en": "Join Server unavailable for JoinEUI `{join_eui}`" diff --git a/cypress/plugins/tasks.js b/cypress/plugins/tasks.js index a9cf17199c..13f0839ff0 100644 --- a/cypress/plugins/tasks.js +++ b/cypress/plugins/tasks.js @@ -1,4 +1,4 @@ -// Copyright © 2020 The Things Network Foundation, The Things Industries B.V. +// Copyright © 2024 The Things Network Foundation, The Things Industries B.V. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -79,7 +79,7 @@ const sqlTask = on => { const exec = util.promisify(childProcess.exec) await Promise.all([ exec('tools/bin/mage dev:sqlRestore', { cwd: '..' }), - exec('tools/bin/mage dev:redisFlush', { cwd: '..' }), + exec('tools/bin/mage -v dev:redisFlush', { cwd: '..' }), ]) return null }, diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 5bee0fd177..24485a2df0 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -126,6 +126,14 @@ Cypress.Commands.add('getAccessToken', callback => { callback(accessToken) }) +Cypress.Commands.add('setAllTutorialSeen', user => { + const tutorialNames = ['TUTORIAL_LIVE_DATA_SPLIT_VIEW'] + cy.task( + 'execSql', + `UPDATE users SET console_preferences = '{"dashboard_layouts":{},"sort_by":{},"tutorials":{"seen":[${tutorialNames.map(name => `"${name}"`).join(',')}]}}'::jsonb::text::bytea WHERE primary_email_address = '${user.primary_email_address}';`, + ) +}) + // Helper function to create a new user programmatically. Cypress.Commands.add('createUser', user => { const baseUrl = Cypress.config('baseUrl') @@ -147,6 +155,8 @@ Cypress.Commands.add('createUser', user => { }) }) + // Set all tutorials as seen. + cy.setAllTutorialSeen(user) // Reset cookies and local storage to avoid csrf and session state inconsistencies within tests. cy.clearCookies() cy.clearLocalStorage() diff --git a/go.mod b/go.mod index 8a33ff386e..14af6bee2a 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ go 1.23.3 replace github.com/mitchellh/mapstructure => github.com/TheThingsIndustries/mapstructure v0.0.0-20230413130846-941bcd1deec3 require ( - github.com/KimMachineGun/automemlimit v0.6.1 + github.com/KimMachineGun/automemlimit v0.7.0 github.com/Masterminds/sprig/v3 v3.3.0 github.com/TheThingsIndustries/mystique v0.0.0-20221125120501-80ab21781b6d github.com/TheThingsIndustries/protoc-gen-go-flags v1.2.0 @@ -24,7 +24,7 @@ require ( github.com/emersion/go-smtp v0.21.3 github.com/envoyproxy/protoc-gen-validate v1.1.0 github.com/felixge/httpsnoop v1.0.4 - github.com/getsentry/sentry-go v0.30.0 + github.com/getsentry/sentry-go v0.31.1 github.com/golang/gddo v0.0.0-20210115222349-20d68f94ee1f github.com/google/go-cmp v0.6.0 github.com/google/uuid v1.6.0 @@ -71,9 +71,9 @@ require ( github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.19.0 github.com/throttled/throttled/v2 v2.12.0 - github.com/uptrace/bun v1.2.6 - github.com/uptrace/bun/dialect/pgdialect v1.2.6 - github.com/uptrace/bun/driver/pgdriver v1.2.6 + github.com/uptrace/bun v1.2.8 + github.com/uptrace/bun/dialect/pgdialect v1.2.8 + github.com/uptrace/bun/driver/pgdriver v1.2.8 github.com/vmihailenco/msgpack/v5 v5.4.1 go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.58.0 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0 @@ -97,16 +97,16 @@ require ( go.uber.org/zap v1.27.0 gocloud.dev v0.40.0 gocloud.dev/pubsub/natspubsub v0.40.0 - golang.org/x/crypto v0.31.0 + golang.org/x/crypto v0.32.0 golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f - golang.org/x/net v0.33.0 - golang.org/x/oauth2 v0.24.0 + golang.org/x/net v0.34.0 + golang.org/x/oauth2 v0.25.0 golang.org/x/sync v0.10.0 google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 google.golang.org/genproto/googleapis/api v0.0.0-20241219192143-6b3ec007d9bb google.golang.org/genproto/googleapis/rpc v0.0.0-20241219192143-6b3ec007d9bb - google.golang.org/grpc v1.69.2 - google.golang.org/protobuf v1.36.1 + google.golang.org/grpc v1.69.4 + google.golang.org/protobuf v1.36.2 gopkg.in/mail.v2 v2.3.1 gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/yaml.v2 v2.4.0 @@ -158,7 +158,6 @@ require ( github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.5 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.33.1 // indirect github.com/aws/smithy-go v1.22.1 // indirect - github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.17.0 // indirect github.com/blevesearch/go-porterstemmer v1.0.3 // indirect @@ -170,27 +169,20 @@ require ( github.com/blevesearch/zap/v13 v13.0.6 // indirect github.com/blevesearch/zap/v14 v14.0.5 // indirect github.com/blevesearch/zap/v15 v15.0.3 // indirect - github.com/buger/jsonparser v1.1.1 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/cilium/ebpf v0.16.0 // indirect github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 // indirect - github.com/containerd/cgroups/v3 v3.0.4 // indirect - github.com/containerd/log v0.1.0 // indirect - github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/couchbase/vellum v1.0.2 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dlclark/regexp2 v1.11.4 // indirect - github.com/docker/go-units v0.5.0 // indirect github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 // indirect github.com/envoyproxy/go-control-plane v0.13.1 // indirect github.com/fsnotify/fsnotify v1.8.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-sourcemap/sourcemap v2.1.4+incompatible // indirect - github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/golang-jwt/jwt/v5 v5.2.1 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect @@ -218,12 +210,10 @@ require ( github.com/kr/text v0.2.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/magiconair/properties v1.8.7 // indirect - github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect github.com/minio/highwayhash v1.0.3 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect - github.com/moby/sys/userns v0.1.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mschoch/smat v0.2.0 // indirect @@ -232,7 +222,6 @@ require ( github.com/nats-io/nkeys v0.4.9 // indirect github.com/nats-io/nuid v1.0.1 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect - github.com/opencontainers/runtime-spec v1.2.0 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/pborman/uuid v1.2.1 // indirect github.com/pelletier/go-toml/v2 v2.2.3 // indirect @@ -248,7 +237,6 @@ require ( github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sendgrid/rest v2.6.9+incompatible // indirect github.com/shopspring/decimal v1.4.0 // indirect - github.com/sirupsen/logrus v1.9.3 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect @@ -257,7 +245,6 @@ require ( github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/willf/bitset v1.1.11 // indirect - github.com/wk8/go-ordered-map/v2 v2.1.9-0.20240816141633-0a40785b4f41 // indirect go.etcd.io/bbolt v1.3.11 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect @@ -267,8 +254,8 @@ require ( go.opentelemetry.io/proto/otlp v1.4.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/image v0.22.0 // indirect - golang.org/x/sys v0.28.0 // indirect - golang.org/x/term v0.27.0 // indirect + golang.org/x/sys v0.29.0 // indirect + golang.org/x/term v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect golang.org/x/time v0.8.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect diff --git a/go.sum b/go.sum index 6056a95754..58f0ac9d7c 100644 --- a/go.sum +++ b/go.sum @@ -58,8 +58,8 @@ github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0 github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.49.0/go.mod h1:l2fIqmwB+FKSfvn3bAD/0i+AXAxhIZjTK2svT/mgUXs= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.49.0 h1:GYUJLfvd++4DMuMhCFLgLXvFwofIxh/qOwoGuS/LTew= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.49.0/go.mod h1:wRbFgBQUVm1YXrvWKofAEmq9HNJTDphbAaJSSX01KUI= -github.com/KimMachineGun/automemlimit v0.6.1 h1:ILa9j1onAAMadBsyyUJv5cack8Y1WT26yLj/V+ulKp8= -github.com/KimMachineGun/automemlimit v0.6.1/go.mod h1:T7xYht7B8r6AG/AqFcUdc7fzd2bIdBKmepfP2S1svPY= +github.com/KimMachineGun/automemlimit v0.7.0 h1:7G06p/dMSf7G8E6oq+f2uOPuVncFyIlDI/pBWK49u88= +github.com/KimMachineGun/automemlimit v0.7.0/go.mod h1:QZxpHaGOQoYvFhv/r4u3U0JTC2ZcOwbSr11UZF46UBM= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4= @@ -124,8 +124,6 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.33.1 h1:6SZUVRQNvExYlMLbHdlKB48x0fLb github.com/aws/aws-sdk-go-v2/service/sts v1.33.1/go.mod h1:GqWyYCwLXnlUB1lOAXQyNSPqPLQJvmo8J0DWBzp9mtg= github.com/aws/smithy-go v1.22.1 h1:/HPHZQ0g7f4eUeK6HKglFz8uwVfZKgoI25rb/J+dnro= github.com/aws/smithy-go v1.22.1/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= -github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= -github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= @@ -168,8 +166,6 @@ github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdb github.com/bsm/gomega v1.26.0/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= -github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= -github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -179,23 +175,15 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cilium/ebpf v0.16.0 h1:+BiEnHL6Z7lXnlGUsXQPPAE7+kenAd4ES8MQ5min0Ok= -github.com/cilium/ebpf v0.16.0/go.mod h1:L7u2Blt2jMM/vLAVgjxluxtBKlz3/GWjB0dMOEngfwE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 h1:QVw89YDxXxEe+l8gU8ETbOasdwEV+avkR75ZzsVV9WI= github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo= github.com/coder/websocket v1.8.12/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs= -github.com/containerd/cgroups/v3 v3.0.4 h1:2fs7l3P0Qxb1nKWuJNFiwhp2CqiKzho71DQkDrHJIo4= -github.com/containerd/cgroups/v3 v3.0.4/go.mod h1:SA5DLYnXO8pTGYiAHXz94qvLQTKfVM5GEVisn4jpins= -github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= -github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= -github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/couchbase/ghistogram v0.1.0/go.mod h1:s1Jhy76zqfEecpNWJfWUiKZookAFaiGOEoyzgHt9i7k= github.com/couchbase/moss v0.1.0/go.mod h1:9MaHIaRuy9pvLPUJxB8sh8OrLfyDczECVL37grCIubs= github.com/couchbase/vellum v1.0.2 h1:BrbP0NKiyDdndMPec8Jjhy0U47CZ0Lgx3xUC2r9rZqw= @@ -220,8 +208,6 @@ github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1 github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo= github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= -github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= -github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dop251/goja v0.0.0-20241024094426-79f3a7efcdbd h1:QMSNEh9uQkDjyPwu/J541GgSH+4hw+0skJDIj9HJ3mE= github.com/dop251/goja v0.0.0-20241024094426-79f3a7efcdbd/go.mod h1:MxLav0peU43GgvwVgNbLAj1s/bSGboKkhuULvq/7hx4= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= @@ -253,8 +239,8 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4 github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/garyburd/redigo v1.1.1-0.20170914051019-70e1b1943d4f/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= -github.com/getsentry/sentry-go v0.30.0 h1:lWUwDnY7sKHaVIoZ9wYqRHJ5iEmoc0pqcRqFkosKzBo= -github.com/getsentry/sentry-go v0.30.0/go.mod h1:WU9B9/1/sHDqeV8T+3VwwbjeR5MSXs/6aqG3mqZrezA= +github.com/getsentry/sentry-go v0.31.1 h1:ELVc0h7gwyhnXHDouXkhqTFSO5oslsRDk0++eyE0KJ4= +github.com/getsentry/sentry-go v0.31.1/go.mod h1:CYNcMMz73YigoHljQRG+qPF+eMq8gG72XcGN/p71BAY= github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= @@ -266,17 +252,12 @@ github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= -github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= github.com/go-redis/redis v6.15.8+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-redis/redis/v8 v8.4.2/go.mod h1:A1tbYoHSa1fXwN+//ljcCYYJeLmVrwL9hbQN45Jdy0M= github.com/go-sourcemap/sourcemap v2.1.4+incompatible h1:a+iTbH5auLKxaNwQFg0B+TCYl6lbukKPc7b5x0n1s6Q= github.com/go-sourcemap/sourcemap v2.1.4+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-stack/stack v1.6.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= -github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= @@ -424,11 +405,6 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGw github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= -github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= -github.com/jsimonetti/rtnetlink/v2 v2.0.1 h1:xda7qaHDSVOsADNouv7ukSuicKZO7GgVUCXxpaIEIlM= -github.com/jsimonetti/rtnetlink/v2 v2.0.1/go.mod h1:7MoNYNbb3UaDHtF8udiJo/RH6VsTKP1pqKLUTVCvToE= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jtacoma/uritemplates v1.0.0 h1:xwx5sBF7pPAb0Uj8lDC1Q/aBPpOFyQza7OC705ZlLCo= @@ -458,8 +434,6 @@ github.com/magiconair/properties v1.7.4-0.20170902060319-8d7837e64d3c/go.mod h1: github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.0.10-0.20170816031813-ad5389df28cd/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.2/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= @@ -467,10 +441,6 @@ github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6T github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/maxatome/go-testdeep v1.12.0 h1:Ql7Go8Tg0C1D/uMMX59LAoYK7LffeJQ6X2T04nTH68g= github.com/maxatome/go-testdeep v1.12.0/go.mod h1:lPZc/HAcJMP92l7yI6TRz1aZN5URwUBUAfUNvrclaNM= -github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g= -github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= -github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= -github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= github.com/mileusna/useragent v1.3.5 h1:SJM5NzBmh/hO+4LGeATKpaEX9+b4vcGg2qXGLiNGDws= github.com/mileusna/useragent v1.3.5/go.mod h1:3d8TOmwL/5I8pJjyVDteHtgDGcefrFUX4ccGOMKNYYc= github.com/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD6Q= @@ -480,8 +450,6 @@ github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HK github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= -github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -517,8 +485,6 @@ github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= -github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk= -github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/openshift/build-machinery-go v0.0.0-20200917070002-f171684f77ab/go.mod h1:b1BuldmJlbA/xYtdZvKi+7j5YGB44qJUJDZ9zwiNCfE= github.com/openshift/osin v1.0.2-0.20220317075346-0f4d38c6e53f h1:4da9vH8eDlJo58703cADj3FlsdnFRgsnfuwj/4lYXfY= github.com/openshift/osin v1.0.2-0.20220317075346-0f4d38c6e53f/go.mod h1:DoYehsADYGKlXTIvqyZVnopfJbWgT6UsQYf8ETt1vjw= @@ -586,8 +552,6 @@ github.com/sendgrid/sendgrid-go v3.16.0+incompatible/go.mod h1:QRQt+LX/NmgVEvmdR github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M= github.com/smarty/assertions v1.16.0 h1:EvHNkdRA4QHMrn75NZSoUQ/mAUXAYWfatfB01yTCzfY= @@ -650,12 +614,12 @@ github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDW github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo= github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/uptrace/bun v1.2.6 h1:lyGBQAhNiClchb97HA2cBnDeRxwTRLhSIgiFPXVisV8= -github.com/uptrace/bun v1.2.6/go.mod h1:xMgnVFf+/5xsrFBU34HjDJmzZnXbVuNEt/Ih56I8qBU= -github.com/uptrace/bun/dialect/pgdialect v1.2.6 h1:iNd1YLx619K+sZK+dRcWPzluurXYK1QwIkp9FEfNB/8= -github.com/uptrace/bun/dialect/pgdialect v1.2.6/go.mod h1:OL7d3qZLxKYP8kxNhMg3IheN1pDR3UScGjoUP+ivxJQ= -github.com/uptrace/bun/driver/pgdriver v1.2.6 h1:dD7ckqIhVDayfYTwMKZ0dJM9AZfNJNBu5Cg/8g0EMOk= -github.com/uptrace/bun/driver/pgdriver v1.2.6/go.mod h1:ChrVrMZlRzPQHTP4QCm/p1FfQqgnYXWlES0GS9qjWEY= +github.com/uptrace/bun v1.2.8 h1:HEiLvy9wc7ehU5S02+O6NdV5BLz48lL4REPhTkMX3Dg= +github.com/uptrace/bun v1.2.8/go.mod h1:JBq0uBKsKqNT0Ccce1IAFZY337Wkf08c6F6qlmfOHE8= +github.com/uptrace/bun/dialect/pgdialect v1.2.8 h1:9n3qVh6yc+u7F3lpXzsWrAFJG1yLHUC2thjCCVEDpM8= +github.com/uptrace/bun/dialect/pgdialect v1.2.8/go.mod h1:plksD43MjAlPGYLD9/SzsLUpGH5poXE9IB1+ka/sEzE= +github.com/uptrace/bun/driver/pgdriver v1.2.8 h1:5XrNn/9enSrWhhrUpz+6PY9S1vcg/jhCQPJu+ZmsKX4= +github.com/uptrace/bun/driver/pgdriver v1.2.8/go.mod h1:cwRRwqabgePwYBiLlXtbeNmPD7LGJnqP21J2ZKP4ah8= github.com/vitorsalgado/mocha/v2 v2.0.2 h1:wb1QCRzVkp8uhRcUYmb9jJfbMj/qbiqcDyD8rD+Ldfw= github.com/vitorsalgado/mocha/v2 v2.0.2/go.mod h1:l7jRVm7KTL4VAxxazH99UVo+KzwztjrYpFTksTmL1DE= github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= @@ -665,8 +629,6 @@ github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= github.com/willf/bitset v1.1.11 h1:N7Z7E9UvjW+sGsEl7k/SJrvY2reP1A07MrGuCjIOjRE= github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI= -github.com/wk8/go-ordered-map/v2 v2.1.9-0.20240816141633-0a40785b4f41 h1:rnB8ZLMeAr3VcqjfRkAm27qb8y6zFKNfuHvy1Gfe7KI= -github.com/wk8/go-ordered-map/v2 v2.1.9-0.20240816141633-0a40785b4f41/go.mod h1:DbzwytT4g/odXquuOCqroKvtxxldI4nb3nuesHF/Exo= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -748,8 +710,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= -golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= +golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo= golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak= @@ -786,13 +748,13 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= -golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= +golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= golang.org/x/oauth2 v0.0.0-20170912212905-13449ad91cb2/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= -golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.25.0 h1:CY4y7XT9v0cRI9oupztF8AgiIu99L/ksR/Xp/6jrZ70= +golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20170517211232-f52d1811a629/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -825,7 +787,6 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -833,16 +794,16 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= -golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= -golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= +golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -900,8 +861,8 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU= -google.golang.org/grpc v1.69.2/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= +google.golang.org/grpc v1.69.4 h1:MF5TftSMkd8GLw/m0KM6V8CMOCY6NZ1NQDPGFgbTt4A= +google.golang.org/grpc v1.69.4/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -911,8 +872,8 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= -google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.2 h1:R8FeyR1/eLmkutZOM5CWghmo5itiG9z0ktFlTVLuTmU= +google.golang.org/protobuf v1.36.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/package.json b/package.json index 414cadffad..9bc69f831c 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "devDependencies": { "@babel/cli": "^7.26.4", "@babel/core": "^7.26.0", - "@babel/eslint-parser": "^7.25.9", + "@babel/eslint-parser": "^7.26.5", "@babel/plugin-proposal-class-properties": "^7.18.6", "@babel/plugin-proposal-decorators": "^7.25.9", "@babel/plugin-syntax-dynamic-import": "^7.8.3", @@ -19,7 +19,7 @@ "@babel/preset-react": "^7.26.3", "@babel/register": "^7.25.9", "@babel/runtime-corejs2": "^7.26.0", - "@inquirer/prompts": "^7.2.1", + "@inquirer/prompts": "^7.2.2", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.15", "@storybook/addon-designs": "8.0.4", "@storybook/addon-essentials": "8.4.7", @@ -53,7 +53,7 @@ "eslint-plugin-jsdoc": "^50.6.1", "eslint-plugin-prefer-arrow": "^1.2.3", "eslint-plugin-prettier": "5.2.1", - "eslint-plugin-react": "^7.37.3", + "eslint-plugin-react": "^7.37.4", "file-loader": "^6.2.0", "html-webpack-plugin": "^5.6.3", "http-proxy-middleware": "^3.0.3", @@ -69,30 +69,30 @@ "pg": "^8.13.1", "prettier": "3.4.2", "react-refresh": "^0.16.0", - "stylelint": "^16.12.0", + "stylelint": "^16.13.1", "stylelint-stylus": "^1.0.0", "storybook": "^8.1.8", "stylus": "^0.64.0", "stylus-loader": "^8.1.1", - "wait-on": "^8.0.1", + "wait-on": "^8.0.2", "webpack": "^5.97.1", - "webpack-cli": "^5.1.4", + "webpack-cli": "^6.0.1", "webpack-dev-server": "^5.2.0", "webpack-shell-plugin": "https://github.com/cdeutsch/webpack-shell-plugin.git#bee537d", "yargs": "^17.7.2" }, "dependencies": { - "@tabler/icons-react": "^3.26.0", - "@formatjs/intl-datetimeformat": "^6.17.1", - "@formatjs/intl-displaynames": "^6.8.8", - "@formatjs/intl-listformat": "^7.7.8", - "@formatjs/intl-locale": "^4.2.8", - "@formatjs/intl-numberformat": "^8.15.1", - "@formatjs/intl-pluralrules": "^5.4.1", - "@formatjs/intl-relativetimeformat": "^11.4.8", + "@tabler/icons-react": "^3.28.1", + "@formatjs/intl-datetimeformat": "^6.17.2", + "@formatjs/intl-displaynames": "^6.8.9", + "@formatjs/intl-listformat": "^7.7.9", + "@formatjs/intl-locale": "^4.2.9", + "@formatjs/intl-numberformat": "^8.15.2", + "@formatjs/intl-pluralrules": "^5.4.2", + "@formatjs/intl-relativetimeformat": "^11.4.9", "@reduxjs/toolkit": "^2.5.0", "@sentry/integrations": "^7.114.0", - "@sentry/react": "^8.47.0", + "@sentry/react": "^8.48.0", "@tippyjs/react": "^4.2.6", "apexcharts": "^4.3.0", "autobind-decorator": "^2.4.0", @@ -118,7 +118,7 @@ "react-dom": "^17.0.1", "react-focus-lock": "^2.13.5", "react-helmet": "^6.1.0", - "react-intl": "^7.0.4", + "react-intl": "^7.1.0", "react-leaflet": "^4.2.1", "react-paginate": "^8.2.0", "react-redux": "^8.1.2", @@ -134,7 +134,7 @@ "react-window-infinite-loader": "^1.0.9", "redux": "^5.0.1", "redux-actions": "^2.6.5", - "redux-logic": "^5.0.1", + "redux-logic": "^5.0.2", "reselect": "^5.1.1", "scroll-into-view-if-needed": "^3.1.0", "ttn-lw": "file:sdk/js", diff --git a/pkg/applicationserver/applicationserver.go b/pkg/applicationserver/applicationserver.go index 1559c1736f..48aeeb306c 100644 --- a/pkg/applicationserver/applicationserver.go +++ b/pkg/applicationserver/applicationserver.go @@ -81,7 +81,7 @@ type ApplicationServer struct { linkRegistry LinkRegistry deviceRegistry DeviceRegistry - locationRegistry metadata.EndDeviceLocationRegistry + endDeviceRegistry metadata.EndDeviceRegistry formatters messageprocessors.MapPayloadProcessor webhooks ioweb.Webhooks webhookTemplates ioweb.TemplateStore @@ -156,14 +156,14 @@ func New(c *component.Component, conf *Config) (as *ApplicationServer, err error } as = &ApplicationServer{ - Component: c, - ctx: ctx, - config: conf, - linkRegistry: conf.Links, - deviceRegistry: wrapEndDeviceRegistryWithReplacedFields(conf.Devices, replacedEndDeviceFields...), - appPkgRegistry: conf.Packages.Registry, - locationRegistry: conf.EndDeviceMetadataStorage.Location.Registry, - formatters: make(messageprocessors.MapPayloadProcessor), + Component: c, + ctx: ctx, + config: conf, + linkRegistry: conf.Links, + deviceRegistry: wrapEndDeviceRegistryWithReplacedFields(conf.Devices, replacedEndDeviceFields...), + appPkgRegistry: conf.Packages.Registry, + endDeviceRegistry: conf.EndDeviceMetadataStorage.Registry, + formatters: make(messageprocessors.MapPayloadProcessor), clusterDistributor: distribution.NewPubSubDistributor( ctx, c, @@ -1049,6 +1049,14 @@ func (as *ApplicationServer) handleJoinAccept( return err } + if entity, err := as.endDeviceRegistry.Get(ctx, ids, []string{"attributes"}); err != nil { + log.FromContext(ctx).WithError(err).Warn( + "Failed to retrieve end device attributes on join-accept", + ) + } else { + joinAccept.Attributes = entity.Attributes + } + // Publish last seen event. if err := as.deviceLastSeenPool.Publish(ctx, lastSeenAtInfo{ ids: ids, @@ -1159,6 +1167,7 @@ func (as *ApplicationServer) publishNormalizedUplink(ctx context.Context, info u Locations: info.uplink.Locations, VersionIds: info.uplink.VersionIds, NetworkIds: info.uplink.NetworkIds, + Attributes: info.uplink.Attributes, }, }, Simulated: info.simulated, @@ -1208,6 +1217,15 @@ func (as *ApplicationServer) handleUplink(ctx context.Context, info uplinkInfo) return err } + if entity, err := as.endDeviceRegistry.Get(ctx, info.ids, []string{"attributes", "locations"}); err != nil { + log.FromContext(ctx).WithError(err).Warn( + "Failed to retrieve the end device attributes and locations on uplink", + ) + } else { + info.uplink.Attributes = entity.Attributes + info.uplink.Locations = entity.Locations + } + if !as.skipPayloadCrypto(ctx, info.link, dev, dev.Session) { if err := as.decryptAndDecodeUplink(ctx, dev, info.uplink, info.link.DefaultFormatters); err != nil { return err @@ -1227,11 +1245,6 @@ func (as *ApplicationServer) handleUplink(ctx context.Context, info uplinkInfo) } // Set location in message and publish location solved if the payload contains location information. - if locations, err := as.locationRegistry.Get(ctx, info.ids); err != nil { - log.FromContext(ctx).WithError(err).Warn("Failed to retrieve end device locations") - } else { - info.uplink.Locations = locations - } loc := as.locationFromPayload(info.uplink) if loc != nil { if info.uplink.Locations == nil { @@ -1285,10 +1298,14 @@ func (as *ApplicationServer) handleSimulatedUplink(ctx context.Context, info upl return err } - if locations, err := as.locationRegistry.Get(ctx, info.ids); err != nil { - log.FromContext(ctx).WithError(err).Warn("Failed to retrieve end device locations") + if entity, err := as.endDeviceRegistry.Get(ctx, info.ids, []string{"attributes", "locations"}); err != nil { + log.FromContext(ctx).WithError(err).Warn( + "Failed to retrieve the end device from entity registry on simulated uplink", + ) } else { - info.uplink.Locations = locations + info.uplink.Attributes = entity.Attributes + info.uplink.Locations = entity.Locations + } if err := as.decodeUplink(ctx, dev, info.uplink, info.link.DefaultFormatters); err != nil { @@ -1370,7 +1387,19 @@ func (as *ApplicationServer) handleDownlinkQueueInvalidated( return dev, mask, nil }, ) - return pass, err + if err != nil { + return pass, err + } + + if entity, err := as.endDeviceRegistry.Get(ctx, ids, []string{"attributes"}); err != nil { + log.FromContext(ctx).WithError(err).Warn( + "Failed to retrieve end device attributes on downlink queue invalidated", + ) + } else { + invalid.Attributes = entity.Attributes + } + + return pass, nil } func (as *ApplicationServer) handleDownlinkNack( @@ -1455,17 +1484,47 @@ func (as *ApplicationServer) handleDownlinkNack( return dev, mask, nil }, ) - return err + if err != nil { + return err + } + + if _, err = as.endDeviceRegistry.Set(ctx, ids, []string{"attributes"}, + func(entity *ttnpb.EndDevice) (*ttnpb.EndDevice, []string, error) { + if entity == nil { + return nil, nil, errDeviceNotFound.WithAttributes("device_uid", unique.ID(ctx, ids)) + } + msg.Attributes = entity.Attributes + return entity, []string{""}, nil + }, + ); err != nil { + log.FromContext(ctx).WithError(err).Warn( + "Failed to retrieve end device attributes on downlink nack", + ) + } + + return nil } -// handleLocationSolved saves the provided *ttnpb.ApplicationLocation in the Entity Registry as part of the device locations. -// Locations provided by other services will be maintained. +// handleLocationSolved saves the provided *ttnpb.ApplicationLocation in the Entity Registry as part of the device +// locations. Locations provided by other services will be maintained. func (as *ApplicationServer) handleLocationSolved(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers, msg *ttnpb.ApplicationLocation, link *ttnpb.ApplicationLink) error { defer trace.StartRegion(ctx, "handle location solved").End() - if _, err := as.locationRegistry.Merge(ctx, ids, map[string]*ttnpb.Location{ - msg.Service: msg.Location, - }); err != nil { + if _, err := as.endDeviceRegistry.Set(ctx, ids, []string{"locations"}, + func(stored *ttnpb.EndDevice) (*ttnpb.EndDevice, []string, error) { + if stored == nil { + return nil, nil, errDeviceNotFound.WithAttributes("device_uid", unique.ID(ctx, ids)) + } + + if len(stored.Locations) == 0 { + stored.Locations = make(map[string]*ttnpb.Location) + } + + stored.Locations[msg.Service] = msg.Location + + return stored, []string{"locations"}, nil + }, + ); err != nil { log.FromContext(ctx).WithError(err).Warn("Failed to merge end device locations") } return nil @@ -1486,6 +1545,15 @@ func (as *ApplicationServer) decryptDownlinkMessage(ctx context.Context, ids *tt if err != nil { return err } + + if entity, err := as.endDeviceRegistry.Get(ctx, ids, []string{"attributes"}); err != nil { + log.FromContext(ctx).WithError(err).Warn( + "Failed to retrieve end device attributes on downlink message", + ) + } else { + msg.Attributes = entity.Attributes + } + var session *ttnpb.Session switch { case dev.Session != nil && bytes.Equal(dev.Session.Keys.SessionKeyId, msg.SessionKeyId): diff --git a/pkg/applicationserver/applicationserver_test.go b/pkg/applicationserver/applicationserver_test.go index 0c37b39110..ce5999de30 100644 --- a/pkg/applicationserver/applicationserver_test.go +++ b/pkg/applicationserver/applicationserver_test.go @@ -303,9 +303,7 @@ func TestApplicationServer(t *testing.T) { }, }, EndDeviceMetadataStorage: applicationserver.EndDeviceMetadataStorageConfig{ - Location: applicationserver.EndDeviceLocationStorageConfig{ - Registry: metadata.NewNoopEndDeviceLocationRegistry(), - }, + Registry: metadata.NewNoopEndDeviceRegistry(), }, Downlinks: applicationserver.DownlinksConfig{ ConfirmationConfig: applicationserver.ConfirmationConfig{ @@ -2414,9 +2412,7 @@ func TestSkipPayloadCrypto(t *testing.T) { }, }, EndDeviceMetadataStorage: applicationserver.EndDeviceMetadataStorageConfig{ - Location: applicationserver.EndDeviceLocationStorageConfig{ - Registry: metadata.NewNoopEndDeviceLocationRegistry(), - }, + Registry: metadata.NewNoopEndDeviceRegistry(), }, Downlinks: applicationserver.DownlinksConfig{ ConfirmationConfig: applicationserver.ConfirmationConfig{ @@ -2916,9 +2912,7 @@ func TestLocationFromPayload(t *testing.T) { }, }, EndDeviceMetadataStorage: applicationserver.EndDeviceMetadataStorageConfig{ - Location: applicationserver.EndDeviceLocationStorageConfig{ - Registry: metadata.NewClusterEndDeviceLocationRegistry(c, (1<<4)*Timeout), - }, + Registry: metadata.NewClusterEndDeviceRegistry(c, (1<<4)*Timeout), }, Downlinks: applicationserver.DownlinksConfig{ ConfirmationConfig: applicationserver.ConfirmationConfig{ @@ -3101,9 +3095,7 @@ func TestUplinkNormalized(t *testing.T) { }, }, EndDeviceMetadataStorage: applicationserver.EndDeviceMetadataStorageConfig{ - Location: applicationserver.EndDeviceLocationStorageConfig{ - Registry: metadata.NewClusterEndDeviceLocationRegistry(c, (1<<4)*Timeout), - }, + Registry: metadata.NewClusterEndDeviceRegistry(c, (1<<4)*Timeout), }, Downlinks: applicationserver.DownlinksConfig{ ConfirmationConfig: applicationserver.ConfirmationConfig{ diff --git a/pkg/applicationserver/config.go b/pkg/applicationserver/config.go index 54b46ca378..d9b69272fa 100644 --- a/pkg/applicationserver/config.go +++ b/pkg/applicationserver/config.go @@ -49,9 +49,9 @@ type InteropConfig struct { // EndDeviceFetcherConfig represents configuration for the end device fetcher in Application Server. type EndDeviceFetcherConfig struct { - Timeout time.Duration `name:"timeout" description:"Timeout of the end device retrival operation"` - Cache EndDeviceFetcherCacheConfig `name:"cache" description:"Cache configuration options for the end device fetcher"` - CircuitBreaker EndDeviceFetcherCircuitBreakerConfig `name:"circuit-breaker" description:"Circuit breaker options for the end device fetcher"` + Timeout time.Duration `name:"timeout" description:"Timeout of the end device retrival operation"` // nolint:lll + Cache EndDeviceFetcherCacheConfig `name:"cache" description:"Cache configuration options for the end device fetcher"` // nolint:lll + CircuitBreaker EndDeviceFetcherCircuitBreakerConfig `name:"circuit-breaker" description:"Circuit breaker options for the end device fetcher"` // nolint:lll } // EndDeviceFetcherCacheConfig represents configuration for device information caching in Application Server. @@ -65,33 +65,37 @@ type EndDeviceFetcherCacheConfig struct { type EndDeviceFetcherCircuitBreakerConfig struct { Enable bool `name:"enable" description:"Enable circuit breaker behavior on burst errors"` Timeout time.Duration `name:"timeout" description:"Timeout after which the circuit breaker closes"` - Threshold int `name:"threshold" description:"Number of failed fetching attempts after which the circuit breaker opens"` + Threshold int `name:"threshold" description:"Number of failed fetching attempts after which the circuit breaker opens"` // nolint:lll } // EndDeviceMetadataStorageConfig represents the configuration of end device metadata operations. type EndDeviceMetadataStorageConfig struct { - Location EndDeviceLocationStorageConfig `name:"location"` + // DEPRECATED: use the EndDeviceRegistry for location storage. + Location EndDeviceLocationStorageConfig `name:"location" description:"DEPRECATED setting."` + + Registry metadata.EndDeviceRegistry `name:"-"` + Timeout time.Duration `name:"timeout" description:"Timeout of the entity registry retrieval operation"` // nolint:lll } // EndDeviceLocationStorageConfig represents the configuration of end device locations storage. +// DEPRECATED: use the metadata.EndDeviceRegistry for location storage. type EndDeviceLocationStorageConfig struct { - Registry metadata.EndDeviceLocationRegistry `name:"-"` - Timeout time.Duration `name:"timeout" description:"Timeout of the end device retrival operation"` - Cache EndDeviceLocationStorageCacheConfig `name:"cache"` + Timeout time.Duration `name:"timeout" description:"Timeout of the end device retrieval operation. DEPRECATED: use the end device metadata storage directly instead."` // nolint:lll + Cache EndDeviceLocationStorageCacheConfig `name:"cache" description:"DEPRECATED: use the end device metadata storage directly instead."` // nolint:lll } // EndDeviceLocationStorageCacheConfig represents the configuration of end device location registry caching. +// DEPRECATED: use the metadata.EndDeviceRegistryCache and the locations field of end devices for caching. type EndDeviceLocationStorageCacheConfig struct { - Cache metadata.EndDeviceLocationCache `name:"-"` - Enable bool `name:"enable" description:"Enable caching of end device locations"` - MinRefreshInterval time.Duration `name:"min-refresh-interval" description:"Minimum time interval between two asynchronous refreshes"` - MaxRefreshInterval time.Duration `name:"max-refresh-interval" description:"Maximum time interval between two asynchronous refreshes"` - TTL time.Duration `name:"eviction-ttl" description:"Time to live of cached locations"` + Enable bool `name:"enable" description:"Enable caching of end device locations. DEPRECATED: use the end device metadata storage directly instead."` // nolint:lll + MinRefreshInterval time.Duration `name:"min-refresh-interval" description:"Minimum time interval between two asynchronous refreshes. DEPRECATED: use the end device metadata storage directly instead."` // nolint:lll + MaxRefreshInterval time.Duration `name:"max-refresh-interval" description:"Maximum time interval between two asynchronous refreshes. DEPRECATED: use the end device metadata storage directly instead."` // nolint:lll + TTL time.Duration `name:"eviction-ttl" description:"Time to live of cached locations. DEPRECATED: use the end device metadata storage directly instead."` // nolint:lll } // FormattersConfig represents the configuration for payload formatters. type FormattersConfig struct { - MaxParameterLength int `name:"max-parameter-length" description:"Maximum allowed size for length of formatter parameters (payload formatter scripts)"` + MaxParameterLength int `name:"max-parameter-length" description:"Maximum allowed size for length of formatter parameters (payload formatter scripts)"` // nolint:lll } // ConfirmationConfig represents the configuration for confirmed downlink. @@ -112,21 +116,21 @@ type PaginationConfig struct { // Config represents the ApplicationServer configuration. type Config struct { - LinkMode string `name:"link-mode" description:"Deprecated - mode to link applications to their Network Server (all, explicit)"` + LinkMode string `name:"link-mode" description:"Deprecated - mode to link applications to their Network Server (all, explicit)"` // nolint:lll Devices DeviceRegistry `name:"-"` Links LinkRegistry `name:"-"` UplinkStorage UplinkStorageConfig `name:"uplink-storage" description:"Application uplinks storage configuration"` Formatters FormattersConfig `name:"formatters" description:"Payload formatters configuration"` Distribution DistributionConfig `name:"distribution" description:"Distribution configuration"` - EndDeviceFetcher EndDeviceFetcherConfig `name:"fetcher" description:"Deprecated - End Device fetcher configuration"` - EndDeviceMetadataStorage EndDeviceMetadataStorageConfig `name:"end-device-metadata-storage" description:"End device metadata storage configuration"` + EndDeviceFetcher EndDeviceFetcherConfig `name:"fetcher" description:"Deprecated - End Device fetcher configuration"` // nolint:lll + EndDeviceMetadataStorage EndDeviceMetadataStorageConfig `name:"end-device-metadata-storage" description:"End device metadata storage configuration"` // nolint:lll MQTT config.MQTT `name:"mqtt" description:"MQTT configuration"` Webhooks WebhooksConfig `name:"webhooks" description:"Webhooks configuration"` PubSub PubSubConfig `name:"pubsub" description:"Pub/sub messaging configuration"` Packages ApplicationPackagesConfig `name:"packages" description:"Application packages configuration"` Interop InteropConfig `name:"interop" description:"Interop client configuration"` - DeviceKEKLabel string `name:"device-kek-label" description:"Label of KEK used to encrypt device keys at rest"` - DeviceLastSeen LastSeenConfig `name:"device-last-seen" description:"End Device last seen batch update configuration"` + DeviceKEKLabel string `name:"device-kek-label" description:"Label of KEK used to encrypt device keys at rest"` // nolint:lll + DeviceLastSeen LastSeenConfig `name:"device-last-seen" description:"End Device last seen batch update configuration"` // nolint:lll Downlinks DownlinksConfig `name:"downlinks" description:"Downlink configuration"` Pagination PaginationConfig `name:"pagination" description:"Pagination configuration"` } @@ -153,10 +157,10 @@ type UplinkStorageConfig struct { type WebhooksConfig struct { Registry web.WebhookRegistry `name:"-"` Target string `name:"target" description:"Target of the integration (direct)"` - Timeout time.Duration `name:"timeout" description:"Wait timeout of the target to process the request"` + Timeout time.Duration `name:"timeout" description:"Wait timeout of the target to process the request"` // nolint:lll QueueSize int `name:"queue-size" description:"Number of requests to queue"` Workers int `name:"workers" description:"Number of workers to process requests"` - UnhealthyAttemptsThreshold int `name:"unhealthy-attempts-threshold" description:"Number of failed webhook attempts before the webhook is disabled"` + UnhealthyAttemptsThreshold int `name:"unhealthy-attempts-threshold" description:"Number of failed webhook attempts before the webhook is disabled"` // nolint:lll UnhealthyRetryInterval time.Duration `name:"unhealthy-retry-interval" description:"Time interval after which disabled webhooks may execute again"` Templates web.TemplatesConfig `name:"templates" description:"The store of the webhook templates"` Downlinks web.DownlinksConfig `name:"downlink" description:"The downlink queue operations configuration"` @@ -292,7 +296,10 @@ func (c PubSubConfig) NewPubSub(comp *component.Component, server io.Server) (*p // NewApplicationPackages returns a new applications packages frontend based on the configuration. // If the registry is nil, it returns nil. -func (c ApplicationPackagesConfig) NewApplicationPackages(ctx context.Context, server io.Server) (packages.Server, error) { +func (c ApplicationPackagesConfig) NewApplicationPackages( + ctx context.Context, + server io.Server, +) (packages.Server, error) { if c.Registry == nil { return nil, nil } @@ -310,27 +317,19 @@ func (c ApplicationPackagesConfig) NewApplicationPackages(ctx context.Context, s return packages.New(ctx, server, c.Registry, handlers, c.Workers, c.Timeout) } -var ( - errInvalidTimeout = errors.DefineInvalidArgument("invalid_timeout", "invalid timeout `{timeout}`") - errInvalidTTL = errors.DefineInvalidArgument("invalid_ttl", "invalid TTL `{ttl}`") -) +var errInvalidTimeout = errors.DefineInvalidArgument("invalid_timeout", "invalid timeout `{timeout}`") -// NewRegistry returns a new end device location registry based on the configuration. -func (c EndDeviceLocationStorageConfig) NewRegistry(ctx context.Context, comp *component.Component) (metadata.EndDeviceLocationRegistry, error) { +// NewRegistry returns a new end device attributes registry based on the configuration. +func (c EndDeviceMetadataStorageConfig) NewRegistry( + _ context.Context, + comp *component.Component, +) (metadata.EndDeviceRegistry, error) { if c.Timeout <= 0 { return nil, errInvalidTimeout.WithAttributes("timeout", c.Timeout) } - registry := metadata.NewClusterEndDeviceLocationRegistry(comp, c.Timeout) - registry = metadata.NewMetricsEndDeviceLocationRegistry(registry) - if c.Cache.Enable { - for _, ttl := range []time.Duration{c.Cache.MinRefreshInterval, c.Cache.MaxRefreshInterval, c.Cache.TTL} { - if ttl <= 0 { - return nil, errInvalidTTL.WithAttributes("ttl", ttl) - } - } - cache := metadata.NewMetricsEndDeviceLocationCache(c.Cache.Cache) - registry = metadata.NewCachedEndDeviceLocationRegistry(ctx, comp, registry, cache, c.Cache.MinRefreshInterval, c.Cache.MaxRefreshInterval, c.Cache.TTL) - } + registry := metadata.NewClusterEndDeviceRegistry(comp, c.Timeout) + registry = metadata.NewMetricsEndDeviceRegistry(registry) + return registry, nil } diff --git a/pkg/applicationserver/metadata/cluster.go b/pkg/applicationserver/metadata/cluster.go new file mode 100644 index 0000000000..63eee88360 --- /dev/null +++ b/pkg/applicationserver/metadata/cluster.go @@ -0,0 +1,29 @@ +// Copyright © 2025 The Things Network Foundation, The Things Industries B.V. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package metadata + +import ( + "context" + + "go.thethings.network/lorawan-stack/v3/pkg/cluster" + "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" + "google.golang.org/grpc" +) + +// ClusterPeerAccess provides access to cluster peers. +type ClusterPeerAccess interface { + GetPeerConn(ctx context.Context, role ttnpb.ClusterRole, ids cluster.EntityIdentifiers) (*grpc.ClientConn, error) + WithClusterAuth() grpc.CallOption +} diff --git a/pkg/applicationserver/metadata/end_device_registry.go b/pkg/applicationserver/metadata/end_device_registry.go new file mode 100644 index 0000000000..d133c811b4 --- /dev/null +++ b/pkg/applicationserver/metadata/end_device_registry.go @@ -0,0 +1,215 @@ +// Copyright © 2025 The Things Network Foundation, The Things Industries B.V. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package metadata + +import ( + "context" + "time" + + "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" +) + +// allowedFieldMaskPaths defines the allowed field mask paths that can be accessed for end devices from this package. +// Calls to the entity registry require an IS roundtrip call which can be cross-continental. This must be done for a +// high volume of end devices, so we want to limit the amount of data that is being transferred. +var allowedFieldMaskPaths = []string{ + "attributes", + "locations", +} + +// EndDeviceRegistry interface for the identity server. +type EndDeviceRegistry interface { + // Get returns an end device from the entity registry by its identifiers. + Get(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers, paths []string) (*ttnpb.EndDevice, error) + // Set creates, updates or deletes an end device from the entity registry by its identifiers. + Set( + ctx context.Context, + ids *ttnpb.EndDeviceIdentifiers, + paths []string, + f func(*ttnpb.EndDevice) (*ttnpb.EndDevice, []string, error), + ) (*ttnpb.EndDevice, error) +} + +type noopEndDeviceRegistry struct{} + +// Get implements EndDeviceRegistry. +func (noopEndDeviceRegistry) Get( + _ context.Context, + _ *ttnpb.EndDeviceIdentifiers, + _ []string, +) (*ttnpb.EndDevice, error) { + return &ttnpb.EndDevice{}, nil // nolint: nilnil +} + +// Set implements EndDeviceRegistry. +func (noopEndDeviceRegistry) Set( + _ context.Context, + _ *ttnpb.EndDeviceIdentifiers, + _ []string, + f func(*ttnpb.EndDevice) (*ttnpb.EndDevice, []string, error), +) (*ttnpb.EndDevice, error) { + if f == nil { + return &ttnpb.EndDevice{}, nil // nolint: nilnil + } + + endDevice, _, err := f(&ttnpb.EndDevice{}) + return endDevice, err +} + +// NewNoopEndDeviceRegistry returns a noop EndDeviceRegistry. +func NewNoopEndDeviceRegistry() EndDeviceRegistry { + return noopEndDeviceRegistry{} +} + +type metricsEndDeviceRegistry struct { + inner EndDeviceRegistry +} + +// Get implements EndDeviceRegistry. +func (m *metricsEndDeviceRegistry) Get( + ctx context.Context, + ids *ttnpb.EndDeviceIdentifiers, + paths []string, +) (*ttnpb.EndDevice, error) { + registerMetadataRegistryRetrieval(ctx, endDeviceLabel) + return m.inner.Get(ctx, ids, paths) +} + +// Set implements EndDeviceRegistry. +func (m *metricsEndDeviceRegistry) Set( + ctx context.Context, + ids *ttnpb.EndDeviceIdentifiers, + paths []string, + f func(*ttnpb.EndDevice) (*ttnpb.EndDevice, []string, error), +) (*ttnpb.EndDevice, error) { + registerMetadataRegistryUpdate(ctx, endDeviceLabel) + return m.inner.Set(ctx, ids, paths, f) +} + +// NewMetricsEndDeviceRegistry returns an EndDeviceRegistry that collects metrics. +func NewMetricsEndDeviceRegistry(inner EndDeviceRegistry) EndDeviceRegistry { + return &metricsEndDeviceRegistry{ + inner: inner, + } +} + +type clusterEndDeviceRegistry struct { + ClusterPeerAccess + timeout time.Duration +} + +// Get implements EndDeviceRegistry. +func (c clusterEndDeviceRegistry) Get( + ctx context.Context, + ids *ttnpb.EndDeviceIdentifiers, + paths []string, +) (*ttnpb.EndDevice, error) { + paths, err := processEndDeviceFieldMaskPaths(paths) + if err != nil { + return nil, err + } + + cc, err := c.GetPeerConn(ctx, ttnpb.ClusterRole_ENTITY_REGISTRY, nil) + if err != nil { + return nil, err + } + + cl := ttnpb.NewEndDeviceRegistryClient(cc) + ctx, cancel := context.WithTimeout(ctx, c.timeout) + defer cancel() + + dev, err := cl.Get(ctx, &ttnpb.GetEndDeviceRequest{ + EndDeviceIds: ids, + FieldMask: ttnpb.FieldMask(paths...), + }, c.WithClusterAuth()) + if err != nil { + return nil, err + } + + return dev, nil +} + +// Set implements EndDeviceRegistry. +func (c clusterEndDeviceRegistry) Set( + ctx context.Context, + ids *ttnpb.EndDeviceIdentifiers, + paths []string, + f func(*ttnpb.EndDevice) (*ttnpb.EndDevice, []string, error), +) (*ttnpb.EndDevice, error) { + paths, err := processEndDeviceFieldMaskPaths(paths) + if err != nil { + return nil, err + } + + cc, err := c.GetPeerConn(ctx, ttnpb.ClusterRole_ENTITY_REGISTRY, nil) + if err != nil { + return nil, err + } + + cl := ttnpb.NewEndDeviceRegistryClient(cc) + ctx, cancel := context.WithTimeout(ctx, c.timeout) + defer cancel() + + dev, err := cl.Get(ctx, &ttnpb.GetEndDeviceRequest{ + EndDeviceIds: ids, + FieldMask: ttnpb.FieldMask(paths...), + }, c.WithClusterAuth()) + if err != nil { + return nil, err + } + + dev, paths, err = f(dev) + if err != nil || dev == nil { + return nil, err + } + dev, err = cl.Update(ctx, &ttnpb.UpdateEndDeviceRequest{ + EndDevice: dev, + FieldMask: ttnpb.FieldMask(paths...), + }, c.WithClusterAuth()) + if err != nil { + return nil, err + } + + return dev, nil +} + +// NewClusterEndDeviceRegistry returns an EndDeviceRegistry connected to the entity registry of the Identity Server. +func NewClusterEndDeviceRegistry(cluster ClusterPeerAccess, timeout time.Duration) EndDeviceRegistry { + return &clusterEndDeviceRegistry{ + ClusterPeerAccess: cluster, + timeout: timeout, + } +} + +func processEndDeviceFieldMaskPaths(paths []string) ([]string, error) { + if len(paths) == 0 { + return allowedFieldMaskPaths, nil + } + + if err := validateEndDevicePaths(paths); err != nil { + return nil, err + } + + return paths, nil +} + +func validateEndDevicePaths(paths []string) error { + allowedFieldMaskSet := ttnpb.FieldMaskPathsSet(allowedFieldMaskPaths) + if ok, firstNotAllowedPath := ttnpb.FieldMaskPathsSetContainsAll(allowedFieldMaskSet, paths...); !ok { + return errFieldMaskPathNotSupported.WithAttributes("path", firstNotAllowedPath) + } + + return nil +} diff --git a/pkg/applicationserver/metadata/end_device_registry_test.go b/pkg/applicationserver/metadata/end_device_registry_test.go new file mode 100644 index 0000000000..9aac154a89 --- /dev/null +++ b/pkg/applicationserver/metadata/end_device_registry_test.go @@ -0,0 +1,210 @@ +// Copyright © 2025 The Things Network Foundation, The Things Industries B.V. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package metadata_test + +import ( + "testing" + "time" + + "go.thethings.network/lorawan-stack/v3/pkg/errors" + + "go.thethings.network/lorawan-stack/v3/pkg/applicationserver/metadata" + "go.thethings.network/lorawan-stack/v3/pkg/cluster" + "go.thethings.network/lorawan-stack/v3/pkg/component" + componenttest "go.thethings.network/lorawan-stack/v3/pkg/component/test" + "go.thethings.network/lorawan-stack/v3/pkg/config" + mockis "go.thethings.network/lorawan-stack/v3/pkg/identityserver/mock" + "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" + "go.thethings.network/lorawan-stack/v3/pkg/util/test" + "go.thethings.network/lorawan-stack/v3/pkg/util/test/assertions/should" +) + +var ( + originalLocations = map[string]*ttnpb.Location{ + "baz": { + Altitude: 12, + Latitude: 23, + }, + } + locationsPatch = map[string]*ttnpb.Location{ + "bzz": { + Altitude: 23, + Latitude: 34, + }, + } + + originalAttributes = map[string]string{ + "attr1": "val1", + "attr2": "val2", + } + + attributesPatch = map[string]string{ + "attr3": "val3", + "attr4": "val4", + } +) + +func TestClusterEndDeviceRegistry(t *testing.T) { // nolint:gocyclo + registeredEndDeviceIDs := &ttnpb.EndDeviceIdentifiers{ + ApplicationIds: &ttnpb.ApplicationIdentifiers{ + ApplicationId: "foo", + }, + DeviceId: "bar", + } + + t.Parallel() + + a, ctx := test.New(t) + is, isAddr, closeIS := mockis.New(ctx) + defer closeIS() + + registeredEndDevice := ttnpb.EndDevice{ + Ids: registeredEndDeviceIDs, + Locations: originalLocations, + Attributes: originalAttributes, + } + is.EndDeviceRegistry().Add(ctx, ®isteredEndDevice) + + c := componenttest.NewComponent(t, &component.Config{ + ServiceBase: config.ServiceBase{ + Cluster: cluster.Config{ + IdentityServer: isAddr, + }, + }, + }) + componenttest.StartComponent(t, c) + defer c.Close() + mustHavePeer(ctx, c, ttnpb.ClusterRole_ENTITY_REGISTRY) + + registry := metadata.NewClusterEndDeviceRegistry(c, 10*time.Second) + + _, err := registry.Get(ctx, registeredEndDeviceIDs, []string{ + "network_server_address", "application_server_address", "join_server_address", + }) + a.So(errors.IsInvalidArgument(err), should.BeTrue) + + dev, err := registry.Get(ctx, registeredEndDeviceIDs, []string{"attributes", "locations"}) + if a.So(err, should.BeNil) { + a.So(dev, should.NotBeNil) + + a.So(dev.Locations, should.NotBeNil) + a.So(len(dev.Locations), should.Equal, len(registeredEndDevice.Locations)) + for k, v := range dev.Locations { + a.So(registeredEndDevice.Locations[k], should.Resemble, v) + } + for k, v := range originalLocations { + a.So(dev.Locations[k], should.Resemble, v) + } + + a.So(dev.Attributes, should.NotBeNil) + a.So(len(dev.Attributes), should.Equal, len(registeredEndDevice.Attributes)) + for k, v := range dev.Attributes { + a.So(registeredEndDevice.Attributes[k], should.Equal, v) + } + for k, v := range originalAttributes { + a.So(dev.Attributes[k], should.Equal, v) + } + } + + _, err = registry.Set(ctx, registeredEndDeviceIDs, []string{ + "network_server_address", "application_server_address", "join_server_address", + }, func(_ *ttnpb.EndDevice) (*ttnpb.EndDevice, []string, error) { + return nil, nil, nil // nolint: nilnil + }) + a.So(errors.IsInvalidArgument(err), should.BeTrue) + + // Update location and attributes. + dev, err = registry.Set(ctx, registeredEndDeviceIDs, []string{"locations", "attributes"}, + func(stored *ttnpb.EndDevice) (*ttnpb.EndDevice, []string, error) { + if stored == nil { + return nil, nil, errors.New("not found") + } + + if len(stored.Locations) == 0 { + stored.Locations = make(map[string]*ttnpb.Location, len(locationsPatch)) + } + + for k, l := range locationsPatch { + stored.Locations[k] = l + } + + if len(stored.Attributes) == 0 { + stored.Attributes = make(map[string]string, len(attributesPatch)) + } + + for k, v := range attributesPatch { + stored.Attributes[k] = v + } + + return stored, []string{"locations", "attributes"}, nil + }, + ) + if a.So(err, should.BeNil) { + a.So(dev, should.NotBeNil) + + a.So(dev.Locations, should.NotBeNil) + a.So(len(dev.Locations), should.Equal, len(registeredEndDevice.Locations)) + for k, v := range dev.Locations { + a.So(registeredEndDevice.Locations[k], should.Resemble, v) + } + for k, v := range originalLocations { + a.So(dev.Locations[k], should.Resemble, v) + } + for k, v := range locationsPatch { + a.So(dev.Locations[k], should.Resemble, v) + } + + a.So(dev.Attributes, should.NotBeNil) + a.So(len(dev.Attributes), should.Equal, len(registeredEndDevice.Attributes)) + for k, v := range dev.Attributes { + a.So(registeredEndDevice.Attributes[k], should.Equal, v) + } + for k, v := range originalAttributes { + a.So(dev.Attributes[k], should.Equal, v) + } + for k, v := range attributesPatch { + a.So(dev.Attributes[k], should.Equal, v) + } + } + + dev, err = registry.Get(ctx, registeredEndDeviceIDs, []string{"attributes", "locations"}) + if a.So(err, should.BeNil) { + a.So(dev, should.NotBeNil) + + a.So(dev.Locations, should.NotBeNil) + a.So(len(dev.Locations), should.Equal, len(registeredEndDevice.Locations)) + for k, v := range dev.Locations { + a.So(registeredEndDevice.Locations[k], should.Resemble, v) + } + for k, v := range originalLocations { + a.So(dev.Locations[k], should.Resemble, v) + } + for k, v := range locationsPatch { + a.So(dev.Locations[k], should.Resemble, v) + } + + a.So(dev.Attributes, should.NotBeNil) + a.So(len(dev.Attributes), should.Equal, len(registeredEndDevice.Attributes)) + for k, v := range dev.Attributes { + a.So(registeredEndDevice.Attributes[k], should.Equal, v) + } + for k, v := range originalAttributes { + a.So(dev.Attributes[k], should.Equal, v) + } + for k, v := range attributesPatch { + a.So(dev.Attributes[k], should.Equal, v) + } + } +} diff --git a/pkg/applicationserver/metadata/location_cache.go b/pkg/applicationserver/metadata/location_cache.go deleted file mode 100644 index 6ad1a3de1a..0000000000 --- a/pkg/applicationserver/metadata/location_cache.go +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright © 2021 The Things Network Foundation, The Things Industries B.V. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package metadata - -import ( - "context" - "time" - - "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" -) - -// EndDeviceLocationCache is a cache for end device locations. -type EndDeviceLocationCache interface { - // Get retrieves the end device locations and the remaining TTL for the entry. - Get(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers) (map[string]*ttnpb.Location, *time.Time, error) - // Set sets the end device locations. - Set(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers, update map[string]*ttnpb.Location, ttl time.Duration) error - // Delete removes the locations from the cache. - Delete(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers) error -} - -type metricsEndDeviceLocationCache struct { - inner EndDeviceLocationCache -} - -// Get implements EndDeviceLocationCache. -func (c *metricsEndDeviceLocationCache) Get(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers) (map[string]*ttnpb.Location, *time.Time, error) { - m, storedAt, err := c.inner.Get(ctx, ids) - if storedAt == nil { - registerMetadataCacheMiss(ctx, locationLabel) - } else { - registerMetadataCacheHit(ctx, locationLabel) - } - return m, storedAt, err -} - -// Set implements EndDeviceLocationCache. -func (c *metricsEndDeviceLocationCache) Set(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers, update map[string]*ttnpb.Location, ttl time.Duration) error { - return c.inner.Set(ctx, ids, update, ttl) -} - -// Delete implements EndDeviceLocationCache. -func (c *metricsEndDeviceLocationCache) Delete(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers) error { - return c.inner.Delete(ctx, ids) -} - -// NewMetricsEndDeviceLocationCache constructs an EndDeviceLocationCache that collects metrics. -func NewMetricsEndDeviceLocationCache(inner EndDeviceLocationCache) EndDeviceLocationCache { - return &metricsEndDeviceLocationCache{ - inner: inner, - } -} diff --git a/pkg/applicationserver/metadata/location_registry.go b/pkg/applicationserver/metadata/location_registry.go deleted file mode 100644 index b1c1a5fcef..0000000000 --- a/pkg/applicationserver/metadata/location_registry.go +++ /dev/null @@ -1,242 +0,0 @@ -// Copyright © 2021 The Things Network Foundation, The Things Industries B.V. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package metadata - -import ( - "context" - "time" - - "go.thethings.network/lorawan-stack/v3/pkg/cluster" - "go.thethings.network/lorawan-stack/v3/pkg/errors" - "go.thethings.network/lorawan-stack/v3/pkg/log" - "go.thethings.network/lorawan-stack/v3/pkg/random" - "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" - "go.thethings.network/lorawan-stack/v3/pkg/workerpool" - "google.golang.org/grpc" -) - -// EndDeviceLocationRegistry is a registry for end device locations. -type EndDeviceLocationRegistry interface { - // Get retrieves the end device locations. - Get(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers) (map[string]*ttnpb.Location, error) - // Merge merges the end device locations. - Merge(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers, update map[string]*ttnpb.Location) (map[string]*ttnpb.Location, error) -} - -type noopEndDeviceLocationRegistry struct{} - -// Get implements EndDeviceLocationRegistry. -func (noopEndDeviceLocationRegistry) Get(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers) (map[string]*ttnpb.Location, error) { - return nil, nil -} - -// Merge implements EndDeviceLocationRegistry. -func (noopEndDeviceLocationRegistry) Merge(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers, update map[string]*ttnpb.Location) (map[string]*ttnpb.Location, error) { - return update, nil -} - -// NewNoopEndDeviceLocationRegistry returns a noop EndDeviceLocationRegistry. -func NewNoopEndDeviceLocationRegistry() EndDeviceLocationRegistry { - return noopEndDeviceLocationRegistry{} -} - -type metricsEndDeviceLocationRegistry struct { - inner EndDeviceLocationRegistry -} - -// Get implements EndDeviceLocationRegistry. -func (m *metricsEndDeviceLocationRegistry) Get(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers) (map[string]*ttnpb.Location, error) { - registerMetadataRegistryRetrieval(ctx, locationLabel) - return m.inner.Get(ctx, ids) -} - -// Merge implements EndDeviceLocationRegistry. -func (m *metricsEndDeviceLocationRegistry) Merge(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers, update map[string]*ttnpb.Location) (map[string]*ttnpb.Location, error) { - registerMetadataRegistryUpdate(ctx, locationLabel) - return m.inner.Merge(ctx, ids, update) -} - -// NewMetricsEndDeviceLocationRegistry returns an EndDeviceLocationRegistry that collects metrics. -func NewMetricsEndDeviceLocationRegistry(inner EndDeviceLocationRegistry) EndDeviceLocationRegistry { - return &metricsEndDeviceLocationRegistry{ - inner: inner, - } -} - -// ClusterPeerAccess provides access to cluster peers. -type ClusterPeerAccess interface { - GetPeerConn(ctx context.Context, role ttnpb.ClusterRole, ids cluster.EntityIdentifiers) (*grpc.ClientConn, error) - WithClusterAuth() grpc.CallOption -} - -var endDeviceLocationFieldMask = ttnpb.FieldMask("locations") - -type clusterEndDeviceLocationRegistry struct { - ClusterPeerAccess - timeout time.Duration -} - -// Get implements EndDeviceLocationRegistry. -func (c clusterEndDeviceLocationRegistry) Get(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers) (map[string]*ttnpb.Location, error) { - cc, err := c.GetPeerConn(ctx, ttnpb.ClusterRole_ENTITY_REGISTRY, nil) - if err != nil { - return nil, err - } - cl := ttnpb.NewEndDeviceRegistryClient(cc) - ctx, cancel := context.WithTimeout(ctx, c.timeout) - defer cancel() - dev, err := cl.Get(ctx, &ttnpb.GetEndDeviceRequest{ - EndDeviceIds: ids, - FieldMask: endDeviceLocationFieldMask, - }, c.WithClusterAuth()) - if err != nil { - return nil, err - } - return dev.Locations, nil -} - -// Merge implements EndDeviceLocationRegistry. -func (c clusterEndDeviceLocationRegistry) Merge(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers, update map[string]*ttnpb.Location) (map[string]*ttnpb.Location, error) { - cc, err := c.GetPeerConn(ctx, ttnpb.ClusterRole_ENTITY_REGISTRY, nil) - if err != nil { - return nil, err - } - cl := ttnpb.NewEndDeviceRegistryClient(cc) - ctx, cancel := context.WithTimeout(ctx, c.timeout) - defer cancel() - dev, err := cl.Get(ctx, &ttnpb.GetEndDeviceRequest{ - EndDeviceIds: ids, - FieldMask: endDeviceLocationFieldMask, - }, c.WithClusterAuth()) - if err != nil { - return nil, err - } - if len(update) == 0 { - return dev.Locations, nil - } - if dev.Locations == nil { - dev.Locations = make(map[string]*ttnpb.Location, len(update)) - } - for k, l := range update { - dev.Locations[k] = l - } - _, err = cl.Update(ctx, &ttnpb.UpdateEndDeviceRequest{ - EndDevice: &ttnpb.EndDevice{ - Ids: ids, - Locations: dev.Locations, - }, - FieldMask: endDeviceLocationFieldMask, - }, c.WithClusterAuth()) - if err != nil { - return nil, err - } - return dev.Locations, nil -} - -// NewClusterEndDeviceLocationRegistry returns an EndDeviceLocationRegistry connected to the Entity Registry. -func NewClusterEndDeviceLocationRegistry(cluster ClusterPeerAccess, timeout time.Duration) EndDeviceLocationRegistry { - return &clusterEndDeviceLocationRegistry{ - ClusterPeerAccess: cluster, - timeout: timeout, - } -} - -type cachedEndDeviceLocationRegistry struct { - registry EndDeviceLocationRegistry - cache EndDeviceLocationCache - - minRefreshInterval time.Duration - maxRefreshInterval time.Duration - ttl time.Duration - - replicationPool workerpool.WorkerPool[*ttnpb.EndDeviceIdentifiers] -} - -// Get implements EndDeviceLocationRegistry. -func (c *cachedEndDeviceLocationRegistry) Get(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers) (map[string]*ttnpb.Location, error) { - locations, storedAt, err := c.cache.Get(ctx, ids) - switch { - case err != nil && !errors.IsNotFound(err): - return nil, err - case err != nil && errors.IsNotFound(err): - locations = nil - case err == nil: - age := time.Since(*storedAt) - if age <= c.minRefreshInterval { - // If the object is younger than the minimum refresh interval, just return the cached value. - return locations, nil - } - if remaining := c.maxRefreshInterval - age; remaining > 0 { - // If the objects age is between the minimum and maximum refresh interval, check if we should asynchronously - // refresh the cache. - window := c.maxRefreshInterval - c.minRefreshInterval - threshold := time.Duration(random.Int63n(int64(window))) - // remaining is the remaining window of the refresh interval in the (0, window) interval. - // threshold is a uniformly distributed duration in the [0, window) interval. - if remaining >= threshold { - return locations, nil - } - } - } - if err := c.replicationPool.Publish(ctx, ids); err != nil { - log.FromContext(ctx).WithError(err).Warn("Failed to publish end device locations replication request") - } - return locations, nil -} - -// Merge implements EndDeviceLocationRegistry. -func (c *cachedEndDeviceLocationRegistry) Merge(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers, update map[string]*ttnpb.Location) (map[string]*ttnpb.Location, error) { - locations, err := c.registry.Merge(ctx, ids, update) - if err != nil { - return nil, err - } - if err := c.cache.Set(ctx, ids, locations, c.ttl); err != nil { - return nil, err - } - return locations, nil -} - -// NewCachedEndDeviceLocationRegistry returns an EndDeviceLocationRegistry that caches the responses of the provided EndDeviceLocationRegistry in the provided -// EndDeviceLocationCache. On cache miss, the registry will retrieve and cache the locations asynchronously. -// Items whose TTL is within the soft TTL window have a chance to trigger an asynchronous cache synchronization event on location retrieval. -// The probability of a synchronization event increases linearly between the soft TTL (0%) and the hard TTL (100%). -func NewCachedEndDeviceLocationRegistry(ctx context.Context, c workerpool.Component, registry EndDeviceLocationRegistry, cache EndDeviceLocationCache, minRefreshInterval, maxRefreshInterval, ttl time.Duration) EndDeviceLocationRegistry { - st := &cachedEndDeviceLocationRegistry{ - registry: registry, - cache: cache, - - minRefreshInterval: minRefreshInterval, - maxRefreshInterval: maxRefreshInterval, - ttl: ttl, - - replicationPool: workerpool.NewWorkerPool(workerpool.Config[*ttnpb.EndDeviceIdentifiers]{ - Component: c, - Context: ctx, - Name: "replicate_end_device_locations", - Handler: func(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers) { - locations, err := registry.Get(ctx, ids) - if err != nil { - log.FromContext(ctx).WithError(err).Warn("Failed to retrieve end device locations") - return - } - if err := cache.Set(ctx, ids, locations, ttl); err != nil { - log.FromContext(ctx).WithError(err).Warn("Failed to cache end device locations") - return - } - }, - }), - } - return st -} diff --git a/pkg/applicationserver/metadata/location_registry_test.go b/pkg/applicationserver/metadata/location_registry_test.go deleted file mode 100644 index f366942a04..0000000000 --- a/pkg/applicationserver/metadata/location_registry_test.go +++ /dev/null @@ -1,274 +0,0 @@ -// Copyright © 2021 The Things Network Foundation, The Things Industries B.V. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package metadata_test - -import ( - "context" - "testing" - "time" - - "go.thethings.network/lorawan-stack/v3/pkg/applicationserver/metadata" - "go.thethings.network/lorawan-stack/v3/pkg/applicationserver/metadata/redis" - "go.thethings.network/lorawan-stack/v3/pkg/cluster" - "go.thethings.network/lorawan-stack/v3/pkg/component" - componenttest "go.thethings.network/lorawan-stack/v3/pkg/component/test" - "go.thethings.network/lorawan-stack/v3/pkg/config" - mockis "go.thethings.network/lorawan-stack/v3/pkg/identityserver/mock" - "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" - "go.thethings.network/lorawan-stack/v3/pkg/util/test" - "go.thethings.network/lorawan-stack/v3/pkg/util/test/assertions/should" -) - -func mustHavePeer(ctx context.Context, c *component.Component, role ttnpb.ClusterRole) { - for i := 0; i < 20; i++ { - time.Sleep(20 * time.Millisecond) - if _, err := c.GetPeer(ctx, role, nil); err == nil { - return - } - } - panic("could not connect to peer") -} - -var ( - registeredEndDeviceIDs = &ttnpb.EndDeviceIdentifiers{ - ApplicationIds: &ttnpb.ApplicationIdentifiers{ - ApplicationId: "foo", - }, - DeviceId: "bar", - } - originalLocations = map[string]*ttnpb.Location{ - "baz": { - Altitude: 12, - Latitude: 23, - }, - } - locationsPatch = map[string]*ttnpb.Location{ - "bzz": { - Altitude: 23, - Latitude: 34, - }, - } - Timeout = (1 << 7) * test.Delay -) - -func TestClusterEndDeviceLocationRegistry(t *testing.T) { - a, ctx := test.New(t) - is, isAddr, closeIS := mockis.New(ctx) - defer closeIS() - - registeredEndDevice := ttnpb.EndDevice{ - Ids: registeredEndDeviceIDs, - Locations: originalLocations, - } - is.EndDeviceRegistry().Add(ctx, ®isteredEndDevice) - - c := componenttest.NewComponent(t, &component.Config{ - ServiceBase: config.ServiceBase{ - Cluster: cluster.Config{ - IdentityServer: isAddr, - }, - }, - }) - componenttest.StartComponent(t, c) - defer c.Close() - mustHavePeer(ctx, c, ttnpb.ClusterRole_ENTITY_REGISTRY) - - registry := metadata.NewClusterEndDeviceLocationRegistry(c, 10*time.Second) - - locations, err := registry.Get(ctx, registeredEndDeviceIDs) - if a.So(err, should.BeNil) { - a.So(locations, should.NotBeNil) - a.So(len(locations), should.Equal, len(registeredEndDevice.Locations)) - for k, v := range locations { - a.So(registeredEndDevice.Locations[k], should.Resemble, v) - } - for k, v := range originalLocations { - a.So(locations[k], should.Resemble, v) - } - } - - locations, err = registry.Merge(ctx, registeredEndDeviceIDs, locationsPatch) - if a.So(err, should.BeNil) { - a.So(locations, should.NotBeNil) - a.So(len(locations), should.Equal, len(registeredEndDevice.Locations)) - for k, v := range locations { - a.So(registeredEndDevice.Locations[k], should.Resemble, v) - } - for k, v := range originalLocations { - a.So(locations[k], should.Resemble, v) - } - for k, v := range locationsPatch { - a.So(locations[k], should.Resemble, v) - } - } - - locations, err = registry.Get(ctx, registeredEndDeviceIDs) - if a.So(err, should.BeNil) { - a.So(locations, should.NotBeNil) - a.So(len(locations), should.Equal, len(registeredEndDevice.Locations)) - for k, v := range locations { - a.So(registeredEndDevice.Locations[k], should.Resemble, v) - } - for k, v := range originalLocations { - a.So(locations[k], should.Resemble, v) - } - for k, v := range locationsPatch { - a.So(locations[k], should.Resemble, v) - } - } -} - -func TestCachedEndDeviceLocationRegistry(t *testing.T) { - a, ctx := test.New(t) - is, isAddr, closeIS := mockis.New(ctx) - defer closeIS() - - registeredEndDevice := ttnpb.EndDevice{ - Ids: registeredEndDeviceIDs, - Locations: originalLocations, - } - is.EndDeviceRegistry().Add(ctx, ®isteredEndDevice) - - c := componenttest.NewComponent(t, &component.Config{ - ServiceBase: config.ServiceBase{ - Cluster: cluster.Config{ - IdentityServer: isAddr, - }, - }, - }) - componenttest.StartComponent(t, c) - defer c.Close() - mustHavePeer(ctx, c, ttnpb.ClusterRole_ENTITY_REGISTRY) - - registry := metadata.NewClusterEndDeviceLocationRegistry(c, 4*Timeout) - cl, flush := test.NewRedis(ctx, "metadata_redis_test") - defer flush() - cache := &redis.EndDeviceLocationCache{ - Redis: cl, - } - registry = metadata.NewCachedEndDeviceLocationRegistry( - ctx, c, registry, cache, 4*Timeout, 8*Timeout, 16*Timeout, - ) - - locations, err := registry.Get(ctx, registeredEndDeviceIDs) - a.So(err, should.BeNil) - a.So(locations, should.HaveLength, 0) - - // Wait for the cache to be populated asynchronously. - time.Sleep(Timeout) - - locations, err = registry.Get(ctx, registeredEndDeviceIDs) - if a.So(err, should.BeNil) { - a.So(locations, should.NotBeNil) - a.So(len(locations), should.Equal, len(originalLocations)) - for k, v := range originalLocations { - a.So(locations[k], should.Resemble, v) - } - } - - locations, err = registry.Merge(ctx, registeredEndDeviceIDs, locationsPatch) - if a.So(err, should.BeNil) { - a.So(locations, should.NotBeNil) - a.So(len(locations), should.Equal, len(registeredEndDevice.Locations)) - for k, v := range locations { - a.So(registeredEndDevice.Locations[k], should.Resemble, v) - } - for k, v := range originalLocations { - a.So(locations[k], should.Resemble, v) - } - for k, v := range locationsPatch { - a.So(locations[k], should.Resemble, v) - } - } - - locations, err = registry.Get(ctx, registeredEndDeviceIDs) - if a.So(err, should.BeNil) { - a.So(locations, should.NotBeNil) - a.So(len(locations), should.Equal, len(registeredEndDevice.Locations)) - for k, v := range locations { - a.So(registeredEndDevice.Locations[k], should.Resemble, v) - } - for k, v := range originalLocations { - a.So(locations[k], should.Resemble, v) - } - for k, v := range locationsPatch { - a.So(locations[k], should.Resemble, v) - } - } - - // Wait for the entry to be evicted. - time.Sleep(20 * Timeout) - - // There is no cached location anymore, and we have triggered an asynchronous refresh. - locations, err = registry.Get(ctx, registeredEndDeviceIDs) - a.So(err, should.BeNil) - a.So(locations, should.HaveLength, 0) - - time.Sleep(Timeout) - - locations, err = registry.Get(ctx, registeredEndDeviceIDs) - if a.So(err, should.BeNil) { - a.So(locations, should.NotBeNil) - a.So(len(locations), should.Equal, len(registeredEndDevice.Locations)) - for k, v := range locations { - a.So(registeredEndDevice.Locations[k], should.Resemble, v) - } - for k, v := range originalLocations { - a.So(locations[k], should.Resemble, v) - } - for k, v := range locationsPatch { - a.So(locations[k], should.Resemble, v) - } - } - - // Simulate a network partition. - closeIS() - time.Sleep(Timeout) - - // Do a read that will trigger an asynchronous cache refresh. - locations, err = registry.Get(ctx, registeredEndDeviceIDs) - if a.So(err, should.BeNil) { - a.So(locations, should.NotBeNil) - a.So(len(locations), should.Equal, len(registeredEndDevice.Locations)) - for k, v := range locations { - a.So(registeredEndDevice.Locations[k], should.Resemble, v) - } - for k, v := range originalLocations { - a.So(locations[k], should.Resemble, v) - } - for k, v := range locationsPatch { - a.So(locations[k], should.Resemble, v) - } - } - - // Wait for the partition to be detected asynchronously. - time.Sleep(Timeout) - - // We now serve stale data. - locations, err = registry.Get(ctx, registeredEndDeviceIDs) - if a.So(err, should.BeNil) { - a.So(locations, should.NotBeNil) - a.So(len(locations), should.Equal, len(registeredEndDevice.Locations)) - for k, v := range locations { - a.So(registeredEndDevice.Locations[k], should.Resemble, v) - } - for k, v := range originalLocations { - a.So(locations[k], should.Resemble, v) - } - for k, v := range locationsPatch { - a.So(locations[k], should.Resemble, v) - } - } -} diff --git a/pkg/applicationserver/metadata/metadata.go b/pkg/applicationserver/metadata/metadata.go new file mode 100644 index 0000000000..fb442095c6 --- /dev/null +++ b/pkg/applicationserver/metadata/metadata.go @@ -0,0 +1,21 @@ +// Copyright © 2025 The Things Network Foundation, The Things Industries B.V. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package metadata contains the metadata registry clients. +package metadata + +import "go.thethings.network/lorawan-stack/v3/pkg/errors" + +var errFieldMaskPathNotSupported = errors.DefineInvalidArgument( + "field_mask_path_not_supported", "field mask path `{path}` is not supported") diff --git a/pkg/applicationserver/metadata/metadata_util_test.go b/pkg/applicationserver/metadata/metadata_util_test.go new file mode 100644 index 0000000000..56407cc45b --- /dev/null +++ b/pkg/applicationserver/metadata/metadata_util_test.go @@ -0,0 +1,33 @@ +// Copyright © 2025 The Things Network Foundation, The Things Industries B.V. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package metadata_test + +import ( + "context" + "time" + + "go.thethings.network/lorawan-stack/v3/pkg/component" + "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" +) + +func mustHavePeer(ctx context.Context, c *component.Component, role ttnpb.ClusterRole) { // nolint: unparam + for i := 0; i < 20; i++ { + time.Sleep(20 * time.Millisecond) + if _, err := c.GetPeer(ctx, role, nil); err == nil { + return + } + } + panic("could not connect to peer") +} diff --git a/pkg/applicationserver/metadata/observability.go b/pkg/applicationserver/metadata/observability.go index 64ff2f6bc3..75a3c93408 100644 --- a/pkg/applicationserver/metadata/observability.go +++ b/pkg/applicationserver/metadata/observability.go @@ -22,28 +22,13 @@ import ( ) const ( - subsystem = "as_metadata" - metadataLabel = "metadata" - locationLabel = "location" + subsystem = "as_metadata" + metadataLabel = "metadata" + locationLabel = "location" + endDeviceLabel = "end_device" ) var metaMetrics = &metadataMetrics{ - cacheHits: metrics.NewCounterVec( - prometheus.CounterOpts{ - Subsystem: subsystem, - Name: "cache_hits_total", - Help: "Total number of metadata cache hits", - }, - []string{metadataLabel}, - ), - cacheMisses: metrics.NewCounterVec( - prometheus.CounterOpts{ - Subsystem: subsystem, - Name: "cache_misses_total", - Help: "Total number of metadata cache misses", - }, - []string{metadataLabel}, - ), registryRetrievals: metrics.NewCounterVec( prometheus.CounterOpts{ Subsystem: subsystem, @@ -67,40 +52,24 @@ func init() { } type metadataMetrics struct { - cacheHits *prometheus.CounterVec - cacheMisses *prometheus.CounterVec registryRetrievals *prometheus.CounterVec registryUpdates *prometheus.CounterVec } func (m metadataMetrics) Describe(ch chan<- *prometheus.Desc) { - m.cacheHits.Describe(ch) - m.cacheMisses.Describe(ch) m.registryRetrievals.Describe(ch) m.registryUpdates.Describe(ch) } func (m metadataMetrics) Collect(ch chan<- prometheus.Metric) { - m.cacheHits.Collect(ch) - m.cacheMisses.Collect(ch) m.registryRetrievals.Collect(ch) m.registryUpdates.Collect(ch) } -func registerMetadataCacheHit(ctx context.Context, metadata string) { - metaMetrics.cacheHits.WithLabelValues(metadata).Inc() - metaMetrics.cacheMisses.WithLabelValues(metadata) -} - -func registerMetadataCacheMiss(ctx context.Context, metadata string) { - metaMetrics.cacheHits.WithLabelValues(metadata) - metaMetrics.cacheMisses.WithLabelValues(metadata).Inc() -} - -func registerMetadataRegistryRetrieval(ctx context.Context, metadata string) { +func registerMetadataRegistryRetrieval(_ context.Context, metadata string) { metaMetrics.registryRetrievals.WithLabelValues(metadata).Inc() } -func registerMetadataRegistryUpdate(ctx context.Context, metadata string) { +func registerMetadataRegistryUpdate(_ context.Context, metadata string) { metaMetrics.registryUpdates.WithLabelValues(metadata).Inc() } diff --git a/pkg/applicationserver/metadata/redis/location_cache.go b/pkg/applicationserver/metadata/redis/location_cache.go deleted file mode 100644 index c8221e109e..0000000000 --- a/pkg/applicationserver/metadata/redis/location_cache.go +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright © 2021 The Things Network Foundation, The Things Industries B.V. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package redis - -import ( - "context" - "fmt" - "strconv" - "time" - - "github.com/redis/go-redis/v9" - "go.thethings.network/lorawan-stack/v3/pkg/errors" - ttnredis "go.thethings.network/lorawan-stack/v3/pkg/redis" - "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" - "go.thethings.network/lorawan-stack/v3/pkg/unique" -) - -// EndDeviceLocationCache is a Redis end device location cache. -type EndDeviceLocationCache struct { - Redis *ttnredis.Client -} - -func (r *EndDeviceLocationCache) uidKey(uid string) string { - return r.Redis.Key("uid", uid) -} - -const ( - // storedAtMarker is used to store the timestamp of the last Set operation. - storedAtMarker = "_stored_at" - // errorMarker is used to store errors. - errorMarker = "_error" -) - -var errCacheMiss = errors.DefineNotFound("cache_miss", "cache miss") - -// Get returns the locations by the end device identifiers. -func (r *EndDeviceLocationCache) Get(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers) (map[string]*ttnpb.Location, *time.Time, error) { - uidKey := r.uidKey(unique.ID(ctx, ids)) - m, err := r.Redis.HGetAll(ctx, uidKey).Result() - if err != nil { - return nil, nil, ttnredis.ConvertError(err) - } - if len(m) == 0 { - return nil, nil, errCacheMiss.New() - } - var storedAt time.Time - if s, ok := m[storedAtMarker]; ok { - n, err := strconv.ParseInt(s, 10, 64) - if err != nil { - return nil, nil, err - } - storedAt = time.Unix(0, n) - delete(m, storedAtMarker) - } - if s, ok := m[errorMarker]; ok { - details := &ttnpb.ErrorDetails{} - if err := ttnredis.UnmarshalProto(s, details); err != nil { - return nil, nil, err - } - return nil, &storedAt, ttnpb.ErrorDetailsFromProto(details) - } - if len(m) == 0 { - return nil, &storedAt, nil - } - locations := make(map[string]*ttnpb.Location, len(m)) - for k, v := range m { - loc := new(ttnpb.Location) - if err := ttnredis.UnmarshalProto(v, loc); err != nil { - return nil, nil, err - } - locations[k] = loc - } - return locations, &storedAt, nil -} - -// Set updates the locations by the end device identifiers. -func (r *EndDeviceLocationCache) Set(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers, update map[string]*ttnpb.Location, ttl time.Duration) error { - pairs := append(make([]string, 0, 2*len(update)+2), storedAtMarker, fmt.Sprintf("%v", time.Now().UnixNano())) - for k, v := range update { - s, err := ttnredis.MarshalProto(v) - if err != nil { - return err - } - pairs = append(pairs, k, s) - } - uidKey := r.uidKey(unique.ID(ctx, ids)) - if _, err := r.Redis.Pipelined(ctx, func(p redis.Pipeliner) error { - p.Del(ctx, uidKey) - p.HSet(ctx, uidKey, pairs) - p.PExpire(ctx, uidKey, ttl) - return nil - }); err != nil { - return ttnredis.ConvertError(err) - } - return nil -} - -// Delete deletes the locations by the end device identifiers. -func (r *EndDeviceLocationCache) Delete(ctx context.Context, ids *ttnpb.EndDeviceIdentifiers) error { - uidKey := r.uidKey(unique.ID(ctx, ids)) - if err := r.Redis.Del(ctx, uidKey).Err(); err != nil { - return ttnredis.ConvertError(err) - } - return nil -} diff --git a/pkg/applicationserver/metadata/redis/location_cache_test.go b/pkg/applicationserver/metadata/redis/location_cache_test.go deleted file mode 100644 index eee514b062..0000000000 --- a/pkg/applicationserver/metadata/redis/location_cache_test.go +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright © 2021 The Things Network Foundation, The Things Industries B.V. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package redis_test - -import ( - "testing" - "time" - - "go.thethings.network/lorawan-stack/v3/pkg/applicationserver/metadata/redis" - "go.thethings.network/lorawan-stack/v3/pkg/errors" - "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" - "go.thethings.network/lorawan-stack/v3/pkg/util/test" - "go.thethings.network/lorawan-stack/v3/pkg/util/test/assertions/should" -) - -var ( - registeredEndDeviceIDs = &ttnpb.EndDeviceIdentifiers{ - ApplicationIds: &ttnpb.ApplicationIdentifiers{ - ApplicationId: "foo", - }, - DeviceId: "bar", - } - - locationA = map[string]*ttnpb.Location{ - "foo": { - Latitude: 123, - Longitude: 234, - }, - "bar": { - Latitude: 345, - Longitude: 456, - }, - } - locationB = map[string]*ttnpb.Location{ - "baz": { - Latitude: 567, - }, - } - - errUnavailable = errors.DefineUnavailable("unavailable", "unavailable") - - Timeout = (1 << 8) * test.Delay -) - -func TestLocationCache(t *testing.T) { - a, ctx := test.New(t) - cl, flush := test.NewRedis(ctx, "metadata_redis_test") - defer flush() - cache := &redis.EndDeviceLocationCache{ - Redis: cl, - } - - _, _, err := cache.Get(ctx, registeredEndDeviceIDs) - a.So(err, should.NotBeNil) - a.So(errors.IsNotFound(err), should.BeTrue) - - storeTime := time.Now() - err = cache.Set(ctx, registeredEndDeviceIDs, locationA, Timeout) - a.So(err, should.BeNil) - - locations, storedAt, err := cache.Get(ctx, registeredEndDeviceIDs) - if a.So(err, should.BeNil) { - if a.So(storedAt, should.NotBeNil) { - a.So(*storedAt, should.HappenOnOrAfter, storeTime) - } - a.So(len(locations), should.Equal, len(locationA)) - for k, v := range locations { - a.So(locationA[k], should.Resemble, v) - } - } - - storeTime = time.Now() - err = cache.Set(ctx, registeredEndDeviceIDs, locationB, Timeout) - a.So(err, should.BeNil) - - locations, storedAt, err = cache.Get(ctx, registeredEndDeviceIDs) - if a.So(err, should.BeNil) { - if a.So(storedAt, should.NotBeNil) { - a.So(*storedAt, should.HappenOnOrAfter, storeTime) - } - a.So(len(locations), should.Equal, len(locationB)) - for k, v := range locations { - a.So(locationB[k], should.Resemble, v) - } - } - - err = cache.Delete(ctx, registeredEndDeviceIDs) - a.So(err, should.BeNil) - - _, _, err = cache.Get(ctx, registeredEndDeviceIDs) - a.So(err, should.NotBeNil) - a.So(errors.IsNotFound(err), should.BeTrue) - - storeTime = time.Now() - err = cache.Set(ctx, registeredEndDeviceIDs, locationA, Timeout) - a.So(err, should.BeNil) - - locations, storedAt, err = cache.Get(ctx, registeredEndDeviceIDs) - if a.So(err, should.BeNil) { - if a.So(storedAt, should.NotBeNil) { - a.So(*storedAt, should.HappenOnOrAfter, storeTime) - } - a.So(len(locations), should.Equal, len(locationA)) - for k, v := range locations { - a.So(locationA[k], should.Resemble, v) - } - } - - time.Sleep(2 * Timeout) - - _, _, err = cache.Get(ctx, registeredEndDeviceIDs) - a.So(err, should.NotBeNil) - a.So(errors.IsNotFound(err), should.BeTrue) -} diff --git a/pkg/identityserver/bunstore/user_store.go b/pkg/identityserver/bunstore/user_store.go index 0bc40108a4..fcc4f89570 100644 --- a/pkg/identityserver/bunstore/user_store.go +++ b/pkg/identityserver/bunstore/user_store.go @@ -493,7 +493,11 @@ func (s *userStore) updateUserModel( //nolint:gocyclo ) (err error) { columns := store.FieldMask{"updated_at"} - consolePreferences := &ttnpb.UserConsolePreferences{} + consolePreferences := &ttnpb.UserConsolePreferences{ + DashboardLayouts: &ttnpb.UserConsolePreferences_DashboardLayouts{}, + SortBy: &ttnpb.UserConsolePreferences_SortBy{}, + Tutorials: &ttnpb.UserConsolePreferences_Tutorials{}, + } updateConsolePreferences := false if ttnpb.HasAnyField(ttnpb.TopLevelFields(fieldMask), "console_preferences") && len(model.ConsolePreferences) > 0 { @@ -610,6 +614,9 @@ func (s *userStore) updateUserModel( //nolint:gocyclo case "console_preferences.tutorials": updateConsolePreferences = true consolePreferences.Tutorials = pb.ConsolePreferences.GetTutorials() + case "console_preferences.tutorials.seen": + updateConsolePreferences = true + consolePreferences.Tutorials.Seen = pb.ConsolePreferences.Tutorials.GetSeen() case "universal_rights": model.UniversalRights = convertIntSlice[ttnpb.Right, int](pb.UniversalRights) columns = append(columns, "universal_rights") diff --git a/pkg/messageprocessors/javascript/javascript.go b/pkg/messageprocessors/javascript/javascript.go index 81219b288f..8b7c76fb1f 100644 --- a/pkg/messageprocessors/javascript/javascript.go +++ b/pkg/messageprocessors/javascript/javascript.go @@ -21,6 +21,7 @@ import ( "reflect" "runtime/trace" "strings" + "time" "go.thethings.network/lorawan-stack/v3/pkg/errors" "go.thethings.network/lorawan-stack/v3/pkg/goproto" @@ -101,8 +102,8 @@ func (h *host) CompileDownlinkEncoder( return func( ctx context.Context, - ids *ttnpb.EndDeviceIdentifiers, - version *ttnpb.EndDeviceVersionIdentifiers, + _ *ttnpb.EndDeviceIdentifiers, + _ *ttnpb.EndDeviceVersionIdentifiers, msg *ttnpb.ApplicationDownlink, ) error { return h.encodeDownlink(ctx, msg, run) @@ -138,7 +139,7 @@ func (*host) encodeDownlink( if err != nil { return errInput.WithCause(err) } - fPort := uint8(msg.FPort) + fPort := uint8(msg.FPort) // nolint:gosec input := encodeDownlinkInput{ Data: data, FPort: &fPort, @@ -170,8 +171,9 @@ func (*host) encodeDownlink( } type decodeUplinkInput struct { - Bytes []uint8 `json:"bytes"` - FPort uint8 `json:"fPort"` + Bytes []uint8 `json:"bytes"` + FPort uint8 `json:"fPort"` + RecvTime int64 `json:"recvTime"` // UnixNano } type decodeUplinkOutput struct { @@ -200,9 +202,13 @@ func wrapUplinkDecoderScript(script string) string { function main(input) { const bytes = input.bytes.slice(); - const { fPort } = input; + const { fPort, recvTime } = input; + + // Convert UnixNano to JavaScript Date. + const jsDate = new Date(Number(BigInt(recvTime) / 1000000n)); + if (typeof decodeUplink === 'function') { - const decoded = decodeUplink({ bytes, fPort }); + const decoded = decodeUplink({ bytes, fPort, recvTime: jsDate }); let normalized; const { data, errors } = decoded; if ((!errors || !errors.length) && data && typeof normalizeUplink === 'function') { @@ -240,8 +246,8 @@ func (h *host) CompileUplinkDecoder( return func( ctx context.Context, - ids *ttnpb.EndDeviceIdentifiers, - version *ttnpb.EndDeviceVersionIdentifiers, + _ *ttnpb.EndDeviceIdentifiers, + _ *ttnpb.EndDeviceVersionIdentifiers, msg *ttnpb.ApplicationUplink, ) error { return h.decodeUplink(ctx, msg, run) @@ -280,7 +286,7 @@ func appendValidationErrors(dst []string, measurements []normalizedpayload.Parse return dst } -func (*host) decodeUplink( +func (*host) decodeUplink( // nolint: gocyclo ctx context.Context, msg *ttnpb.ApplicationUplink, run func(context.Context, string, ...any) (func(any) error, error), @@ -288,8 +294,9 @@ func (*host) decodeUplink( defer trace.StartRegion(ctx, "decode uplink message").End() input := decodeUplinkInput{ - Bytes: msg.FrmPayload, - FPort: uint8(msg.FPort), + Bytes: msg.FrmPayload, + FPort: uint8(msg.FPort), // nolint:gosec + RecvTime: msg.ReceivedAt.AsTime().UnixNano(), } valueAs, err := run(ctx, "main", input) @@ -306,6 +313,14 @@ func (*host) decodeUplink( if errs := output.Decoded.Errors; len(errs) > 0 { return errOutputErrors.WithAttributes("errors", strings.Join(errs, ", ")) } + + // goproto.Struct does not support time.Time, use UnixNano instead. + for key, item := range output.Decoded.Data { + if t, ok := item.(time.Time); ok { + output.Decoded.Data[key] = t.UnixNano() + } + } + decodedPayload, err := goproto.Struct(output.Decoded.Data) if err != nil { return errOutput.WithCause(err) @@ -432,8 +447,8 @@ func (h *host) CompileDownlinkDecoder( return func( ctx context.Context, - ids *ttnpb.EndDeviceIdentifiers, - version *ttnpb.EndDeviceVersionIdentifiers, + _ *ttnpb.EndDeviceIdentifiers, + _ *ttnpb.EndDeviceVersionIdentifiers, msg *ttnpb.ApplicationDownlink, ) error { return h.decodeDownlink(ctx, msg, run) @@ -463,7 +478,7 @@ func (*host) decodeDownlink( input := decodeDownlinkInput{ Bytes: msg.FrmPayload, - FPort: uint8(msg.FPort), + FPort: uint8(msg.FPort), // nolint:gosec } valueAs, err := run(ctx, "main", input) diff --git a/pkg/messageprocessors/javascript/javascript_test.go b/pkg/messageprocessors/javascript/javascript_test.go index 6684742e6b..fddc66f16a 100644 --- a/pkg/messageprocessors/javascript/javascript_test.go +++ b/pkg/messageprocessors/javascript/javascript_test.go @@ -814,6 +814,33 @@ func TestDecodeUplink(t *testing.T) { err := host.DecodeUplink(ctx, ids, nil, message, script) a.So(err, should.BeNil) } + + // Check recvTime. + { + script := ` + function decodeUplink(input) { + if (input.recvTime === undefined) { + throw new Error('recvTime is undefined'); + } + + if (input.recvTime === null) { + throw new Error('recvTime is null'); + } + + if (!(input.recvTime instanceof Date)) { + throw new Error('recvTime is not a date object, got ' + typeof input.recvTime); + } + + return { + data: { + recvTime: input.recvTime + } + } + } + ` + err := host.DecodeUplink(ctx, ids, nil, message, script) + a.So(err, should.BeNil) + } } func TestDecodeDownlink(t *testing.T) { diff --git a/pkg/networkserver/grpc_deviceregistry.go b/pkg/networkserver/grpc_deviceregistry.go index 756ca39e4c..d050c43a3f 100644 --- a/pkg/networkserver/grpc_deviceregistry.go +++ b/pkg/networkserver/grpc_deviceregistry.go @@ -3021,6 +3021,13 @@ func (ns *NetworkServer) Set(ctx context.Context, req *ttnpb.SetEndDeviceRequest "mac_state.pending_application_downlink.f_cnt", "mac_state.pending_application_downlink.f_port", "mac_state.pending_application_downlink.frm_payload", + "mac_state.pending_application_downlink.network_ids", + "mac_state.pending_application_downlink.network_ids.cluster_address", + "mac_state.pending_application_downlink.network_ids.cluster_id", + "mac_state.pending_application_downlink.network_ids.net_id", + "mac_state.pending_application_downlink.network_ids.ns_id", + "mac_state.pending_application_downlink.network_ids.tenant_address", + "mac_state.pending_application_downlink.network_ids.tenant_id", "mac_state.pending_application_downlink.priority", "mac_state.pending_application_downlink.session_key_id", "mac_state.pending_relay_downlink.raw_payload", diff --git a/pkg/networkserver/grpc_gsns.go b/pkg/networkserver/grpc_gsns.go index b6fb6d6217..53f731e140 100644 --- a/pkg/networkserver/grpc_gsns.go +++ b/pkg/networkserver/grpc_gsns.go @@ -43,6 +43,7 @@ import ( "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/emptypb" "google.golang.org/protobuf/types/known/timestamppb" + "google.golang.org/protobuf/types/known/wrapperspb" ) const ( @@ -568,7 +569,15 @@ macLoop: break } cmds = cmds[dupCount:] - evs, err = mac.HandleLinkADRAns(ctx, dev, pld, uint(dupCount), cmacFMatchResult.FullFCnt, fps) + evs, err = mac.HandleLinkADRAns( + ctx, + dev, + pld, + uint(dupCount), // nolint: gosec + cmacFMatchResult.FullFCnt, + fps, + up.GetPayload().GetMacPayload().GetFHdr().GetFCtrl().GetAdr(), + ) case ttnpb.MACCommandIdentifier_CID_DUTY_CYCLE: evs, err = mac.HandleDutyCycleAns(ctx, dev) case ttnpb.MACCommandIdentifier_CID_RX_PARAM_SETUP: @@ -896,6 +905,18 @@ const ( initialDeduplicationRound = iota ) +func lastBatteryPercentage(dev *ttnpb.EndDevice) *ttnpb.LastBatteryPercentage { + if dev.MacState == nil || dev.BatteryPercentage == nil || dev.LastDevStatusReceivedAt == nil { + return nil + } + + return &ttnpb.LastBatteryPercentage{ + FCnt: dev.MacState.LastDevStatusFCntUp, + Value: wrapperspb.Float(dev.BatteryPercentage.Value * 100), + ReceivedAt: dev.LastDevStatusReceivedAt, + } +} + func (ns *NetworkServer) handleDataUplink(ctx context.Context, up *ttnpb.UplinkMessage) (err error) { defer trace.StartRegion(ctx, "handle data uplink").End() @@ -1141,17 +1162,18 @@ func (ns *NetworkServer) handleDataUplink(ctx context.Context, up *ttnpb.UplinkM CorrelationIds: up.CorrelationIds, Up: &ttnpb.ApplicationUp_UplinkMessage{ UplinkMessage: &ttnpb.ApplicationUplink{ - Confirmed: up.Payload.MHdr.MType == ttnpb.MType_CONFIRMED_UP, - FCnt: pld.FullFCnt, - FPort: pld.FPort, - FrmPayload: frmPayload, - RxMetadata: up.RxMetadata, - SessionKeyId: stored.Session.Keys.SessionKeyId, - Settings: up.Settings, - ReceivedAt: up.ReceivedAt, - ConsumedAirtime: up.ConsumedAirtime, - PacketErrorRate: mac.LossRate(stored.MacState, matched.phy), - NetworkIds: ns.networkIdentifiers(ctx), + Confirmed: up.Payload.MHdr.MType == ttnpb.MType_CONFIRMED_UP, + FCnt: pld.FullFCnt, + FPort: pld.FPort, + FrmPayload: frmPayload, + RxMetadata: up.RxMetadata, + SessionKeyId: stored.Session.Keys.SessionKeyId, + Settings: up.Settings, + ReceivedAt: up.ReceivedAt, + ConsumedAirtime: up.ConsumedAirtime, + PacketErrorRate: mac.LossRate(stored.MacState, matched.phy), + NetworkIds: ns.networkIdentifiers(ctx), + LastBatteryPercentage: lastBatteryPercentage(stored), }, }, }) diff --git a/pkg/networkserver/mac/link_adr.go b/pkg/networkserver/mac/link_adr.go index 8d1b84aa67..ef96b9fd4f 100644 --- a/pkg/networkserver/mac/link_adr.go +++ b/pkg/networkserver/mac/link_adr.go @@ -310,6 +310,7 @@ func HandleLinkADRAns( dupCount uint, fCntUp uint32, fps *frequencyplans.Store, + adrEnabled bool, ) (events.Builders, error) { if pld == nil { return nil, ErrNoPayload.New() @@ -321,7 +322,23 @@ func HandleLinkADRAns( } ev := EvtReceiveLinkADRAccept - if !pld.ChannelMaskAck || !pld.DataRateIndexAck || !pld.TxPowerIndexAck { + rejected := false + + // LoRaWAN 1.0.4 spec L534-538: + // An end-device SHOULD accept the channel mask controls present in LinkADRReq, even + // when the ADR bit is not set. The end-device SHALL respond to all LinkADRReq commands + // with a LinkADRAns indicating which command elements were accepted and which were + // rejected. This behavior differs from when the uplink ADR bit is set, in which case the end- + // device accepts or rejects the entire command. + if macspec.LinkADRReqRejected(macState.LorawanVersion) { + rejected = !pld.ChannelMaskAck || + (adrEnabled && !pld.DataRateIndexAck) || + (adrEnabled && !pld.TxPowerIndexAck) + } else { + rejected = !pld.ChannelMaskAck || !pld.DataRateIndexAck || !pld.TxPowerIndexAck + } + + if rejected { ev = EvtReceiveLinkADRReject // See "Table 6: LinkADRAns status bits signification" of LoRaWAN 1.1 specification diff --git a/pkg/networkserver/mac/link_adr_test.go b/pkg/networkserver/mac/link_adr_test.go index 1b47abb6dd..cd30d6b0e8 100644 --- a/pkg/networkserver/mac/link_adr_test.go +++ b/pkg/networkserver/mac/link_adr_test.go @@ -434,6 +434,7 @@ func TestHandleLinkADRAns(t *testing.T) { DupCount uint Events events.Builders Error error + AdrEnabled bool }{ { Name: "nil payload", @@ -451,7 +452,8 @@ func TestHandleLinkADRAns(t *testing.T) { LorawanVersion: ttnpb.MACVersion_MAC_V1_1, }, }, - Error: ErrNoPayload, + Error: ErrNoPayload, + AdrEnabled: true, }, { Name: "no request", @@ -481,7 +483,163 @@ func TestHandleLinkADRAns(t *testing.T) { TxPowerIndexAck: true, })), }, - Error: ErrRequestNotFound.WithAttributes("cid", ttnpb.MACCommandIdentifier_CID_LINK_ADR), + Error: ErrRequestNotFound.WithAttributes("cid", ttnpb.MACCommandIdentifier_CID_LINK_ADR), + AdrEnabled: true, + }, + { + Name: "1.0.2/channel mask on/adr enabled/rejected", + Device: &ttnpb.EndDevice{ + FrequencyPlanId: test.EUFrequencyPlanID, + LorawanPhyVersion: ttnpb.PHYVersion_RP001_V1_0_2_REV_B, + MacState: &ttnpb.MACState{ + LorawanVersion: ttnpb.MACVersion_MAC_V1_0_2, + }, + }, + Expected: &ttnpb.EndDevice{ + FrequencyPlanId: test.EUFrequencyPlanID, + LorawanPhyVersion: ttnpb.PHYVersion_RP001_V1_0_2_REV_B, + MacState: &ttnpb.MACState{ + LorawanVersion: ttnpb.MACVersion_MAC_V1_0_2, + }, + }, + Payload: &ttnpb.MACCommand_LinkADRAns{ + ChannelMaskAck: true, + DataRateIndexAck: false, + TxPowerIndexAck: false, + }, + Events: events.Builders{ + EvtReceiveLinkADRReject.With(events.WithData(&ttnpb.MACCommand_LinkADRAns{ + ChannelMaskAck: true, + DataRateIndexAck: false, + TxPowerIndexAck: false, + })), + }, + Error: ErrRequestNotFound.WithAttributes("cid", ttnpb.MACCommandIdentifier_CID_LINK_ADR), + AdrEnabled: true, + }, + { + Name: "1.0.4/channel mask on/adr disabled/accepted", + Device: &ttnpb.EndDevice{ + FrequencyPlanId: test.EUFrequencyPlanID, + LorawanPhyVersion: ttnpb.PHYVersion_RP002_V1_0_4, + MacState: &ttnpb.MACState{ + LorawanVersion: ttnpb.MACVersion_MAC_V1_0_4, + }, + }, + Expected: &ttnpb.EndDevice{ + FrequencyPlanId: test.EUFrequencyPlanID, + LorawanPhyVersion: ttnpb.PHYVersion_RP002_V1_0_4, + MacState: &ttnpb.MACState{ + LorawanVersion: ttnpb.MACVersion_MAC_V1_0_4, + }, + }, + Payload: &ttnpb.MACCommand_LinkADRAns{ + ChannelMaskAck: true, + DataRateIndexAck: false, + TxPowerIndexAck: false, + }, + Events: events.Builders{ + EvtReceiveLinkADRAccept.With(events.WithData(&ttnpb.MACCommand_LinkADRAns{ + ChannelMaskAck: true, + DataRateIndexAck: false, + TxPowerIndexAck: false, + })), + }, + Error: ErrRequestNotFound.WithAttributes("cid", ttnpb.MACCommandIdentifier_CID_LINK_ADR), + AdrEnabled: false, + }, + { + Name: "1.0.4/channel mask off/adr disabled/rejected", + Device: &ttnpb.EndDevice{ + FrequencyPlanId: test.EUFrequencyPlanID, + LorawanPhyVersion: ttnpb.PHYVersion_RP002_V1_0_4, + MacState: &ttnpb.MACState{ + LorawanVersion: ttnpb.MACVersion_MAC_V1_0_4, + }, + }, + Expected: &ttnpb.EndDevice{ + FrequencyPlanId: test.EUFrequencyPlanID, + LorawanPhyVersion: ttnpb.PHYVersion_RP002_V1_0_4, + MacState: &ttnpb.MACState{ + LorawanVersion: ttnpb.MACVersion_MAC_V1_0_4, + }, + }, + Payload: &ttnpb.MACCommand_LinkADRAns{ + ChannelMaskAck: false, + DataRateIndexAck: false, + TxPowerIndexAck: false, + }, + Events: events.Builders{ + EvtReceiveLinkADRReject.With(events.WithData(&ttnpb.MACCommand_LinkADRAns{ + ChannelMaskAck: false, + DataRateIndexAck: false, + TxPowerIndexAck: false, + })), + }, + Error: ErrRequestNotFound.WithAttributes("cid", ttnpb.MACCommandIdentifier_CID_LINK_ADR), + AdrEnabled: false, + }, + { + Name: "1.0.4/channel mask on/adr enabled/rejected", + Device: &ttnpb.EndDevice{ + FrequencyPlanId: test.EUFrequencyPlanID, + LorawanPhyVersion: ttnpb.PHYVersion_RP002_V1_0_4, + MacState: &ttnpb.MACState{ + LorawanVersion: ttnpb.MACVersion_MAC_V1_0_4, + }, + }, + Expected: &ttnpb.EndDevice{ + FrequencyPlanId: test.EUFrequencyPlanID, + LorawanPhyVersion: ttnpb.PHYVersion_RP002_V1_0_4, + MacState: &ttnpb.MACState{ + LorawanVersion: ttnpb.MACVersion_MAC_V1_0_4, + }, + }, + Payload: &ttnpb.MACCommand_LinkADRAns{ + ChannelMaskAck: true, + DataRateIndexAck: false, + TxPowerIndexAck: false, + }, + Events: events.Builders{ + EvtReceiveLinkADRReject.With(events.WithData(&ttnpb.MACCommand_LinkADRAns{ + ChannelMaskAck: true, + DataRateIndexAck: false, + TxPowerIndexAck: false, + })), + }, + Error: ErrRequestNotFound.WithAttributes("cid", ttnpb.MACCommandIdentifier_CID_LINK_ADR), + AdrEnabled: true, + }, + { + Name: "1.0.4/channel mask off/adr enabled/rejected", + Device: &ttnpb.EndDevice{ + FrequencyPlanId: test.EUFrequencyPlanID, + LorawanPhyVersion: ttnpb.PHYVersion_RP002_V1_0_4, + MacState: &ttnpb.MACState{ + LorawanVersion: ttnpb.MACVersion_MAC_V1_0_4, + }, + }, + Expected: &ttnpb.EndDevice{ + FrequencyPlanId: test.EUFrequencyPlanID, + LorawanPhyVersion: ttnpb.PHYVersion_RP002_V1_0_4, + MacState: &ttnpb.MACState{ + LorawanVersion: ttnpb.MACVersion_MAC_V1_0_4, + }, + }, + Payload: &ttnpb.MACCommand_LinkADRAns{ + ChannelMaskAck: false, + DataRateIndexAck: false, + TxPowerIndexAck: false, + }, + Events: events.Builders{ + EvtReceiveLinkADRReject.With(events.WithData(&ttnpb.MACCommand_LinkADRAns{ + ChannelMaskAck: false, + DataRateIndexAck: false, + TxPowerIndexAck: false, + })), + }, + Error: ErrRequestNotFound.WithAttributes("cid", ttnpb.MACCommandIdentifier_CID_LINK_ADR), + AdrEnabled: true, }, { Name: "1 request/all ack", @@ -547,6 +705,7 @@ func TestHandleLinkADRAns(t *testing.T) { TxPowerIndexAck: true, })), }, + AdrEnabled: true, }, { Name: "1.1/2 requests/all ack", @@ -636,6 +795,7 @@ func TestHandleLinkADRAns(t *testing.T) { TxPowerIndexAck: true, })), }, + AdrEnabled: true, }, { Name: "1.0.2/2 requests/all ack", @@ -726,6 +886,7 @@ func TestHandleLinkADRAns(t *testing.T) { TxPowerIndexAck: true, })), }, + AdrEnabled: true, }, { Name: "1.0/2 requests/all ack", @@ -825,6 +986,7 @@ func TestHandleLinkADRAns(t *testing.T) { TxPowerIndexAck: true, })), }, + AdrEnabled: true, }, { Name: "1.0.2/2 requests/US915 FSB2", @@ -888,6 +1050,7 @@ func TestHandleLinkADRAns(t *testing.T) { TxPowerIndexAck: true, })), }, + AdrEnabled: true, }, } { tc := tc @@ -897,7 +1060,8 @@ func TestHandleLinkADRAns(t *testing.T) { Func: func(ctx context.Context, t *testing.T, a *assertions.Assertion) { dev := ttnpb.Clone(tc.Device) - evs, err := HandleLinkADRAns(ctx, dev, tc.Payload, tc.DupCount, fCntUp, frequencyplans.NewStore(test.FrequencyPlansFetcher)) + fps := frequencyplans.NewStore(test.FrequencyPlansFetcher) + evs, err := HandleLinkADRAns(ctx, dev, tc.Payload, tc.DupCount, fCntUp, fps, tc.AdrEnabled) if tc.Error != nil && !a.So(err, should.EqualErrorOrDefinition, tc.Error) || tc.Error == nil && !a.So(err, should.BeNil) { t.FailNow() diff --git a/pkg/specification/macspec/specification.go b/pkg/specification/macspec/specification.go index 78eed64f6b..06d9a29a02 100644 --- a/pkg/specification/macspec/specification.go +++ b/pkg/specification/macspec/specification.go @@ -237,3 +237,10 @@ func EncryptionOptions(v ttnpb.MACVersion, frameType FrameType, fPort uint32, cm func ValidateUplinkPayloadSize(v ttnpb.MACVersion) bool { return compareMACVersion(v, ttnpb.MACVersion_MAC_V1_1) >= 0 } + +// LinkADRReqRejected reports whether v uses the ADR bit in the FCtrl field +// to modify which ACK bits needs to check in the LinkADRAns. +func LinkADRReqRejected(v ttnpb.MACVersion) bool { + return compareMACVersion(v, ttnpb.MACVersion_MAC_V1_0_3) >= 0 && + compareMACVersion(v, ttnpb.MACVersion_MAC_V1_0_4) <= 0 +} diff --git a/pkg/ttnpb/applicationserver.pb.paths.fm.go b/pkg/ttnpb/applicationserver.pb.paths.fm.go index f71deb4fc6..9d5a558dea 100644 --- a/pkg/ttnpb/applicationserver.pb.paths.fm.go +++ b/pkg/ttnpb/applicationserver.pb.paths.fm.go @@ -99,6 +99,7 @@ var NsAsHandleUplinkRequestFieldPathsTopLevel = []string{ } var EncodeDownlinkRequestFieldPathsNested = []string{ "downlink", + "downlink.attributes", "downlink.class_b_c", "downlink.class_b_c.absolute_time", "downlink.class_b_c.gateways", @@ -112,8 +113,22 @@ var EncodeDownlinkRequestFieldPathsNested = []string{ "downlink.f_cnt", "downlink.f_port", "downlink.frm_payload", + "downlink.locations", + "downlink.network_ids", + "downlink.network_ids.cluster_address", + "downlink.network_ids.cluster_id", + "downlink.network_ids.net_id", + "downlink.network_ids.ns_id", + "downlink.network_ids.tenant_address", + "downlink.network_ids.tenant_id", "downlink.priority", "downlink.session_key_id", + "downlink.version_ids", + "downlink.version_ids.band_id", + "downlink.version_ids.brand_id", + "downlink.version_ids.firmware_version", + "downlink.version_ids.hardware_version", + "downlink.version_ids.model_id", "end_device_ids", "end_device_ids.application_ids", "end_device_ids.application_ids.application_id", @@ -140,6 +155,7 @@ var EncodeDownlinkRequestFieldPathsTopLevel = []string{ } var EncodeDownlinkResponseFieldPathsNested = []string{ "downlink", + "downlink.attributes", "downlink.class_b_c", "downlink.class_b_c.absolute_time", "downlink.class_b_c.gateways", @@ -153,8 +169,22 @@ var EncodeDownlinkResponseFieldPathsNested = []string{ "downlink.f_cnt", "downlink.f_port", "downlink.frm_payload", + "downlink.locations", + "downlink.network_ids", + "downlink.network_ids.cluster_address", + "downlink.network_ids.cluster_id", + "downlink.network_ids.net_id", + "downlink.network_ids.ns_id", + "downlink.network_ids.tenant_address", + "downlink.network_ids.tenant_id", "downlink.priority", "downlink.session_key_id", + "downlink.version_ids", + "downlink.version_ids.band_id", + "downlink.version_ids.brand_id", + "downlink.version_ids.firmware_version", + "downlink.version_ids.hardware_version", + "downlink.version_ids.model_id", } var EncodeDownlinkResponseFieldPathsTopLevel = []string{ @@ -175,6 +205,7 @@ var DecodeUplinkRequestFieldPathsNested = []string{ "uplink.app_s_key.encrypted_key", "uplink.app_s_key.kek_label", "uplink.app_s_key.key", + "uplink.attributes", "uplink.confirmed", "uplink.consumed_airtime", "uplink.decoded_payload", @@ -183,6 +214,10 @@ var DecodeUplinkRequestFieldPathsNested = []string{ "uplink.f_port", "uplink.frm_payload", "uplink.last_a_f_cnt_down", + "uplink.last_battery_percentage", + "uplink.last_battery_percentage.f_cnt", + "uplink.last_battery_percentage.received_at", + "uplink.last_battery_percentage.value", "uplink.locations", "uplink.network_ids", "uplink.network_ids.cluster_address", @@ -246,6 +281,7 @@ var DecodeUplinkResponseFieldPathsNested = []string{ "uplink.app_s_key.encrypted_key", "uplink.app_s_key.kek_label", "uplink.app_s_key.key", + "uplink.attributes", "uplink.confirmed", "uplink.consumed_airtime", "uplink.decoded_payload", @@ -254,6 +290,10 @@ var DecodeUplinkResponseFieldPathsNested = []string{ "uplink.f_port", "uplink.frm_payload", "uplink.last_a_f_cnt_down", + "uplink.last_battery_percentage", + "uplink.last_battery_percentage.f_cnt", + "uplink.last_battery_percentage.received_at", + "uplink.last_battery_percentage.value", "uplink.locations", "uplink.network_ids", "uplink.network_ids.cluster_address", @@ -303,6 +343,7 @@ var DecodeUplinkResponseFieldPathsTopLevel = []string{ } var DecodeDownlinkRequestFieldPathsNested = []string{ "downlink", + "downlink.attributes", "downlink.class_b_c", "downlink.class_b_c.absolute_time", "downlink.class_b_c.gateways", @@ -316,8 +357,22 @@ var DecodeDownlinkRequestFieldPathsNested = []string{ "downlink.f_cnt", "downlink.f_port", "downlink.frm_payload", + "downlink.locations", + "downlink.network_ids", + "downlink.network_ids.cluster_address", + "downlink.network_ids.cluster_id", + "downlink.network_ids.net_id", + "downlink.network_ids.ns_id", + "downlink.network_ids.tenant_address", + "downlink.network_ids.tenant_id", "downlink.priority", "downlink.session_key_id", + "downlink.version_ids", + "downlink.version_ids.band_id", + "downlink.version_ids.brand_id", + "downlink.version_ids.firmware_version", + "downlink.version_ids.hardware_version", + "downlink.version_ids.model_id", "end_device_ids", "end_device_ids.application_ids", "end_device_ids.application_ids.application_id", @@ -344,6 +399,7 @@ var DecodeDownlinkRequestFieldPathsTopLevel = []string{ } var DecodeDownlinkResponseFieldPathsNested = []string{ "downlink", + "downlink.attributes", "downlink.class_b_c", "downlink.class_b_c.absolute_time", "downlink.class_b_c.gateways", @@ -357,8 +413,22 @@ var DecodeDownlinkResponseFieldPathsNested = []string{ "downlink.f_cnt", "downlink.f_port", "downlink.frm_payload", + "downlink.locations", + "downlink.network_ids", + "downlink.network_ids.cluster_address", + "downlink.network_ids.cluster_id", + "downlink.network_ids.net_id", + "downlink.network_ids.ns_id", + "downlink.network_ids.tenant_address", + "downlink.network_ids.tenant_id", "downlink.priority", "downlink.session_key_id", + "downlink.version_ids", + "downlink.version_ids.band_id", + "downlink.version_ids.brand_id", + "downlink.version_ids.firmware_version", + "downlink.version_ids.hardware_version", + "downlink.version_ids.model_id", } var DecodeDownlinkResponseFieldPathsTopLevel = []string{ diff --git a/pkg/ttnpb/end_device.go b/pkg/ttnpb/end_device.go index 41985da6de..1e79c4d18c 100644 --- a/pkg/ttnpb/end_device.go +++ b/pkg/ttnpb/end_device.go @@ -1829,6 +1829,8 @@ func (v *MACState) FieldIsZero(p string) bool { return v.LorawanVersion == 0 case "pending_application_downlink": return v.PendingApplicationDownlink == nil + case "pending_application_downlink.attributes": + return v.PendingApplicationDownlink.FieldIsZero("attributes") case "pending_application_downlink.class_b_c": return v.PendingApplicationDownlink.FieldIsZero("class_b_c") case "pending_application_downlink.class_b_c.absolute_time": @@ -1855,10 +1857,38 @@ func (v *MACState) FieldIsZero(p string) bool { return v.PendingApplicationDownlink.FieldIsZero("f_port") case "pending_application_downlink.frm_payload": return v.PendingApplicationDownlink.FieldIsZero("frm_payload") + case "pending_application_downlink.locations": + return v.PendingApplicationDownlink.FieldIsZero("locations") + case "pending_application_downlink.network_ids": + return v.PendingApplicationDownlink.FieldIsZero("network_ids") + case "pending_application_downlink.network_ids.cluster_address": + return v.PendingApplicationDownlink.FieldIsZero("network_ids.cluster_address") + case "pending_application_downlink.network_ids.cluster_id": + return v.PendingApplicationDownlink.FieldIsZero("network_ids.cluster_id") + case "pending_application_downlink.network_ids.net_id": + return v.PendingApplicationDownlink.FieldIsZero("network_ids.net_id") + case "pending_application_downlink.network_ids.ns_id": + return v.PendingApplicationDownlink.FieldIsZero("network_ids.ns_id") + case "pending_application_downlink.network_ids.tenant_address": + return v.PendingApplicationDownlink.FieldIsZero("network_ids.tenant_address") + case "pending_application_downlink.network_ids.tenant_id": + return v.PendingApplicationDownlink.FieldIsZero("network_ids.tenant_id") case "pending_application_downlink.priority": return v.PendingApplicationDownlink.FieldIsZero("priority") case "pending_application_downlink.session_key_id": return v.PendingApplicationDownlink.FieldIsZero("session_key_id") + case "pending_application_downlink.version_ids": + return v.PendingApplicationDownlink.FieldIsZero("version_ids") + case "pending_application_downlink.version_ids.band_id": + return v.PendingApplicationDownlink.FieldIsZero("version_ids.band_id") + case "pending_application_downlink.version_ids.brand_id": + return v.PendingApplicationDownlink.FieldIsZero("version_ids.brand_id") + case "pending_application_downlink.version_ids.firmware_version": + return v.PendingApplicationDownlink.FieldIsZero("version_ids.firmware_version") + case "pending_application_downlink.version_ids.hardware_version": + return v.PendingApplicationDownlink.FieldIsZero("version_ids.hardware_version") + case "pending_application_downlink.version_ids.model_id": + return v.PendingApplicationDownlink.FieldIsZero("version_ids.model_id") case "pending_join_request": return v.PendingJoinRequest == nil case "pending_join_request.cf_list": @@ -2998,3 +3028,25 @@ func (d *EndDevice) UpdateTimestamps(src *EndDevice) { // EndDeviceFieldPathsNestedWithoutWrappers is the set of EndDevice nested paths without the wrapper paths. var EndDeviceFieldPathsNestedWithoutWrappers = FieldsWithoutWrappers(EndDeviceFieldPathsNested) + +// FieldIsZero returns whether path p is zero. +func (v *NetworkIdentifiers) FieldIsZero(p string) bool { + if v == nil { + return true + } + switch p { + case "cluster_address": + return v.ClusterAddress == "" + case "cluster_id": + return v.ClusterId == "" + case "net_id": + return len(v.NetId) == 0 + case "ns_id": + return len(v.NsId) == 0 + case "tenant_address": + return v.TenantAddress == "" + case "tenant_id": // nolint:goconst + return v.TenantId == "" + } + panic(fmt.Sprintf("unknown path '%s'", p)) +} diff --git a/pkg/ttnpb/end_device.pb.paths.fm.go b/pkg/ttnpb/end_device.pb.paths.fm.go index 089bfe8399..07447f5e95 100644 --- a/pkg/ttnpb/end_device.pb.paths.fm.go +++ b/pkg/ttnpb/end_device.pb.paths.fm.go @@ -1268,6 +1268,7 @@ var MACStateFieldPathsNested = []string{ "last_network_initiated_downlink_at", "lorawan_version", "pending_application_downlink", + "pending_application_downlink.attributes", "pending_application_downlink.class_b_c", "pending_application_downlink.class_b_c.absolute_time", "pending_application_downlink.class_b_c.gateways", @@ -1281,8 +1282,22 @@ var MACStateFieldPathsNested = []string{ "pending_application_downlink.f_cnt", "pending_application_downlink.f_port", "pending_application_downlink.frm_payload", + "pending_application_downlink.locations", + "pending_application_downlink.network_ids", + "pending_application_downlink.network_ids.cluster_address", + "pending_application_downlink.network_ids.cluster_id", + "pending_application_downlink.network_ids.net_id", + "pending_application_downlink.network_ids.ns_id", + "pending_application_downlink.network_ids.tenant_address", + "pending_application_downlink.network_ids.tenant_id", "pending_application_downlink.priority", "pending_application_downlink.session_key_id", + "pending_application_downlink.version_ids", + "pending_application_downlink.version_ids.band_id", + "pending_application_downlink.version_ids.brand_id", + "pending_application_downlink.version_ids.firmware_version", + "pending_application_downlink.version_ids.hardware_version", + "pending_application_downlink.version_ids.model_id", "pending_join_request", "pending_join_request.cf_list", "pending_join_request.cf_list.ch_masks", @@ -1758,6 +1773,7 @@ var EndDeviceFieldPathsNested = []string{ "mac_state.last_network_initiated_downlink_at", "mac_state.lorawan_version", "mac_state.pending_application_downlink", + "mac_state.pending_application_downlink.attributes", "mac_state.pending_application_downlink.class_b_c", "mac_state.pending_application_downlink.class_b_c.absolute_time", "mac_state.pending_application_downlink.class_b_c.gateways", @@ -1771,8 +1787,22 @@ var EndDeviceFieldPathsNested = []string{ "mac_state.pending_application_downlink.f_cnt", "mac_state.pending_application_downlink.f_port", "mac_state.pending_application_downlink.frm_payload", + "mac_state.pending_application_downlink.locations", + "mac_state.pending_application_downlink.network_ids", + "mac_state.pending_application_downlink.network_ids.cluster_address", + "mac_state.pending_application_downlink.network_ids.cluster_id", + "mac_state.pending_application_downlink.network_ids.net_id", + "mac_state.pending_application_downlink.network_ids.ns_id", + "mac_state.pending_application_downlink.network_ids.tenant_address", + "mac_state.pending_application_downlink.network_ids.tenant_id", "mac_state.pending_application_downlink.priority", "mac_state.pending_application_downlink.session_key_id", + "mac_state.pending_application_downlink.version_ids", + "mac_state.pending_application_downlink.version_ids.band_id", + "mac_state.pending_application_downlink.version_ids.brand_id", + "mac_state.pending_application_downlink.version_ids.firmware_version", + "mac_state.pending_application_downlink.version_ids.hardware_version", + "mac_state.pending_application_downlink.version_ids.model_id", "mac_state.pending_join_request", "mac_state.pending_join_request.cf_list", "mac_state.pending_join_request.cf_list.ch_masks", @@ -1974,6 +2004,7 @@ var EndDeviceFieldPathsNested = []string{ "pending_mac_state.last_network_initiated_downlink_at", "pending_mac_state.lorawan_version", "pending_mac_state.pending_application_downlink", + "pending_mac_state.pending_application_downlink.attributes", "pending_mac_state.pending_application_downlink.class_b_c", "pending_mac_state.pending_application_downlink.class_b_c.absolute_time", "pending_mac_state.pending_application_downlink.class_b_c.gateways", @@ -1987,8 +2018,22 @@ var EndDeviceFieldPathsNested = []string{ "pending_mac_state.pending_application_downlink.f_cnt", "pending_mac_state.pending_application_downlink.f_port", "pending_mac_state.pending_application_downlink.frm_payload", + "pending_mac_state.pending_application_downlink.locations", + "pending_mac_state.pending_application_downlink.network_ids", + "pending_mac_state.pending_application_downlink.network_ids.cluster_address", + "pending_mac_state.pending_application_downlink.network_ids.cluster_id", + "pending_mac_state.pending_application_downlink.network_ids.net_id", + "pending_mac_state.pending_application_downlink.network_ids.ns_id", + "pending_mac_state.pending_application_downlink.network_ids.tenant_address", + "pending_mac_state.pending_application_downlink.network_ids.tenant_id", "pending_mac_state.pending_application_downlink.priority", "pending_mac_state.pending_application_downlink.session_key_id", + "pending_mac_state.pending_application_downlink.version_ids", + "pending_mac_state.pending_application_downlink.version_ids.band_id", + "pending_mac_state.pending_application_downlink.version_ids.brand_id", + "pending_mac_state.pending_application_downlink.version_ids.firmware_version", + "pending_mac_state.pending_application_downlink.version_ids.hardware_version", + "pending_mac_state.pending_application_downlink.version_ids.model_id", "pending_mac_state.pending_join_request", "pending_mac_state.pending_join_request.cf_list", "pending_mac_state.pending_join_request.cf_list.ch_masks", @@ -2586,6 +2631,7 @@ var CreateEndDeviceRequestFieldPathsNested = []string{ "end_device.mac_state.last_network_initiated_downlink_at", "end_device.mac_state.lorawan_version", "end_device.mac_state.pending_application_downlink", + "end_device.mac_state.pending_application_downlink.attributes", "end_device.mac_state.pending_application_downlink.class_b_c", "end_device.mac_state.pending_application_downlink.class_b_c.absolute_time", "end_device.mac_state.pending_application_downlink.class_b_c.gateways", @@ -2599,8 +2645,22 @@ var CreateEndDeviceRequestFieldPathsNested = []string{ "end_device.mac_state.pending_application_downlink.f_cnt", "end_device.mac_state.pending_application_downlink.f_port", "end_device.mac_state.pending_application_downlink.frm_payload", + "end_device.mac_state.pending_application_downlink.locations", + "end_device.mac_state.pending_application_downlink.network_ids", + "end_device.mac_state.pending_application_downlink.network_ids.cluster_address", + "end_device.mac_state.pending_application_downlink.network_ids.cluster_id", + "end_device.mac_state.pending_application_downlink.network_ids.net_id", + "end_device.mac_state.pending_application_downlink.network_ids.ns_id", + "end_device.mac_state.pending_application_downlink.network_ids.tenant_address", + "end_device.mac_state.pending_application_downlink.network_ids.tenant_id", "end_device.mac_state.pending_application_downlink.priority", "end_device.mac_state.pending_application_downlink.session_key_id", + "end_device.mac_state.pending_application_downlink.version_ids", + "end_device.mac_state.pending_application_downlink.version_ids.band_id", + "end_device.mac_state.pending_application_downlink.version_ids.brand_id", + "end_device.mac_state.pending_application_downlink.version_ids.firmware_version", + "end_device.mac_state.pending_application_downlink.version_ids.hardware_version", + "end_device.mac_state.pending_application_downlink.version_ids.model_id", "end_device.mac_state.pending_join_request", "end_device.mac_state.pending_join_request.cf_list", "end_device.mac_state.pending_join_request.cf_list.ch_masks", @@ -2802,6 +2862,7 @@ var CreateEndDeviceRequestFieldPathsNested = []string{ "end_device.pending_mac_state.last_network_initiated_downlink_at", "end_device.pending_mac_state.lorawan_version", "end_device.pending_mac_state.pending_application_downlink", + "end_device.pending_mac_state.pending_application_downlink.attributes", "end_device.pending_mac_state.pending_application_downlink.class_b_c", "end_device.pending_mac_state.pending_application_downlink.class_b_c.absolute_time", "end_device.pending_mac_state.pending_application_downlink.class_b_c.gateways", @@ -2815,8 +2876,22 @@ var CreateEndDeviceRequestFieldPathsNested = []string{ "end_device.pending_mac_state.pending_application_downlink.f_cnt", "end_device.pending_mac_state.pending_application_downlink.f_port", "end_device.pending_mac_state.pending_application_downlink.frm_payload", + "end_device.pending_mac_state.pending_application_downlink.locations", + "end_device.pending_mac_state.pending_application_downlink.network_ids", + "end_device.pending_mac_state.pending_application_downlink.network_ids.cluster_address", + "end_device.pending_mac_state.pending_application_downlink.network_ids.cluster_id", + "end_device.pending_mac_state.pending_application_downlink.network_ids.net_id", + "end_device.pending_mac_state.pending_application_downlink.network_ids.ns_id", + "end_device.pending_mac_state.pending_application_downlink.network_ids.tenant_address", + "end_device.pending_mac_state.pending_application_downlink.network_ids.tenant_id", "end_device.pending_mac_state.pending_application_downlink.priority", "end_device.pending_mac_state.pending_application_downlink.session_key_id", + "end_device.pending_mac_state.pending_application_downlink.version_ids", + "end_device.pending_mac_state.pending_application_downlink.version_ids.band_id", + "end_device.pending_mac_state.pending_application_downlink.version_ids.brand_id", + "end_device.pending_mac_state.pending_application_downlink.version_ids.firmware_version", + "end_device.pending_mac_state.pending_application_downlink.version_ids.hardware_version", + "end_device.pending_mac_state.pending_application_downlink.version_ids.model_id", "end_device.pending_mac_state.pending_join_request", "end_device.pending_mac_state.pending_join_request.cf_list", "end_device.pending_mac_state.pending_join_request.cf_list.ch_masks", @@ -3346,6 +3421,7 @@ var UpdateEndDeviceRequestFieldPathsNested = []string{ "end_device.mac_state.last_network_initiated_downlink_at", "end_device.mac_state.lorawan_version", "end_device.mac_state.pending_application_downlink", + "end_device.mac_state.pending_application_downlink.attributes", "end_device.mac_state.pending_application_downlink.class_b_c", "end_device.mac_state.pending_application_downlink.class_b_c.absolute_time", "end_device.mac_state.pending_application_downlink.class_b_c.gateways", @@ -3359,8 +3435,22 @@ var UpdateEndDeviceRequestFieldPathsNested = []string{ "end_device.mac_state.pending_application_downlink.f_cnt", "end_device.mac_state.pending_application_downlink.f_port", "end_device.mac_state.pending_application_downlink.frm_payload", + "end_device.mac_state.pending_application_downlink.locations", + "end_device.mac_state.pending_application_downlink.network_ids", + "end_device.mac_state.pending_application_downlink.network_ids.cluster_address", + "end_device.mac_state.pending_application_downlink.network_ids.cluster_id", + "end_device.mac_state.pending_application_downlink.network_ids.net_id", + "end_device.mac_state.pending_application_downlink.network_ids.ns_id", + "end_device.mac_state.pending_application_downlink.network_ids.tenant_address", + "end_device.mac_state.pending_application_downlink.network_ids.tenant_id", "end_device.mac_state.pending_application_downlink.priority", "end_device.mac_state.pending_application_downlink.session_key_id", + "end_device.mac_state.pending_application_downlink.version_ids", + "end_device.mac_state.pending_application_downlink.version_ids.band_id", + "end_device.mac_state.pending_application_downlink.version_ids.brand_id", + "end_device.mac_state.pending_application_downlink.version_ids.firmware_version", + "end_device.mac_state.pending_application_downlink.version_ids.hardware_version", + "end_device.mac_state.pending_application_downlink.version_ids.model_id", "end_device.mac_state.pending_join_request", "end_device.mac_state.pending_join_request.cf_list", "end_device.mac_state.pending_join_request.cf_list.ch_masks", @@ -3562,6 +3652,7 @@ var UpdateEndDeviceRequestFieldPathsNested = []string{ "end_device.pending_mac_state.last_network_initiated_downlink_at", "end_device.pending_mac_state.lorawan_version", "end_device.pending_mac_state.pending_application_downlink", + "end_device.pending_mac_state.pending_application_downlink.attributes", "end_device.pending_mac_state.pending_application_downlink.class_b_c", "end_device.pending_mac_state.pending_application_downlink.class_b_c.absolute_time", "end_device.pending_mac_state.pending_application_downlink.class_b_c.gateways", @@ -3575,8 +3666,22 @@ var UpdateEndDeviceRequestFieldPathsNested = []string{ "end_device.pending_mac_state.pending_application_downlink.f_cnt", "end_device.pending_mac_state.pending_application_downlink.f_port", "end_device.pending_mac_state.pending_application_downlink.frm_payload", + "end_device.pending_mac_state.pending_application_downlink.locations", + "end_device.pending_mac_state.pending_application_downlink.network_ids", + "end_device.pending_mac_state.pending_application_downlink.network_ids.cluster_address", + "end_device.pending_mac_state.pending_application_downlink.network_ids.cluster_id", + "end_device.pending_mac_state.pending_application_downlink.network_ids.net_id", + "end_device.pending_mac_state.pending_application_downlink.network_ids.ns_id", + "end_device.pending_mac_state.pending_application_downlink.network_ids.tenant_address", + "end_device.pending_mac_state.pending_application_downlink.network_ids.tenant_id", "end_device.pending_mac_state.pending_application_downlink.priority", "end_device.pending_mac_state.pending_application_downlink.session_key_id", + "end_device.pending_mac_state.pending_application_downlink.version_ids", + "end_device.pending_mac_state.pending_application_downlink.version_ids.band_id", + "end_device.pending_mac_state.pending_application_downlink.version_ids.brand_id", + "end_device.pending_mac_state.pending_application_downlink.version_ids.firmware_version", + "end_device.pending_mac_state.pending_application_downlink.version_ids.hardware_version", + "end_device.pending_mac_state.pending_application_downlink.version_ids.model_id", "end_device.pending_mac_state.pending_join_request", "end_device.pending_mac_state.pending_join_request.cf_list", "end_device.pending_mac_state.pending_join_request.cf_list.ch_masks", @@ -4157,6 +4262,7 @@ var SetEndDeviceRequestFieldPathsNested = []string{ "end_device.mac_state.last_network_initiated_downlink_at", "end_device.mac_state.lorawan_version", "end_device.mac_state.pending_application_downlink", + "end_device.mac_state.pending_application_downlink.attributes", "end_device.mac_state.pending_application_downlink.class_b_c", "end_device.mac_state.pending_application_downlink.class_b_c.absolute_time", "end_device.mac_state.pending_application_downlink.class_b_c.gateways", @@ -4170,8 +4276,22 @@ var SetEndDeviceRequestFieldPathsNested = []string{ "end_device.mac_state.pending_application_downlink.f_cnt", "end_device.mac_state.pending_application_downlink.f_port", "end_device.mac_state.pending_application_downlink.frm_payload", + "end_device.mac_state.pending_application_downlink.locations", + "end_device.mac_state.pending_application_downlink.network_ids", + "end_device.mac_state.pending_application_downlink.network_ids.cluster_address", + "end_device.mac_state.pending_application_downlink.network_ids.cluster_id", + "end_device.mac_state.pending_application_downlink.network_ids.net_id", + "end_device.mac_state.pending_application_downlink.network_ids.ns_id", + "end_device.mac_state.pending_application_downlink.network_ids.tenant_address", + "end_device.mac_state.pending_application_downlink.network_ids.tenant_id", "end_device.mac_state.pending_application_downlink.priority", "end_device.mac_state.pending_application_downlink.session_key_id", + "end_device.mac_state.pending_application_downlink.version_ids", + "end_device.mac_state.pending_application_downlink.version_ids.band_id", + "end_device.mac_state.pending_application_downlink.version_ids.brand_id", + "end_device.mac_state.pending_application_downlink.version_ids.firmware_version", + "end_device.mac_state.pending_application_downlink.version_ids.hardware_version", + "end_device.mac_state.pending_application_downlink.version_ids.model_id", "end_device.mac_state.pending_join_request", "end_device.mac_state.pending_join_request.cf_list", "end_device.mac_state.pending_join_request.cf_list.ch_masks", @@ -4373,6 +4493,7 @@ var SetEndDeviceRequestFieldPathsNested = []string{ "end_device.pending_mac_state.last_network_initiated_downlink_at", "end_device.pending_mac_state.lorawan_version", "end_device.pending_mac_state.pending_application_downlink", + "end_device.pending_mac_state.pending_application_downlink.attributes", "end_device.pending_mac_state.pending_application_downlink.class_b_c", "end_device.pending_mac_state.pending_application_downlink.class_b_c.absolute_time", "end_device.pending_mac_state.pending_application_downlink.class_b_c.gateways", @@ -4386,8 +4507,22 @@ var SetEndDeviceRequestFieldPathsNested = []string{ "end_device.pending_mac_state.pending_application_downlink.f_cnt", "end_device.pending_mac_state.pending_application_downlink.f_port", "end_device.pending_mac_state.pending_application_downlink.frm_payload", + "end_device.pending_mac_state.pending_application_downlink.locations", + "end_device.pending_mac_state.pending_application_downlink.network_ids", + "end_device.pending_mac_state.pending_application_downlink.network_ids.cluster_address", + "end_device.pending_mac_state.pending_application_downlink.network_ids.cluster_id", + "end_device.pending_mac_state.pending_application_downlink.network_ids.net_id", + "end_device.pending_mac_state.pending_application_downlink.network_ids.ns_id", + "end_device.pending_mac_state.pending_application_downlink.network_ids.tenant_address", + "end_device.pending_mac_state.pending_application_downlink.network_ids.tenant_id", "end_device.pending_mac_state.pending_application_downlink.priority", "end_device.pending_mac_state.pending_application_downlink.session_key_id", + "end_device.pending_mac_state.pending_application_downlink.version_ids", + "end_device.pending_mac_state.pending_application_downlink.version_ids.band_id", + "end_device.pending_mac_state.pending_application_downlink.version_ids.brand_id", + "end_device.pending_mac_state.pending_application_downlink.version_ids.firmware_version", + "end_device.pending_mac_state.pending_application_downlink.version_ids.hardware_version", + "end_device.pending_mac_state.pending_application_downlink.version_ids.model_id", "end_device.pending_mac_state.pending_join_request", "end_device.pending_mac_state.pending_join_request.cf_list", "end_device.pending_mac_state.pending_join_request.cf_list.ch_masks", @@ -4934,6 +5069,7 @@ var EndDeviceTemplateFieldPathsNested = []string{ "end_device.mac_state.last_network_initiated_downlink_at", "end_device.mac_state.lorawan_version", "end_device.mac_state.pending_application_downlink", + "end_device.mac_state.pending_application_downlink.attributes", "end_device.mac_state.pending_application_downlink.class_b_c", "end_device.mac_state.pending_application_downlink.class_b_c.absolute_time", "end_device.mac_state.pending_application_downlink.class_b_c.gateways", @@ -4947,8 +5083,22 @@ var EndDeviceTemplateFieldPathsNested = []string{ "end_device.mac_state.pending_application_downlink.f_cnt", "end_device.mac_state.pending_application_downlink.f_port", "end_device.mac_state.pending_application_downlink.frm_payload", + "end_device.mac_state.pending_application_downlink.locations", + "end_device.mac_state.pending_application_downlink.network_ids", + "end_device.mac_state.pending_application_downlink.network_ids.cluster_address", + "end_device.mac_state.pending_application_downlink.network_ids.cluster_id", + "end_device.mac_state.pending_application_downlink.network_ids.net_id", + "end_device.mac_state.pending_application_downlink.network_ids.ns_id", + "end_device.mac_state.pending_application_downlink.network_ids.tenant_address", + "end_device.mac_state.pending_application_downlink.network_ids.tenant_id", "end_device.mac_state.pending_application_downlink.priority", "end_device.mac_state.pending_application_downlink.session_key_id", + "end_device.mac_state.pending_application_downlink.version_ids", + "end_device.mac_state.pending_application_downlink.version_ids.band_id", + "end_device.mac_state.pending_application_downlink.version_ids.brand_id", + "end_device.mac_state.pending_application_downlink.version_ids.firmware_version", + "end_device.mac_state.pending_application_downlink.version_ids.hardware_version", + "end_device.mac_state.pending_application_downlink.version_ids.model_id", "end_device.mac_state.pending_join_request", "end_device.mac_state.pending_join_request.cf_list", "end_device.mac_state.pending_join_request.cf_list.ch_masks", @@ -5150,6 +5300,7 @@ var EndDeviceTemplateFieldPathsNested = []string{ "end_device.pending_mac_state.last_network_initiated_downlink_at", "end_device.pending_mac_state.lorawan_version", "end_device.pending_mac_state.pending_application_downlink", + "end_device.pending_mac_state.pending_application_downlink.attributes", "end_device.pending_mac_state.pending_application_downlink.class_b_c", "end_device.pending_mac_state.pending_application_downlink.class_b_c.absolute_time", "end_device.pending_mac_state.pending_application_downlink.class_b_c.gateways", @@ -5163,8 +5314,22 @@ var EndDeviceTemplateFieldPathsNested = []string{ "end_device.pending_mac_state.pending_application_downlink.f_cnt", "end_device.pending_mac_state.pending_application_downlink.f_port", "end_device.pending_mac_state.pending_application_downlink.frm_payload", + "end_device.pending_mac_state.pending_application_downlink.locations", + "end_device.pending_mac_state.pending_application_downlink.network_ids", + "end_device.pending_mac_state.pending_application_downlink.network_ids.cluster_address", + "end_device.pending_mac_state.pending_application_downlink.network_ids.cluster_id", + "end_device.pending_mac_state.pending_application_downlink.network_ids.net_id", + "end_device.pending_mac_state.pending_application_downlink.network_ids.ns_id", + "end_device.pending_mac_state.pending_application_downlink.network_ids.tenant_address", + "end_device.pending_mac_state.pending_application_downlink.network_ids.tenant_id", "end_device.pending_mac_state.pending_application_downlink.priority", "end_device.pending_mac_state.pending_application_downlink.session_key_id", + "end_device.pending_mac_state.pending_application_downlink.version_ids", + "end_device.pending_mac_state.pending_application_downlink.version_ids.band_id", + "end_device.pending_mac_state.pending_application_downlink.version_ids.brand_id", + "end_device.pending_mac_state.pending_application_downlink.version_ids.firmware_version", + "end_device.pending_mac_state.pending_application_downlink.version_ids.hardware_version", + "end_device.pending_mac_state.pending_application_downlink.version_ids.model_id", "end_device.pending_mac_state.pending_join_request", "end_device.pending_mac_state.pending_join_request.cf_list", "end_device.pending_mac_state.pending_join_request.cf_list.ch_masks", diff --git a/pkg/ttnpb/field_mask_validation.go b/pkg/ttnpb/field_mask_validation.go index d07e53d09a..42e9acdebc 100644 --- a/pkg/ttnpb/field_mask_validation.go +++ b/pkg/ttnpb/field_mask_validation.go @@ -439,6 +439,7 @@ var nsEndDeviceReadFieldPaths = [...]string{ "mac_state.last_network_initiated_downlink_at", "mac_state.lorawan_version", "mac_state.pending_application_downlink", + "mac_state.pending_application_downlink.attributes", "mac_state.pending_application_downlink.class_b_c", "mac_state.pending_application_downlink.class_b_c.absolute_time", "mac_state.pending_application_downlink.class_b_c.gateways", @@ -447,8 +448,22 @@ var nsEndDeviceReadFieldPaths = [...]string{ "mac_state.pending_application_downlink.f_cnt", "mac_state.pending_application_downlink.f_port", "mac_state.pending_application_downlink.frm_payload", + "mac_state.pending_application_downlink.locations", + "mac_state.pending_application_downlink.network_ids", + "mac_state.pending_application_downlink.network_ids.cluster_address", + "mac_state.pending_application_downlink.network_ids.cluster_id", + "mac_state.pending_application_downlink.network_ids.net_id", + "mac_state.pending_application_downlink.network_ids.ns_id", + "mac_state.pending_application_downlink.network_ids.tenant_address", + "mac_state.pending_application_downlink.network_ids.tenant_id", "mac_state.pending_application_downlink.priority", "mac_state.pending_application_downlink.session_key_id", + "mac_state.pending_application_downlink.version_ids", + "mac_state.pending_application_downlink.version_ids.band_id", + "mac_state.pending_application_downlink.version_ids.brand_id", + "mac_state.pending_application_downlink.version_ids.firmware_version", + "mac_state.pending_application_downlink.version_ids.hardware_version", + "mac_state.pending_application_downlink.version_ids.model_id", "mac_state.pending_relay_downlink", "mac_state.pending_relay_downlink.raw_payload", "mac_state.pending_requests", @@ -1358,6 +1373,13 @@ var RPCFieldMaskPaths = map[string]RPCFieldMaskPathValue{ "mac_state.pending_application_downlink.f_cnt", "mac_state.pending_application_downlink.f_port", "mac_state.pending_application_downlink.frm_payload", + "mac_state.pending_application_downlink.network_ids", + "mac_state.pending_application_downlink.network_ids.cluster_address", + "mac_state.pending_application_downlink.network_ids.cluster_id", + "mac_state.pending_application_downlink.network_ids.net_id", + "mac_state.pending_application_downlink.network_ids.ns_id", + "mac_state.pending_application_downlink.network_ids.tenant_address", + "mac_state.pending_application_downlink.network_ids.tenant_id", "mac_state.pending_application_downlink.priority", "mac_state.pending_application_downlink.session_key_id", "mac_state.pending_relay_downlink", diff --git a/pkg/ttnpb/messages.go b/pkg/ttnpb/messages.go index d7cfc2a436..18e06b66b5 100644 --- a/pkg/ttnpb/messages.go +++ b/pkg/ttnpb/messages.go @@ -71,6 +71,8 @@ func (v *ApplicationDownlink) FieldIsZero(p string) bool { return true } switch p { + case "attributes": + return v.Attributes == nil case "class_b_c": return v.ClassBC == nil case "class_b_c.absolute_time": @@ -79,6 +81,12 @@ func (v *ApplicationDownlink) FieldIsZero(p string) bool { return v.ClassBC.FieldIsZero("gateways") case "confirmed": return !v.Confirmed + case "confirmed_retry": + return v.ConfirmedRetry == nil + case "confirmed_retry.attempt": + return v.ConfirmedRetry.FieldIsZero("attempt") + case "confirmed_retry.max_attempts": + return v.ConfirmedRetry.FieldIsZero("max_attempts") case "correlation_ids": return v.CorrelationIds == nil case "decoded_payload": @@ -91,16 +99,38 @@ func (v *ApplicationDownlink) FieldIsZero(p string) bool { return v.FPort == 0 case "frm_payload": return v.FrmPayload == nil + case "locations": + return v.Locations == nil + case "network_ids": // nolint: goconst + return v.NetworkIds == nil + case "network_ids.cluster_address": + return v.NetworkIds.FieldIsZero("cluster_address") + case "network_ids.cluster_id": + return v.NetworkIds.FieldIsZero("cluster_id") + case "network_ids.net_id": + return v.NetworkIds.FieldIsZero("net_id") + case "network_ids.ns_id": + return v.NetworkIds.FieldIsZero("ns_id") + case "network_ids.tenant_address": + return v.NetworkIds.FieldIsZero("tenant_address") + case "network_ids.tenant_id": + return v.NetworkIds.FieldIsZero("tenant_id") case "priority": return v.Priority == 0 case "session_key_id": return v.SessionKeyId == nil - case "confirmed_retry": - return v.ConfirmedRetry == nil - case "confirmed_retry.attempt": - return v.ConfirmedRetry.FieldIsZero("attempt") - case "confirmed_retry.max_attempts": - return v.ConfirmedRetry.FieldIsZero("max_attempts") + case "version_ids": + return v.VersionIds == nil + case "version_ids.band_id": + return v.VersionIds.FieldIsZero("band_id") + case "version_ids.brand_id": + return v.VersionIds.FieldIsZero("brand_id") + case "version_ids.firmware_version": + return v.VersionIds.FieldIsZero("firmware_version") + case "version_ids.hardware_version": + return v.VersionIds.FieldIsZero("hardware_version") + case "version_ids.model_id": + return v.VersionIds.FieldIsZero("model_id") } panic(fmt.Sprintf("unknown path '%s'", p)) } diff --git a/pkg/ttnpb/messages.pb.go b/pkg/ttnpb/messages.pb.go index 57aa6472b7..22323c0fb5 100644 --- a/pkg/ttnpb/messages.pb.go +++ b/pkg/ttnpb/messages.pb.go @@ -588,6 +588,73 @@ func (x *GatewayUplinkMessage) GetBandId() string { return "" } +type LastBatteryPercentage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Frame counter value of last uplink containing DevStatusAns. + FCnt uint32 `protobuf:"varint,1,opt,name=f_cnt,json=fCnt,proto3" json:"f_cnt,omitempty"` + // The battery percentage of the end device. + // The value is defined in the [0, 100] interval. + Value *wrapperspb.FloatValue `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` + // Time when last DevStatus MAC command was received. + ReceivedAt *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=received_at,json=receivedAt,proto3" json:"received_at,omitempty"` +} + +func (x *LastBatteryPercentage) Reset() { + *x = LastBatteryPercentage{} + if protoimpl.UnsafeEnabled { + mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LastBatteryPercentage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LastBatteryPercentage) ProtoMessage() {} + +func (x *LastBatteryPercentage) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[5] + 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 LastBatteryPercentage.ProtoReflect.Descriptor instead. +func (*LastBatteryPercentage) Descriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_messages_proto_rawDescGZIP(), []int{5} +} + +func (x *LastBatteryPercentage) GetFCnt() uint32 { + if x != nil { + return x.FCnt + } + return 0 +} + +func (x *LastBatteryPercentage) GetValue() *wrapperspb.FloatValue { + if x != nil { + return x.Value + } + return nil +} + +func (x *LastBatteryPercentage) GetReceivedAt() *timestamppb.Timestamp { + if x != nil { + return x.ReceivedAt + } + return nil +} + type ApplicationUplink struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -644,12 +711,18 @@ type ApplicationUplink struct { VersionIds *EndDeviceVersionIdentifiers `protobuf:"bytes,15,opt,name=version_ids,json=versionIds,proto3" json:"version_ids,omitempty"` // Network identifiers, set by the Network Server that handles the message. NetworkIds *NetworkIdentifiers `protobuf:"bytes,16,opt,name=network_ids,json=networkIds,proto3" json:"network_ids,omitempty"` + // Last battery percentage of the end device. + // Received via the DevStatus MAC command at last_dev_status_received_at or earlier. + // Set by the Network Server while handling the message. + LastBatteryPercentage *LastBatteryPercentage `protobuf:"bytes,20,opt,name=last_battery_percentage,json=lastBatteryPercentage,proto3" json:"last_battery_percentage,omitempty"` + // Attributes for devices, set by the Application Server while handling the message. + Attributes map[string]string `protobuf:"bytes,21,rep,name=attributes,proto3" json:"attributes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (x *ApplicationUplink) Reset() { *x = ApplicationUplink{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[5] + mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -662,7 +735,7 @@ func (x *ApplicationUplink) String() string { func (*ApplicationUplink) ProtoMessage() {} func (x *ApplicationUplink) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[5] + mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -675,7 +748,7 @@ func (x *ApplicationUplink) ProtoReflect() protoreflect.Message { // Deprecated: Use ApplicationUplink.ProtoReflect.Descriptor instead. func (*ApplicationUplink) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_messages_proto_rawDescGZIP(), []int{5} + return file_ttn_lorawan_v3_messages_proto_rawDescGZIP(), []int{6} } func (x *ApplicationUplink) GetSessionKeyId() []byte { @@ -811,6 +884,20 @@ func (x *ApplicationUplink) GetNetworkIds() *NetworkIdentifiers { return nil } +func (x *ApplicationUplink) GetLastBatteryPercentage() *LastBatteryPercentage { + if x != nil { + return x.LastBatteryPercentage + } + return nil +} + +func (x *ApplicationUplink) GetAttributes() map[string]string { + if x != nil { + return x.Attributes + } + return nil +} + type ApplicationUplinkNormalized struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -846,12 +933,14 @@ type ApplicationUplinkNormalized struct { VersionIds *EndDeviceVersionIdentifiers `protobuf:"bytes,13,opt,name=version_ids,json=versionIds,proto3" json:"version_ids,omitempty"` // Network identifiers, set by the Network Server that handles the message. NetworkIds *NetworkIdentifiers `protobuf:"bytes,14,opt,name=network_ids,json=networkIds,proto3" json:"network_ids,omitempty"` + // Attributes for devices, set by the Application Server while handling the message. + Attributes map[string]string `protobuf:"bytes,15,rep,name=attributes,proto3" json:"attributes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (x *ApplicationUplinkNormalized) Reset() { *x = ApplicationUplinkNormalized{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[6] + mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -864,7 +953,7 @@ func (x *ApplicationUplinkNormalized) String() string { func (*ApplicationUplinkNormalized) ProtoMessage() {} func (x *ApplicationUplinkNormalized) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[6] + mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -877,7 +966,7 @@ func (x *ApplicationUplinkNormalized) ProtoReflect() protoreflect.Message { // Deprecated: Use ApplicationUplinkNormalized.ProtoReflect.Descriptor instead. func (*ApplicationUplinkNormalized) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_messages_proto_rawDescGZIP(), []int{6} + return file_ttn_lorawan_v3_messages_proto_rawDescGZIP(), []int{7} } func (x *ApplicationUplinkNormalized) GetSessionKeyId() []byte { @@ -978,6 +1067,13 @@ func (x *ApplicationUplinkNormalized) GetNetworkIds() *NetworkIdentifiers { return nil } +func (x *ApplicationUplinkNormalized) GetAttributes() map[string]string { + if x != nil { + return x.Attributes + } + return nil +} + type ApplicationLocation struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -991,7 +1087,7 @@ type ApplicationLocation struct { func (x *ApplicationLocation) Reset() { *x = ApplicationLocation{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[7] + mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1004,7 +1100,7 @@ func (x *ApplicationLocation) String() string { func (*ApplicationLocation) ProtoMessage() {} func (x *ApplicationLocation) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[7] + mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1017,7 +1113,7 @@ func (x *ApplicationLocation) ProtoReflect() protoreflect.Message { // Deprecated: Use ApplicationLocation.ProtoReflect.Descriptor instead. func (*ApplicationLocation) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_messages_proto_rawDescGZIP(), []int{7} + return file_ttn_lorawan_v3_messages_proto_rawDescGZIP(), []int{8} } func (x *ApplicationLocation) GetService() string { @@ -1057,12 +1153,20 @@ type ApplicationJoinAccept struct { PendingSession bool `protobuf:"varint,4,opt,name=pending_session,json=pendingSession,proto3" json:"pending_session,omitempty"` // Server time when the Network Server received the message. ReceivedAt *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=received_at,json=receivedAt,proto3" json:"received_at,omitempty"` + // End device location metadata, set by the Application Server while handling the message. + Locations map[string]*Location `protobuf:"bytes,9,rep,name=locations,proto3" json:"locations,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // End device version identifiers, set by the Application Server while handling the message. + VersionIds *EndDeviceVersionIdentifiers `protobuf:"bytes,10,opt,name=version_ids,json=versionIds,proto3" json:"version_ids,omitempty"` + // Network identifiers, set by the Network Server that handles the message. + NetworkIds *NetworkIdentifiers `protobuf:"bytes,11,opt,name=network_ids,json=networkIds,proto3" json:"network_ids,omitempty"` + // Attributes for devices, set by the Application Server while handling the message. + Attributes map[string]string `protobuf:"bytes,12,rep,name=attributes,proto3" json:"attributes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (x *ApplicationJoinAccept) Reset() { *x = ApplicationJoinAccept{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[8] + mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1075,7 +1179,7 @@ func (x *ApplicationJoinAccept) String() string { func (*ApplicationJoinAccept) ProtoMessage() {} func (x *ApplicationJoinAccept) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[8] + mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1088,7 +1192,7 @@ func (x *ApplicationJoinAccept) ProtoReflect() protoreflect.Message { // Deprecated: Use ApplicationJoinAccept.ProtoReflect.Descriptor instead. func (*ApplicationJoinAccept) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_messages_proto_rawDescGZIP(), []int{8} + return file_ttn_lorawan_v3_messages_proto_rawDescGZIP(), []int{9} } func (x *ApplicationJoinAccept) GetSessionKeyId() []byte { @@ -1126,6 +1230,34 @@ func (x *ApplicationJoinAccept) GetReceivedAt() *timestamppb.Timestamp { return nil } +func (x *ApplicationJoinAccept) GetLocations() map[string]*Location { + if x != nil { + return x.Locations + } + return nil +} + +func (x *ApplicationJoinAccept) GetVersionIds() *EndDeviceVersionIdentifiers { + if x != nil { + return x.VersionIds + } + return nil +} + +func (x *ApplicationJoinAccept) GetNetworkIds() *NetworkIdentifiers { + if x != nil { + return x.NetworkIds + } + return nil +} + +func (x *ApplicationJoinAccept) GetAttributes() map[string]string { + if x != nil { + return x.Attributes + } + return nil +} + type ApplicationDownlink struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1155,12 +1287,20 @@ type ApplicationDownlink struct { Priority TxSchedulePriority `protobuf:"varint,8,opt,name=priority,proto3,enum=ttn.lorawan.v3.TxSchedulePriority" json:"priority,omitempty"` CorrelationIds []string `protobuf:"bytes,9,rep,name=correlation_ids,json=correlationIds,proto3" json:"correlation_ids,omitempty"` ConfirmedRetry *ApplicationDownlink_ConfirmedRetry `protobuf:"bytes,11,opt,name=confirmed_retry,json=confirmedRetry,proto3" json:"confirmed_retry,omitempty"` + // End device location metadata, set by the Application Server while handling the message. + Locations map[string]*Location `protobuf:"bytes,12,rep,name=locations,proto3" json:"locations,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // End device version identifiers, set by the Application Server while handling the message. + VersionIds *EndDeviceVersionIdentifiers `protobuf:"bytes,13,opt,name=version_ids,json=versionIds,proto3" json:"version_ids,omitempty"` + // Network identifiers, set by the Network Server that handles the message. + NetworkIds *NetworkIdentifiers `protobuf:"bytes,14,opt,name=network_ids,json=networkIds,proto3" json:"network_ids,omitempty"` + // Attributes for devices, set by the Application Server while handling the message. + Attributes map[string]string `protobuf:"bytes,15,rep,name=attributes,proto3" json:"attributes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (x *ApplicationDownlink) Reset() { *x = ApplicationDownlink{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[9] + mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1173,7 +1313,7 @@ func (x *ApplicationDownlink) String() string { func (*ApplicationDownlink) ProtoMessage() {} func (x *ApplicationDownlink) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[9] + mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1186,7 +1326,7 @@ func (x *ApplicationDownlink) ProtoReflect() protoreflect.Message { // Deprecated: Use ApplicationDownlink.ProtoReflect.Descriptor instead. func (*ApplicationDownlink) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_messages_proto_rawDescGZIP(), []int{9} + return file_ttn_lorawan_v3_messages_proto_rawDescGZIP(), []int{10} } func (x *ApplicationDownlink) GetSessionKeyId() []byte { @@ -1266,6 +1406,34 @@ func (x *ApplicationDownlink) GetConfirmedRetry() *ApplicationDownlink_Confirmed return nil } +func (x *ApplicationDownlink) GetLocations() map[string]*Location { + if x != nil { + return x.Locations + } + return nil +} + +func (x *ApplicationDownlink) GetVersionIds() *EndDeviceVersionIdentifiers { + if x != nil { + return x.VersionIds + } + return nil +} + +func (x *ApplicationDownlink) GetNetworkIds() *NetworkIdentifiers { + if x != nil { + return x.NetworkIds + } + return nil +} + +func (x *ApplicationDownlink) GetAttributes() map[string]string { + if x != nil { + return x.Attributes + } + return nil +} + type ApplicationDownlinks struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1277,7 +1445,7 @@ type ApplicationDownlinks struct { func (x *ApplicationDownlinks) Reset() { *x = ApplicationDownlinks{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[10] + mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1290,7 +1458,7 @@ func (x *ApplicationDownlinks) String() string { func (*ApplicationDownlinks) ProtoMessage() {} func (x *ApplicationDownlinks) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[10] + mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1303,7 +1471,7 @@ func (x *ApplicationDownlinks) ProtoReflect() protoreflect.Message { // Deprecated: Use ApplicationDownlinks.ProtoReflect.Descriptor instead. func (*ApplicationDownlinks) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_messages_proto_rawDescGZIP(), []int{10} + return file_ttn_lorawan_v3_messages_proto_rawDescGZIP(), []int{11} } func (x *ApplicationDownlinks) GetDownlinks() []*ApplicationDownlink { @@ -1320,12 +1488,20 @@ type ApplicationDownlinkFailed struct { Downlink *ApplicationDownlink `protobuf:"bytes,1,opt,name=downlink,proto3" json:"downlink,omitempty"` Error *ErrorDetails `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` + // End device location metadata, set by the Application Server while handling the message. + Locations map[string]*Location `protobuf:"bytes,3,rep,name=locations,proto3" json:"locations,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // End device version identifiers, set by the Application Server while handling the message. + VersionIds *EndDeviceVersionIdentifiers `protobuf:"bytes,4,opt,name=version_ids,json=versionIds,proto3" json:"version_ids,omitempty"` + // Network identifiers, set by the Network Server that handles the message. + NetworkIds *NetworkIdentifiers `protobuf:"bytes,5,opt,name=network_ids,json=networkIds,proto3" json:"network_ids,omitempty"` + // Attributes for devices, set by the Application Server while handling the message. + Attributes map[string]string `protobuf:"bytes,6,rep,name=attributes,proto3" json:"attributes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (x *ApplicationDownlinkFailed) Reset() { *x = ApplicationDownlinkFailed{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[11] + mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1338,7 +1514,7 @@ func (x *ApplicationDownlinkFailed) String() string { func (*ApplicationDownlinkFailed) ProtoMessage() {} func (x *ApplicationDownlinkFailed) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[11] + mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1351,7 +1527,7 @@ func (x *ApplicationDownlinkFailed) ProtoReflect() protoreflect.Message { // Deprecated: Use ApplicationDownlinkFailed.ProtoReflect.Descriptor instead. func (*ApplicationDownlinkFailed) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_messages_proto_rawDescGZIP(), []int{11} + return file_ttn_lorawan_v3_messages_proto_rawDescGZIP(), []int{12} } func (x *ApplicationDownlinkFailed) GetDownlink() *ApplicationDownlink { @@ -1368,6 +1544,34 @@ func (x *ApplicationDownlinkFailed) GetError() *ErrorDetails { return nil } +func (x *ApplicationDownlinkFailed) GetLocations() map[string]*Location { + if x != nil { + return x.Locations + } + return nil +} + +func (x *ApplicationDownlinkFailed) GetVersionIds() *EndDeviceVersionIdentifiers { + if x != nil { + return x.VersionIds + } + return nil +} + +func (x *ApplicationDownlinkFailed) GetNetworkIds() *NetworkIdentifiers { + if x != nil { + return x.NetworkIds + } + return nil +} + +func (x *ApplicationDownlinkFailed) GetAttributes() map[string]string { + if x != nil { + return x.Attributes + } + return nil +} + type ApplicationInvalidatedDownlinks struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1376,12 +1580,20 @@ type ApplicationInvalidatedDownlinks struct { Downlinks []*ApplicationDownlink `protobuf:"bytes,1,rep,name=downlinks,proto3" json:"downlinks,omitempty"` LastFCntDown uint32 `protobuf:"varint,2,opt,name=last_f_cnt_down,json=lastFCntDown,proto3" json:"last_f_cnt_down,omitempty"` SessionKeyId []byte `protobuf:"bytes,3,opt,name=session_key_id,json=sessionKeyId,proto3" json:"session_key_id,omitempty"` + // End device location metadata, set by the Application Server while handling the message. + Locations map[string]*Location `protobuf:"bytes,4,rep,name=locations,proto3" json:"locations,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // End device version identifiers, set by the Application Server while handling the message. + VersionIds *EndDeviceVersionIdentifiers `protobuf:"bytes,5,opt,name=version_ids,json=versionIds,proto3" json:"version_ids,omitempty"` + // Network identifiers, set by the Network Server that handles the message. + NetworkIds *NetworkIdentifiers `protobuf:"bytes,6,opt,name=network_ids,json=networkIds,proto3" json:"network_ids,omitempty"` + // Attributes for devices, set by the Application Server while handling the message. + Attributes map[string]string `protobuf:"bytes,7,rep,name=attributes,proto3" json:"attributes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (x *ApplicationInvalidatedDownlinks) Reset() { *x = ApplicationInvalidatedDownlinks{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[12] + mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1394,7 +1606,7 @@ func (x *ApplicationInvalidatedDownlinks) String() string { func (*ApplicationInvalidatedDownlinks) ProtoMessage() {} func (x *ApplicationInvalidatedDownlinks) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[12] + mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1407,7 +1619,7 @@ func (x *ApplicationInvalidatedDownlinks) ProtoReflect() protoreflect.Message { // Deprecated: Use ApplicationInvalidatedDownlinks.ProtoReflect.Descriptor instead. func (*ApplicationInvalidatedDownlinks) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_messages_proto_rawDescGZIP(), []int{12} + return file_ttn_lorawan_v3_messages_proto_rawDescGZIP(), []int{13} } func (x *ApplicationInvalidatedDownlinks) GetDownlinks() []*ApplicationDownlink { @@ -1431,6 +1643,34 @@ func (x *ApplicationInvalidatedDownlinks) GetSessionKeyId() []byte { return nil } +func (x *ApplicationInvalidatedDownlinks) GetLocations() map[string]*Location { + if x != nil { + return x.Locations + } + return nil +} + +func (x *ApplicationInvalidatedDownlinks) GetVersionIds() *EndDeviceVersionIdentifiers { + if x != nil { + return x.VersionIds + } + return nil +} + +func (x *ApplicationInvalidatedDownlinks) GetNetworkIds() *NetworkIdentifiers { + if x != nil { + return x.NetworkIds + } + return nil +} + +func (x *ApplicationInvalidatedDownlinks) GetAttributes() map[string]string { + if x != nil { + return x.Attributes + } + return nil +} + type DownlinkQueueOperationErrorDetails struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1447,7 +1687,7 @@ type DownlinkQueueOperationErrorDetails struct { func (x *DownlinkQueueOperationErrorDetails) Reset() { *x = DownlinkQueueOperationErrorDetails{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[13] + mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1460,7 +1700,7 @@ func (x *DownlinkQueueOperationErrorDetails) String() string { func (*DownlinkQueueOperationErrorDetails) ProtoMessage() {} func (x *DownlinkQueueOperationErrorDetails) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[13] + mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1473,7 +1713,7 @@ func (x *DownlinkQueueOperationErrorDetails) ProtoReflect() protoreflect.Message // Deprecated: Use DownlinkQueueOperationErrorDetails.ProtoReflect.Descriptor instead. func (*DownlinkQueueOperationErrorDetails) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_messages_proto_rawDescGZIP(), []int{13} + return file_ttn_lorawan_v3_messages_proto_rawDescGZIP(), []int{14} } func (x *DownlinkQueueOperationErrorDetails) GetDevAddr() []byte { @@ -1525,12 +1765,20 @@ type ApplicationServiceData struct { Service string `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"` Data *structpb.Struct `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` + // End device location metadata, set by the Application Server while handling the message. + Locations map[string]*Location `protobuf:"bytes,3,rep,name=locations,proto3" json:"locations,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // End device version identifiers, set by the Application Server while handling the message. + VersionIds *EndDeviceVersionIdentifiers `protobuf:"bytes,4,opt,name=version_ids,json=versionIds,proto3" json:"version_ids,omitempty"` + // Network identifiers, set by the Network Server that handles the message. + NetworkIds *NetworkIdentifiers `protobuf:"bytes,5,opt,name=network_ids,json=networkIds,proto3" json:"network_ids,omitempty"` + // Attributes for devices, set by the Application Server while handling the message. + Attributes map[string]string `protobuf:"bytes,6,rep,name=attributes,proto3" json:"attributes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (x *ApplicationServiceData) Reset() { *x = ApplicationServiceData{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[14] + mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1543,7 +1791,7 @@ func (x *ApplicationServiceData) String() string { func (*ApplicationServiceData) ProtoMessage() {} func (x *ApplicationServiceData) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[14] + mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1556,7 +1804,7 @@ func (x *ApplicationServiceData) ProtoReflect() protoreflect.Message { // Deprecated: Use ApplicationServiceData.ProtoReflect.Descriptor instead. func (*ApplicationServiceData) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_messages_proto_rawDescGZIP(), []int{14} + return file_ttn_lorawan_v3_messages_proto_rawDescGZIP(), []int{15} } func (x *ApplicationServiceData) GetService() string { @@ -1573,6 +1821,34 @@ func (x *ApplicationServiceData) GetData() *structpb.Struct { return nil } +func (x *ApplicationServiceData) GetLocations() map[string]*Location { + if x != nil { + return x.Locations + } + return nil +} + +func (x *ApplicationServiceData) GetVersionIds() *EndDeviceVersionIdentifiers { + if x != nil { + return x.VersionIds + } + return nil +} + +func (x *ApplicationServiceData) GetNetworkIds() *NetworkIdentifiers { + if x != nil { + return x.NetworkIds + } + return nil +} + +func (x *ApplicationServiceData) GetAttributes() map[string]string { + if x != nil { + return x.Attributes + } + return nil +} + // Application uplink message. type ApplicationUp struct { state protoimpl.MessageState @@ -1604,7 +1880,7 @@ type ApplicationUp struct { func (x *ApplicationUp) Reset() { *x = ApplicationUp{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[15] + mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1617,7 +1893,7 @@ func (x *ApplicationUp) String() string { func (*ApplicationUp) ProtoMessage() {} func (x *ApplicationUp) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[15] + mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1630,7 +1906,7 @@ func (x *ApplicationUp) ProtoReflect() protoreflect.Message { // Deprecated: Use ApplicationUp.ProtoReflect.Descriptor instead. func (*ApplicationUp) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_messages_proto_rawDescGZIP(), []int{15} + return file_ttn_lorawan_v3_messages_proto_rawDescGZIP(), []int{16} } func (x *ApplicationUp) GetEndDeviceIds() *EndDeviceIdentifiers { @@ -1833,7 +2109,7 @@ type MessagePayloadFormatters struct { func (x *MessagePayloadFormatters) Reset() { *x = MessagePayloadFormatters{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[16] + mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1846,7 +2122,7 @@ func (x *MessagePayloadFormatters) String() string { func (*MessagePayloadFormatters) ProtoMessage() {} func (x *MessagePayloadFormatters) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[16] + mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1859,7 +2135,7 @@ func (x *MessagePayloadFormatters) ProtoReflect() protoreflect.Message { // Deprecated: Use MessagePayloadFormatters.ProtoReflect.Descriptor instead. func (*MessagePayloadFormatters) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_messages_proto_rawDescGZIP(), []int{16} + return file_ttn_lorawan_v3_messages_proto_rawDescGZIP(), []int{17} } func (x *MessagePayloadFormatters) GetUpFormatter() PayloadFormatter { @@ -1902,7 +2178,7 @@ type DownlinkQueueRequest struct { func (x *DownlinkQueueRequest) Reset() { *x = DownlinkQueueRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[17] + mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1915,7 +2191,7 @@ func (x *DownlinkQueueRequest) String() string { func (*DownlinkQueueRequest) ProtoMessage() {} func (x *DownlinkQueueRequest) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[17] + mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1928,7 +2204,7 @@ func (x *DownlinkQueueRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DownlinkQueueRequest.ProtoReflect.Descriptor instead. func (*DownlinkQueueRequest) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_messages_proto_rawDescGZIP(), []int{17} + return file_ttn_lorawan_v3_messages_proto_rawDescGZIP(), []int{18} } func (x *DownlinkQueueRequest) GetEndDeviceIds() *EndDeviceIdentifiers { @@ -1966,7 +2242,7 @@ type ApplicationDownlink_ClassBC struct { func (x *ApplicationDownlink_ClassBC) Reset() { *x = ApplicationDownlink_ClassBC{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[21] + mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1979,7 +2255,7 @@ func (x *ApplicationDownlink_ClassBC) String() string { func (*ApplicationDownlink_ClassBC) ProtoMessage() {} func (x *ApplicationDownlink_ClassBC) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[21] + mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[26] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1992,7 +2268,7 @@ func (x *ApplicationDownlink_ClassBC) ProtoReflect() protoreflect.Message { // Deprecated: Use ApplicationDownlink_ClassBC.ProtoReflect.Descriptor instead. func (*ApplicationDownlink_ClassBC) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_messages_proto_rawDescGZIP(), []int{9, 0} + return file_ttn_lorawan_v3_messages_proto_rawDescGZIP(), []int{10, 0} } func (x *ApplicationDownlink_ClassBC) GetGateways() []*ClassBCGatewayIdentifiers { @@ -2024,7 +2300,7 @@ type ApplicationDownlink_ConfirmedRetry struct { func (x *ApplicationDownlink_ConfirmedRetry) Reset() { *x = ApplicationDownlink_ConfirmedRetry{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[22] + mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2037,7 +2313,7 @@ func (x *ApplicationDownlink_ConfirmedRetry) String() string { func (*ApplicationDownlink_ConfirmedRetry) ProtoMessage() {} func (x *ApplicationDownlink_ConfirmedRetry) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[22] + mi := &file_ttn_lorawan_v3_messages_proto_msgTypes[27] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2050,7 +2326,7 @@ func (x *ApplicationDownlink_ConfirmedRetry) ProtoReflect() protoreflect.Message // Deprecated: Use ApplicationDownlink_ConfirmedRetry.ProtoReflect.Descriptor instead. func (*ApplicationDownlink_ConfirmedRetry) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_messages_proto_rawDescGZIP(), []int{9, 1} + return file_ttn_lorawan_v3_messages_proto_rawDescGZIP(), []int{10, 1} } func (x *ApplicationDownlink_ConfirmedRetry) GetAttempt() uint32 { @@ -2200,7 +2476,18 @@ var file_ttn_lorawan_v3_messages_proto_rawDesc = []byte{ 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x62, 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x61, 0x6e, 0x64, 0x49, 0x64, 0x22, 0x95, 0x09, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x61, 0x6e, 0x64, 0x49, 0x64, 0x22, 0xad, 0x01, + 0x0a, 0x15, 0x4c, 0x61, 0x73, 0x74, 0x42, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x50, 0x65, 0x72, + 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x12, 0x13, 0x0a, 0x05, 0x66, 0x5f, 0x63, 0x6e, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x66, 0x43, 0x6e, 0x74, 0x12, 0x42, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x6c, + 0x6f, 0x61, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x0f, 0xfa, 0x42, 0x0c, 0x0a, 0x0a, 0x1d, + 0x00, 0x00, 0xc8, 0x42, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x12, 0x3b, 0x0a, 0x0b, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x61, 0x74, 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, 0x0a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x41, 0x74, 0x22, 0xbe, 0x0b, 0x0a, 0x11, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x2e, 0x0a, 0x0e, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x08, 0xfa, 0x42, 0x05, @@ -2268,118 +2555,199 @@ var file_ttn_lorawan_v3_messages_proto_rawDesc = []byte{ 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x52, 0x0a, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, - 0x49, 0x64, 0x73, 0x1a, 0x56, 0x0a, 0x0e, 0x4c, 0x6f, 0x63, 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, 0x2e, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, - 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x3a, 0x08, 0xf2, 0xaa, 0x19, - 0x04, 0x08, 0x01, 0x10, 0x01, 0x22, 0xb4, 0x07, 0x0a, 0x1b, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, + 0x49, 0x64, 0x73, 0x12, 0x5d, 0x0a, 0x17, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x62, 0x61, 0x74, 0x74, + 0x65, 0x72, 0x79, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x18, 0x14, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, + 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x61, 0x73, 0x74, 0x42, 0x61, 0x74, 0x74, 0x65, 0x72, + 0x79, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x52, 0x15, 0x6c, 0x61, 0x73, + 0x74, 0x42, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, + 0x67, 0x65, 0x12, 0x88, 0x01, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, + 0x73, 0x18, 0x15, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, + 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, + 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x35, 0xfa, 0x42, 0x32, 0x9a, + 0x01, 0x2f, 0x10, 0x0a, 0x22, 0x24, 0x72, 0x22, 0x18, 0x24, 0x32, 0x1e, 0x5e, 0x5b, 0x61, 0x2d, + 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x28, 0x3f, 0x3a, 0x5b, 0x2d, 0x5d, 0x3f, 0x5b, 0x61, 0x2d, 0x7a, + 0x30, 0x2d, 0x39, 0x5d, 0x29, 0x7b, 0x32, 0x2c, 0x7d, 0x24, 0x2a, 0x05, 0x72, 0x03, 0x18, 0xc8, + 0x01, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x1a, 0x56, 0x0a, + 0x0e, 0x4c, 0x6f, 0x63, 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, 0x2e, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x18, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, + 0x33, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, + 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x3a, 0x02, 0x38, 0x01, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x22, 0x88, + 0x09, 0x0a, 0x1b, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x70, + 0x6c, 0x69, 0x6e, 0x6b, 0x4e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x12, 0x2e, + 0x0a, 0x0e, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x7a, 0x03, 0x18, 0x80, 0x10, + 0x52, 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x24, + 0x0a, 0x06, 0x66, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x0d, + 0xfa, 0x42, 0x0a, 0x2a, 0x08, 0x18, 0xff, 0x01, 0x28, 0x01, 0x38, 0xe0, 0x01, 0x52, 0x05, 0x66, + 0x50, 0x6f, 0x72, 0x74, 0x12, 0x13, 0x0a, 0x05, 0x66, 0x5f, 0x63, 0x6e, 0x74, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x04, 0x66, 0x43, 0x6e, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x72, 0x6d, + 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, + 0x66, 0x72, 0x6d, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x50, 0x0a, 0x12, 0x6e, 0x6f, + 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, + 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, 0x42, + 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x11, 0x6e, 0x6f, 0x72, 0x6d, 0x61, + 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x3e, 0x0a, 0x1b, + 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, + 0x61, 0x64, 0x5f, 0x77, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x19, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x50, 0x61, 0x79, + 0x6c, 0x6f, 0x61, 0x64, 0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3b, 0x0a, 0x0b, + 0x72, 0x78, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x07, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, + 0x76, 0x33, 0x2e, 0x52, 0x78, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0a, 0x72, + 0x78, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x40, 0x0a, 0x08, 0x73, 0x65, 0x74, + 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x74, + 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x54, 0x78, 0x53, + 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, + 0x01, 0x52, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x45, 0x0a, 0x0b, 0x72, + 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x09, 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, 0x42, 0x08, 0xfa, 0x42, + 0x05, 0xb2, 0x01, 0x02, 0x08, 0x01, 0x52, 0x0a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, + 0x41, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x18, + 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, + 0x12, 0x44, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x64, 0x5f, 0x61, 0x69, 0x72, + 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x64, 0x41, + 0x69, 0x72, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x58, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, + 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x4e, 0x6f, 0x72, 0x6d, + 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x12, 0x4c, 0x0a, 0x0b, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, + 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, + 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, + 0x72, 0x73, 0x52, 0x0a, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x43, + 0x0a, 0x0b, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x0e, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, + 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x52, 0x0a, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x49, 0x64, 0x73, 0x12, 0x92, 0x01, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, + 0x65, 0x73, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, + 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x4e, 0x6f, 0x72, 0x6d, 0x61, - 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x12, 0x2e, 0x0a, 0x0e, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x08, 0xfa, - 0x42, 0x05, 0x7a, 0x03, 0x18, 0x80, 0x10, 0x52, 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x4b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x06, 0x66, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x0d, 0xfa, 0x42, 0x0a, 0x2a, 0x08, 0x18, 0xff, 0x01, 0x28, - 0x01, 0x38, 0xe0, 0x01, 0x52, 0x05, 0x66, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x13, 0x0a, 0x05, 0x66, - 0x5f, 0x63, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x66, 0x43, 0x6e, 0x74, - 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x72, 0x6d, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x66, 0x72, 0x6d, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, - 0x64, 0x12, 0x50, 0x0a, 0x12, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x5f, - 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 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, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, - 0x52, 0x11, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x50, 0x61, 0x79, 0x6c, - 0x6f, 0x61, 0x64, 0x12, 0x3e, 0x0a, 0x1b, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x7a, 0x65, - 0x64, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x77, 0x61, 0x72, 0x6e, 0x69, 0x6e, - 0x67, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x19, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, - 0x69, 0x7a, 0x65, 0x64, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x57, 0x61, 0x72, 0x6e, 0x69, - 0x6e, 0x67, 0x73, 0x12, 0x3b, 0x0a, 0x0b, 0x72, 0x78, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, - 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x78, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x52, 0x0a, 0x72, 0x78, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0x12, 0x40, 0x0a, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x08, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, - 0x2e, 0x76, 0x33, 0x2e, 0x54, 0x78, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x42, 0x08, - 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, - 0x67, 0x73, 0x12, 0x45, 0x0a, 0x0b, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x61, - 0x74, 0x18, 0x09, 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, 0x42, 0x08, 0xfa, 0x42, 0x05, 0xb2, 0x01, 0x02, 0x08, 0x01, 0x52, 0x0a, 0x72, - 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, - 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x63, 0x6f, - 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x12, 0x44, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x73, 0x75, - 0x6d, 0x65, 0x64, 0x5f, 0x61, 0x69, 0x72, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0f, 0x63, 0x6f, - 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x64, 0x41, 0x69, 0x72, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x58, 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x3a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, - 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x70, 0x6c, - 0x69, 0x6e, 0x6b, 0x4e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x2e, 0x4c, 0x6f, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6c, 0x6f, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x4c, 0x0a, 0x0b, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x74, - 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x45, 0x6e, - 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x52, 0x0a, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x43, 0x0a, 0x0b, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, - 0x5f, 0x69, 0x64, 0x73, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x74, 0x6e, - 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x52, 0x0a, - 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x73, 0x1a, 0x56, 0x0a, 0x0e, 0x4c, 0x6f, - 0x63, 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, 0x2e, - 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, + 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x35, 0xfa, 0x42, 0x32, 0x9a, 0x01, 0x2f, 0x10, 0x0a, 0x22, + 0x24, 0x72, 0x22, 0x18, 0x24, 0x32, 0x1e, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, + 0x28, 0x3f, 0x3a, 0x5b, 0x2d, 0x5d, 0x3f, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x29, + 0x7b, 0x32, 0x2c, 0x7d, 0x24, 0x2a, 0x05, 0x72, 0x03, 0x18, 0xc8, 0x01, 0x52, 0x0a, 0x61, 0x74, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x1a, 0x56, 0x0a, 0x0e, 0x4c, 0x6f, 0x63, 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, 0x2e, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x74, + 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x6f, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, + 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x3a, + 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x00, 0x22, 0xc5, 0x02, 0x0a, 0x13, 0x41, 0x70, + 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x3e, 0x0a, 0x08, 0x6c, + 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4c, - 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, - 0x38, 0x01, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x00, 0x22, 0xc5, 0x02, 0x0a, - 0x13, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x6f, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x3e, - 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x18, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, - 0x33, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, - 0x01, 0x02, 0x10, 0x01, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x8a, - 0x01, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, + 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, + 0x01, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x8a, 0x01, 0x0a, 0x0a, + 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x33, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, + 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x6f, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x35, 0xfa, 0x42, 0x32, 0x9a, 0x01, 0x2f, 0x10, 0x0a, 0x22, + 0x24, 0x72, 0x22, 0x18, 0x24, 0x32, 0x1e, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, + 0x28, 0x3f, 0x3a, 0x5b, 0x2d, 0x5d, 0x3f, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x29, + 0x7b, 0x32, 0x2c, 0x7d, 0x24, 0x2a, 0x05, 0x72, 0x03, 0x18, 0xc8, 0x01, 0x52, 0x0a, 0x61, 0x74, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, + 0x00, 0x22, 0xe1, 0x06, 0x0a, 0x15, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x4a, 0x6f, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x12, 0x2e, 0x0a, 0x0e, 0x73, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x7a, 0x03, 0x18, 0x80, 0x10, 0x52, 0x0c, 0x73, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x37, 0x0a, 0x09, 0x61, + 0x70, 0x70, 0x5f, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, + 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, + 0x4b, 0x65, 0x79, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x52, 0x07, 0x61, 0x70, 0x70, + 0x53, 0x4b, 0x65, 0x79, 0x12, 0x58, 0x0a, 0x15, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, + 0x74, 0x65, 0x64, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x18, 0x03, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, - 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x35, 0xfa, 0x42, 0x32, 0x9a, 0x01, 0x2f, - 0x10, 0x0a, 0x22, 0x24, 0x72, 0x22, 0x18, 0x24, 0x32, 0x1e, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x30, - 0x2d, 0x39, 0x5d, 0x28, 0x3f, 0x3a, 0x5b, 0x2d, 0x5d, 0x3f, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, - 0x39, 0x5d, 0x29, 0x7b, 0x32, 0x2c, 0x7d, 0x24, 0x2a, 0x05, 0x72, 0x03, 0x18, 0xc8, 0x01, 0x52, - 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, - 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, - 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, - 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, - 0x08, 0x01, 0x10, 0x00, 0x22, 0xd4, 0x02, 0x0a, 0x15, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x4a, 0x6f, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x12, 0x2e, + 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x52, 0x14, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, + 0x64, 0x61, 0x74, 0x65, 0x64, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x12, 0x27, + 0x0a, 0x0f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, + 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x45, 0x0a, 0x0b, 0x72, 0x65, 0x63, 0x65, 0x69, + 0x76, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x08, 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, 0x42, 0x08, 0xfa, 0x42, 0x05, 0xb2, 0x01, 0x02, + 0x08, 0x01, 0x52, 0x0a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x41, 0x74, 0x12, 0x52, + 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x34, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, + 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4a, 0x6f, + 0x69, 0x6e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x12, 0x4c, 0x0a, 0x0b, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, + 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, + 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, + 0x69, 0x65, 0x72, 0x73, 0x52, 0x0a, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, + 0x12, 0x43, 0x0a, 0x0b, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x69, 0x64, 0x73, 0x18, + 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, + 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x52, 0x0a, 0x6e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x49, 0x64, 0x73, 0x12, 0x8c, 0x01, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, + 0x75, 0x74, 0x65, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x74, 0x74, 0x6e, + 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4a, 0x6f, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x65, 0x70, + 0x74, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x42, 0x35, 0xfa, 0x42, 0x32, 0x9a, 0x01, 0x2f, 0x10, 0x0a, 0x22, 0x24, 0x72, 0x22, 0x18, + 0x24, 0x32, 0x1e, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x28, 0x3f, 0x3a, 0x5b, + 0x2d, 0x5d, 0x3f, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x29, 0x7b, 0x32, 0x2c, 0x7d, + 0x24, 0x2a, 0x05, 0x72, 0x03, 0x18, 0xc8, 0x01, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, + 0x75, 0x74, 0x65, 0x73, 0x1a, 0x56, 0x0a, 0x0e, 0x4c, 0x6f, 0x63, 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, 0x2e, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, + 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3d, 0x0a, 0x0f, + 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x3a, 0x08, 0xf2, 0xaa, 0x19, + 0x04, 0x08, 0x01, 0x10, 0x00, 0x22, 0xde, 0x0d, 0x0a, 0x13, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0xcd, 0x01, 0x0a, 0x0e, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x7a, 0x03, 0x18, 0x80, 0x10, - 0x52, 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x37, - 0x0a, 0x09, 0x61, 0x70, 0x70, 0x5f, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, - 0x76, 0x33, 0x2e, 0x4b, 0x65, 0x79, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x52, 0x07, - 0x61, 0x70, 0x70, 0x53, 0x4b, 0x65, 0x79, 0x12, 0x58, 0x0a, 0x15, 0x69, 0x6e, 0x76, 0x61, 0x6c, - 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, - 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, - 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x52, 0x14, 0x69, 0x6e, 0x76, - 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, - 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x70, 0x65, 0x6e, 0x64, - 0x69, 0x6e, 0x67, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x45, 0x0a, 0x0b, 0x72, 0x65, - 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x08, 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, 0x42, 0x08, 0xfa, 0x42, 0x05, - 0xb2, 0x01, 0x02, 0x08, 0x01, 0x52, 0x0a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x41, - 0x74, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x00, 0x22, 0xd5, 0x09, 0x0a, 0x13, - 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, - 0x69, 0x6e, 0x6b, 0x12, 0xcd, 0x01, 0x0a, 0x0e, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, - 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42, 0xa6, 0x01, 0xfa, - 0x42, 0x05, 0x7a, 0x03, 0x18, 0x80, 0x10, 0xf2, 0xaa, 0x19, 0x99, 0x01, 0x1a, 0x4e, 0x67, 0x69, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42, 0xa6, 0x01, 0xfa, 0x42, 0x05, 0x7a, 0x03, 0x18, 0x80, + 0x10, 0xf2, 0xaa, 0x19, 0x99, 0x01, 0x1a, 0x4e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x54, 0x68, 0x65, 0x54, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x49, 0x6e, 0x64, 0x75, + 0x73, 0x74, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, + 0x6e, 0x2d, 0x67, 0x6f, 0x2d, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x2f, 0x66, 0x6c, 0x61, 0x67, 0x73, + 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x4e, 0x65, 0x77, 0x48, 0x65, 0x78, 0x42, 0x79, 0x74, + 0x65, 0x73, 0x46, 0x6c, 0x61, 0x67, 0x22, 0x47, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x54, 0x68, 0x65, 0x54, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x49, 0x6e, 0x64, 0x75, + 0x73, 0x74, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, + 0x6e, 0x2d, 0x67, 0x6f, 0x2d, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x2f, 0x66, 0x6c, 0x61, 0x67, 0x73, + 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, + 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x22, 0x0a, + 0x06, 0x66, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x0b, 0xfa, + 0x42, 0x08, 0x2a, 0x06, 0x18, 0xff, 0x01, 0x38, 0xe0, 0x01, 0x52, 0x05, 0x66, 0x50, 0x6f, 0x72, + 0x74, 0x12, 0x13, 0x0a, 0x05, 0x66, 0x5f, 0x63, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x04, 0x66, 0x43, 0x6e, 0x74, 0x12, 0xc8, 0x01, 0x0a, 0x0b, 0x66, 0x72, 0x6d, 0x5f, 0x70, + 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x42, 0xa6, 0x01, 0xfa, + 0x42, 0x05, 0x7a, 0x03, 0x18, 0xff, 0x01, 0xf2, 0xaa, 0x19, 0x99, 0x01, 0x1a, 0x4e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x54, 0x68, 0x65, 0x54, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x49, 0x6e, 0x64, 0x75, 0x73, 0x74, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x67, 0x6f, 0x2d, 0x66, 0x6c, 0x61, 0x67, 0x73, @@ -2389,268 +2757,385 @@ var file_ttn_lorawan_v3_messages_proto_rawDesc = []byte{ 0x67, 0x73, 0x49, 0x6e, 0x64, 0x75, 0x73, 0x74, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x67, 0x6f, 0x2d, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x2f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, - 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x65, - 0x79, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x06, 0x66, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0d, 0x42, 0x0b, 0xfa, 0x42, 0x08, 0x2a, 0x06, 0x18, 0xff, 0x01, 0x38, 0xe0, 0x01, - 0x52, 0x05, 0x66, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x13, 0x0a, 0x05, 0x66, 0x5f, 0x63, 0x6e, 0x74, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x66, 0x43, 0x6e, 0x74, 0x12, 0xc8, 0x01, 0x0a, - 0x0b, 0x66, 0x72, 0x6d, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x0c, 0x42, 0xa6, 0x01, 0xfa, 0x42, 0x05, 0x7a, 0x03, 0x18, 0xff, 0x01, 0xf2, 0xaa, 0x19, - 0x99, 0x01, 0x1a, 0x4e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x54, - 0x68, 0x65, 0x54, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x49, 0x6e, 0x64, 0x75, 0x73, 0x74, 0x72, 0x69, - 0x65, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x67, 0x6f, - 0x2d, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x2f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x70, 0x6c, 0x75, 0x67, - 0x69, 0x6e, 0x2e, 0x4e, 0x65, 0x77, 0x48, 0x65, 0x78, 0x42, 0x79, 0x74, 0x65, 0x73, 0x46, 0x6c, - 0x61, 0x67, 0x22, 0x47, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x54, - 0x68, 0x65, 0x54, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x49, 0x6e, 0x64, 0x75, 0x73, 0x74, 0x72, 0x69, - 0x65, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x67, 0x6f, - 0x2d, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x2f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x70, 0x6c, 0x75, 0x67, - 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x0a, 0x66, 0x72, 0x6d, - 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x40, 0x0a, 0x0f, 0x64, 0x65, 0x63, 0x6f, 0x64, - 0x65, 0x64, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 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, 0x0e, 0x64, 0x65, 0x63, 0x6f, 0x64, - 0x65, 0x64, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x38, 0x0a, 0x18, 0x64, 0x65, 0x63, - 0x6f, 0x64, 0x65, 0x64, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x77, 0x61, 0x72, - 0x6e, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x09, 0x52, 0x16, 0x64, 0x65, 0x63, - 0x6f, 0x64, 0x65, 0x64, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x57, 0x61, 0x72, 0x6e, 0x69, - 0x6e, 0x67, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, - 0x64, 0x12, 0x47, 0x0a, 0x09, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f, 0x62, 0x5f, 0x63, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, - 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x42, - 0x43, 0x52, 0x07, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x42, 0x43, 0x12, 0x48, 0x0a, 0x08, 0x70, 0x72, - 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x74, - 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x54, 0x78, - 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, - 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, - 0x72, 0x69, 0x74, 0x79, 0x12, 0x35, 0x0a, 0x0f, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x42, 0x0c, 0xfa, - 0x42, 0x09, 0x92, 0x01, 0x06, 0x22, 0x04, 0x72, 0x02, 0x18, 0x64, 0x52, 0x0e, 0x63, 0x6f, 0x72, - 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x5b, 0x0a, 0x0f, 0x63, - 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x74, 0x72, 0x79, 0x18, 0x0b, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, - 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, - 0x6d, 0x65, 0x64, 0x52, 0x65, 0x74, 0x72, 0x79, 0x52, 0x0e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, - 0x6d, 0x65, 0x64, 0x52, 0x65, 0x74, 0x72, 0x79, 0x1a, 0x9b, 0x01, 0x0a, 0x07, 0x43, 0x6c, 0x61, - 0x73, 0x73, 0x42, 0x43, 0x12, 0x45, 0x0a, 0x08, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x73, - 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, - 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x42, 0x43, 0x47, - 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, - 0x73, 0x52, 0x08, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x73, 0x12, 0x3f, 0x0a, 0x0d, 0x61, - 0x62, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x08, 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, 0x0c, - 0x61, 0x62, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x3a, 0x08, 0xf2, 0xaa, - 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x1a, 0x80, 0x01, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x72, 0x6d, 0x65, 0x64, 0x52, 0x65, 0x74, 0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x74, 0x74, - 0x65, 0x6d, 0x70, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x61, 0x74, 0x74, 0x65, - 0x6d, 0x70, 0x74, 0x12, 0x4a, 0x0a, 0x0c, 0x6d, 0x61, 0x78, 0x5f, 0x61, 0x74, 0x74, 0x65, 0x6d, - 0x70, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, - 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x2a, 0x04, 0x18, 0x64, - 0x20, 0x00, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x41, 0x74, 0x74, 0x65, 0x6d, 0x70, 0x74, 0x73, 0x3a, - 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, - 0x01, 0x10, 0x01, 0x22, 0x59, 0x0a, 0x14, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x12, 0x41, 0x0a, 0x09, 0x64, - 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, + 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x0a, 0x66, 0x72, 0x6d, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, + 0x64, 0x12, 0x40, 0x0a, 0x0f, 0x64, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x5f, 0x70, 0x61, 0x79, + 0x6c, 0x6f, 0x61, 0x64, 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, 0x0e, 0x64, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x50, 0x61, 0x79, 0x6c, + 0x6f, 0x61, 0x64, 0x12, 0x38, 0x0a, 0x18, 0x64, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x5f, 0x70, + 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x77, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x73, 0x18, + 0x0a, 0x20, 0x03, 0x28, 0x09, 0x52, 0x16, 0x64, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x50, 0x61, + 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x1c, 0x0a, + 0x09, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x12, 0x47, 0x0a, 0x09, 0x63, + 0x6c, 0x61, 0x73, 0x73, 0x5f, 0x62, 0x5f, 0x63, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, + 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, + 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, + 0x69, 0x6e, 0x6b, 0x2e, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x42, 0x43, 0x52, 0x07, 0x63, 0x6c, 0x61, + 0x73, 0x73, 0x42, 0x43, 0x12, 0x48, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, + 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x54, 0x78, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, + 0x6c, 0x65, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, + 0x01, 0x02, 0x10, 0x01, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x35, + 0x0a, 0x0f, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, + 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x42, 0x0c, 0xfa, 0x42, 0x09, 0x92, 0x01, 0x06, 0x22, + 0x04, 0x72, 0x02, 0x18, 0x64, 0x52, 0x0e, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x5b, 0x0a, 0x0f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, + 0x65, 0x64, 0x5f, 0x72, 0x65, 0x74, 0x72, 0x79, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, - 0x69, 0x6e, 0x6b, 0x52, 0x09, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x22, 0xae, - 0x01, 0x0a, 0x19, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, - 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x12, 0x49, 0x0a, 0x08, - 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, + 0x69, 0x6e, 0x6b, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x52, 0x65, 0x74, + 0x72, 0x79, 0x52, 0x0e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x52, 0x65, 0x74, + 0x72, 0x79, 0x12, 0x50, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, + 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x4c, 0x0a, 0x0b, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, + 0x69, 0x64, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x74, 0x74, 0x6e, 0x2e, + 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x45, 0x6e, 0x64, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x52, 0x0a, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 0x73, 0x12, 0x43, 0x0a, 0x0b, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x69, 0x64, + 0x73, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, + 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x52, 0x0a, 0x6e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x73, 0x12, 0x8a, 0x01, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x74, + 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, + 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, + 0x6b, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x42, 0x35, 0xfa, 0x42, 0x32, 0x9a, 0x01, 0x2f, 0x10, 0x0a, 0x22, 0x24, 0x72, 0x22, 0x18, + 0x24, 0x32, 0x1e, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x28, 0x3f, 0x3a, 0x5b, + 0x2d, 0x5d, 0x3f, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x29, 0x7b, 0x32, 0x2c, 0x7d, + 0x24, 0x2a, 0x05, 0x72, 0x03, 0x18, 0xc8, 0x01, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, + 0x75, 0x74, 0x65, 0x73, 0x1a, 0x9b, 0x01, 0x0a, 0x07, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x42, 0x43, + 0x12, 0x45, 0x0a, 0x08, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x73, 0x18, 0x07, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, + 0x2e, 0x76, 0x33, 0x2e, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x42, 0x43, 0x47, 0x61, 0x74, 0x65, 0x77, + 0x61, 0x79, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x52, 0x08, 0x67, + 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x73, 0x12, 0x3f, 0x0a, 0x0d, 0x61, 0x62, 0x73, 0x6f, 0x6c, + 0x75, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x08, 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, 0x0c, 0x61, 0x62, 0x73, 0x6f, + 0x6c, 0x75, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, + 0x10, 0x01, 0x1a, 0x80, 0x01, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, + 0x52, 0x65, 0x74, 0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x74, 0x74, 0x65, 0x6d, 0x70, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x61, 0x74, 0x74, 0x65, 0x6d, 0x70, 0x74, 0x12, + 0x4a, 0x0a, 0x0c, 0x6d, 0x61, 0x78, 0x5f, 0x61, 0x74, 0x74, 0x65, 0x6d, 0x70, 0x74, 0x73, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x2a, 0x04, 0x18, 0x64, 0x20, 0x00, 0x52, 0x0b, + 0x6d, 0x61, 0x78, 0x41, 0x74, 0x74, 0x65, 0x6d, 0x70, 0x74, 0x73, 0x3a, 0x08, 0xf2, 0xaa, 0x19, + 0x04, 0x08, 0x01, 0x10, 0x01, 0x1a, 0x56, 0x0a, 0x0e, 0x4c, 0x6f, 0x63, 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, 0x2e, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, + 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3d, 0x0a, + 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, + 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x3a, 0x08, 0xf2, 0xaa, + 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x22, 0x59, 0x0a, 0x14, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x12, 0x41, + 0x0a, 0x09, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, + 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, + 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x52, 0x09, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, + 0x73, 0x22, 0xc3, 0x05, 0x0a, 0x19, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x12, + 0x49, 0x0a, 0x08, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, + 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, + 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, + 0x52, 0x08, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x3c, 0x0a, 0x05, 0x65, 0x72, + 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x74, 0x6e, 0x2e, + 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, + 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, + 0x01, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x56, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x74, 0x74, + 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, + 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, + 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x12, 0x4c, 0x0a, 0x0b, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, + 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, + 0x72, 0x73, 0x52, 0x0a, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x43, + 0x0a, 0x0b, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, + 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x52, 0x0a, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x49, 0x64, 0x73, 0x12, 0x90, 0x01, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, + 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, + 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x46, 0x61, 0x69, + 0x6c, 0x65, 0x64, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x42, 0x35, 0xfa, 0x42, 0x32, 0x9a, 0x01, 0x2f, 0x10, 0x0a, 0x22, 0x24, 0x72, + 0x22, 0x18, 0x24, 0x32, 0x1e, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x28, 0x3f, + 0x3a, 0x5b, 0x2d, 0x5d, 0x3f, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x29, 0x7b, 0x32, + 0x2c, 0x7d, 0x24, 0x2a, 0x05, 0x72, 0x03, 0x18, 0xc8, 0x01, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x1a, 0x56, 0x0a, 0x0e, 0x4c, 0x6f, 0x63, 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, 0x2e, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x74, 0x6e, 0x2e, + 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3d, + 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x3a, 0x08, 0xf2, + 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x00, 0x22, 0xe6, 0x05, 0x0a, 0x1f, 0x41, 0x70, 0x70, 0x6c, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, + 0x65, 0x64, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x12, 0x41, 0x0a, 0x09, 0x64, + 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, - 0x69, 0x6e, 0x6b, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x08, 0x64, - 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x3c, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, - 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x44, 0x65, 0x74, - 0x61, 0x69, 0x6c, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x05, - 0x65, 0x72, 0x72, 0x6f, 0x72, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x00, 0x22, - 0xc5, 0x01, 0x0a, 0x1f, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, - 0x6e, 0x6b, 0x73, 0x12, 0x41, 0x0a, 0x09, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, - 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x52, 0x09, 0x64, 0x6f, 0x77, - 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x12, 0x25, 0x0a, 0x0f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x66, - 0x5f, 0x63, 0x6e, 0x74, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x46, 0x43, 0x6e, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x12, 0x2e, 0x0a, - 0x0e, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x7a, 0x03, 0x18, 0x80, 0x10, 0x52, - 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x3a, 0x08, 0xf2, - 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x00, 0x22, 0x91, 0x05, 0x0a, 0x22, 0x44, 0x6f, 0x77, 0x6e, - 0x6c, 0x69, 0x6e, 0x6b, 0x51, 0x75, 0x65, 0x75, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0xc8, - 0x01, 0x0a, 0x08, 0x64, 0x65, 0x76, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0c, 0x42, 0xac, 0x01, 0x92, 0x41, 0x19, 0x4a, 0x0a, 0x22, 0x32, 0x36, 0x30, 0x30, 0x41, 0x42, - 0x43, 0x44, 0x22, 0x9a, 0x02, 0x01, 0x07, 0xa2, 0x02, 0x06, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, - 0xfa, 0x42, 0x06, 0x7a, 0x04, 0x68, 0x04, 0x70, 0x01, 0xea, 0xaa, 0x19, 0x82, 0x01, 0x0a, 0x3f, - 0x67, 0x6f, 0x2e, 0x74, 0x68, 0x65, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x6e, 0x65, 0x74, - 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2d, 0x73, 0x74, 0x61, - 0x63, 0x6b, 0x2f, 0x76, 0x33, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, - 0x4d, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6c, 0x48, 0x45, 0x58, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, + 0x69, 0x6e, 0x6b, 0x52, 0x09, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x12, 0x25, + 0x0a, 0x0f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x66, 0x5f, 0x63, 0x6e, 0x74, 0x5f, 0x64, 0x6f, 0x77, + 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x46, 0x43, 0x6e, + 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x12, 0x2e, 0x0a, 0x0e, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x08, 0xfa, + 0x42, 0x05, 0x7a, 0x03, 0x18, 0x80, 0x10, 0x52, 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x4b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x5c, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3e, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, + 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, + 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x12, 0x4c, 0x0a, 0x0b, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, + 0x64, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, + 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x66, 0x69, 0x65, 0x72, 0x73, 0x52, 0x0a, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, + 0x73, 0x12, 0x43, 0x0a, 0x0b, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x69, 0x64, 0x73, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, + 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x52, 0x0a, 0x6e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x73, 0x12, 0x96, 0x01, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, + 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x74, 0x74, + 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, + 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, + 0x74, 0x65, 0x64, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x2e, 0x41, 0x74, 0x74, + 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x35, 0xfa, 0x42, + 0x32, 0x9a, 0x01, 0x2f, 0x10, 0x0a, 0x22, 0x24, 0x72, 0x22, 0x18, 0x24, 0x32, 0x1e, 0x5e, 0x5b, + 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x28, 0x3f, 0x3a, 0x5b, 0x2d, 0x5d, 0x3f, 0x5b, 0x61, + 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x29, 0x7b, 0x32, 0x2c, 0x7d, 0x24, 0x2a, 0x05, 0x72, 0x03, + 0x18, 0xc8, 0x01, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x1a, + 0x56, 0x0a, 0x0e, 0x4c, 0x6f, 0x63, 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, 0x2e, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, + 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, + 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x00, + 0x22, 0x91, 0x05, 0x0a, 0x22, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x51, 0x75, 0x65, + 0x75, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, + 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0xc8, 0x01, 0x0a, 0x08, 0x64, 0x65, 0x76, 0x5f, + 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42, 0xac, 0x01, 0x92, 0x41, 0x19, + 0x4a, 0x0a, 0x22, 0x32, 0x36, 0x30, 0x30, 0x41, 0x42, 0x43, 0x44, 0x22, 0x9a, 0x02, 0x01, 0x07, + 0xa2, 0x02, 0x06, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0xfa, 0x42, 0x06, 0x7a, 0x04, 0x68, 0x04, + 0x70, 0x01, 0xea, 0xaa, 0x19, 0x82, 0x01, 0x0a, 0x3f, 0x67, 0x6f, 0x2e, 0x74, 0x68, 0x65, 0x74, + 0x68, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x6c, 0x6f, + 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2d, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2f, 0x76, 0x33, 0x2f, 0x70, + 0x6b, 0x67, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x4d, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6c, + 0x48, 0x45, 0x58, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x3f, 0x67, 0x6f, 0x2e, 0x74, 0x68, 0x65, + 0x74, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x6c, + 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2d, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2f, 0x76, 0x33, 0x2f, + 0x70, 0x6b, 0x67, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x55, 0x6e, 0x6d, 0x61, 0x72, 0x73, + 0x68, 0x61, 0x6c, 0x34, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x07, 0x64, 0x65, 0x76, 0x41, 0x64, + 0x64, 0x72, 0x12, 0x2e, 0x0a, 0x0e, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, + 0x79, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x7a, + 0x03, 0x18, 0x80, 0x10, 0x52, 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, + 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0e, 0x6d, 0x69, 0x6e, 0x5f, 0x66, 0x5f, 0x63, 0x6e, 0x74, 0x5f, + 0x64, 0x6f, 0x77, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x6d, 0x69, 0x6e, 0x46, + 0x43, 0x6e, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x12, 0xd7, 0x01, 0x0a, 0x10, 0x70, 0x65, 0x6e, 0x64, + 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x76, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0c, 0x42, 0xac, 0x01, 0x92, 0x41, 0x19, 0x4a, 0x0a, 0x22, 0x32, 0x36, 0x30, 0x30, 0x41, + 0x42, 0x43, 0x44, 0x22, 0x9a, 0x02, 0x01, 0x07, 0xa2, 0x02, 0x06, 0x73, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0xfa, 0x42, 0x06, 0x7a, 0x04, 0x68, 0x04, 0x70, 0x01, 0xea, 0xaa, 0x19, 0x82, 0x01, 0x0a, 0x3f, 0x67, 0x6f, 0x2e, 0x74, 0x68, 0x65, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2d, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2f, 0x76, 0x33, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, - 0x2e, 0x55, 0x6e, 0x6d, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6c, 0x34, 0x42, 0x79, 0x74, 0x65, 0x73, - 0x52, 0x07, 0x64, 0x65, 0x76, 0x41, 0x64, 0x64, 0x72, 0x12, 0x2e, 0x0a, 0x0e, 0x73, 0x65, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0c, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x7a, 0x03, 0x18, 0x80, 0x10, 0x52, 0x0c, 0x73, 0x65, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0e, 0x6d, 0x69, 0x6e, - 0x5f, 0x66, 0x5f, 0x63, 0x6e, 0x74, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x0b, 0x6d, 0x69, 0x6e, 0x46, 0x43, 0x6e, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x12, 0xd7, - 0x01, 0x0a, 0x10, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x76, 0x5f, 0x61, - 0x64, 0x64, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x42, 0xac, 0x01, 0x92, 0x41, 0x19, 0x4a, - 0x0a, 0x22, 0x32, 0x36, 0x30, 0x30, 0x41, 0x42, 0x43, 0x44, 0x22, 0x9a, 0x02, 0x01, 0x07, 0xa2, - 0x02, 0x06, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0xfa, 0x42, 0x06, 0x7a, 0x04, 0x68, 0x04, 0x70, - 0x01, 0xea, 0xaa, 0x19, 0x82, 0x01, 0x0a, 0x3f, 0x67, 0x6f, 0x2e, 0x74, 0x68, 0x65, 0x74, 0x68, - 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x6c, 0x6f, 0x72, - 0x61, 0x77, 0x61, 0x6e, 0x2d, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2f, 0x76, 0x33, 0x2f, 0x70, 0x6b, - 0x67, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x4d, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6c, 0x48, - 0x45, 0x58, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x3f, 0x67, 0x6f, 0x2e, 0x74, 0x68, 0x65, 0x74, - 0x68, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x6c, 0x6f, - 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2d, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2f, 0x76, 0x33, 0x2f, 0x70, - 0x6b, 0x67, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x55, 0x6e, 0x6d, 0x61, 0x72, 0x73, 0x68, - 0x61, 0x6c, 0x34, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x0e, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, - 0x67, 0x44, 0x65, 0x76, 0x41, 0x64, 0x64, 0x72, 0x12, 0x3d, 0x0a, 0x16, 0x70, 0x65, 0x6e, 0x64, - 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x5f, - 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x7a, 0x03, 0x18, - 0x80, 0x10, 0x52, 0x13, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x32, 0x0a, 0x16, 0x70, 0x65, 0x6e, 0x64, 0x69, - 0x6e, 0x67, 0x5f, 0x6d, 0x69, 0x6e, 0x5f, 0x66, 0x5f, 0x63, 0x6e, 0x74, 0x5f, 0x64, 0x6f, 0x77, - 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x12, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, - 0x4d, 0x69, 0x6e, 0x46, 0x43, 0x6e, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x22, 0x69, 0x0a, 0x16, 0x41, - 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, - 0x2b, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 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, 0x04, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x08, 0xf2, 0xaa, - 0x19, 0x04, 0x08, 0x01, 0x10, 0x00, 0x22, 0x94, 0x09, 0x0a, 0x0d, 0x41, 0x70, 0x70, 0x6c, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x70, 0x12, 0x54, 0x0a, 0x0e, 0x65, 0x6e, 0x64, 0x5f, - 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x24, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, - 0x33, 0x2e, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, - 0x52, 0x0c, 0x65, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x73, 0x12, 0x35, - 0x0a, 0x0f, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, - 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x42, 0x0c, 0xfa, 0x42, 0x09, 0x92, 0x01, 0x06, 0x22, - 0x04, 0x72, 0x02, 0x18, 0x64, 0x52, 0x0e, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x3b, 0x0a, 0x0b, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, - 0x64, 0x5f, 0x61, 0x74, 0x18, 0x0c, 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, 0x0a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, - 0x41, 0x74, 0x12, 0x4a, 0x0a, 0x0e, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x74, 0x6e, - 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x48, 0x00, 0x52, - 0x0d, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x5a, - 0x0a, 0x11, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x69, - 0x7a, 0x65, 0x64, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x74, 0x74, 0x6e, 0x2e, + 0x2e, 0x4d, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6c, 0x48, 0x45, 0x58, 0x42, 0x79, 0x74, 0x65, 0x73, + 0x12, 0x3f, 0x67, 0x6f, 0x2e, 0x74, 0x68, 0x65, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x6e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2d, 0x73, + 0x74, 0x61, 0x63, 0x6b, 0x2f, 0x76, 0x33, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x74, 0x79, 0x70, 0x65, + 0x73, 0x2e, 0x55, 0x6e, 0x6d, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6c, 0x34, 0x42, 0x79, 0x74, 0x65, + 0x73, 0x52, 0x0e, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x76, 0x41, 0x64, 0x64, + 0x72, 0x12, 0x3d, 0x0a, 0x16, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x0c, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x7a, 0x03, 0x18, 0x80, 0x10, 0x52, 0x13, 0x70, 0x65, 0x6e, + 0x64, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x49, 0x64, + 0x12, 0x32, 0x0a, 0x16, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6d, 0x69, 0x6e, 0x5f, + 0x66, 0x5f, 0x63, 0x6e, 0x74, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x12, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4d, 0x69, 0x6e, 0x46, 0x43, 0x6e, 0x74, + 0x44, 0x6f, 0x77, 0x6e, 0x22, 0xf8, 0x04, 0x0a, 0x16, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, + 0x18, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x2b, 0x0a, 0x04, 0x64, 0x61, 0x74, + 0x61, 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, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x53, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x4e, 0x6f, 0x72, 0x6d, - 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x48, 0x00, 0x52, 0x10, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, - 0x4e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x12, 0x48, 0x0a, 0x0b, 0x6a, 0x6f, - 0x69, 0x6e, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x25, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, - 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4a, 0x6f, 0x69, 0x6e, - 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x48, 0x00, 0x52, 0x0a, 0x6a, 0x6f, 0x69, 0x6e, 0x41, 0x63, - 0x63, 0x65, 0x70, 0x74, 0x12, 0x48, 0x0a, 0x0c, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, - 0x5f, 0x61, 0x63, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x61, 0x74, + 0x61, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x4c, 0x0a, 0x0b, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2b, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, + 0x33, 0x2e, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x52, 0x0a, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x43, 0x0a, 0x0b, 0x6e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, + 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, + 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, + 0x72, 0x73, 0x52, 0x0a, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x73, 0x12, 0x8d, + 0x01, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x06, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, + 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x41, 0x74, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x35, 0xfa, 0x42, 0x32, + 0x9a, 0x01, 0x2f, 0x10, 0x0a, 0x22, 0x24, 0x72, 0x22, 0x18, 0x24, 0x32, 0x1e, 0x5e, 0x5b, 0x61, + 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x28, 0x3f, 0x3a, 0x5b, 0x2d, 0x5d, 0x3f, 0x5b, 0x61, 0x2d, + 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x29, 0x7b, 0x32, 0x2c, 0x7d, 0x24, 0x2a, 0x05, 0x72, 0x03, 0x18, + 0xc8, 0x01, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x1a, 0x56, + 0x0a, 0x0e, 0x4c, 0x6f, 0x63, 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, 0x2e, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, + 0x76, 0x33, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, + 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x3a, 0x02, 0x38, 0x01, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x00, 0x22, + 0x94, 0x09, 0x0a, 0x0d, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, + 0x70, 0x12, 0x54, 0x0a, 0x0e, 0x65, 0x6e, 0x64, 0x5f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, + 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x74, 0x74, 0x6e, 0x2e, + 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x45, 0x6e, 0x64, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, + 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0c, 0x65, 0x6e, 0x64, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x73, 0x12, 0x35, 0x0a, 0x0f, 0x63, 0x6f, 0x72, 0x72, 0x65, + 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, + 0x42, 0x0c, 0xfa, 0x42, 0x09, 0x92, 0x01, 0x06, 0x22, 0x04, 0x72, 0x02, 0x18, 0x64, 0x52, 0x0e, + 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x3b, + 0x0a, 0x0b, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x0c, 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, + 0x0a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x41, 0x74, 0x12, 0x4a, 0x0a, 0x0e, 0x75, + 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, + 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x48, 0x00, 0x52, 0x0d, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x5a, 0x0a, 0x11, 0x75, 0x70, 0x6c, 0x69, 0x6e, + 0x6b, 0x5f, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x18, 0x0f, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, + 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, + 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x4e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x48, + 0x00, 0x52, 0x10, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x4e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x69, + 0x7a, 0x65, 0x64, 0x12, 0x48, 0x0a, 0x0b, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x61, 0x63, 0x63, 0x65, + 0x70, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, + 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4a, 0x6f, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x48, + 0x00, 0x52, 0x0a, 0x6a, 0x6f, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x12, 0x48, 0x0a, + 0x0c, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x61, 0x63, 0x6b, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, + 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x48, 0x00, 0x52, 0x0b, 0x64, 0x6f, 0x77, 0x6e, + 0x6c, 0x69, 0x6e, 0x6b, 0x41, 0x63, 0x6b, 0x12, 0x4a, 0x0a, 0x0d, 0x64, 0x6f, 0x77, 0x6e, 0x6c, + 0x69, 0x6e, 0x6b, 0x5f, 0x6e, 0x61, 0x63, 0x6b, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, + 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, + 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, + 0x69, 0x6e, 0x6b, 0x48, 0x00, 0x52, 0x0c, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x4e, + 0x61, 0x63, 0x6b, 0x12, 0x4a, 0x0a, 0x0d, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, + 0x73, 0x65, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x48, - 0x00, 0x52, 0x0b, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x41, 0x63, 0x6b, 0x12, 0x4a, - 0x0a, 0x0d, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x6e, 0x61, 0x63, 0x6b, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, - 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x48, 0x00, 0x52, 0x0c, 0x64, 0x6f, - 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x4e, 0x61, 0x63, 0x6b, 0x12, 0x4a, 0x0a, 0x0d, 0x64, 0x6f, - 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, - 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, - 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x48, 0x00, 0x52, 0x0c, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, - 0x6e, 0x6b, 0x53, 0x65, 0x6e, 0x74, 0x12, 0x54, 0x0a, 0x0f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, - 0x6e, 0x6b, 0x5f, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x29, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, - 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, - 0x6c, 0x69, 0x6e, 0x6b, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x48, 0x00, 0x52, 0x0e, 0x64, 0x6f, - 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x12, 0x4e, 0x0a, 0x0f, - 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x71, 0x75, 0x65, 0x75, 0x65, 0x64, 0x18, - 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, - 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x48, 0x00, 0x52, 0x0e, 0x64, 0x6f, - 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x51, 0x75, 0x65, 0x75, 0x65, 0x64, 0x12, 0x6f, 0x0a, 0x1a, - 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x71, 0x75, 0x65, 0x75, 0x65, 0x5f, 0x69, - 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x2f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, - 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x76, - 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, - 0x73, 0x48, 0x00, 0x52, 0x18, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x51, 0x75, 0x65, - 0x75, 0x65, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x12, 0x4e, 0x0a, - 0x0f, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x64, - 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, - 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0e, 0x6c, - 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x6f, 0x6c, 0x76, 0x65, 0x64, 0x12, 0x4b, 0x0a, - 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0d, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, - 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x0b, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, - 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, - 0x69, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, - 0x10, 0x00, 0x42, 0x09, 0x0a, 0x02, 0x75, 0x70, 0x12, 0x03, 0xf8, 0x42, 0x01, 0x22, 0xcc, 0x02, - 0x0a, 0x18, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, - 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x73, 0x12, 0x4d, 0x0a, 0x0c, 0x75, 0x70, - 0x5f, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x20, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, - 0x33, 0x2e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, - 0x65, 0x72, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0b, 0x75, 0x70, - 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x12, 0x3f, 0x0a, 0x16, 0x75, 0x70, 0x5f, - 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, - 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x72, 0x04, - 0x18, 0x80, 0xc0, 0x02, 0x52, 0x14, 0x75, 0x70, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, - 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x12, 0x51, 0x0a, 0x0e, 0x64, 0x6f, - 0x77, 0x6e, 0x5f, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, - 0x2e, 0x76, 0x33, 0x2e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x6f, 0x72, 0x6d, 0x61, - 0x74, 0x74, 0x65, 0x72, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0d, - 0x64, 0x6f, 0x77, 0x6e, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x12, 0x43, 0x0a, - 0x18, 0x64, 0x6f, 0x77, 0x6e, 0x5f, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x5f, - 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, - 0x09, 0xfa, 0x42, 0x06, 0x72, 0x04, 0x18, 0x80, 0xc0, 0x02, 0x52, 0x16, 0x64, 0x6f, 0x77, 0x6e, - 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, - 0x65, 0x72, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x22, 0xbb, 0x01, 0x0a, - 0x14, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x51, 0x75, 0x65, 0x75, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x54, 0x0a, 0x0e, 0x65, 0x6e, 0x64, 0x5f, 0x64, 0x65, 0x76, - 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, - 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x45, - 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, - 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0c, 0x65, - 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x73, 0x12, 0x4d, 0x0a, 0x09, 0x64, - 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, + 0x00, 0x52, 0x0c, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x53, 0x65, 0x6e, 0x74, 0x12, + 0x54, 0x0a, 0x0f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x66, 0x61, 0x69, 0x6c, + 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, + 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x46, 0x61, 0x69, + 0x6c, 0x65, 0x64, 0x48, 0x00, 0x52, 0x0e, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x46, + 0x61, 0x69, 0x6c, 0x65, 0x64, 0x12, 0x4e, 0x0a, 0x0f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, + 0x6b, 0x5f, 0x71, 0x75, 0x65, 0x75, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, - 0x69, 0x6e, 0x6b, 0x42, 0x0a, 0xfa, 0x42, 0x07, 0x92, 0x01, 0x04, 0x10, 0xa0, 0x8d, 0x06, 0x52, - 0x09, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x2a, 0xa3, 0x01, 0x0a, 0x10, 0x50, - 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x12, - 0x12, 0x0a, 0x0e, 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x54, 0x45, 0x52, 0x5f, 0x4e, 0x4f, 0x4e, - 0x45, 0x10, 0x00, 0x12, 0x18, 0x0a, 0x14, 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x54, 0x45, 0x52, - 0x5f, 0x52, 0x45, 0x50, 0x4f, 0x53, 0x49, 0x54, 0x4f, 0x52, 0x59, 0x10, 0x01, 0x12, 0x1a, 0x0a, - 0x16, 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x54, 0x45, 0x52, 0x5f, 0x47, 0x52, 0x50, 0x43, 0x5f, - 0x53, 0x45, 0x52, 0x56, 0x49, 0x43, 0x45, 0x10, 0x02, 0x12, 0x18, 0x0a, 0x14, 0x46, 0x4f, 0x52, - 0x4d, 0x41, 0x54, 0x54, 0x45, 0x52, 0x5f, 0x4a, 0x41, 0x56, 0x41, 0x53, 0x43, 0x52, 0x49, 0x50, - 0x54, 0x10, 0x03, 0x12, 0x18, 0x0a, 0x14, 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x54, 0x45, 0x52, - 0x5f, 0x43, 0x41, 0x59, 0x45, 0x4e, 0x4e, 0x45, 0x4c, 0x50, 0x50, 0x10, 0x04, 0x1a, 0x11, 0xea, - 0xaa, 0x19, 0x0d, 0x18, 0x01, 0x2a, 0x09, 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x54, 0x45, 0x52, - 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x6f, 0x2e, 0x74, 0x68, 0x65, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x73, - 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, - 0x2d, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2f, 0x76, 0x33, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x74, 0x74, - 0x6e, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x69, 0x6e, 0x6b, 0x48, 0x00, 0x52, 0x0e, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x51, + 0x75, 0x65, 0x75, 0x65, 0x64, 0x12, 0x6f, 0x0a, 0x1a, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, + 0x6b, 0x5f, 0x71, 0x75, 0x65, 0x75, 0x65, 0x5f, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, + 0x74, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, + 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, + 0x64, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x48, 0x00, 0x52, 0x18, 0x64, 0x6f, + 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x51, 0x75, 0x65, 0x75, 0x65, 0x49, 0x6e, 0x76, 0x61, 0x6c, + 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x12, 0x4e, 0x0a, 0x0f, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, + 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x6f, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0e, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x53, 0x6f, 0x6c, 0x76, 0x65, 0x64, 0x12, 0x4b, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x74, + 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, + 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x44, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, + 0x61, 0x74, 0x61, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x64, + 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x69, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x65, + 0x64, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x00, 0x42, 0x09, 0x0a, 0x02, 0x75, + 0x70, 0x12, 0x03, 0xf8, 0x42, 0x01, 0x22, 0xcc, 0x02, 0x0a, 0x18, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, + 0x65, 0x72, 0x73, 0x12, 0x4d, 0x0a, 0x0c, 0x75, 0x70, 0x5f, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, + 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x74, 0x74, 0x6e, 0x2e, + 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x50, 0x61, 0x79, 0x6c, 0x6f, + 0x61, 0x64, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x42, 0x08, 0xfa, 0x42, 0x05, + 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0b, 0x75, 0x70, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, + 0x65, 0x72, 0x12, 0x3f, 0x0a, 0x16, 0x75, 0x70, 0x5f, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, + 0x65, 0x72, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x72, 0x04, 0x18, 0x80, 0xc0, 0x02, 0x52, 0x14, 0x75, + 0x70, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, + 0x74, 0x65, 0x72, 0x12, 0x51, 0x0a, 0x0e, 0x64, 0x6f, 0x77, 0x6e, 0x5f, 0x66, 0x6f, 0x72, 0x6d, + 0x61, 0x74, 0x74, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x74, 0x74, + 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x50, 0x61, 0x79, + 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x42, 0x08, 0xfa, + 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0d, 0x64, 0x6f, 0x77, 0x6e, 0x46, 0x6f, 0x72, + 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x12, 0x43, 0x0a, 0x18, 0x64, 0x6f, 0x77, 0x6e, 0x5f, 0x66, + 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, + 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x72, 0x04, 0x18, + 0x80, 0xc0, 0x02, 0x52, 0x16, 0x64, 0x6f, 0x77, 0x6e, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, + 0x65, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x3a, 0x08, 0xf2, 0xaa, 0x19, + 0x04, 0x08, 0x01, 0x10, 0x01, 0x22, 0xbb, 0x01, 0x0a, 0x14, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, + 0x6e, 0x6b, 0x51, 0x75, 0x65, 0x75, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x54, + 0x0a, 0x0e, 0x65, 0x6e, 0x64, 0x5f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, + 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, + 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0c, 0x65, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x49, 0x64, 0x73, 0x12, 0x4d, 0x0a, 0x09, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, + 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x42, 0x0a, 0xfa, 0x42, + 0x07, 0x92, 0x01, 0x04, 0x10, 0xa0, 0x8d, 0x06, 0x52, 0x09, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, + 0x6e, 0x6b, 0x73, 0x2a, 0xa3, 0x01, 0x0a, 0x10, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x46, + 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x0e, 0x46, 0x4f, 0x52, 0x4d, + 0x41, 0x54, 0x54, 0x45, 0x52, 0x5f, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x18, 0x0a, 0x14, + 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x54, 0x45, 0x52, 0x5f, 0x52, 0x45, 0x50, 0x4f, 0x53, 0x49, + 0x54, 0x4f, 0x52, 0x59, 0x10, 0x01, 0x12, 0x1a, 0x0a, 0x16, 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, + 0x54, 0x45, 0x52, 0x5f, 0x47, 0x52, 0x50, 0x43, 0x5f, 0x53, 0x45, 0x52, 0x56, 0x49, 0x43, 0x45, + 0x10, 0x02, 0x12, 0x18, 0x0a, 0x14, 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x54, 0x45, 0x52, 0x5f, + 0x4a, 0x41, 0x56, 0x41, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x10, 0x03, 0x12, 0x18, 0x0a, 0x14, + 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x54, 0x45, 0x52, 0x5f, 0x43, 0x41, 0x59, 0x45, 0x4e, 0x4e, + 0x45, 0x4c, 0x50, 0x50, 0x10, 0x04, 0x1a, 0x11, 0xea, 0xaa, 0x19, 0x0d, 0x18, 0x01, 0x2a, 0x09, + 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x54, 0x45, 0x52, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x6f, 0x2e, + 0x74, 0x68, 0x65, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x2f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2d, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2f, + 0x76, 0x33, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x74, 0x74, 0x6e, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -2666,7 +3151,7 @@ func file_ttn_lorawan_v3_messages_proto_rawDescGZIP() []byte { } var file_ttn_lorawan_v3_messages_proto_enumTypes = make([]protoimpl.EnumInfo, 2) -var file_ttn_lorawan_v3_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 23) +var file_ttn_lorawan_v3_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 36) var file_ttn_lorawan_v3_messages_proto_goTypes = []interface{}{ (PayloadFormatter)(0), // 0: ttn.lorawan.v3.PayloadFormatter (TxAcknowledgment_Result)(0), // 1: ttn.lorawan.v3.TxAcknowledgment.Result @@ -2675,118 +3160,162 @@ var file_ttn_lorawan_v3_messages_proto_goTypes = []interface{}{ (*TxAcknowledgment)(nil), // 4: ttn.lorawan.v3.TxAcknowledgment (*GatewayTxAcknowledgment)(nil), // 5: ttn.lorawan.v3.GatewayTxAcknowledgment (*GatewayUplinkMessage)(nil), // 6: ttn.lorawan.v3.GatewayUplinkMessage - (*ApplicationUplink)(nil), // 7: ttn.lorawan.v3.ApplicationUplink - (*ApplicationUplinkNormalized)(nil), // 8: ttn.lorawan.v3.ApplicationUplinkNormalized - (*ApplicationLocation)(nil), // 9: ttn.lorawan.v3.ApplicationLocation - (*ApplicationJoinAccept)(nil), // 10: ttn.lorawan.v3.ApplicationJoinAccept - (*ApplicationDownlink)(nil), // 11: ttn.lorawan.v3.ApplicationDownlink - (*ApplicationDownlinks)(nil), // 12: ttn.lorawan.v3.ApplicationDownlinks - (*ApplicationDownlinkFailed)(nil), // 13: ttn.lorawan.v3.ApplicationDownlinkFailed - (*ApplicationInvalidatedDownlinks)(nil), // 14: ttn.lorawan.v3.ApplicationInvalidatedDownlinks - (*DownlinkQueueOperationErrorDetails)(nil), // 15: ttn.lorawan.v3.DownlinkQueueOperationErrorDetails - (*ApplicationServiceData)(nil), // 16: ttn.lorawan.v3.ApplicationServiceData - (*ApplicationUp)(nil), // 17: ttn.lorawan.v3.ApplicationUp - (*MessagePayloadFormatters)(nil), // 18: ttn.lorawan.v3.MessagePayloadFormatters - (*DownlinkQueueRequest)(nil), // 19: ttn.lorawan.v3.DownlinkQueueRequest - nil, // 20: ttn.lorawan.v3.ApplicationUplink.LocationsEntry - nil, // 21: ttn.lorawan.v3.ApplicationUplinkNormalized.LocationsEntry - nil, // 22: ttn.lorawan.v3.ApplicationLocation.AttributesEntry - (*ApplicationDownlink_ClassBC)(nil), // 23: ttn.lorawan.v3.ApplicationDownlink.ClassBC - (*ApplicationDownlink_ConfirmedRetry)(nil), // 24: ttn.lorawan.v3.ApplicationDownlink.ConfirmedRetry - (*Message)(nil), // 25: ttn.lorawan.v3.Message - (*TxSettings)(nil), // 26: ttn.lorawan.v3.TxSettings - (*RxMetadata)(nil), // 27: ttn.lorawan.v3.RxMetadata - (*timestamppb.Timestamp)(nil), // 28: google.protobuf.Timestamp - (*durationpb.Duration)(nil), // 29: google.protobuf.Duration - (*wrapperspb.BoolValue)(nil), // 30: google.protobuf.BoolValue - (*EndDeviceIdentifiers)(nil), // 31: ttn.lorawan.v3.EndDeviceIdentifiers - (*TxRequest)(nil), // 32: ttn.lorawan.v3.TxRequest - (*GatewayIdentifiers)(nil), // 33: ttn.lorawan.v3.GatewayIdentifiers - (*structpb.Struct)(nil), // 34: google.protobuf.Struct - (*KeyEnvelope)(nil), // 35: ttn.lorawan.v3.KeyEnvelope - (*EndDeviceVersionIdentifiers)(nil), // 36: ttn.lorawan.v3.EndDeviceVersionIdentifiers - (*NetworkIdentifiers)(nil), // 37: ttn.lorawan.v3.NetworkIdentifiers - (*Location)(nil), // 38: ttn.lorawan.v3.Location - (TxSchedulePriority)(0), // 39: ttn.lorawan.v3.TxSchedulePriority - (*ErrorDetails)(nil), // 40: ttn.lorawan.v3.ErrorDetails - (*ClassBCGatewayIdentifiers)(nil), // 41: ttn.lorawan.v3.ClassBCGatewayIdentifiers - (*wrapperspb.UInt32Value)(nil), // 42: google.protobuf.UInt32Value + (*LastBatteryPercentage)(nil), // 7: ttn.lorawan.v3.LastBatteryPercentage + (*ApplicationUplink)(nil), // 8: ttn.lorawan.v3.ApplicationUplink + (*ApplicationUplinkNormalized)(nil), // 9: ttn.lorawan.v3.ApplicationUplinkNormalized + (*ApplicationLocation)(nil), // 10: ttn.lorawan.v3.ApplicationLocation + (*ApplicationJoinAccept)(nil), // 11: ttn.lorawan.v3.ApplicationJoinAccept + (*ApplicationDownlink)(nil), // 12: ttn.lorawan.v3.ApplicationDownlink + (*ApplicationDownlinks)(nil), // 13: ttn.lorawan.v3.ApplicationDownlinks + (*ApplicationDownlinkFailed)(nil), // 14: ttn.lorawan.v3.ApplicationDownlinkFailed + (*ApplicationInvalidatedDownlinks)(nil), // 15: ttn.lorawan.v3.ApplicationInvalidatedDownlinks + (*DownlinkQueueOperationErrorDetails)(nil), // 16: ttn.lorawan.v3.DownlinkQueueOperationErrorDetails + (*ApplicationServiceData)(nil), // 17: ttn.lorawan.v3.ApplicationServiceData + (*ApplicationUp)(nil), // 18: ttn.lorawan.v3.ApplicationUp + (*MessagePayloadFormatters)(nil), // 19: ttn.lorawan.v3.MessagePayloadFormatters + (*DownlinkQueueRequest)(nil), // 20: ttn.lorawan.v3.DownlinkQueueRequest + nil, // 21: ttn.lorawan.v3.ApplicationUplink.LocationsEntry + nil, // 22: ttn.lorawan.v3.ApplicationUplink.AttributesEntry + nil, // 23: ttn.lorawan.v3.ApplicationUplinkNormalized.LocationsEntry + nil, // 24: ttn.lorawan.v3.ApplicationUplinkNormalized.AttributesEntry + nil, // 25: ttn.lorawan.v3.ApplicationLocation.AttributesEntry + nil, // 26: ttn.lorawan.v3.ApplicationJoinAccept.LocationsEntry + nil, // 27: ttn.lorawan.v3.ApplicationJoinAccept.AttributesEntry + (*ApplicationDownlink_ClassBC)(nil), // 28: ttn.lorawan.v3.ApplicationDownlink.ClassBC + (*ApplicationDownlink_ConfirmedRetry)(nil), // 29: ttn.lorawan.v3.ApplicationDownlink.ConfirmedRetry + nil, // 30: ttn.lorawan.v3.ApplicationDownlink.LocationsEntry + nil, // 31: ttn.lorawan.v3.ApplicationDownlink.AttributesEntry + nil, // 32: ttn.lorawan.v3.ApplicationDownlinkFailed.LocationsEntry + nil, // 33: ttn.lorawan.v3.ApplicationDownlinkFailed.AttributesEntry + nil, // 34: ttn.lorawan.v3.ApplicationInvalidatedDownlinks.LocationsEntry + nil, // 35: ttn.lorawan.v3.ApplicationInvalidatedDownlinks.AttributesEntry + nil, // 36: ttn.lorawan.v3.ApplicationServiceData.LocationsEntry + nil, // 37: ttn.lorawan.v3.ApplicationServiceData.AttributesEntry + (*Message)(nil), // 38: ttn.lorawan.v3.Message + (*TxSettings)(nil), // 39: ttn.lorawan.v3.TxSettings + (*RxMetadata)(nil), // 40: ttn.lorawan.v3.RxMetadata + (*timestamppb.Timestamp)(nil), // 41: google.protobuf.Timestamp + (*durationpb.Duration)(nil), // 42: google.protobuf.Duration + (*wrapperspb.BoolValue)(nil), // 43: google.protobuf.BoolValue + (*EndDeviceIdentifiers)(nil), // 44: ttn.lorawan.v3.EndDeviceIdentifiers + (*TxRequest)(nil), // 45: ttn.lorawan.v3.TxRequest + (*GatewayIdentifiers)(nil), // 46: ttn.lorawan.v3.GatewayIdentifiers + (*wrapperspb.FloatValue)(nil), // 47: google.protobuf.FloatValue + (*structpb.Struct)(nil), // 48: google.protobuf.Struct + (*KeyEnvelope)(nil), // 49: ttn.lorawan.v3.KeyEnvelope + (*EndDeviceVersionIdentifiers)(nil), // 50: ttn.lorawan.v3.EndDeviceVersionIdentifiers + (*NetworkIdentifiers)(nil), // 51: ttn.lorawan.v3.NetworkIdentifiers + (*Location)(nil), // 52: ttn.lorawan.v3.Location + (TxSchedulePriority)(0), // 53: ttn.lorawan.v3.TxSchedulePriority + (*ErrorDetails)(nil), // 54: ttn.lorawan.v3.ErrorDetails + (*ClassBCGatewayIdentifiers)(nil), // 55: ttn.lorawan.v3.ClassBCGatewayIdentifiers + (*wrapperspb.UInt32Value)(nil), // 56: google.protobuf.UInt32Value } var file_ttn_lorawan_v3_messages_proto_depIdxs = []int32{ - 25, // 0: ttn.lorawan.v3.UplinkMessage.payload:type_name -> ttn.lorawan.v3.Message - 26, // 1: ttn.lorawan.v3.UplinkMessage.settings:type_name -> ttn.lorawan.v3.TxSettings - 27, // 2: ttn.lorawan.v3.UplinkMessage.rx_metadata:type_name -> ttn.lorawan.v3.RxMetadata - 28, // 3: ttn.lorawan.v3.UplinkMessage.received_at:type_name -> google.protobuf.Timestamp - 29, // 4: ttn.lorawan.v3.UplinkMessage.consumed_airtime:type_name -> google.protobuf.Duration - 30, // 5: ttn.lorawan.v3.UplinkMessage.crc_status:type_name -> google.protobuf.BoolValue - 25, // 6: ttn.lorawan.v3.DownlinkMessage.payload:type_name -> ttn.lorawan.v3.Message - 31, // 7: ttn.lorawan.v3.DownlinkMessage.end_device_ids:type_name -> ttn.lorawan.v3.EndDeviceIdentifiers - 32, // 8: ttn.lorawan.v3.DownlinkMessage.request:type_name -> ttn.lorawan.v3.TxRequest - 26, // 9: ttn.lorawan.v3.DownlinkMessage.scheduled:type_name -> ttn.lorawan.v3.TxSettings + 38, // 0: ttn.lorawan.v3.UplinkMessage.payload:type_name -> ttn.lorawan.v3.Message + 39, // 1: ttn.lorawan.v3.UplinkMessage.settings:type_name -> ttn.lorawan.v3.TxSettings + 40, // 2: ttn.lorawan.v3.UplinkMessage.rx_metadata:type_name -> ttn.lorawan.v3.RxMetadata + 41, // 3: ttn.lorawan.v3.UplinkMessage.received_at:type_name -> google.protobuf.Timestamp + 42, // 4: ttn.lorawan.v3.UplinkMessage.consumed_airtime:type_name -> google.protobuf.Duration + 43, // 5: ttn.lorawan.v3.UplinkMessage.crc_status:type_name -> google.protobuf.BoolValue + 38, // 6: ttn.lorawan.v3.DownlinkMessage.payload:type_name -> ttn.lorawan.v3.Message + 44, // 7: ttn.lorawan.v3.DownlinkMessage.end_device_ids:type_name -> ttn.lorawan.v3.EndDeviceIdentifiers + 45, // 8: ttn.lorawan.v3.DownlinkMessage.request:type_name -> ttn.lorawan.v3.TxRequest + 39, // 9: ttn.lorawan.v3.DownlinkMessage.scheduled:type_name -> ttn.lorawan.v3.TxSettings 1, // 10: ttn.lorawan.v3.TxAcknowledgment.result:type_name -> ttn.lorawan.v3.TxAcknowledgment.Result 3, // 11: ttn.lorawan.v3.TxAcknowledgment.downlink_message:type_name -> ttn.lorawan.v3.DownlinkMessage - 33, // 12: ttn.lorawan.v3.GatewayTxAcknowledgment.gateway_ids:type_name -> ttn.lorawan.v3.GatewayIdentifiers + 46, // 12: ttn.lorawan.v3.GatewayTxAcknowledgment.gateway_ids:type_name -> ttn.lorawan.v3.GatewayIdentifiers 4, // 13: ttn.lorawan.v3.GatewayTxAcknowledgment.tx_ack:type_name -> ttn.lorawan.v3.TxAcknowledgment 2, // 14: ttn.lorawan.v3.GatewayUplinkMessage.message:type_name -> ttn.lorawan.v3.UplinkMessage - 34, // 15: ttn.lorawan.v3.ApplicationUplink.decoded_payload:type_name -> google.protobuf.Struct - 34, // 16: ttn.lorawan.v3.ApplicationUplink.normalized_payload:type_name -> google.protobuf.Struct - 27, // 17: ttn.lorawan.v3.ApplicationUplink.rx_metadata:type_name -> ttn.lorawan.v3.RxMetadata - 26, // 18: ttn.lorawan.v3.ApplicationUplink.settings:type_name -> ttn.lorawan.v3.TxSettings - 28, // 19: ttn.lorawan.v3.ApplicationUplink.received_at:type_name -> google.protobuf.Timestamp - 35, // 20: ttn.lorawan.v3.ApplicationUplink.app_s_key:type_name -> ttn.lorawan.v3.KeyEnvelope - 29, // 21: ttn.lorawan.v3.ApplicationUplink.consumed_airtime:type_name -> google.protobuf.Duration - 20, // 22: ttn.lorawan.v3.ApplicationUplink.locations:type_name -> ttn.lorawan.v3.ApplicationUplink.LocationsEntry - 36, // 23: ttn.lorawan.v3.ApplicationUplink.version_ids:type_name -> ttn.lorawan.v3.EndDeviceVersionIdentifiers - 37, // 24: ttn.lorawan.v3.ApplicationUplink.network_ids:type_name -> ttn.lorawan.v3.NetworkIdentifiers - 34, // 25: ttn.lorawan.v3.ApplicationUplinkNormalized.normalized_payload:type_name -> google.protobuf.Struct - 27, // 26: ttn.lorawan.v3.ApplicationUplinkNormalized.rx_metadata:type_name -> ttn.lorawan.v3.RxMetadata - 26, // 27: ttn.lorawan.v3.ApplicationUplinkNormalized.settings:type_name -> ttn.lorawan.v3.TxSettings - 28, // 28: ttn.lorawan.v3.ApplicationUplinkNormalized.received_at:type_name -> google.protobuf.Timestamp - 29, // 29: ttn.lorawan.v3.ApplicationUplinkNormalized.consumed_airtime:type_name -> google.protobuf.Duration - 21, // 30: ttn.lorawan.v3.ApplicationUplinkNormalized.locations:type_name -> ttn.lorawan.v3.ApplicationUplinkNormalized.LocationsEntry - 36, // 31: ttn.lorawan.v3.ApplicationUplinkNormalized.version_ids:type_name -> ttn.lorawan.v3.EndDeviceVersionIdentifiers - 37, // 32: ttn.lorawan.v3.ApplicationUplinkNormalized.network_ids:type_name -> ttn.lorawan.v3.NetworkIdentifiers - 38, // 33: ttn.lorawan.v3.ApplicationLocation.location:type_name -> ttn.lorawan.v3.Location - 22, // 34: ttn.lorawan.v3.ApplicationLocation.attributes:type_name -> ttn.lorawan.v3.ApplicationLocation.AttributesEntry - 35, // 35: ttn.lorawan.v3.ApplicationJoinAccept.app_s_key:type_name -> ttn.lorawan.v3.KeyEnvelope - 11, // 36: ttn.lorawan.v3.ApplicationJoinAccept.invalidated_downlinks:type_name -> ttn.lorawan.v3.ApplicationDownlink - 28, // 37: ttn.lorawan.v3.ApplicationJoinAccept.received_at:type_name -> google.protobuf.Timestamp - 34, // 38: ttn.lorawan.v3.ApplicationDownlink.decoded_payload:type_name -> google.protobuf.Struct - 23, // 39: ttn.lorawan.v3.ApplicationDownlink.class_b_c:type_name -> ttn.lorawan.v3.ApplicationDownlink.ClassBC - 39, // 40: ttn.lorawan.v3.ApplicationDownlink.priority:type_name -> ttn.lorawan.v3.TxSchedulePriority - 24, // 41: ttn.lorawan.v3.ApplicationDownlink.confirmed_retry:type_name -> ttn.lorawan.v3.ApplicationDownlink.ConfirmedRetry - 11, // 42: ttn.lorawan.v3.ApplicationDownlinks.downlinks:type_name -> ttn.lorawan.v3.ApplicationDownlink - 11, // 43: ttn.lorawan.v3.ApplicationDownlinkFailed.downlink:type_name -> ttn.lorawan.v3.ApplicationDownlink - 40, // 44: ttn.lorawan.v3.ApplicationDownlinkFailed.error:type_name -> ttn.lorawan.v3.ErrorDetails - 11, // 45: ttn.lorawan.v3.ApplicationInvalidatedDownlinks.downlinks:type_name -> ttn.lorawan.v3.ApplicationDownlink - 34, // 46: ttn.lorawan.v3.ApplicationServiceData.data:type_name -> google.protobuf.Struct - 31, // 47: ttn.lorawan.v3.ApplicationUp.end_device_ids:type_name -> ttn.lorawan.v3.EndDeviceIdentifiers - 28, // 48: ttn.lorawan.v3.ApplicationUp.received_at:type_name -> google.protobuf.Timestamp - 7, // 49: ttn.lorawan.v3.ApplicationUp.uplink_message:type_name -> ttn.lorawan.v3.ApplicationUplink - 8, // 50: ttn.lorawan.v3.ApplicationUp.uplink_normalized:type_name -> ttn.lorawan.v3.ApplicationUplinkNormalized - 10, // 51: ttn.lorawan.v3.ApplicationUp.join_accept:type_name -> ttn.lorawan.v3.ApplicationJoinAccept - 11, // 52: ttn.lorawan.v3.ApplicationUp.downlink_ack:type_name -> ttn.lorawan.v3.ApplicationDownlink - 11, // 53: ttn.lorawan.v3.ApplicationUp.downlink_nack:type_name -> ttn.lorawan.v3.ApplicationDownlink - 11, // 54: ttn.lorawan.v3.ApplicationUp.downlink_sent:type_name -> ttn.lorawan.v3.ApplicationDownlink - 13, // 55: ttn.lorawan.v3.ApplicationUp.downlink_failed:type_name -> ttn.lorawan.v3.ApplicationDownlinkFailed - 11, // 56: ttn.lorawan.v3.ApplicationUp.downlink_queued:type_name -> ttn.lorawan.v3.ApplicationDownlink - 14, // 57: ttn.lorawan.v3.ApplicationUp.downlink_queue_invalidated:type_name -> ttn.lorawan.v3.ApplicationInvalidatedDownlinks - 9, // 58: ttn.lorawan.v3.ApplicationUp.location_solved:type_name -> ttn.lorawan.v3.ApplicationLocation - 16, // 59: ttn.lorawan.v3.ApplicationUp.service_data:type_name -> ttn.lorawan.v3.ApplicationServiceData - 0, // 60: ttn.lorawan.v3.MessagePayloadFormatters.up_formatter:type_name -> ttn.lorawan.v3.PayloadFormatter - 0, // 61: ttn.lorawan.v3.MessagePayloadFormatters.down_formatter:type_name -> ttn.lorawan.v3.PayloadFormatter - 31, // 62: ttn.lorawan.v3.DownlinkQueueRequest.end_device_ids:type_name -> ttn.lorawan.v3.EndDeviceIdentifiers - 11, // 63: ttn.lorawan.v3.DownlinkQueueRequest.downlinks:type_name -> ttn.lorawan.v3.ApplicationDownlink - 38, // 64: ttn.lorawan.v3.ApplicationUplink.LocationsEntry.value:type_name -> ttn.lorawan.v3.Location - 38, // 65: ttn.lorawan.v3.ApplicationUplinkNormalized.LocationsEntry.value:type_name -> ttn.lorawan.v3.Location - 41, // 66: ttn.lorawan.v3.ApplicationDownlink.ClassBC.gateways:type_name -> ttn.lorawan.v3.ClassBCGatewayIdentifiers - 28, // 67: ttn.lorawan.v3.ApplicationDownlink.ClassBC.absolute_time:type_name -> google.protobuf.Timestamp - 42, // 68: ttn.lorawan.v3.ApplicationDownlink.ConfirmedRetry.max_attempts:type_name -> google.protobuf.UInt32Value - 69, // [69:69] is the sub-list for method output_type - 69, // [69:69] is the sub-list for method input_type - 69, // [69:69] is the sub-list for extension type_name - 69, // [69:69] is the sub-list for extension extendee - 0, // [0:69] is the sub-list for field type_name + 47, // 15: ttn.lorawan.v3.LastBatteryPercentage.value:type_name -> google.protobuf.FloatValue + 41, // 16: ttn.lorawan.v3.LastBatteryPercentage.received_at:type_name -> google.protobuf.Timestamp + 48, // 17: ttn.lorawan.v3.ApplicationUplink.decoded_payload:type_name -> google.protobuf.Struct + 48, // 18: ttn.lorawan.v3.ApplicationUplink.normalized_payload:type_name -> google.protobuf.Struct + 40, // 19: ttn.lorawan.v3.ApplicationUplink.rx_metadata:type_name -> ttn.lorawan.v3.RxMetadata + 39, // 20: ttn.lorawan.v3.ApplicationUplink.settings:type_name -> ttn.lorawan.v3.TxSettings + 41, // 21: ttn.lorawan.v3.ApplicationUplink.received_at:type_name -> google.protobuf.Timestamp + 49, // 22: ttn.lorawan.v3.ApplicationUplink.app_s_key:type_name -> ttn.lorawan.v3.KeyEnvelope + 42, // 23: ttn.lorawan.v3.ApplicationUplink.consumed_airtime:type_name -> google.protobuf.Duration + 21, // 24: ttn.lorawan.v3.ApplicationUplink.locations:type_name -> ttn.lorawan.v3.ApplicationUplink.LocationsEntry + 50, // 25: ttn.lorawan.v3.ApplicationUplink.version_ids:type_name -> ttn.lorawan.v3.EndDeviceVersionIdentifiers + 51, // 26: ttn.lorawan.v3.ApplicationUplink.network_ids:type_name -> ttn.lorawan.v3.NetworkIdentifiers + 7, // 27: ttn.lorawan.v3.ApplicationUplink.last_battery_percentage:type_name -> ttn.lorawan.v3.LastBatteryPercentage + 22, // 28: ttn.lorawan.v3.ApplicationUplink.attributes:type_name -> ttn.lorawan.v3.ApplicationUplink.AttributesEntry + 48, // 29: ttn.lorawan.v3.ApplicationUplinkNormalized.normalized_payload:type_name -> google.protobuf.Struct + 40, // 30: ttn.lorawan.v3.ApplicationUplinkNormalized.rx_metadata:type_name -> ttn.lorawan.v3.RxMetadata + 39, // 31: ttn.lorawan.v3.ApplicationUplinkNormalized.settings:type_name -> ttn.lorawan.v3.TxSettings + 41, // 32: ttn.lorawan.v3.ApplicationUplinkNormalized.received_at:type_name -> google.protobuf.Timestamp + 42, // 33: ttn.lorawan.v3.ApplicationUplinkNormalized.consumed_airtime:type_name -> google.protobuf.Duration + 23, // 34: ttn.lorawan.v3.ApplicationUplinkNormalized.locations:type_name -> ttn.lorawan.v3.ApplicationUplinkNormalized.LocationsEntry + 50, // 35: ttn.lorawan.v3.ApplicationUplinkNormalized.version_ids:type_name -> ttn.lorawan.v3.EndDeviceVersionIdentifiers + 51, // 36: ttn.lorawan.v3.ApplicationUplinkNormalized.network_ids:type_name -> ttn.lorawan.v3.NetworkIdentifiers + 24, // 37: ttn.lorawan.v3.ApplicationUplinkNormalized.attributes:type_name -> ttn.lorawan.v3.ApplicationUplinkNormalized.AttributesEntry + 52, // 38: ttn.lorawan.v3.ApplicationLocation.location:type_name -> ttn.lorawan.v3.Location + 25, // 39: ttn.lorawan.v3.ApplicationLocation.attributes:type_name -> ttn.lorawan.v3.ApplicationLocation.AttributesEntry + 49, // 40: ttn.lorawan.v3.ApplicationJoinAccept.app_s_key:type_name -> ttn.lorawan.v3.KeyEnvelope + 12, // 41: ttn.lorawan.v3.ApplicationJoinAccept.invalidated_downlinks:type_name -> ttn.lorawan.v3.ApplicationDownlink + 41, // 42: ttn.lorawan.v3.ApplicationJoinAccept.received_at:type_name -> google.protobuf.Timestamp + 26, // 43: ttn.lorawan.v3.ApplicationJoinAccept.locations:type_name -> ttn.lorawan.v3.ApplicationJoinAccept.LocationsEntry + 50, // 44: ttn.lorawan.v3.ApplicationJoinAccept.version_ids:type_name -> ttn.lorawan.v3.EndDeviceVersionIdentifiers + 51, // 45: ttn.lorawan.v3.ApplicationJoinAccept.network_ids:type_name -> ttn.lorawan.v3.NetworkIdentifiers + 27, // 46: ttn.lorawan.v3.ApplicationJoinAccept.attributes:type_name -> ttn.lorawan.v3.ApplicationJoinAccept.AttributesEntry + 48, // 47: ttn.lorawan.v3.ApplicationDownlink.decoded_payload:type_name -> google.protobuf.Struct + 28, // 48: ttn.lorawan.v3.ApplicationDownlink.class_b_c:type_name -> ttn.lorawan.v3.ApplicationDownlink.ClassBC + 53, // 49: ttn.lorawan.v3.ApplicationDownlink.priority:type_name -> ttn.lorawan.v3.TxSchedulePriority + 29, // 50: ttn.lorawan.v3.ApplicationDownlink.confirmed_retry:type_name -> ttn.lorawan.v3.ApplicationDownlink.ConfirmedRetry + 30, // 51: ttn.lorawan.v3.ApplicationDownlink.locations:type_name -> ttn.lorawan.v3.ApplicationDownlink.LocationsEntry + 50, // 52: ttn.lorawan.v3.ApplicationDownlink.version_ids:type_name -> ttn.lorawan.v3.EndDeviceVersionIdentifiers + 51, // 53: ttn.lorawan.v3.ApplicationDownlink.network_ids:type_name -> ttn.lorawan.v3.NetworkIdentifiers + 31, // 54: ttn.lorawan.v3.ApplicationDownlink.attributes:type_name -> ttn.lorawan.v3.ApplicationDownlink.AttributesEntry + 12, // 55: ttn.lorawan.v3.ApplicationDownlinks.downlinks:type_name -> ttn.lorawan.v3.ApplicationDownlink + 12, // 56: ttn.lorawan.v3.ApplicationDownlinkFailed.downlink:type_name -> ttn.lorawan.v3.ApplicationDownlink + 54, // 57: ttn.lorawan.v3.ApplicationDownlinkFailed.error:type_name -> ttn.lorawan.v3.ErrorDetails + 32, // 58: ttn.lorawan.v3.ApplicationDownlinkFailed.locations:type_name -> ttn.lorawan.v3.ApplicationDownlinkFailed.LocationsEntry + 50, // 59: ttn.lorawan.v3.ApplicationDownlinkFailed.version_ids:type_name -> ttn.lorawan.v3.EndDeviceVersionIdentifiers + 51, // 60: ttn.lorawan.v3.ApplicationDownlinkFailed.network_ids:type_name -> ttn.lorawan.v3.NetworkIdentifiers + 33, // 61: ttn.lorawan.v3.ApplicationDownlinkFailed.attributes:type_name -> ttn.lorawan.v3.ApplicationDownlinkFailed.AttributesEntry + 12, // 62: ttn.lorawan.v3.ApplicationInvalidatedDownlinks.downlinks:type_name -> ttn.lorawan.v3.ApplicationDownlink + 34, // 63: ttn.lorawan.v3.ApplicationInvalidatedDownlinks.locations:type_name -> ttn.lorawan.v3.ApplicationInvalidatedDownlinks.LocationsEntry + 50, // 64: ttn.lorawan.v3.ApplicationInvalidatedDownlinks.version_ids:type_name -> ttn.lorawan.v3.EndDeviceVersionIdentifiers + 51, // 65: ttn.lorawan.v3.ApplicationInvalidatedDownlinks.network_ids:type_name -> ttn.lorawan.v3.NetworkIdentifiers + 35, // 66: ttn.lorawan.v3.ApplicationInvalidatedDownlinks.attributes:type_name -> ttn.lorawan.v3.ApplicationInvalidatedDownlinks.AttributesEntry + 48, // 67: ttn.lorawan.v3.ApplicationServiceData.data:type_name -> google.protobuf.Struct + 36, // 68: ttn.lorawan.v3.ApplicationServiceData.locations:type_name -> ttn.lorawan.v3.ApplicationServiceData.LocationsEntry + 50, // 69: ttn.lorawan.v3.ApplicationServiceData.version_ids:type_name -> ttn.lorawan.v3.EndDeviceVersionIdentifiers + 51, // 70: ttn.lorawan.v3.ApplicationServiceData.network_ids:type_name -> ttn.lorawan.v3.NetworkIdentifiers + 37, // 71: ttn.lorawan.v3.ApplicationServiceData.attributes:type_name -> ttn.lorawan.v3.ApplicationServiceData.AttributesEntry + 44, // 72: ttn.lorawan.v3.ApplicationUp.end_device_ids:type_name -> ttn.lorawan.v3.EndDeviceIdentifiers + 41, // 73: ttn.lorawan.v3.ApplicationUp.received_at:type_name -> google.protobuf.Timestamp + 8, // 74: ttn.lorawan.v3.ApplicationUp.uplink_message:type_name -> ttn.lorawan.v3.ApplicationUplink + 9, // 75: ttn.lorawan.v3.ApplicationUp.uplink_normalized:type_name -> ttn.lorawan.v3.ApplicationUplinkNormalized + 11, // 76: ttn.lorawan.v3.ApplicationUp.join_accept:type_name -> ttn.lorawan.v3.ApplicationJoinAccept + 12, // 77: ttn.lorawan.v3.ApplicationUp.downlink_ack:type_name -> ttn.lorawan.v3.ApplicationDownlink + 12, // 78: ttn.lorawan.v3.ApplicationUp.downlink_nack:type_name -> ttn.lorawan.v3.ApplicationDownlink + 12, // 79: ttn.lorawan.v3.ApplicationUp.downlink_sent:type_name -> ttn.lorawan.v3.ApplicationDownlink + 14, // 80: ttn.lorawan.v3.ApplicationUp.downlink_failed:type_name -> ttn.lorawan.v3.ApplicationDownlinkFailed + 12, // 81: ttn.lorawan.v3.ApplicationUp.downlink_queued:type_name -> ttn.lorawan.v3.ApplicationDownlink + 15, // 82: ttn.lorawan.v3.ApplicationUp.downlink_queue_invalidated:type_name -> ttn.lorawan.v3.ApplicationInvalidatedDownlinks + 10, // 83: ttn.lorawan.v3.ApplicationUp.location_solved:type_name -> ttn.lorawan.v3.ApplicationLocation + 17, // 84: ttn.lorawan.v3.ApplicationUp.service_data:type_name -> ttn.lorawan.v3.ApplicationServiceData + 0, // 85: ttn.lorawan.v3.MessagePayloadFormatters.up_formatter:type_name -> ttn.lorawan.v3.PayloadFormatter + 0, // 86: ttn.lorawan.v3.MessagePayloadFormatters.down_formatter:type_name -> ttn.lorawan.v3.PayloadFormatter + 44, // 87: ttn.lorawan.v3.DownlinkQueueRequest.end_device_ids:type_name -> ttn.lorawan.v3.EndDeviceIdentifiers + 12, // 88: ttn.lorawan.v3.DownlinkQueueRequest.downlinks:type_name -> ttn.lorawan.v3.ApplicationDownlink + 52, // 89: ttn.lorawan.v3.ApplicationUplink.LocationsEntry.value:type_name -> ttn.lorawan.v3.Location + 52, // 90: ttn.lorawan.v3.ApplicationUplinkNormalized.LocationsEntry.value:type_name -> ttn.lorawan.v3.Location + 52, // 91: ttn.lorawan.v3.ApplicationJoinAccept.LocationsEntry.value:type_name -> ttn.lorawan.v3.Location + 55, // 92: ttn.lorawan.v3.ApplicationDownlink.ClassBC.gateways:type_name -> ttn.lorawan.v3.ClassBCGatewayIdentifiers + 41, // 93: ttn.lorawan.v3.ApplicationDownlink.ClassBC.absolute_time:type_name -> google.protobuf.Timestamp + 56, // 94: ttn.lorawan.v3.ApplicationDownlink.ConfirmedRetry.max_attempts:type_name -> google.protobuf.UInt32Value + 52, // 95: ttn.lorawan.v3.ApplicationDownlink.LocationsEntry.value:type_name -> ttn.lorawan.v3.Location + 52, // 96: ttn.lorawan.v3.ApplicationDownlinkFailed.LocationsEntry.value:type_name -> ttn.lorawan.v3.Location + 52, // 97: ttn.lorawan.v3.ApplicationInvalidatedDownlinks.LocationsEntry.value:type_name -> ttn.lorawan.v3.Location + 52, // 98: ttn.lorawan.v3.ApplicationServiceData.LocationsEntry.value:type_name -> ttn.lorawan.v3.Location + 99, // [99:99] is the sub-list for method output_type + 99, // [99:99] is the sub-list for method input_type + 99, // [99:99] is the sub-list for extension type_name + 99, // [99:99] is the sub-list for extension extendee + 0, // [0:99] is the sub-list for field type_name } func init() { file_ttn_lorawan_v3_messages_proto_init() } @@ -2861,7 +3390,7 @@ func file_ttn_lorawan_v3_messages_proto_init() { } } file_ttn_lorawan_v3_messages_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ApplicationUplink); i { + switch v := v.(*LastBatteryPercentage); i { case 0: return &v.state case 1: @@ -2873,7 +3402,7 @@ func file_ttn_lorawan_v3_messages_proto_init() { } } file_ttn_lorawan_v3_messages_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ApplicationUplinkNormalized); i { + switch v := v.(*ApplicationUplink); i { case 0: return &v.state case 1: @@ -2885,7 +3414,7 @@ func file_ttn_lorawan_v3_messages_proto_init() { } } file_ttn_lorawan_v3_messages_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ApplicationLocation); i { + switch v := v.(*ApplicationUplinkNormalized); i { case 0: return &v.state case 1: @@ -2897,7 +3426,7 @@ func file_ttn_lorawan_v3_messages_proto_init() { } } file_ttn_lorawan_v3_messages_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ApplicationJoinAccept); i { + switch v := v.(*ApplicationLocation); i { case 0: return &v.state case 1: @@ -2909,7 +3438,7 @@ func file_ttn_lorawan_v3_messages_proto_init() { } } file_ttn_lorawan_v3_messages_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ApplicationDownlink); i { + switch v := v.(*ApplicationJoinAccept); i { case 0: return &v.state case 1: @@ -2921,7 +3450,7 @@ func file_ttn_lorawan_v3_messages_proto_init() { } } file_ttn_lorawan_v3_messages_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ApplicationDownlinks); i { + switch v := v.(*ApplicationDownlink); i { case 0: return &v.state case 1: @@ -2933,7 +3462,7 @@ func file_ttn_lorawan_v3_messages_proto_init() { } } file_ttn_lorawan_v3_messages_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ApplicationDownlinkFailed); i { + switch v := v.(*ApplicationDownlinks); i { case 0: return &v.state case 1: @@ -2945,7 +3474,7 @@ func file_ttn_lorawan_v3_messages_proto_init() { } } file_ttn_lorawan_v3_messages_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ApplicationInvalidatedDownlinks); i { + switch v := v.(*ApplicationDownlinkFailed); i { case 0: return &v.state case 1: @@ -2957,7 +3486,7 @@ func file_ttn_lorawan_v3_messages_proto_init() { } } file_ttn_lorawan_v3_messages_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DownlinkQueueOperationErrorDetails); i { + switch v := v.(*ApplicationInvalidatedDownlinks); i { case 0: return &v.state case 1: @@ -2969,7 +3498,7 @@ func file_ttn_lorawan_v3_messages_proto_init() { } } file_ttn_lorawan_v3_messages_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ApplicationServiceData); i { + switch v := v.(*DownlinkQueueOperationErrorDetails); i { case 0: return &v.state case 1: @@ -2981,7 +3510,7 @@ func file_ttn_lorawan_v3_messages_proto_init() { } } file_ttn_lorawan_v3_messages_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ApplicationUp); i { + switch v := v.(*ApplicationServiceData); i { case 0: return &v.state case 1: @@ -2993,7 +3522,7 @@ func file_ttn_lorawan_v3_messages_proto_init() { } } file_ttn_lorawan_v3_messages_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MessagePayloadFormatters); i { + switch v := v.(*ApplicationUp); i { case 0: return &v.state case 1: @@ -3005,6 +3534,18 @@ func file_ttn_lorawan_v3_messages_proto_init() { } } file_ttn_lorawan_v3_messages_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MessagePayloadFormatters); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ttn_lorawan_v3_messages_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DownlinkQueueRequest); i { case 0: return &v.state @@ -3016,7 +3557,7 @@ func file_ttn_lorawan_v3_messages_proto_init() { return nil } } - file_ttn_lorawan_v3_messages_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + file_ttn_lorawan_v3_messages_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ApplicationDownlink_ClassBC); i { case 0: return &v.state @@ -3028,7 +3569,7 @@ func file_ttn_lorawan_v3_messages_proto_init() { return nil } } - file_ttn_lorawan_v3_messages_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + file_ttn_lorawan_v3_messages_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ApplicationDownlink_ConfirmedRetry); i { case 0: return &v.state @@ -3045,7 +3586,7 @@ func file_ttn_lorawan_v3_messages_proto_init() { (*DownlinkMessage_Request)(nil), (*DownlinkMessage_Scheduled)(nil), } - file_ttn_lorawan_v3_messages_proto_msgTypes[15].OneofWrappers = []interface{}{ + file_ttn_lorawan_v3_messages_proto_msgTypes[16].OneofWrappers = []interface{}{ (*ApplicationUp_UplinkMessage)(nil), (*ApplicationUp_UplinkNormalized)(nil), (*ApplicationUp_JoinAccept)(nil), @@ -3064,7 +3605,7 @@ func file_ttn_lorawan_v3_messages_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_ttn_lorawan_v3_messages_proto_rawDesc, NumEnums: 2, - NumMessages: 23, + NumMessages: 36, NumExtensions: 0, NumServices: 0, }, diff --git a/pkg/ttnpb/messages.pb.paths.fm.go b/pkg/ttnpb/messages.pb.paths.fm.go index a214a23716..81094e2700 100644 --- a/pkg/ttnpb/messages.pb.paths.fm.go +++ b/pkg/ttnpb/messages.pb.paths.fm.go @@ -545,11 +545,23 @@ var GatewayUplinkMessageFieldPathsTopLevel = []string{ "band_id", "message", } +var LastBatteryPercentageFieldPathsNested = []string{ + "f_cnt", + "received_at", + "value", +} + +var LastBatteryPercentageFieldPathsTopLevel = []string{ + "f_cnt", + "received_at", + "value", +} var ApplicationUplinkFieldPathsNested = []string{ "app_s_key", "app_s_key.encrypted_key", "app_s_key.kek_label", "app_s_key.key", + "attributes", "confirmed", "consumed_airtime", "decoded_payload", @@ -558,6 +570,10 @@ var ApplicationUplinkFieldPathsNested = []string{ "f_port", "frm_payload", "last_a_f_cnt_down", + "last_battery_percentage", + "last_battery_percentage.f_cnt", + "last_battery_percentage.received_at", + "last_battery_percentage.value", "locations", "network_ids", "network_ids.cluster_address", @@ -604,6 +620,7 @@ var ApplicationUplinkFieldPathsNested = []string{ var ApplicationUplinkFieldPathsTopLevel = []string{ "app_s_key", + "attributes", "confirmed", "consumed_airtime", "decoded_payload", @@ -612,6 +629,7 @@ var ApplicationUplinkFieldPathsTopLevel = []string{ "f_port", "frm_payload", "last_a_f_cnt_down", + "last_battery_percentage", "locations", "network_ids", "normalized_payload", @@ -624,6 +642,7 @@ var ApplicationUplinkFieldPathsTopLevel = []string{ "version_ids", } var ApplicationUplinkNormalizedFieldPathsNested = []string{ + "attributes", "confirmed", "consumed_airtime", "f_cnt", @@ -673,6 +692,7 @@ var ApplicationUplinkNormalizedFieldPathsNested = []string{ } var ApplicationUplinkNormalizedFieldPathsTopLevel = []string{ + "attributes", "confirmed", "consumed_airtime", "f_cnt", @@ -709,20 +729,40 @@ var ApplicationJoinAcceptFieldPathsNested = []string{ "app_s_key.encrypted_key", "app_s_key.kek_label", "app_s_key.key", + "attributes", "invalidated_downlinks", + "locations", + "network_ids", + "network_ids.cluster_address", + "network_ids.cluster_id", + "network_ids.net_id", + "network_ids.ns_id", + "network_ids.tenant_address", + "network_ids.tenant_id", "pending_session", "received_at", "session_key_id", + "version_ids", + "version_ids.band_id", + "version_ids.brand_id", + "version_ids.firmware_version", + "version_ids.hardware_version", + "version_ids.model_id", } var ApplicationJoinAcceptFieldPathsTopLevel = []string{ "app_s_key", + "attributes", "invalidated_downlinks", + "locations", + "network_ids", "pending_session", "received_at", "session_key_id", + "version_ids", } var ApplicationDownlinkFieldPathsNested = []string{ + "attributes", "class_b_c", "class_b_c.absolute_time", "class_b_c.gateways", @@ -736,11 +776,26 @@ var ApplicationDownlinkFieldPathsNested = []string{ "f_cnt", "f_port", "frm_payload", + "locations", + "network_ids", + "network_ids.cluster_address", + "network_ids.cluster_id", + "network_ids.net_id", + "network_ids.ns_id", + "network_ids.tenant_address", + "network_ids.tenant_id", "priority", "session_key_id", + "version_ids", + "version_ids.band_id", + "version_ids.brand_id", + "version_ids.firmware_version", + "version_ids.hardware_version", + "version_ids.model_id", } var ApplicationDownlinkFieldPathsTopLevel = []string{ + "attributes", "class_b_c", "confirmed", "confirmed_retry", @@ -750,8 +805,11 @@ var ApplicationDownlinkFieldPathsTopLevel = []string{ "f_cnt", "f_port", "frm_payload", + "locations", + "network_ids", "priority", "session_key_id", + "version_ids", } var ApplicationDownlinksFieldPathsNested = []string{ "downlinks", @@ -761,7 +819,9 @@ var ApplicationDownlinksFieldPathsTopLevel = []string{ "downlinks", } var ApplicationDownlinkFailedFieldPathsNested = []string{ + "attributes", "downlink", + "downlink.attributes", "downlink.class_b_c", "downlink.class_b_c.absolute_time", "downlink.class_b_c.gateways", @@ -775,8 +835,22 @@ var ApplicationDownlinkFailedFieldPathsNested = []string{ "downlink.f_cnt", "downlink.f_port", "downlink.frm_payload", + "downlink.locations", + "downlink.network_ids", + "downlink.network_ids.cluster_address", + "downlink.network_ids.cluster_id", + "downlink.network_ids.net_id", + "downlink.network_ids.ns_id", + "downlink.network_ids.tenant_address", + "downlink.network_ids.tenant_id", "downlink.priority", "downlink.session_key_id", + "downlink.version_ids", + "downlink.version_ids.band_id", + "downlink.version_ids.brand_id", + "downlink.version_ids.firmware_version", + "downlink.version_ids.hardware_version", + "downlink.version_ids.model_id", "error", "error.attributes", "error.cause", @@ -791,22 +865,59 @@ var ApplicationDownlinkFailedFieldPathsNested = []string{ "error.message_format", "error.name", "error.namespace", + "locations", + "network_ids", + "network_ids.cluster_address", + "network_ids.cluster_id", + "network_ids.net_id", + "network_ids.ns_id", + "network_ids.tenant_address", + "network_ids.tenant_id", + "version_ids", + "version_ids.band_id", + "version_ids.brand_id", + "version_ids.firmware_version", + "version_ids.hardware_version", + "version_ids.model_id", } var ApplicationDownlinkFailedFieldPathsTopLevel = []string{ + "attributes", "downlink", "error", + "locations", + "network_ids", + "version_ids", } var ApplicationInvalidatedDownlinksFieldPathsNested = []string{ + "attributes", "downlinks", "last_f_cnt_down", + "locations", + "network_ids", + "network_ids.cluster_address", + "network_ids.cluster_id", + "network_ids.net_id", + "network_ids.ns_id", + "network_ids.tenant_address", + "network_ids.tenant_id", "session_key_id", + "version_ids", + "version_ids.band_id", + "version_ids.brand_id", + "version_ids.firmware_version", + "version_ids.hardware_version", + "version_ids.model_id", } var ApplicationInvalidatedDownlinksFieldPathsTopLevel = []string{ + "attributes", "downlinks", "last_f_cnt_down", + "locations", + "network_ids", "session_key_id", + "version_ids", } var DownlinkQueueOperationErrorDetailsFieldPathsNested = []string{ "dev_addr", @@ -826,13 +937,32 @@ var DownlinkQueueOperationErrorDetailsFieldPathsTopLevel = []string{ "session_key_id", } var ApplicationServiceDataFieldPathsNested = []string{ + "attributes", "data", + "locations", + "network_ids", + "network_ids.cluster_address", + "network_ids.cluster_id", + "network_ids.net_id", + "network_ids.ns_id", + "network_ids.tenant_address", + "network_ids.tenant_id", "service", + "version_ids", + "version_ids.band_id", + "version_ids.brand_id", + "version_ids.firmware_version", + "version_ids.hardware_version", + "version_ids.model_id", } var ApplicationServiceDataFieldPathsTopLevel = []string{ + "attributes", "data", + "locations", + "network_ids", "service", + "version_ids", } var ApplicationUpFieldPathsNested = []string{ "correlation_ids", @@ -847,6 +977,7 @@ var ApplicationUpFieldPathsNested = []string{ "simulated", "up", "up.downlink_ack", + "up.downlink_ack.attributes", "up.downlink_ack.class_b_c", "up.downlink_ack.class_b_c.absolute_time", "up.downlink_ack.class_b_c.gateways", @@ -860,10 +991,26 @@ var ApplicationUpFieldPathsNested = []string{ "up.downlink_ack.f_cnt", "up.downlink_ack.f_port", "up.downlink_ack.frm_payload", + "up.downlink_ack.locations", + "up.downlink_ack.network_ids", + "up.downlink_ack.network_ids.cluster_address", + "up.downlink_ack.network_ids.cluster_id", + "up.downlink_ack.network_ids.net_id", + "up.downlink_ack.network_ids.ns_id", + "up.downlink_ack.network_ids.tenant_address", + "up.downlink_ack.network_ids.tenant_id", "up.downlink_ack.priority", "up.downlink_ack.session_key_id", + "up.downlink_ack.version_ids", + "up.downlink_ack.version_ids.band_id", + "up.downlink_ack.version_ids.brand_id", + "up.downlink_ack.version_ids.firmware_version", + "up.downlink_ack.version_ids.hardware_version", + "up.downlink_ack.version_ids.model_id", "up.downlink_failed", + "up.downlink_failed.attributes", "up.downlink_failed.downlink", + "up.downlink_failed.downlink.attributes", "up.downlink_failed.downlink.class_b_c", "up.downlink_failed.downlink.class_b_c.absolute_time", "up.downlink_failed.downlink.class_b_c.gateways", @@ -877,8 +1024,22 @@ var ApplicationUpFieldPathsNested = []string{ "up.downlink_failed.downlink.f_cnt", "up.downlink_failed.downlink.f_port", "up.downlink_failed.downlink.frm_payload", + "up.downlink_failed.downlink.locations", + "up.downlink_failed.downlink.network_ids", + "up.downlink_failed.downlink.network_ids.cluster_address", + "up.downlink_failed.downlink.network_ids.cluster_id", + "up.downlink_failed.downlink.network_ids.net_id", + "up.downlink_failed.downlink.network_ids.ns_id", + "up.downlink_failed.downlink.network_ids.tenant_address", + "up.downlink_failed.downlink.network_ids.tenant_id", "up.downlink_failed.downlink.priority", "up.downlink_failed.downlink.session_key_id", + "up.downlink_failed.downlink.version_ids", + "up.downlink_failed.downlink.version_ids.band_id", + "up.downlink_failed.downlink.version_ids.brand_id", + "up.downlink_failed.downlink.version_ids.firmware_version", + "up.downlink_failed.downlink.version_ids.hardware_version", + "up.downlink_failed.downlink.version_ids.model_id", "up.downlink_failed.error", "up.downlink_failed.error.attributes", "up.downlink_failed.error.cause", @@ -893,7 +1054,22 @@ var ApplicationUpFieldPathsNested = []string{ "up.downlink_failed.error.message_format", "up.downlink_failed.error.name", "up.downlink_failed.error.namespace", + "up.downlink_failed.locations", + "up.downlink_failed.network_ids", + "up.downlink_failed.network_ids.cluster_address", + "up.downlink_failed.network_ids.cluster_id", + "up.downlink_failed.network_ids.net_id", + "up.downlink_failed.network_ids.ns_id", + "up.downlink_failed.network_ids.tenant_address", + "up.downlink_failed.network_ids.tenant_id", + "up.downlink_failed.version_ids", + "up.downlink_failed.version_ids.band_id", + "up.downlink_failed.version_ids.brand_id", + "up.downlink_failed.version_ids.firmware_version", + "up.downlink_failed.version_ids.hardware_version", + "up.downlink_failed.version_ids.model_id", "up.downlink_nack", + "up.downlink_nack.attributes", "up.downlink_nack.class_b_c", "up.downlink_nack.class_b_c.absolute_time", "up.downlink_nack.class_b_c.gateways", @@ -907,13 +1083,43 @@ var ApplicationUpFieldPathsNested = []string{ "up.downlink_nack.f_cnt", "up.downlink_nack.f_port", "up.downlink_nack.frm_payload", + "up.downlink_nack.locations", + "up.downlink_nack.network_ids", + "up.downlink_nack.network_ids.cluster_address", + "up.downlink_nack.network_ids.cluster_id", + "up.downlink_nack.network_ids.net_id", + "up.downlink_nack.network_ids.ns_id", + "up.downlink_nack.network_ids.tenant_address", + "up.downlink_nack.network_ids.tenant_id", "up.downlink_nack.priority", "up.downlink_nack.session_key_id", + "up.downlink_nack.version_ids", + "up.downlink_nack.version_ids.band_id", + "up.downlink_nack.version_ids.brand_id", + "up.downlink_nack.version_ids.firmware_version", + "up.downlink_nack.version_ids.hardware_version", + "up.downlink_nack.version_ids.model_id", "up.downlink_queue_invalidated", + "up.downlink_queue_invalidated.attributes", "up.downlink_queue_invalidated.downlinks", "up.downlink_queue_invalidated.last_f_cnt_down", + "up.downlink_queue_invalidated.locations", + "up.downlink_queue_invalidated.network_ids", + "up.downlink_queue_invalidated.network_ids.cluster_address", + "up.downlink_queue_invalidated.network_ids.cluster_id", + "up.downlink_queue_invalidated.network_ids.net_id", + "up.downlink_queue_invalidated.network_ids.ns_id", + "up.downlink_queue_invalidated.network_ids.tenant_address", + "up.downlink_queue_invalidated.network_ids.tenant_id", "up.downlink_queue_invalidated.session_key_id", + "up.downlink_queue_invalidated.version_ids", + "up.downlink_queue_invalidated.version_ids.band_id", + "up.downlink_queue_invalidated.version_ids.brand_id", + "up.downlink_queue_invalidated.version_ids.firmware_version", + "up.downlink_queue_invalidated.version_ids.hardware_version", + "up.downlink_queue_invalidated.version_ids.model_id", "up.downlink_queued", + "up.downlink_queued.attributes", "up.downlink_queued.class_b_c", "up.downlink_queued.class_b_c.absolute_time", "up.downlink_queued.class_b_c.gateways", @@ -927,9 +1133,24 @@ var ApplicationUpFieldPathsNested = []string{ "up.downlink_queued.f_cnt", "up.downlink_queued.f_port", "up.downlink_queued.frm_payload", + "up.downlink_queued.locations", + "up.downlink_queued.network_ids", + "up.downlink_queued.network_ids.cluster_address", + "up.downlink_queued.network_ids.cluster_id", + "up.downlink_queued.network_ids.net_id", + "up.downlink_queued.network_ids.ns_id", + "up.downlink_queued.network_ids.tenant_address", + "up.downlink_queued.network_ids.tenant_id", "up.downlink_queued.priority", "up.downlink_queued.session_key_id", + "up.downlink_queued.version_ids", + "up.downlink_queued.version_ids.band_id", + "up.downlink_queued.version_ids.brand_id", + "up.downlink_queued.version_ids.firmware_version", + "up.downlink_queued.version_ids.hardware_version", + "up.downlink_queued.version_ids.model_id", "up.downlink_sent", + "up.downlink_sent.attributes", "up.downlink_sent.class_b_c", "up.downlink_sent.class_b_c.absolute_time", "up.downlink_sent.class_b_c.gateways", @@ -943,17 +1164,46 @@ var ApplicationUpFieldPathsNested = []string{ "up.downlink_sent.f_cnt", "up.downlink_sent.f_port", "up.downlink_sent.frm_payload", + "up.downlink_sent.locations", + "up.downlink_sent.network_ids", + "up.downlink_sent.network_ids.cluster_address", + "up.downlink_sent.network_ids.cluster_id", + "up.downlink_sent.network_ids.net_id", + "up.downlink_sent.network_ids.ns_id", + "up.downlink_sent.network_ids.tenant_address", + "up.downlink_sent.network_ids.tenant_id", "up.downlink_sent.priority", "up.downlink_sent.session_key_id", + "up.downlink_sent.version_ids", + "up.downlink_sent.version_ids.band_id", + "up.downlink_sent.version_ids.brand_id", + "up.downlink_sent.version_ids.firmware_version", + "up.downlink_sent.version_ids.hardware_version", + "up.downlink_sent.version_ids.model_id", "up.join_accept", "up.join_accept.app_s_key", "up.join_accept.app_s_key.encrypted_key", "up.join_accept.app_s_key.kek_label", "up.join_accept.app_s_key.key", + "up.join_accept.attributes", "up.join_accept.invalidated_downlinks", + "up.join_accept.locations", + "up.join_accept.network_ids", + "up.join_accept.network_ids.cluster_address", + "up.join_accept.network_ids.cluster_id", + "up.join_accept.network_ids.net_id", + "up.join_accept.network_ids.ns_id", + "up.join_accept.network_ids.tenant_address", + "up.join_accept.network_ids.tenant_id", "up.join_accept.pending_session", "up.join_accept.received_at", "up.join_accept.session_key_id", + "up.join_accept.version_ids", + "up.join_accept.version_ids.band_id", + "up.join_accept.version_ids.brand_id", + "up.join_accept.version_ids.firmware_version", + "up.join_accept.version_ids.hardware_version", + "up.join_accept.version_ids.model_id", "up.location_solved", "up.location_solved.attributes", "up.location_solved.location", @@ -964,13 +1214,29 @@ var ApplicationUpFieldPathsNested = []string{ "up.location_solved.location.source", "up.location_solved.service", "up.service_data", + "up.service_data.attributes", "up.service_data.data", + "up.service_data.locations", + "up.service_data.network_ids", + "up.service_data.network_ids.cluster_address", + "up.service_data.network_ids.cluster_id", + "up.service_data.network_ids.net_id", + "up.service_data.network_ids.ns_id", + "up.service_data.network_ids.tenant_address", + "up.service_data.network_ids.tenant_id", "up.service_data.service", + "up.service_data.version_ids", + "up.service_data.version_ids.band_id", + "up.service_data.version_ids.brand_id", + "up.service_data.version_ids.firmware_version", + "up.service_data.version_ids.hardware_version", + "up.service_data.version_ids.model_id", "up.uplink_message", "up.uplink_message.app_s_key", "up.uplink_message.app_s_key.encrypted_key", "up.uplink_message.app_s_key.kek_label", "up.uplink_message.app_s_key.key", + "up.uplink_message.attributes", "up.uplink_message.confirmed", "up.uplink_message.consumed_airtime", "up.uplink_message.decoded_payload", @@ -979,6 +1245,10 @@ var ApplicationUpFieldPathsNested = []string{ "up.uplink_message.f_port", "up.uplink_message.frm_payload", "up.uplink_message.last_a_f_cnt_down", + "up.uplink_message.last_battery_percentage", + "up.uplink_message.last_battery_percentage.f_cnt", + "up.uplink_message.last_battery_percentage.received_at", + "up.uplink_message.last_battery_percentage.value", "up.uplink_message.locations", "up.uplink_message.network_ids", "up.uplink_message.network_ids.cluster_address", @@ -1022,6 +1292,7 @@ var ApplicationUpFieldPathsNested = []string{ "up.uplink_message.version_ids.hardware_version", "up.uplink_message.version_ids.model_id", "up.uplink_normalized", + "up.uplink_normalized.attributes", "up.uplink_normalized.confirmed", "up.uplink_normalized.consumed_airtime", "up.uplink_normalized.f_cnt", diff --git a/pkg/ttnpb/messages.pb.setters.fm.go b/pkg/ttnpb/messages.pb.setters.fm.go index 7e790005fd..ad7dc055f6 100644 --- a/pkg/ttnpb/messages.pb.setters.fm.go +++ b/pkg/ttnpb/messages.pb.setters.fm.go @@ -471,6 +471,45 @@ func (dst *GatewayUplinkMessage) SetFields(src *GatewayUplinkMessage, paths ...s return nil } +func (dst *LastBatteryPercentage) SetFields(src *LastBatteryPercentage, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "f_cnt": + if len(subs) > 0 { + return fmt.Errorf("'f_cnt' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.FCnt = src.FCnt + } else { + var zero uint32 + dst.FCnt = zero + } + case "value": + if len(subs) > 0 { + return fmt.Errorf("'value' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Value = src.Value + } else { + dst.Value = nil + } + case "received_at": + if len(subs) > 0 { + return fmt.Errorf("'received_at' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.ReceivedAt = src.ReceivedAt + } else { + dst.ReceivedAt = nil + } + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + func (dst *ApplicationUplink) SetFields(src *ApplicationUplink, paths ...string) error { for name, subs := range _processPaths(paths) { switch name { @@ -714,6 +753,40 @@ func (dst *ApplicationUplink) SetFields(src *ApplicationUplink, paths ...string) dst.NetworkIds = nil } } + case "last_battery_percentage": + if len(subs) > 0 { + var newDst, newSrc *LastBatteryPercentage + if (src == nil || src.LastBatteryPercentage == nil) && dst.LastBatteryPercentage == nil { + continue + } + if src != nil { + newSrc = src.LastBatteryPercentage + } + if dst.LastBatteryPercentage != nil { + newDst = dst.LastBatteryPercentage + } else { + newDst = &LastBatteryPercentage{} + dst.LastBatteryPercentage = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.LastBatteryPercentage = src.LastBatteryPercentage + } else { + dst.LastBatteryPercentage = nil + } + } + case "attributes": + if len(subs) > 0 { + return fmt.Errorf("'attributes' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Attributes = src.Attributes + } else { + dst.Attributes = nil + } default: return fmt.Errorf("invalid field: '%s'", name) @@ -902,6 +975,15 @@ func (dst *ApplicationUplinkNormalized) SetFields(src *ApplicationUplinkNormaliz dst.NetworkIds = nil } } + case "attributes": + if len(subs) > 0 { + return fmt.Errorf("'attributes' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Attributes = src.Attributes + } else { + dst.Attributes = nil + } default: return fmt.Errorf("invalid field: '%s'", name) @@ -1030,6 +1112,74 @@ func (dst *ApplicationJoinAccept) SetFields(src *ApplicationJoinAccept, paths .. } else { dst.ReceivedAt = nil } + case "locations": + if len(subs) > 0 { + return fmt.Errorf("'locations' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Locations = src.Locations + } else { + dst.Locations = nil + } + case "version_ids": + if len(subs) > 0 { + var newDst, newSrc *EndDeviceVersionIdentifiers + if (src == nil || src.VersionIds == nil) && dst.VersionIds == nil { + continue + } + if src != nil { + newSrc = src.VersionIds + } + if dst.VersionIds != nil { + newDst = dst.VersionIds + } else { + newDst = &EndDeviceVersionIdentifiers{} + dst.VersionIds = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.VersionIds = src.VersionIds + } else { + dst.VersionIds = nil + } + } + case "network_ids": + if len(subs) > 0 { + var newDst, newSrc *NetworkIdentifiers + if (src == nil || src.NetworkIds == nil) && dst.NetworkIds == nil { + continue + } + if src != nil { + newSrc = src.NetworkIds + } + if dst.NetworkIds != nil { + newDst = dst.NetworkIds + } else { + newDst = &NetworkIdentifiers{} + dst.NetworkIds = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.NetworkIds = src.NetworkIds + } else { + dst.NetworkIds = nil + } + } + case "attributes": + if len(subs) > 0 { + return fmt.Errorf("'attributes' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Attributes = src.Attributes + } else { + dst.Attributes = nil + } default: return fmt.Errorf("invalid field: '%s'", name) @@ -1175,6 +1325,74 @@ func (dst *ApplicationDownlink) SetFields(src *ApplicationDownlink, paths ...str dst.ConfirmedRetry = nil } } + case "locations": + if len(subs) > 0 { + return fmt.Errorf("'locations' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Locations = src.Locations + } else { + dst.Locations = nil + } + case "version_ids": + if len(subs) > 0 { + var newDst, newSrc *EndDeviceVersionIdentifiers + if (src == nil || src.VersionIds == nil) && dst.VersionIds == nil { + continue + } + if src != nil { + newSrc = src.VersionIds + } + if dst.VersionIds != nil { + newDst = dst.VersionIds + } else { + newDst = &EndDeviceVersionIdentifiers{} + dst.VersionIds = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.VersionIds = src.VersionIds + } else { + dst.VersionIds = nil + } + } + case "network_ids": + if len(subs) > 0 { + var newDst, newSrc *NetworkIdentifiers + if (src == nil || src.NetworkIds == nil) && dst.NetworkIds == nil { + continue + } + if src != nil { + newSrc = src.NetworkIds + } + if dst.NetworkIds != nil { + newDst = dst.NetworkIds + } else { + newDst = &NetworkIdentifiers{} + dst.NetworkIds = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.NetworkIds = src.NetworkIds + } else { + dst.NetworkIds = nil + } + } + case "attributes": + if len(subs) > 0 { + return fmt.Errorf("'attributes' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Attributes = src.Attributes + } else { + dst.Attributes = nil + } default: return fmt.Errorf("invalid field: '%s'", name) @@ -1256,6 +1474,74 @@ func (dst *ApplicationDownlinkFailed) SetFields(src *ApplicationDownlinkFailed, dst.Error = nil } } + case "locations": + if len(subs) > 0 { + return fmt.Errorf("'locations' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Locations = src.Locations + } else { + dst.Locations = nil + } + case "version_ids": + if len(subs) > 0 { + var newDst, newSrc *EndDeviceVersionIdentifiers + if (src == nil || src.VersionIds == nil) && dst.VersionIds == nil { + continue + } + if src != nil { + newSrc = src.VersionIds + } + if dst.VersionIds != nil { + newDst = dst.VersionIds + } else { + newDst = &EndDeviceVersionIdentifiers{} + dst.VersionIds = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.VersionIds = src.VersionIds + } else { + dst.VersionIds = nil + } + } + case "network_ids": + if len(subs) > 0 { + var newDst, newSrc *NetworkIdentifiers + if (src == nil || src.NetworkIds == nil) && dst.NetworkIds == nil { + continue + } + if src != nil { + newSrc = src.NetworkIds + } + if dst.NetworkIds != nil { + newDst = dst.NetworkIds + } else { + newDst = &NetworkIdentifiers{} + dst.NetworkIds = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.NetworkIds = src.NetworkIds + } else { + dst.NetworkIds = nil + } + } + case "attributes": + if len(subs) > 0 { + return fmt.Errorf("'attributes' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Attributes = src.Attributes + } else { + dst.Attributes = nil + } default: return fmt.Errorf("invalid field: '%s'", name) @@ -1295,6 +1581,74 @@ func (dst *ApplicationInvalidatedDownlinks) SetFields(src *ApplicationInvalidate } else { dst.SessionKeyId = nil } + case "locations": + if len(subs) > 0 { + return fmt.Errorf("'locations' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Locations = src.Locations + } else { + dst.Locations = nil + } + case "version_ids": + if len(subs) > 0 { + var newDst, newSrc *EndDeviceVersionIdentifiers + if (src == nil || src.VersionIds == nil) && dst.VersionIds == nil { + continue + } + if src != nil { + newSrc = src.VersionIds + } + if dst.VersionIds != nil { + newDst = dst.VersionIds + } else { + newDst = &EndDeviceVersionIdentifiers{} + dst.VersionIds = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.VersionIds = src.VersionIds + } else { + dst.VersionIds = nil + } + } + case "network_ids": + if len(subs) > 0 { + var newDst, newSrc *NetworkIdentifiers + if (src == nil || src.NetworkIds == nil) && dst.NetworkIds == nil { + continue + } + if src != nil { + newSrc = src.NetworkIds + } + if dst.NetworkIds != nil { + newDst = dst.NetworkIds + } else { + newDst = &NetworkIdentifiers{} + dst.NetworkIds = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.NetworkIds = src.NetworkIds + } else { + dst.NetworkIds = nil + } + } + case "attributes": + if len(subs) > 0 { + return fmt.Errorf("'attributes' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Attributes = src.Attributes + } else { + dst.Attributes = nil + } default: return fmt.Errorf("invalid field: '%s'", name) @@ -1392,6 +1746,74 @@ func (dst *ApplicationServiceData) SetFields(src *ApplicationServiceData, paths } else { dst.Data = nil } + case "locations": + if len(subs) > 0 { + return fmt.Errorf("'locations' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Locations = src.Locations + } else { + dst.Locations = nil + } + case "version_ids": + if len(subs) > 0 { + var newDst, newSrc *EndDeviceVersionIdentifiers + if (src == nil || src.VersionIds == nil) && dst.VersionIds == nil { + continue + } + if src != nil { + newSrc = src.VersionIds + } + if dst.VersionIds != nil { + newDst = dst.VersionIds + } else { + newDst = &EndDeviceVersionIdentifiers{} + dst.VersionIds = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.VersionIds = src.VersionIds + } else { + dst.VersionIds = nil + } + } + case "network_ids": + if len(subs) > 0 { + var newDst, newSrc *NetworkIdentifiers + if (src == nil || src.NetworkIds == nil) && dst.NetworkIds == nil { + continue + } + if src != nil { + newSrc = src.NetworkIds + } + if dst.NetworkIds != nil { + newDst = dst.NetworkIds + } else { + newDst = &NetworkIdentifiers{} + dst.NetworkIds = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.NetworkIds = src.NetworkIds + } else { + dst.NetworkIds = nil + } + } + case "attributes": + if len(subs) > 0 { + return fmt.Errorf("'attributes' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Attributes = src.Attributes + } else { + dst.Attributes = nil + } default: return fmt.Errorf("invalid field: '%s'", name) diff --git a/pkg/ttnpb/messages.pb.validate.go b/pkg/ttnpb/messages.pb.validate.go index fafe2734b0..6d13b82dd1 100644 --- a/pkg/ttnpb/messages.pb.validate.go +++ b/pkg/ttnpb/messages.pb.validate.go @@ -718,6 +718,114 @@ var _ interface { ErrorName() string } = GatewayUplinkMessageValidationError{} +// ValidateFields checks the field values on LastBatteryPercentage with the +// rules defined in the proto definition for this message. If any rules are +// violated, an error is returned. +func (m *LastBatteryPercentage) ValidateFields(paths ...string) error { + if m == nil { + return nil + } + + if len(paths) == 0 { + paths = LastBatteryPercentageFieldPathsNested + } + + for name, subs := range _processPaths(append(paths[:0:0], paths...)) { + _ = subs + switch name { + case "f_cnt": + // no validation rules for FCnt + case "value": + + if wrapper := m.GetValue(); wrapper != nil { + + if val := wrapper.GetValue(); val < 0 || val > 100 { + return LastBatteryPercentageValidationError{ + field: "value", + reason: "value must be inside range [0, 100]", + } + } + + } + + case "received_at": + + if v, ok := interface{}(m.GetReceivedAt()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return LastBatteryPercentageValidationError{ + field: "received_at", + reason: "embedded message failed validation", + cause: err, + } + } + } + + default: + return LastBatteryPercentageValidationError{ + field: name, + reason: "invalid field path", + } + } + } + return nil +} + +// LastBatteryPercentageValidationError is the validation error returned by +// LastBatteryPercentage.ValidateFields if the designated constraints aren't met. +type LastBatteryPercentageValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e LastBatteryPercentageValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e LastBatteryPercentageValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e LastBatteryPercentageValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e LastBatteryPercentageValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e LastBatteryPercentageValidationError) ErrorName() string { + return "LastBatteryPercentageValidationError" +} + +// Error satisfies the builtin error interface +func (e LastBatteryPercentageValidationError) 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 %sLastBatteryPercentage.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = LastBatteryPercentageValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = LastBatteryPercentageValidationError{} + // ValidateFields checks the field values on ApplicationUplink with the rules // defined in the proto definition for this message. If any rules are // violated, an error is returned. @@ -916,6 +1024,53 @@ func (m *ApplicationUplink) ValidateFields(paths ...string) error { } } + case "last_battery_percentage": + + if v, ok := interface{}(m.GetLastBatteryPercentage()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return ApplicationUplinkValidationError{ + field: "last_battery_percentage", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "attributes": + + if len(m.GetAttributes()) > 10 { + return ApplicationUplinkValidationError{ + field: "attributes", + reason: "value must contain no more than 10 pair(s)", + } + } + + for key, val := range m.GetAttributes() { + _ = val + + if utf8.RuneCountInString(key) > 36 { + return ApplicationUplinkValidationError{ + field: fmt.Sprintf("attributes[%v]", key), + reason: "value length must be at most 36 runes", + } + } + + if !_ApplicationUplink_Attributes_Pattern.MatchString(key) { + return ApplicationUplinkValidationError{ + field: fmt.Sprintf("attributes[%v]", key), + reason: "value does not match regex pattern \"^[a-z0-9](?:[-]?[a-z0-9]){2,}$\"", + } + } + + if utf8.RuneCountInString(val) > 200 { + return ApplicationUplinkValidationError{ + field: fmt.Sprintf("attributes[%v]", key), + reason: "value length must be at most 200 runes", + } + } + + } + default: return ApplicationUplinkValidationError{ field: name, @@ -986,6 +1141,8 @@ var _ApplicationUplink_FPort_NotInLookup = map[uint32]struct{}{ 224: {}, } +var _ApplicationUplink_Attributes_Pattern = regexp.MustCompile("^[a-z0-9](?:[-]?[a-z0-9]){2,}$") + // ValidateFields checks the field values on ApplicationUplinkNormalized with // the rules defined in the proto definition for this message. If any rules // are violated, an error is returned. @@ -1153,6 +1310,41 @@ func (m *ApplicationUplinkNormalized) ValidateFields(paths ...string) error { } } + case "attributes": + + if len(m.GetAttributes()) > 10 { + return ApplicationUplinkNormalizedValidationError{ + field: "attributes", + reason: "value must contain no more than 10 pair(s)", + } + } + + for key, val := range m.GetAttributes() { + _ = val + + if utf8.RuneCountInString(key) > 36 { + return ApplicationUplinkNormalizedValidationError{ + field: fmt.Sprintf("attributes[%v]", key), + reason: "value length must be at most 36 runes", + } + } + + if !_ApplicationUplinkNormalized_Attributes_Pattern.MatchString(key) { + return ApplicationUplinkNormalizedValidationError{ + field: fmt.Sprintf("attributes[%v]", key), + reason: "value does not match regex pattern \"^[a-z0-9](?:[-]?[a-z0-9]){2,}$\"", + } + } + + if utf8.RuneCountInString(val) > 200 { + return ApplicationUplinkNormalizedValidationError{ + field: fmt.Sprintf("attributes[%v]", key), + reason: "value length must be at most 200 runes", + } + } + + } + default: return ApplicationUplinkNormalizedValidationError{ field: name, @@ -1224,6 +1416,8 @@ var _ApplicationUplinkNormalized_FPort_NotInLookup = map[uint32]struct{}{ 224: {}, } +var _ApplicationUplinkNormalized_Attributes_Pattern = regexp.MustCompile("^[a-z0-9](?:[-]?[a-z0-9]){2,}$") + // ValidateFields checks the field values on ApplicationLocation with the rules // defined in the proto definition for this message. If any rules are // violated, an error is returned. @@ -1427,6 +1621,84 @@ func (m *ApplicationJoinAccept) ValidateFields(paths ...string) error { } } + case "locations": + + for key, val := range m.GetLocations() { + _ = val + + // no validation rules for Locations[key] + + if v, ok := interface{}(val).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return ApplicationJoinAcceptValidationError{ + field: fmt.Sprintf("locations[%v]", key), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + + case "version_ids": + + if v, ok := interface{}(m.GetVersionIds()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return ApplicationJoinAcceptValidationError{ + field: "version_ids", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "network_ids": + + if v, ok := interface{}(m.GetNetworkIds()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return ApplicationJoinAcceptValidationError{ + field: "network_ids", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "attributes": + + if len(m.GetAttributes()) > 10 { + return ApplicationJoinAcceptValidationError{ + field: "attributes", + reason: "value must contain no more than 10 pair(s)", + } + } + + for key, val := range m.GetAttributes() { + _ = val + + if utf8.RuneCountInString(key) > 36 { + return ApplicationJoinAcceptValidationError{ + field: fmt.Sprintf("attributes[%v]", key), + reason: "value length must be at most 36 runes", + } + } + + if !_ApplicationJoinAccept_Attributes_Pattern.MatchString(key) { + return ApplicationJoinAcceptValidationError{ + field: fmt.Sprintf("attributes[%v]", key), + reason: "value does not match regex pattern \"^[a-z0-9](?:[-]?[a-z0-9]){2,}$\"", + } + } + + if utf8.RuneCountInString(val) > 200 { + return ApplicationJoinAcceptValidationError{ + field: fmt.Sprintf("attributes[%v]", key), + reason: "value length must be at most 200 runes", + } + } + + } + default: return ApplicationJoinAcceptValidationError{ field: name, @@ -1493,6 +1765,8 @@ var _ interface { ErrorName() string } = ApplicationJoinAcceptValidationError{} +var _ApplicationJoinAccept_Attributes_Pattern = regexp.MustCompile("^[a-z0-9](?:[-]?[a-z0-9]){2,}$") + // ValidateFields checks the field values on ApplicationDownlink with the rules // defined in the proto definition for this message. If any rules are // violated, an error is returned. @@ -1607,21 +1881,99 @@ func (m *ApplicationDownlink) ValidateFields(paths ...string) error { } } - default: - return ApplicationDownlinkValidationError{ - field: name, - reason: "invalid field path", - } - } - } - return nil -} + case "locations": -// ApplicationDownlinkValidationError is the validation error returned by -// ApplicationDownlink.ValidateFields if the designated constraints aren't met. -type ApplicationDownlinkValidationError struct { - field string - reason string + for key, val := range m.GetLocations() { + _ = val + + // no validation rules for Locations[key] + + if v, ok := interface{}(val).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return ApplicationDownlinkValidationError{ + field: fmt.Sprintf("locations[%v]", key), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + + case "version_ids": + + if v, ok := interface{}(m.GetVersionIds()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return ApplicationDownlinkValidationError{ + field: "version_ids", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "network_ids": + + if v, ok := interface{}(m.GetNetworkIds()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return ApplicationDownlinkValidationError{ + field: "network_ids", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "attributes": + + if len(m.GetAttributes()) > 10 { + return ApplicationDownlinkValidationError{ + field: "attributes", + reason: "value must contain no more than 10 pair(s)", + } + } + + for key, val := range m.GetAttributes() { + _ = val + + if utf8.RuneCountInString(key) > 36 { + return ApplicationDownlinkValidationError{ + field: fmt.Sprintf("attributes[%v]", key), + reason: "value length must be at most 36 runes", + } + } + + if !_ApplicationDownlink_Attributes_Pattern.MatchString(key) { + return ApplicationDownlinkValidationError{ + field: fmt.Sprintf("attributes[%v]", key), + reason: "value does not match regex pattern \"^[a-z0-9](?:[-]?[a-z0-9]){2,}$\"", + } + } + + if utf8.RuneCountInString(val) > 200 { + return ApplicationDownlinkValidationError{ + field: fmt.Sprintf("attributes[%v]", key), + reason: "value length must be at most 200 runes", + } + } + + } + + default: + return ApplicationDownlinkValidationError{ + field: name, + reason: "invalid field path", + } + } + } + return nil +} + +// ApplicationDownlinkValidationError is the validation error returned by +// ApplicationDownlink.ValidateFields if the designated constraints aren't met. +type ApplicationDownlinkValidationError struct { + field string + reason string cause error key bool } @@ -1677,6 +2029,8 @@ var _ApplicationDownlink_FPort_NotInLookup = map[uint32]struct{}{ 224: {}, } +var _ApplicationDownlink_Attributes_Pattern = regexp.MustCompile("^[a-z0-9](?:[-]?[a-z0-9]){2,}$") + // ValidateFields checks the field values on ApplicationDownlinks with the // rules defined in the proto definition for this message. If any rules are // violated, an error is returned. @@ -1828,6 +2182,84 @@ func (m *ApplicationDownlinkFailed) ValidateFields(paths ...string) error { } } + case "locations": + + for key, val := range m.GetLocations() { + _ = val + + // no validation rules for Locations[key] + + if v, ok := interface{}(val).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return ApplicationDownlinkFailedValidationError{ + field: fmt.Sprintf("locations[%v]", key), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + + case "version_ids": + + if v, ok := interface{}(m.GetVersionIds()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return ApplicationDownlinkFailedValidationError{ + field: "version_ids", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "network_ids": + + if v, ok := interface{}(m.GetNetworkIds()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return ApplicationDownlinkFailedValidationError{ + field: "network_ids", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "attributes": + + if len(m.GetAttributes()) > 10 { + return ApplicationDownlinkFailedValidationError{ + field: "attributes", + reason: "value must contain no more than 10 pair(s)", + } + } + + for key, val := range m.GetAttributes() { + _ = val + + if utf8.RuneCountInString(key) > 36 { + return ApplicationDownlinkFailedValidationError{ + field: fmt.Sprintf("attributes[%v]", key), + reason: "value length must be at most 36 runes", + } + } + + if !_ApplicationDownlinkFailed_Attributes_Pattern.MatchString(key) { + return ApplicationDownlinkFailedValidationError{ + field: fmt.Sprintf("attributes[%v]", key), + reason: "value does not match regex pattern \"^[a-z0-9](?:[-]?[a-z0-9]){2,}$\"", + } + } + + if utf8.RuneCountInString(val) > 200 { + return ApplicationDownlinkFailedValidationError{ + field: fmt.Sprintf("attributes[%v]", key), + reason: "value length must be at most 200 runes", + } + } + + } + default: return ApplicationDownlinkFailedValidationError{ field: name, @@ -1895,6 +2327,8 @@ var _ interface { ErrorName() string } = ApplicationDownlinkFailedValidationError{} +var _ApplicationDownlinkFailed_Attributes_Pattern = regexp.MustCompile("^[a-z0-9](?:[-]?[a-z0-9]){2,}$") + // ValidateFields checks the field values on ApplicationInvalidatedDownlinks // with the rules defined in the proto definition for this message. If any // rules are violated, an error is returned. @@ -1938,6 +2372,84 @@ func (m *ApplicationInvalidatedDownlinks) ValidateFields(paths ...string) error } } + case "locations": + + for key, val := range m.GetLocations() { + _ = val + + // no validation rules for Locations[key] + + if v, ok := interface{}(val).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return ApplicationInvalidatedDownlinksValidationError{ + field: fmt.Sprintf("locations[%v]", key), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + + case "version_ids": + + if v, ok := interface{}(m.GetVersionIds()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return ApplicationInvalidatedDownlinksValidationError{ + field: "version_ids", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "network_ids": + + if v, ok := interface{}(m.GetNetworkIds()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return ApplicationInvalidatedDownlinksValidationError{ + field: "network_ids", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "attributes": + + if len(m.GetAttributes()) > 10 { + return ApplicationInvalidatedDownlinksValidationError{ + field: "attributes", + reason: "value must contain no more than 10 pair(s)", + } + } + + for key, val := range m.GetAttributes() { + _ = val + + if utf8.RuneCountInString(key) > 36 { + return ApplicationInvalidatedDownlinksValidationError{ + field: fmt.Sprintf("attributes[%v]", key), + reason: "value length must be at most 36 runes", + } + } + + if !_ApplicationInvalidatedDownlinks_Attributes_Pattern.MatchString(key) { + return ApplicationInvalidatedDownlinksValidationError{ + field: fmt.Sprintf("attributes[%v]", key), + reason: "value does not match regex pattern \"^[a-z0-9](?:[-]?[a-z0-9]){2,}$\"", + } + } + + if utf8.RuneCountInString(val) > 200 { + return ApplicationInvalidatedDownlinksValidationError{ + field: fmt.Sprintf("attributes[%v]", key), + reason: "value length must be at most 200 runes", + } + } + + } + default: return ApplicationInvalidatedDownlinksValidationError{ field: name, @@ -2005,6 +2517,8 @@ var _ interface { ErrorName() string } = ApplicationInvalidatedDownlinksValidationError{} +var _ApplicationInvalidatedDownlinks_Attributes_Pattern = regexp.MustCompile("^[a-z0-9](?:[-]?[a-z0-9]){2,}$") + // ValidateFields checks the field values on DownlinkQueueOperationErrorDetails // with the rules defined in the proto definition for this message. If any // rules are violated, an error is returned. @@ -2164,6 +2678,84 @@ func (m *ApplicationServiceData) ValidateFields(paths ...string) error { } } + case "locations": + + for key, val := range m.GetLocations() { + _ = val + + // no validation rules for Locations[key] + + if v, ok := interface{}(val).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return ApplicationServiceDataValidationError{ + field: fmt.Sprintf("locations[%v]", key), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + + case "version_ids": + + if v, ok := interface{}(m.GetVersionIds()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return ApplicationServiceDataValidationError{ + field: "version_ids", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "network_ids": + + if v, ok := interface{}(m.GetNetworkIds()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return ApplicationServiceDataValidationError{ + field: "network_ids", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "attributes": + + if len(m.GetAttributes()) > 10 { + return ApplicationServiceDataValidationError{ + field: "attributes", + reason: "value must contain no more than 10 pair(s)", + } + } + + for key, val := range m.GetAttributes() { + _ = val + + if utf8.RuneCountInString(key) > 36 { + return ApplicationServiceDataValidationError{ + field: fmt.Sprintf("attributes[%v]", key), + reason: "value length must be at most 36 runes", + } + } + + if !_ApplicationServiceData_Attributes_Pattern.MatchString(key) { + return ApplicationServiceDataValidationError{ + field: fmt.Sprintf("attributes[%v]", key), + reason: "value does not match regex pattern \"^[a-z0-9](?:[-]?[a-z0-9]){2,}$\"", + } + } + + if utf8.RuneCountInString(val) > 200 { + return ApplicationServiceDataValidationError{ + field: fmt.Sprintf("attributes[%v]", key), + reason: "value length must be at most 200 runes", + } + } + + } + default: return ApplicationServiceDataValidationError{ field: name, @@ -2230,6 +2822,8 @@ var _ interface { ErrorName() string } = ApplicationServiceDataValidationError{} +var _ApplicationServiceData_Attributes_Pattern = regexp.MustCompile("^[a-z0-9](?:[-]?[a-z0-9]){2,}$") + // ValidateFields checks the field values on ApplicationUp with the rules // defined in the proto definition for this message. If any rules are // violated, an error is returned. diff --git a/pkg/ttnpb/messages_flags.pb.go b/pkg/ttnpb/messages_flags.pb.go index 45c12c6541..80f01568ec 100644 --- a/pkg/ttnpb/messages_flags.pb.go +++ b/pkg/ttnpb/messages_flags.pb.go @@ -38,6 +38,9 @@ func AddSelectFlagsForApplicationUplink(flags *pflag.FlagSet, prefix string, hid AddSelectFlagsForEndDeviceVersionIdentifiers(flags, flagsplugin.Prefix("version-ids", prefix), hidden) flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("network-ids", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("network-ids", prefix), true), flagsplugin.WithHidden(hidden))) AddSelectFlagsForNetworkIdentifiers(flags, flagsplugin.Prefix("network-ids", prefix), hidden) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("last-battery-percentage", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("last-battery-percentage", prefix), true), flagsplugin.WithHidden(hidden))) + // NOTE: last_battery_percentage (LastBatteryPercentage) does not seem to have select flags. + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("attributes", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("attributes", prefix), false), flagsplugin.WithHidden(hidden))) } // SelectFromFlags outputs the fieldmask paths forApplicationUplink message from select flags. @@ -157,6 +160,17 @@ func PathsFromSelectFlagsForApplicationUplink(flags *pflag.FlagSet, prefix strin } else { paths = append(paths, selectPaths...) } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("last_battery_percentage", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("last_battery_percentage", prefix)) + } + // NOTE: last_battery_percentage (LastBatteryPercentage) does not seem to have select flags. + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("attributes", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("attributes", prefix)) + } return paths, nil } @@ -181,6 +195,8 @@ func AddSetFlagsForApplicationUplink(flags *pflag.FlagSet, prefix string, hidden // FIXME: Skipping Locations because maps with message value types are currently not supported. AddSetFlagsForEndDeviceVersionIdentifiers(flags, flagsplugin.Prefix("version-ids", prefix), hidden) AddSetFlagsForNetworkIdentifiers(flags, flagsplugin.Prefix("network-ids", prefix), hidden) + // FIXME: Skipping LastBatteryPercentage because it does not seem to implement AddSetFlags. + flags.AddFlag(flagsplugin.NewStringStringMapFlag(flagsplugin.Prefix("attributes", prefix), "", flagsplugin.WithHidden(hidden))) } // SetFromFlags sets the ApplicationUplink message from flags. @@ -295,6 +311,13 @@ func (m *ApplicationUplink) SetFromFlags(flags *pflag.FlagSet, prefix string) (p paths = append(paths, setPaths...) } } + // FIXME: Skipping LastBatteryPercentage because it does not seem to implement AddSetFlags. + if val, changed, err := flagsplugin.GetStringStringMap(flags, flagsplugin.Prefix("attributes", prefix)); err != nil { + return nil, err + } else if changed { + m.Attributes = val + paths = append(paths, flagsplugin.Prefix("attributes", prefix)) + } return paths, nil } @@ -317,6 +340,7 @@ func AddSelectFlagsForApplicationUplinkNormalized(flags *pflag.FlagSet, prefix s AddSelectFlagsForEndDeviceVersionIdentifiers(flags, flagsplugin.Prefix("version-ids", prefix), hidden) flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("network-ids", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("network-ids", prefix), true), flagsplugin.WithHidden(hidden))) AddSelectFlagsForNetworkIdentifiers(flags, flagsplugin.Prefix("network-ids", prefix), hidden) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("attributes", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("attributes", prefix), false), flagsplugin.WithHidden(hidden))) } // SelectFromFlags outputs the fieldmask paths forApplicationUplinkNormalized message from select flags. @@ -406,6 +430,11 @@ func PathsFromSelectFlagsForApplicationUplinkNormalized(flags *pflag.FlagSet, pr } else { paths = append(paths, selectPaths...) } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("attributes", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("attributes", prefix)) + } return paths, nil } @@ -450,6 +479,12 @@ func AddSelectFlagsForApplicationJoinAccept(flags *pflag.FlagSet, prefix string, flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("invalidated-downlinks", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("invalidated-downlinks", prefix), false), flagsplugin.WithHidden(hidden))) flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("pending-session", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("pending-session", prefix), false), flagsplugin.WithHidden(hidden))) flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("received-at", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("received-at", prefix), false), flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("locations", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("locations", prefix), false), flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("version-ids", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("version-ids", prefix), true), flagsplugin.WithHidden(hidden))) + AddSelectFlagsForEndDeviceVersionIdentifiers(flags, flagsplugin.Prefix("version-ids", prefix), hidden) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("network-ids", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("network-ids", prefix), true), flagsplugin.WithHidden(hidden))) + AddSelectFlagsForNetworkIdentifiers(flags, flagsplugin.Prefix("network-ids", prefix), hidden) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("attributes", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("attributes", prefix), false), flagsplugin.WithHidden(hidden))) } // SelectFromFlags outputs the fieldmask paths forApplicationJoinAccept message from select flags. @@ -484,6 +519,36 @@ func PathsFromSelectFlagsForApplicationJoinAccept(flags *pflag.FlagSet, prefix s } else if selected && val { paths = append(paths, flagsplugin.Prefix("received_at", prefix)) } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("locations", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("locations", prefix)) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("version_ids", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("version_ids", prefix)) + } + if selectPaths, err := PathsFromSelectFlagsForEndDeviceVersionIdentifiers(flags, flagsplugin.Prefix("version_ids", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, selectPaths...) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("network_ids", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("network_ids", prefix)) + } + if selectPaths, err := PathsFromSelectFlagsForNetworkIdentifiers(flags, flagsplugin.Prefix("network_ids", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, selectPaths...) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("attributes", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("attributes", prefix)) + } return paths, nil } @@ -585,6 +650,12 @@ func AddSelectFlagsForApplicationDownlink(flags *pflag.FlagSet, prefix string, h flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("correlation-ids", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("correlation-ids", prefix), false), flagsplugin.WithHidden(hidden))) flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("confirmed-retry", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("confirmed-retry", prefix), true), flagsplugin.WithHidden(hidden))) AddSelectFlagsForApplicationDownlink_ConfirmedRetry(flags, flagsplugin.Prefix("confirmed-retry", prefix), hidden) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("locations", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("locations", prefix), false), flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("version-ids", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("version-ids", prefix), true), flagsplugin.WithHidden(hidden))) + AddSelectFlagsForEndDeviceVersionIdentifiers(flags, flagsplugin.Prefix("version-ids", prefix), hidden) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("network-ids", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("network-ids", prefix), true), flagsplugin.WithHidden(hidden))) + AddSelectFlagsForNetworkIdentifiers(flags, flagsplugin.Prefix("network-ids", prefix), hidden) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("attributes", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("attributes", prefix), false), flagsplugin.WithHidden(hidden))) } // SelectFromFlags outputs the fieldmask paths forApplicationDownlink message from select flags. @@ -654,6 +725,36 @@ func PathsFromSelectFlagsForApplicationDownlink(flags *pflag.FlagSet, prefix str } else { paths = append(paths, selectPaths...) } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("locations", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("locations", prefix)) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("version_ids", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("version_ids", prefix)) + } + if selectPaths, err := PathsFromSelectFlagsForEndDeviceVersionIdentifiers(flags, flagsplugin.Prefix("version_ids", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, selectPaths...) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("network_ids", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("network_ids", prefix)) + } + if selectPaths, err := PathsFromSelectFlagsForNetworkIdentifiers(flags, flagsplugin.Prefix("network_ids", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, selectPaths...) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("attributes", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("attributes", prefix)) + } return paths, nil } @@ -670,6 +771,10 @@ func AddSetFlagsForApplicationDownlink(flags *pflag.FlagSet, prefix string, hidd flags.AddFlag(flagsplugin.NewStringFlag(flagsplugin.Prefix("priority", prefix), flagsplugin.EnumValueDesc(TxSchedulePriority_value), flagsplugin.WithHidden(hidden))) flags.AddFlag(flagsplugin.NewStringSliceFlag(flagsplugin.Prefix("correlation-ids", prefix), "", flagsplugin.WithHidden(hidden))) AddSetFlagsForApplicationDownlink_ConfirmedRetry(flags, flagsplugin.Prefix("confirmed-retry", prefix), hidden) + // FIXME: Skipping Locations because maps with message value types are currently not supported. + AddSetFlagsForEndDeviceVersionIdentifiers(flags, flagsplugin.Prefix("version-ids", prefix), hidden) + AddSetFlagsForNetworkIdentifiers(flags, flagsplugin.Prefix("network-ids", prefix), hidden) + flags.AddFlag(flagsplugin.NewStringStringMapFlag(flagsplugin.Prefix("attributes", prefix), "", flagsplugin.WithHidden(hidden))) } // SetFromFlags sets the ApplicationDownlink message from flags. @@ -747,6 +852,33 @@ func (m *ApplicationDownlink) SetFromFlags(flags *pflag.FlagSet, prefix string) paths = append(paths, setPaths...) } } + // FIXME: Skipping Locations because maps with message value types are currently not supported. + if changed := flagsplugin.IsAnyPrefixSet(flags, flagsplugin.Prefix("version_ids", prefix)); changed { + if m.VersionIds == nil { + m.VersionIds = &EndDeviceVersionIdentifiers{} + } + if setPaths, err := m.VersionIds.SetFromFlags(flags, flagsplugin.Prefix("version_ids", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, setPaths...) + } + } + if changed := flagsplugin.IsAnyPrefixSet(flags, flagsplugin.Prefix("network_ids", prefix)); changed { + if m.NetworkIds == nil { + m.NetworkIds = &NetworkIdentifiers{} + } + if setPaths, err := m.NetworkIds.SetFromFlags(flags, flagsplugin.Prefix("network_ids", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, setPaths...) + } + } + if val, changed, err := flagsplugin.GetStringStringMap(flags, flagsplugin.Prefix("attributes", prefix)); err != nil { + return nil, err + } else if changed { + m.Attributes = val + paths = append(paths, flagsplugin.Prefix("attributes", prefix)) + } return paths, nil } @@ -756,6 +888,12 @@ func AddSelectFlagsForApplicationDownlinkFailed(flags *pflag.FlagSet, prefix str AddSelectFlagsForApplicationDownlink(flags, flagsplugin.Prefix("downlink", prefix), hidden) flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("error", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("error", prefix), true), flagsplugin.WithHidden(hidden))) // NOTE: error (ErrorDetails) does not seem to have select flags. + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("locations", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("locations", prefix), false), flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("version-ids", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("version-ids", prefix), true), flagsplugin.WithHidden(hidden))) + AddSelectFlagsForEndDeviceVersionIdentifiers(flags, flagsplugin.Prefix("version-ids", prefix), hidden) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("network-ids", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("network-ids", prefix), true), flagsplugin.WithHidden(hidden))) + AddSelectFlagsForNetworkIdentifiers(flags, flagsplugin.Prefix("network-ids", prefix), hidden) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("attributes", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("attributes", prefix), false), flagsplugin.WithHidden(hidden))) } // SelectFromFlags outputs the fieldmask paths forApplicationDownlinkFailed message from select flags. @@ -776,6 +914,36 @@ func PathsFromSelectFlagsForApplicationDownlinkFailed(flags *pflag.FlagSet, pref paths = append(paths, flagsplugin.Prefix("error", prefix)) } // NOTE: error (ErrorDetails) does not seem to have select flags. + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("locations", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("locations", prefix)) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("version_ids", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("version_ids", prefix)) + } + if selectPaths, err := PathsFromSelectFlagsForEndDeviceVersionIdentifiers(flags, flagsplugin.Prefix("version_ids", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, selectPaths...) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("network_ids", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("network_ids", prefix)) + } + if selectPaths, err := PathsFromSelectFlagsForNetworkIdentifiers(flags, flagsplugin.Prefix("network_ids", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, selectPaths...) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("attributes", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("attributes", prefix)) + } return paths, nil } @@ -784,6 +952,12 @@ func AddSelectFlagsForApplicationInvalidatedDownlinks(flags *pflag.FlagSet, pref flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("downlinks", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("downlinks", prefix), false), flagsplugin.WithHidden(hidden))) flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("last-f-cnt-down", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("last-f-cnt-down", prefix), false), flagsplugin.WithHidden(hidden))) flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("session-key-id", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("session-key-id", prefix), false), flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("locations", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("locations", prefix), false), flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("version-ids", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("version-ids", prefix), true), flagsplugin.WithHidden(hidden))) + AddSelectFlagsForEndDeviceVersionIdentifiers(flags, flagsplugin.Prefix("version-ids", prefix), hidden) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("network-ids", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("network-ids", prefix), true), flagsplugin.WithHidden(hidden))) + AddSelectFlagsForNetworkIdentifiers(flags, flagsplugin.Prefix("network-ids", prefix), hidden) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("attributes", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("attributes", prefix), false), flagsplugin.WithHidden(hidden))) } // SelectFromFlags outputs the fieldmask paths forApplicationInvalidatedDownlinks message from select flags. @@ -803,6 +977,36 @@ func PathsFromSelectFlagsForApplicationInvalidatedDownlinks(flags *pflag.FlagSet } else if selected && val { paths = append(paths, flagsplugin.Prefix("session_key_id", prefix)) } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("locations", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("locations", prefix)) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("version_ids", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("version_ids", prefix)) + } + if selectPaths, err := PathsFromSelectFlagsForEndDeviceVersionIdentifiers(flags, flagsplugin.Prefix("version_ids", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, selectPaths...) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("network_ids", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("network_ids", prefix)) + } + if selectPaths, err := PathsFromSelectFlagsForNetworkIdentifiers(flags, flagsplugin.Prefix("network_ids", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, selectPaths...) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("attributes", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("attributes", prefix)) + } return paths, nil } @@ -810,6 +1014,12 @@ func PathsFromSelectFlagsForApplicationInvalidatedDownlinks(flags *pflag.FlagSet func AddSelectFlagsForApplicationServiceData(flags *pflag.FlagSet, prefix string, hidden bool) { flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("service", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("service", prefix), false), flagsplugin.WithHidden(hidden))) flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("data", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("data", prefix), false), flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("locations", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("locations", prefix), false), flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("version-ids", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("version-ids", prefix), true), flagsplugin.WithHidden(hidden))) + AddSelectFlagsForEndDeviceVersionIdentifiers(flags, flagsplugin.Prefix("version-ids", prefix), hidden) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("network-ids", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("network-ids", prefix), true), flagsplugin.WithHidden(hidden))) + AddSelectFlagsForNetworkIdentifiers(flags, flagsplugin.Prefix("network-ids", prefix), hidden) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("attributes", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("attributes", prefix), false), flagsplugin.WithHidden(hidden))) } // SelectFromFlags outputs the fieldmask paths forApplicationServiceData message from select flags. @@ -824,6 +1034,36 @@ func PathsFromSelectFlagsForApplicationServiceData(flags *pflag.FlagSet, prefix } else if selected && val { paths = append(paths, flagsplugin.Prefix("data", prefix)) } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("locations", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("locations", prefix)) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("version_ids", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("version_ids", prefix)) + } + if selectPaths, err := PathsFromSelectFlagsForEndDeviceVersionIdentifiers(flags, flagsplugin.Prefix("version_ids", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, selectPaths...) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("network_ids", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("network_ids", prefix)) + } + if selectPaths, err := PathsFromSelectFlagsForNetworkIdentifiers(flags, flagsplugin.Prefix("network_ids", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, selectPaths...) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("attributes", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("attributes", prefix)) + } return paths, nil } diff --git a/pkg/ttnpb/messages_json.pb.go b/pkg/ttnpb/messages_json.pb.go index 8b69bcf8b3..8fdbb15b89 100644 --- a/pkg/ttnpb/messages_json.pb.go +++ b/pkg/ttnpb/messages_json.pb.go @@ -719,6 +719,24 @@ func (x *ApplicationUplink) MarshalProtoJSON(s *jsonplugin.MarshalState) { s.WriteObjectField("network_ids") x.NetworkIds.MarshalProtoJSON(s.WithField("network_ids")) } + if x.LastBatteryPercentage != nil || s.HasField("last_battery_percentage") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("last_battery_percentage") + // NOTE: LastBatteryPercentage does not seem to implement MarshalProtoJSON. + golang.MarshalMessage(s, x.LastBatteryPercentage) + } + if x.Attributes != nil || s.HasField("attributes") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("attributes") + s.WriteObjectStart() + var wroteElement bool + for k, v := range x.Attributes { + s.WriteMoreIf(&wroteElement) + s.WriteObjectStringField(k) + s.WriteString(v) + } + s.WriteObjectEnd() + } s.WriteObjectEnd() } @@ -881,6 +899,26 @@ func (x *ApplicationUplink) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { } x.NetworkIds = &NetworkIdentifiers{} x.NetworkIds.UnmarshalProtoJSON(s.WithField("network_ids", true)) + case "last_battery_percentage", "lastBatteryPercentage": + s.AddField("last_battery_percentage") + if s.ReadNil() { + x.LastBatteryPercentage = nil + return + } + // NOTE: LastBatteryPercentage does not seem to implement UnmarshalProtoJSON. + var v LastBatteryPercentage + golang.UnmarshalMessage(s, &v) + x.LastBatteryPercentage = &v + case "attributes": + s.AddField("attributes") + if s.ReadNil() { + x.Attributes = nil + return + } + x.Attributes = make(map[string]string) + s.ReadStringMap(func(key string) { + x.Attributes[key] = s.ReadString() + }) } }) } @@ -995,6 +1033,18 @@ func (x *ApplicationUplinkNormalized) MarshalProtoJSON(s *jsonplugin.MarshalStat s.WriteObjectField("network_ids") x.NetworkIds.MarshalProtoJSON(s.WithField("network_ids")) } + if x.Attributes != nil || s.HasField("attributes") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("attributes") + s.WriteObjectStart() + var wroteElement bool + for k, v := range x.Attributes { + s.WriteMoreIf(&wroteElement) + s.WriteObjectStringField(k) + s.WriteString(v) + } + s.WriteObjectEnd() + } s.WriteObjectEnd() } @@ -1124,6 +1174,16 @@ func (x *ApplicationUplinkNormalized) UnmarshalProtoJSON(s *jsonplugin.Unmarshal } x.NetworkIds = &NetworkIdentifiers{} x.NetworkIds.UnmarshalProtoJSON(s.WithField("network_ids", true)) + case "attributes": + s.AddField("attributes") + if s.ReadNil() { + x.Attributes = nil + return + } + x.Attributes = make(map[string]string) + s.ReadStringMap(func(key string) { + x.Attributes[key] = s.ReadString() + }) } }) } @@ -1252,6 +1312,41 @@ func (x *ApplicationJoinAccept) MarshalProtoJSON(s *jsonplugin.MarshalState) { golang.MarshalTimestamp(s, x.ReceivedAt) } } + if x.Locations != nil || s.HasField("locations") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("locations") + s.WriteObjectStart() + var wroteElement bool + for k, v := range x.Locations { + s.WriteMoreIf(&wroteElement) + s.WriteObjectStringField(k) + v.MarshalProtoJSON(s.WithField("locations")) + } + s.WriteObjectEnd() + } + if x.VersionIds != nil || s.HasField("version_ids") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("version_ids") + // NOTE: EndDeviceVersionIdentifiers does not seem to implement MarshalProtoJSON. + golang.MarshalMessage(s, x.VersionIds) + } + if x.NetworkIds != nil || s.HasField("network_ids") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("network_ids") + x.NetworkIds.MarshalProtoJSON(s.WithField("network_ids")) + } + if x.Attributes != nil || s.HasField("attributes") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("attributes") + s.WriteObjectStart() + var wroteElement bool + for k, v := range x.Attributes { + s.WriteMoreIf(&wroteElement) + s.WriteObjectStringField(k) + s.WriteString(v) + } + s.WriteObjectEnd() + } s.WriteObjectEnd() } @@ -1311,6 +1406,45 @@ func (x *ApplicationJoinAccept) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) return } x.ReceivedAt = v + case "locations": + s.AddField("locations") + if s.ReadNil() { + x.Locations = nil + return + } + x.Locations = make(map[string]*Location) + s.ReadStringMap(func(key string) { + var v Location + v.UnmarshalProtoJSON(s) + x.Locations[key] = &v + }) + case "version_ids", "versionIds": + s.AddField("version_ids") + if s.ReadNil() { + x.VersionIds = nil + return + } + // NOTE: EndDeviceVersionIdentifiers does not seem to implement UnmarshalProtoJSON. + var v EndDeviceVersionIdentifiers + golang.UnmarshalMessage(s, &v) + x.VersionIds = &v + case "network_ids", "networkIds": + if s.ReadNil() { + x.NetworkIds = nil + return + } + x.NetworkIds = &NetworkIdentifiers{} + x.NetworkIds.UnmarshalProtoJSON(s.WithField("network_ids", true)) + case "attributes": + s.AddField("attributes") + if s.ReadNil() { + x.Attributes = nil + return + } + x.Attributes = make(map[string]string) + s.ReadStringMap(func(key string) { + x.Attributes[key] = s.ReadString() + }) } }) } @@ -1471,6 +1605,41 @@ func (x *ApplicationDownlink) MarshalProtoJSON(s *jsonplugin.MarshalState) { // NOTE: ApplicationDownlink_ConfirmedRetry does not seem to implement MarshalProtoJSON. golang.MarshalMessage(s, x.ConfirmedRetry) } + if x.Locations != nil || s.HasField("locations") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("locations") + s.WriteObjectStart() + var wroteElement bool + for k, v := range x.Locations { + s.WriteMoreIf(&wroteElement) + s.WriteObjectStringField(k) + v.MarshalProtoJSON(s.WithField("locations")) + } + s.WriteObjectEnd() + } + if x.VersionIds != nil || s.HasField("version_ids") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("version_ids") + // NOTE: EndDeviceVersionIdentifiers does not seem to implement MarshalProtoJSON. + golang.MarshalMessage(s, x.VersionIds) + } + if x.NetworkIds != nil || s.HasField("network_ids") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("network_ids") + x.NetworkIds.MarshalProtoJSON(s.WithField("network_ids")) + } + if x.Attributes != nil || s.HasField("attributes") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("attributes") + s.WriteObjectStart() + var wroteElement bool + for k, v := range x.Attributes { + s.WriteMoreIf(&wroteElement) + s.WriteObjectStringField(k) + s.WriteString(v) + } + s.WriteObjectEnd() + } s.WriteObjectEnd() } @@ -1548,6 +1717,45 @@ func (x *ApplicationDownlink) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { var v ApplicationDownlink_ConfirmedRetry golang.UnmarshalMessage(s, &v) x.ConfirmedRetry = &v + case "locations": + s.AddField("locations") + if s.ReadNil() { + x.Locations = nil + return + } + x.Locations = make(map[string]*Location) + s.ReadStringMap(func(key string) { + var v Location + v.UnmarshalProtoJSON(s) + x.Locations[key] = &v + }) + case "version_ids", "versionIds": + s.AddField("version_ids") + if s.ReadNil() { + x.VersionIds = nil + return + } + // NOTE: EndDeviceVersionIdentifiers does not seem to implement UnmarshalProtoJSON. + var v EndDeviceVersionIdentifiers + golang.UnmarshalMessage(s, &v) + x.VersionIds = &v + case "network_ids", "networkIds": + if s.ReadNil() { + x.NetworkIds = nil + return + } + x.NetworkIds = &NetworkIdentifiers{} + x.NetworkIds.UnmarshalProtoJSON(s.WithField("network_ids", true)) + case "attributes": + s.AddField("attributes") + if s.ReadNil() { + x.Attributes = nil + return + } + x.Attributes = make(map[string]string) + s.ReadStringMap(func(key string) { + x.Attributes[key] = s.ReadString() + }) } }) } @@ -1639,6 +1847,41 @@ func (x *ApplicationDownlinkFailed) MarshalProtoJSON(s *jsonplugin.MarshalState) // NOTE: ErrorDetails does not seem to implement MarshalProtoJSON. golang.MarshalMessage(s, x.Error) } + if x.Locations != nil || s.HasField("locations") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("locations") + s.WriteObjectStart() + var wroteElement bool + for k, v := range x.Locations { + s.WriteMoreIf(&wroteElement) + s.WriteObjectStringField(k) + v.MarshalProtoJSON(s.WithField("locations")) + } + s.WriteObjectEnd() + } + if x.VersionIds != nil || s.HasField("version_ids") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("version_ids") + // NOTE: EndDeviceVersionIdentifiers does not seem to implement MarshalProtoJSON. + golang.MarshalMessage(s, x.VersionIds) + } + if x.NetworkIds != nil || s.HasField("network_ids") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("network_ids") + x.NetworkIds.MarshalProtoJSON(s.WithField("network_ids")) + } + if x.Attributes != nil || s.HasField("attributes") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("attributes") + s.WriteObjectStart() + var wroteElement bool + for k, v := range x.Attributes { + s.WriteMoreIf(&wroteElement) + s.WriteObjectStringField(k) + s.WriteString(v) + } + s.WriteObjectEnd() + } s.WriteObjectEnd() } @@ -1673,6 +1916,45 @@ func (x *ApplicationDownlinkFailed) UnmarshalProtoJSON(s *jsonplugin.UnmarshalSt var v ErrorDetails golang.UnmarshalMessage(s, &v) x.Error = &v + case "locations": + s.AddField("locations") + if s.ReadNil() { + x.Locations = nil + return + } + x.Locations = make(map[string]*Location) + s.ReadStringMap(func(key string) { + var v Location + v.UnmarshalProtoJSON(s) + x.Locations[key] = &v + }) + case "version_ids", "versionIds": + s.AddField("version_ids") + if s.ReadNil() { + x.VersionIds = nil + return + } + // NOTE: EndDeviceVersionIdentifiers does not seem to implement UnmarshalProtoJSON. + var v EndDeviceVersionIdentifiers + golang.UnmarshalMessage(s, &v) + x.VersionIds = &v + case "network_ids", "networkIds": + if s.ReadNil() { + x.NetworkIds = nil + return + } + x.NetworkIds = &NetworkIdentifiers{} + x.NetworkIds.UnmarshalProtoJSON(s.WithField("network_ids", true)) + case "attributes": + s.AddField("attributes") + if s.ReadNil() { + x.Attributes = nil + return + } + x.Attributes = make(map[string]string) + s.ReadStringMap(func(key string) { + x.Attributes[key] = s.ReadString() + }) } }) } @@ -1711,6 +1993,41 @@ func (x *ApplicationInvalidatedDownlinks) MarshalProtoJSON(s *jsonplugin.Marshal s.WriteObjectField("session_key_id") s.WriteBytes(x.SessionKeyId) } + if x.Locations != nil || s.HasField("locations") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("locations") + s.WriteObjectStart() + var wroteElement bool + for k, v := range x.Locations { + s.WriteMoreIf(&wroteElement) + s.WriteObjectStringField(k) + v.MarshalProtoJSON(s.WithField("locations")) + } + s.WriteObjectEnd() + } + if x.VersionIds != nil || s.HasField("version_ids") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("version_ids") + // NOTE: EndDeviceVersionIdentifiers does not seem to implement MarshalProtoJSON. + golang.MarshalMessage(s, x.VersionIds) + } + if x.NetworkIds != nil || s.HasField("network_ids") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("network_ids") + x.NetworkIds.MarshalProtoJSON(s.WithField("network_ids")) + } + if x.Attributes != nil || s.HasField("attributes") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("attributes") + s.WriteObjectStart() + var wroteElement bool + for k, v := range x.Attributes { + s.WriteMoreIf(&wroteElement) + s.WriteObjectStringField(k) + s.WriteString(v) + } + s.WriteObjectEnd() + } s.WriteObjectEnd() } @@ -1752,6 +2069,45 @@ func (x *ApplicationInvalidatedDownlinks) UnmarshalProtoJSON(s *jsonplugin.Unmar case "session_key_id", "sessionKeyId": s.AddField("session_key_id") x.SessionKeyId = s.ReadBytes() + case "locations": + s.AddField("locations") + if s.ReadNil() { + x.Locations = nil + return + } + x.Locations = make(map[string]*Location) + s.ReadStringMap(func(key string) { + var v Location + v.UnmarshalProtoJSON(s) + x.Locations[key] = &v + }) + case "version_ids", "versionIds": + s.AddField("version_ids") + if s.ReadNil() { + x.VersionIds = nil + return + } + // NOTE: EndDeviceVersionIdentifiers does not seem to implement UnmarshalProtoJSON. + var v EndDeviceVersionIdentifiers + golang.UnmarshalMessage(s, &v) + x.VersionIds = &v + case "network_ids", "networkIds": + if s.ReadNil() { + x.NetworkIds = nil + return + } + x.NetworkIds = &NetworkIdentifiers{} + x.NetworkIds.UnmarshalProtoJSON(s.WithField("network_ids", true)) + case "attributes": + s.AddField("attributes") + if s.ReadNil() { + x.Attributes = nil + return + } + x.Attributes = make(map[string]string) + s.ReadStringMap(func(key string) { + x.Attributes[key] = s.ReadString() + }) } }) } @@ -1843,6 +2199,142 @@ func (x *DownlinkQueueOperationErrorDetails) UnmarshalJSON(b []byte) error { return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) } +// MarshalProtoJSON marshals the ApplicationServiceData message to JSON. +func (x *ApplicationServiceData) MarshalProtoJSON(s *jsonplugin.MarshalState) { + if x == nil { + s.WriteNil() + return + } + s.WriteObjectStart() + var wroteField bool + if x.Service != "" || s.HasField("service") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("service") + s.WriteString(x.Service) + } + if x.Data != nil || s.HasField("data") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("data") + if x.Data == nil { + s.WriteNil() + } else { + golang.MarshalStruct(s, x.Data) + } + } + if x.Locations != nil || s.HasField("locations") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("locations") + s.WriteObjectStart() + var wroteElement bool + for k, v := range x.Locations { + s.WriteMoreIf(&wroteElement) + s.WriteObjectStringField(k) + v.MarshalProtoJSON(s.WithField("locations")) + } + s.WriteObjectEnd() + } + if x.VersionIds != nil || s.HasField("version_ids") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("version_ids") + // NOTE: EndDeviceVersionIdentifiers does not seem to implement MarshalProtoJSON. + golang.MarshalMessage(s, x.VersionIds) + } + if x.NetworkIds != nil || s.HasField("network_ids") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("network_ids") + x.NetworkIds.MarshalProtoJSON(s.WithField("network_ids")) + } + if x.Attributes != nil || s.HasField("attributes") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("attributes") + s.WriteObjectStart() + var wroteElement bool + for k, v := range x.Attributes { + s.WriteMoreIf(&wroteElement) + s.WriteObjectStringField(k) + s.WriteString(v) + } + s.WriteObjectEnd() + } + s.WriteObjectEnd() +} + +// MarshalJSON marshals the ApplicationServiceData to JSON. +func (x *ApplicationServiceData) MarshalJSON() ([]byte, error) { + return jsonplugin.DefaultMarshalerConfig.Marshal(x) +} + +// UnmarshalProtoJSON unmarshals the ApplicationServiceData message from JSON. +func (x *ApplicationServiceData) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { + if s.ReadNil() { + return + } + s.ReadObject(func(key string) { + switch key { + default: + s.ReadAny() // ignore unknown field + case "service": + s.AddField("service") + x.Service = s.ReadString() + case "data": + s.AddField("data") + if s.ReadNil() { + x.Data = nil + return + } + v := golang.UnmarshalStruct(s) + if s.Err() != nil { + return + } + x.Data = v + case "locations": + s.AddField("locations") + if s.ReadNil() { + x.Locations = nil + return + } + x.Locations = make(map[string]*Location) + s.ReadStringMap(func(key string) { + var v Location + v.UnmarshalProtoJSON(s) + x.Locations[key] = &v + }) + case "version_ids", "versionIds": + s.AddField("version_ids") + if s.ReadNil() { + x.VersionIds = nil + return + } + // NOTE: EndDeviceVersionIdentifiers does not seem to implement UnmarshalProtoJSON. + var v EndDeviceVersionIdentifiers + golang.UnmarshalMessage(s, &v) + x.VersionIds = &v + case "network_ids", "networkIds": + if s.ReadNil() { + x.NetworkIds = nil + return + } + x.NetworkIds = &NetworkIdentifiers{} + x.NetworkIds.UnmarshalProtoJSON(s.WithField("network_ids", true)) + case "attributes": + s.AddField("attributes") + if s.ReadNil() { + x.Attributes = nil + return + } + x.Attributes = make(map[string]string) + s.ReadStringMap(func(key string) { + x.Attributes[key] = s.ReadString() + }) + } + }) +} + +// UnmarshalJSON unmarshals the ApplicationServiceData from JSON. +func (x *ApplicationServiceData) UnmarshalJSON(b []byte) error { + return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) +} + // MarshalProtoJSON marshals the ApplicationUp message to JSON. func (x *ApplicationUp) MarshalProtoJSON(s *jsonplugin.MarshalState) { if x == nil { @@ -1915,8 +2407,7 @@ func (x *ApplicationUp) MarshalProtoJSON(s *jsonplugin.MarshalState) { case *ApplicationUp_ServiceData: s.WriteMoreIf(&wroteField) s.WriteObjectField("service_data") - // NOTE: ApplicationServiceData does not seem to implement MarshalProtoJSON. - golang.MarshalMessage(s, ov.ServiceData) + ov.ServiceData.MarshalProtoJSON(s.WithField("service_data")) } } if x.Simulated || s.HasField("simulated") { @@ -2057,17 +2548,14 @@ func (x *ApplicationUp) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { ov.LocationSolved = &ApplicationLocation{} ov.LocationSolved.UnmarshalProtoJSON(s.WithField("location_solved", true)) case "service_data", "serviceData": - s.AddField("service_data") ov := &ApplicationUp_ServiceData{} x.Up = ov if s.ReadNil() { ov.ServiceData = nil return } - // NOTE: ApplicationServiceData does not seem to implement UnmarshalProtoJSON. - var v ApplicationServiceData - golang.UnmarshalMessage(s, &v) - ov.ServiceData = &v + ov.ServiceData = &ApplicationServiceData{} + ov.ServiceData.UnmarshalProtoJSON(s.WithField("service_data", true)) case "simulated": s.AddField("simulated") x.Simulated = s.ReadBool() diff --git a/pkg/ttnpb/qrcodegenerator.pb.paths.fm.go b/pkg/ttnpb/qrcodegenerator.pb.paths.fm.go index 0c6cc9e100..f921d78b07 100644 --- a/pkg/ttnpb/qrcodegenerator.pb.paths.fm.go +++ b/pkg/ttnpb/qrcodegenerator.pb.paths.fm.go @@ -407,6 +407,7 @@ var GenerateEndDeviceQRCodeRequestFieldPathsNested = []string{ "end_device.mac_state.last_network_initiated_downlink_at", "end_device.mac_state.lorawan_version", "end_device.mac_state.pending_application_downlink", + "end_device.mac_state.pending_application_downlink.attributes", "end_device.mac_state.pending_application_downlink.class_b_c", "end_device.mac_state.pending_application_downlink.class_b_c.absolute_time", "end_device.mac_state.pending_application_downlink.class_b_c.gateways", @@ -420,8 +421,22 @@ var GenerateEndDeviceQRCodeRequestFieldPathsNested = []string{ "end_device.mac_state.pending_application_downlink.f_cnt", "end_device.mac_state.pending_application_downlink.f_port", "end_device.mac_state.pending_application_downlink.frm_payload", + "end_device.mac_state.pending_application_downlink.locations", + "end_device.mac_state.pending_application_downlink.network_ids", + "end_device.mac_state.pending_application_downlink.network_ids.cluster_address", + "end_device.mac_state.pending_application_downlink.network_ids.cluster_id", + "end_device.mac_state.pending_application_downlink.network_ids.net_id", + "end_device.mac_state.pending_application_downlink.network_ids.ns_id", + "end_device.mac_state.pending_application_downlink.network_ids.tenant_address", + "end_device.mac_state.pending_application_downlink.network_ids.tenant_id", "end_device.mac_state.pending_application_downlink.priority", "end_device.mac_state.pending_application_downlink.session_key_id", + "end_device.mac_state.pending_application_downlink.version_ids", + "end_device.mac_state.pending_application_downlink.version_ids.band_id", + "end_device.mac_state.pending_application_downlink.version_ids.brand_id", + "end_device.mac_state.pending_application_downlink.version_ids.firmware_version", + "end_device.mac_state.pending_application_downlink.version_ids.hardware_version", + "end_device.mac_state.pending_application_downlink.version_ids.model_id", "end_device.mac_state.pending_join_request", "end_device.mac_state.pending_join_request.cf_list", "end_device.mac_state.pending_join_request.cf_list.ch_masks", @@ -623,6 +638,7 @@ var GenerateEndDeviceQRCodeRequestFieldPathsNested = []string{ "end_device.pending_mac_state.last_network_initiated_downlink_at", "end_device.pending_mac_state.lorawan_version", "end_device.pending_mac_state.pending_application_downlink", + "end_device.pending_mac_state.pending_application_downlink.attributes", "end_device.pending_mac_state.pending_application_downlink.class_b_c", "end_device.pending_mac_state.pending_application_downlink.class_b_c.absolute_time", "end_device.pending_mac_state.pending_application_downlink.class_b_c.gateways", @@ -636,8 +652,22 @@ var GenerateEndDeviceQRCodeRequestFieldPathsNested = []string{ "end_device.pending_mac_state.pending_application_downlink.f_cnt", "end_device.pending_mac_state.pending_application_downlink.f_port", "end_device.pending_mac_state.pending_application_downlink.frm_payload", + "end_device.pending_mac_state.pending_application_downlink.locations", + "end_device.pending_mac_state.pending_application_downlink.network_ids", + "end_device.pending_mac_state.pending_application_downlink.network_ids.cluster_address", + "end_device.pending_mac_state.pending_application_downlink.network_ids.cluster_id", + "end_device.pending_mac_state.pending_application_downlink.network_ids.net_id", + "end_device.pending_mac_state.pending_application_downlink.network_ids.ns_id", + "end_device.pending_mac_state.pending_application_downlink.network_ids.tenant_address", + "end_device.pending_mac_state.pending_application_downlink.network_ids.tenant_id", "end_device.pending_mac_state.pending_application_downlink.priority", "end_device.pending_mac_state.pending_application_downlink.session_key_id", + "end_device.pending_mac_state.pending_application_downlink.version_ids", + "end_device.pending_mac_state.pending_application_downlink.version_ids.band_id", + "end_device.pending_mac_state.pending_application_downlink.version_ids.brand_id", + "end_device.pending_mac_state.pending_application_downlink.version_ids.firmware_version", + "end_device.pending_mac_state.pending_application_downlink.version_ids.hardware_version", + "end_device.pending_mac_state.pending_application_downlink.version_ids.model_id", "end_device.pending_mac_state.pending_join_request", "end_device.pending_mac_state.pending_join_request.cf_list", "end_device.pending_mac_state.pending_join_request.cf_list.ch_masks", @@ -1195,6 +1225,7 @@ var ParseEndDeviceQRCodeResponseFieldPathsNested = []string{ "end_device_template.end_device.mac_state.last_network_initiated_downlink_at", "end_device_template.end_device.mac_state.lorawan_version", "end_device_template.end_device.mac_state.pending_application_downlink", + "end_device_template.end_device.mac_state.pending_application_downlink.attributes", "end_device_template.end_device.mac_state.pending_application_downlink.class_b_c", "end_device_template.end_device.mac_state.pending_application_downlink.class_b_c.absolute_time", "end_device_template.end_device.mac_state.pending_application_downlink.class_b_c.gateways", @@ -1208,8 +1239,22 @@ var ParseEndDeviceQRCodeResponseFieldPathsNested = []string{ "end_device_template.end_device.mac_state.pending_application_downlink.f_cnt", "end_device_template.end_device.mac_state.pending_application_downlink.f_port", "end_device_template.end_device.mac_state.pending_application_downlink.frm_payload", + "end_device_template.end_device.mac_state.pending_application_downlink.locations", + "end_device_template.end_device.mac_state.pending_application_downlink.network_ids", + "end_device_template.end_device.mac_state.pending_application_downlink.network_ids.cluster_address", + "end_device_template.end_device.mac_state.pending_application_downlink.network_ids.cluster_id", + "end_device_template.end_device.mac_state.pending_application_downlink.network_ids.net_id", + "end_device_template.end_device.mac_state.pending_application_downlink.network_ids.ns_id", + "end_device_template.end_device.mac_state.pending_application_downlink.network_ids.tenant_address", + "end_device_template.end_device.mac_state.pending_application_downlink.network_ids.tenant_id", "end_device_template.end_device.mac_state.pending_application_downlink.priority", "end_device_template.end_device.mac_state.pending_application_downlink.session_key_id", + "end_device_template.end_device.mac_state.pending_application_downlink.version_ids", + "end_device_template.end_device.mac_state.pending_application_downlink.version_ids.band_id", + "end_device_template.end_device.mac_state.pending_application_downlink.version_ids.brand_id", + "end_device_template.end_device.mac_state.pending_application_downlink.version_ids.firmware_version", + "end_device_template.end_device.mac_state.pending_application_downlink.version_ids.hardware_version", + "end_device_template.end_device.mac_state.pending_application_downlink.version_ids.model_id", "end_device_template.end_device.mac_state.pending_join_request", "end_device_template.end_device.mac_state.pending_join_request.cf_list", "end_device_template.end_device.mac_state.pending_join_request.cf_list.ch_masks", @@ -1411,6 +1456,7 @@ var ParseEndDeviceQRCodeResponseFieldPathsNested = []string{ "end_device_template.end_device.pending_mac_state.last_network_initiated_downlink_at", "end_device_template.end_device.pending_mac_state.lorawan_version", "end_device_template.end_device.pending_mac_state.pending_application_downlink", + "end_device_template.end_device.pending_mac_state.pending_application_downlink.attributes", "end_device_template.end_device.pending_mac_state.pending_application_downlink.class_b_c", "end_device_template.end_device.pending_mac_state.pending_application_downlink.class_b_c.absolute_time", "end_device_template.end_device.pending_mac_state.pending_application_downlink.class_b_c.gateways", @@ -1424,8 +1470,22 @@ var ParseEndDeviceQRCodeResponseFieldPathsNested = []string{ "end_device_template.end_device.pending_mac_state.pending_application_downlink.f_cnt", "end_device_template.end_device.pending_mac_state.pending_application_downlink.f_port", "end_device_template.end_device.pending_mac_state.pending_application_downlink.frm_payload", + "end_device_template.end_device.pending_mac_state.pending_application_downlink.locations", + "end_device_template.end_device.pending_mac_state.pending_application_downlink.network_ids", + "end_device_template.end_device.pending_mac_state.pending_application_downlink.network_ids.cluster_address", + "end_device_template.end_device.pending_mac_state.pending_application_downlink.network_ids.cluster_id", + "end_device_template.end_device.pending_mac_state.pending_application_downlink.network_ids.net_id", + "end_device_template.end_device.pending_mac_state.pending_application_downlink.network_ids.ns_id", + "end_device_template.end_device.pending_mac_state.pending_application_downlink.network_ids.tenant_address", + "end_device_template.end_device.pending_mac_state.pending_application_downlink.network_ids.tenant_id", "end_device_template.end_device.pending_mac_state.pending_application_downlink.priority", "end_device_template.end_device.pending_mac_state.pending_application_downlink.session_key_id", + "end_device_template.end_device.pending_mac_state.pending_application_downlink.version_ids", + "end_device_template.end_device.pending_mac_state.pending_application_downlink.version_ids.band_id", + "end_device_template.end_device.pending_mac_state.pending_application_downlink.version_ids.brand_id", + "end_device_template.end_device.pending_mac_state.pending_application_downlink.version_ids.firmware_version", + "end_device_template.end_device.pending_mac_state.pending_application_downlink.version_ids.hardware_version", + "end_device_template.end_device.pending_mac_state.pending_application_downlink.version_ids.model_id", "end_device_template.end_device.pending_mac_state.pending_join_request", "end_device_template.end_device.pending_mac_state.pending_join_request.cf_list", "end_device_template.end_device.pending_mac_state.pending_join_request.cf_list.ch_masks", diff --git a/pkg/ttnpb/user.pb.go b/pkg/ttnpb/user.pb.go index 7c665595e2..35be0b1996 100644 --- a/pkg/ttnpb/user.pb.go +++ b/pkg/ttnpb/user.pb.go @@ -2707,7 +2707,7 @@ var file_ttn_lorawan_v3_user_proto_rawDesc = []byte{ 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x42, 0x0f, 0xfa, 0x42, 0x0c, 0x92, 0x01, 0x09, 0x18, 0x01, 0x22, 0x05, - 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x22, 0xd9, 0x0e, 0x0a, + 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x22, 0xe3, 0x0e, 0x0a, 0x16, 0x55, 0x73, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x41, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x5f, 0x74, 0x68, 0x65, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, @@ -2820,475 +2820,475 @@ var file_ttn_lorawan_v3_user_proto_rawDesc = []byte{ 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x52, 0x06, 0x2d, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x52, 0x0b, 0x2d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x52, 0x04, 0x75, 0x73, - 0x65, 0x72, 0x1a, 0x4a, 0x0a, 0x09, 0x54, 0x75, 0x74, 0x6f, 0x72, 0x69, 0x61, 0x6c, 0x73, 0x12, + 0x65, 0x72, 0x1a, 0x54, 0x0a, 0x09, 0x54, 0x75, 0x74, 0x6f, 0x72, 0x69, 0x61, 0x6c, 0x73, 0x12, 0x3d, 0x0a, 0x04, 0x73, 0x65, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x54, 0x75, 0x74, 0x6f, 0x72, 0x69, 0x61, 0x6c, 0x42, 0x0f, 0xfa, 0x42, 0x0c, 0x92, 0x01, 0x09, 0x18, 0x01, 0x22, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x04, 0x73, 0x65, 0x65, 0x6e, 0x3a, 0x08, - 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x22, 0x8a, 0x0e, 0x0a, 0x04, 0x55, 0x73, 0x65, - 0x72, 0x12, 0x43, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, - 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, - 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, - 0x10, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x00, 0x28, - 0x01, 0x52, 0x03, 0x69, 0x64, 0x73, 0x12, 0x43, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x64, 0x5f, 0x61, 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, 0x42, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x00, 0x10, 0x00, - 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x43, 0x0a, 0x0a, 0x75, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 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, 0x42, 0x08, 0xf2, 0xaa, 0x19, - 0x04, 0x08, 0x00, 0x10, 0x00, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, - 0x12, 0x43, 0x0a, 0x0a, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x13, - 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, - 0x42, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x00, 0x52, 0x09, 0x64, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1b, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x18, 0x32, 0x52, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x12, 0x2a, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0xd0, - 0x0f, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x7b, - 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, - 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, - 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x35, 0xfa, 0x42, 0x32, 0x9a, 0x01, 0x2f, - 0x10, 0x0a, 0x22, 0x24, 0x72, 0x22, 0x18, 0x24, 0x32, 0x1e, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x30, - 0x2d, 0x39, 0x5d, 0x28, 0x3f, 0x3a, 0x5b, 0x2d, 0x5d, 0x3f, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, - 0x39, 0x5d, 0x29, 0x7b, 0x32, 0x2c, 0x7d, 0x24, 0x2a, 0x05, 0x72, 0x03, 0x18, 0xc8, 0x01, 0x52, - 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x4a, 0x0a, 0x0c, 0x63, - 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x07, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, - 0x76, 0x33, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x42, 0x0a, - 0xfa, 0x42, 0x05, 0x92, 0x01, 0x02, 0x10, 0x0a, 0x18, 0x01, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, - 0x61, 0x63, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3b, 0x0a, 0x15, 0x70, 0x72, 0x69, 0x6d, 0x61, - 0x72, 0x79, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x60, 0x01, 0x52, - 0x13, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x12, 0x66, 0x0a, 0x22, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, - 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x76, 0x61, - 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x09, 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, 0x1e, 0x70, 0x72, - 0x69, 0x6d, 0x61, 0x72, 0x79, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x24, 0x0a, 0x08, - 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, - 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0xe8, 0x07, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, - 0x72, 0x64, 0x12, 0x54, 0x0a, 0x13, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x75, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x0b, 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, 0x42, 0x08, 0xf2, 0xaa, 0x19, - 0x04, 0x08, 0x01, 0x10, 0x00, 0x52, 0x11, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x36, 0x0a, 0x17, 0x72, 0x65, 0x71, 0x75, - 0x69, 0x72, 0x65, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x75, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x72, 0x65, 0x71, 0x75, 0x69, - 0x72, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x12, 0x35, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x15, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, - 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, - 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x35, 0x0a, 0x11, 0x73, 0x74, 0x61, 0x74, 0x65, - 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x14, 0x20, 0x01, - 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0x80, 0x01, 0x52, 0x10, 0x73, 0x74, - 0x61, 0x74, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, - 0x0a, 0x05, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x61, - 0x64, 0x6d, 0x69, 0x6e, 0x12, 0x37, 0x0a, 0x12, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, - 0x79, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, - 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0xe8, 0x07, 0x52, 0x11, 0x74, 0x65, 0x6d, 0x70, - 0x6f, 0x72, 0x61, 0x72, 0x79, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x67, 0x0a, - 0x1d, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, 0x79, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, - 0x6f, 0x72, 0x64, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x10, + 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, + 0x10, 0x01, 0x22, 0x8a, 0x0e, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x43, 0x0a, 0x03, 0x69, + 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, + 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x10, 0xfa, 0x42, 0x05, 0x8a, 0x01, + 0x02, 0x10, 0x01, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x00, 0x28, 0x01, 0x52, 0x03, 0x69, 0x64, 0x73, + 0x12, 0x43, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 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, - 0x42, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x00, 0x52, 0x1a, 0x74, 0x65, 0x6d, 0x70, - 0x6f, 0x72, 0x61, 0x72, 0x79, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x67, 0x0a, 0x1d, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, - 0x61, 0x72, 0x79, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x65, 0x78, 0x70, - 0x69, 0x72, 0x65, 0x73, 0x5f, 0x61, 0x74, 0x18, 0x11, 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, 0x42, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, - 0x01, 0x10, 0x00, 0x52, 0x1a, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, 0x79, 0x50, 0x61, - 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x12, - 0x40, 0x0a, 0x0f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x69, 0x63, 0x74, 0x75, - 0x72, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, - 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x50, 0x69, 0x63, 0x74, 0x75, 0x72, - 0x65, 0x52, 0x0e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x69, 0x63, 0x74, 0x75, 0x72, - 0x65, 0x12, 0x57, 0x0a, 0x13, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x5f, 0x70, 0x72, 0x65, - 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, - 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, - 0x55, 0x73, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x50, 0x72, 0x65, 0x66, 0x65, - 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x12, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x50, - 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x72, 0x0a, 0x1e, 0x65, 0x6d, - 0x61, 0x69, 0x6c, 0x5f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x5f, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x1a, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, - 0x2e, 0x76, 0x33, 0x2e, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, - 0x52, 0x1c, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x40, - 0x0a, 0x10, 0x75, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, 0x5f, 0x72, 0x69, 0x67, 0x68, - 0x74, 0x73, 0x18, 0x1b, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, - 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x69, 0x67, 0x68, 0x74, 0x52, - 0x0f, 0x75, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, 0x52, 0x69, 0x67, 0x68, 0x74, 0x73, - 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x3a, - 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x4a, 0x04, 0x08, 0x15, 0x10, 0x16, 0x4a, - 0x04, 0x08, 0x16, 0x10, 0x17, 0x4a, 0x04, 0x08, 0x17, 0x10, 0x18, 0x4a, 0x04, 0x08, 0x18, 0x10, - 0x19, 0x52, 0x11, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, - 0x69, 0x6d, 0x69, 0x74, 0x52, 0x0c, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x6c, 0x69, 0x6d, - 0x69, 0x74, 0x52, 0x0d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x5f, 0x6c, 0x69, 0x6d, 0x69, - 0x74, 0x52, 0x12, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, - 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x33, 0x0a, 0x05, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x2a, - 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, - 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, - 0x73, 0x65, 0x72, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x22, 0x91, 0x01, 0x0a, 0x0e, 0x47, - 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, - 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, - 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, - 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, - 0x49, 0x64, 0x73, 0x12, 0x39, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, - 0x6b, 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, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, - 0x61, 0x73, 0x6b, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0xce, - 0x02, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, - 0x6b, 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, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, - 0x61, 0x73, 0x6b, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x12, 0xa6, - 0x01, 0x0a, 0x05, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x8f, - 0x01, 0xfa, 0x42, 0x8b, 0x01, 0x72, 0x88, 0x01, 0x52, 0x00, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, - 0x5f, 0x69, 0x64, 0x52, 0x08, 0x2d, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x52, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x52, 0x05, 0x2d, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x15, 0x70, 0x72, 0x69, 0x6d, - 0x61, 0x72, 0x79, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x52, 0x16, 0x2d, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x65, 0x6d, 0x61, 0x69, - 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, - 0x52, 0x06, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x52, - 0x06, 0x2d, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, - 0x5f, 0x61, 0x74, 0x52, 0x0b, 0x2d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, - 0x52, 0x05, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x2a, 0x03, 0x18, 0xe8, 0x07, - 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x67, 0x65, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x64, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x64, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x22, - 0x72, 0x0a, 0x11, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x32, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, - 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, - 0x10, 0x01, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x29, 0x0a, 0x10, 0x69, 0x6e, 0x76, 0x69, - 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0f, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, - 0x6b, 0x65, 0x6e, 0x22, 0x82, 0x01, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, - 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x32, 0x0a, 0x04, 0x75, 0x73, 0x65, - 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, - 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x42, 0x08, 0xfa, - 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x39, 0x0a, + 0x42, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x00, 0x10, 0x00, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x43, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, + 0x5f, 0x61, 0x74, 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, 0x42, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x00, 0x10, 0x00, 0x52, + 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x43, 0x0a, 0x0a, 0x64, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x13, 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, 0x42, 0x08, 0xf2, 0xaa, 0x19, 0x04, + 0x08, 0x01, 0x10, 0x00, 0x52, 0x09, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, + 0x1b, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, + 0x42, 0x04, 0x72, 0x02, 0x18, 0x32, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2a, 0x0a, 0x0b, + 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0xd0, 0x0f, 0x52, 0x0b, 0x64, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x7b, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x74, + 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, + 0x65, 0x72, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x42, 0x35, 0xfa, 0x42, 0x32, 0x9a, 0x01, 0x2f, 0x10, 0x0a, 0x22, 0x24, 0x72, 0x22, + 0x18, 0x24, 0x32, 0x1e, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x28, 0x3f, 0x3a, + 0x5b, 0x2d, 0x5d, 0x3f, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x29, 0x7b, 0x32, 0x2c, + 0x7d, 0x24, 0x2a, 0x05, 0x72, 0x03, 0x18, 0xc8, 0x01, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, + 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x4a, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, + 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x74, + 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x43, 0x6f, 0x6e, + 0x74, 0x61, 0x63, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x42, 0x0a, 0xfa, 0x42, 0x05, 0x92, 0x01, 0x02, + 0x10, 0x0a, 0x18, 0x01, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x49, 0x6e, 0x66, + 0x6f, 0x12, 0x3b, 0x0a, 0x15, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x65, 0x6d, 0x61, + 0x69, 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, + 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x60, 0x01, 0x52, 0x13, 0x70, 0x72, 0x69, 0x6d, 0x61, + 0x72, 0x79, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x66, + 0x0a, 0x22, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x5f, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, + 0x64, 0x5f, 0x61, 0x74, 0x18, 0x09, 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, 0x1e, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x45, + 0x6d, 0x61, 0x69, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x56, 0x61, 0x6c, 0x69, 0x64, + 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x24, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, + 0x72, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, + 0xe8, 0x07, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x54, 0x0a, 0x13, + 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, + 0x5f, 0x61, 0x74, 0x18, 0x0b, 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, 0x42, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x00, 0x52, + 0x11, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, + 0x41, 0x74, 0x12, 0x36, 0x0a, 0x17, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x5f, 0x70, 0x61, + 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x0c, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x15, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x50, 0x61, 0x73, 0x73, + 0x77, 0x6f, 0x72, 0x64, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x35, 0x0a, 0x05, 0x73, 0x74, + 0x61, 0x74, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x74, 0x74, 0x6e, 0x2e, + 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, + 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, + 0x65, 0x12, 0x35, 0x0a, 0x11, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, + 0x05, 0x72, 0x03, 0x18, 0x80, 0x01, 0x52, 0x10, 0x73, 0x74, 0x61, 0x74, 0x65, 0x44, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x12, 0x37, + 0x0a, 0x12, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, 0x79, 0x5f, 0x70, 0x61, 0x73, 0x73, + 0x77, 0x6f, 0x72, 0x64, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, + 0x03, 0x18, 0xe8, 0x07, 0x52, 0x11, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, 0x79, 0x50, + 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x67, 0x0a, 0x1d, 0x74, 0x65, 0x6d, 0x70, 0x6f, + 0x72, 0x61, 0x72, 0x79, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x10, 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, 0x42, 0x08, 0xf2, 0xaa, 0x19, 0x04, + 0x08, 0x01, 0x10, 0x00, 0x52, 0x1a, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, 0x79, 0x50, + 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, + 0x12, 0x67, 0x0a, 0x1d, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, 0x79, 0x5f, 0x70, 0x61, + 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x61, + 0x74, 0x18, 0x11, 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, 0x42, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x00, 0x52, 0x1a, 0x74, + 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, 0x79, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, + 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x12, 0x40, 0x0a, 0x0f, 0x70, 0x72, 0x6f, + 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x69, 0x63, 0x74, 0x75, 0x72, 0x65, 0x18, 0x12, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, + 0x2e, 0x76, 0x33, 0x2e, 0x50, 0x69, 0x63, 0x74, 0x75, 0x72, 0x65, 0x52, 0x0e, 0x70, 0x72, 0x6f, + 0x66, 0x69, 0x6c, 0x65, 0x50, 0x69, 0x63, 0x74, 0x75, 0x72, 0x65, 0x12, 0x57, 0x0a, 0x13, 0x63, + 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, + 0x65, 0x73, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, + 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x43, 0x6f, + 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, + 0x52, 0x12, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, + 0x6e, 0x63, 0x65, 0x73, 0x12, 0x72, 0x0a, 0x1e, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x5f, 0x6e, 0x6f, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x65, + 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x74, + 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x45, 0x6d, + 0x61, 0x69, 0x6c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, + 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x1c, 0x65, 0x6d, 0x61, 0x69, + 0x6c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x65, + 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x40, 0x0a, 0x10, 0x75, 0x6e, 0x69, 0x76, + 0x65, 0x72, 0x73, 0x61, 0x6c, 0x5f, 0x72, 0x69, 0x67, 0x68, 0x74, 0x73, 0x18, 0x1b, 0x20, 0x03, + 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, + 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x69, 0x67, 0x68, 0x74, 0x52, 0x0f, 0x75, 0x6e, 0x69, 0x76, 0x65, + 0x72, 0x73, 0x61, 0x6c, 0x52, 0x69, 0x67, 0x68, 0x74, 0x73, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, + 0x01, 0x10, 0x01, 0x4a, 0x04, 0x08, 0x15, 0x10, 0x16, 0x4a, 0x04, 0x08, 0x16, 0x10, 0x17, 0x4a, + 0x04, 0x08, 0x17, 0x10, 0x18, 0x4a, 0x04, 0x08, 0x18, 0x10, 0x19, 0x52, 0x11, 0x61, 0x70, 0x70, + 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x0c, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x0d, 0x67, 0x61, + 0x74, 0x65, 0x77, 0x61, 0x79, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x12, 0x6f, 0x72, 0x67, + 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, + 0x33, 0x0a, 0x05, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x2a, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, + 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x05, 0x75, + 0x73, 0x65, 0x72, 0x73, 0x22, 0x91, 0x01, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, + 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, + 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, + 0x01, 0x02, 0x10, 0x01, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x39, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 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, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x09, 0x66, - 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0x66, 0x0a, 0x1e, 0x43, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, 0x79, 0x50, 0x61, 0x73, 0x73, 0x77, - 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x08, 0x75, 0x73, - 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, + 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0xce, 0x02, 0x0a, 0x10, 0x4c, 0x69, 0x73, + 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x39, 0x0a, + 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 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, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x09, 0x66, + 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x12, 0xa6, 0x01, 0x0a, 0x05, 0x6f, 0x72, 0x64, + 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x8f, 0x01, 0xfa, 0x42, 0x8b, 0x01, 0x72, + 0x88, 0x01, 0x52, 0x00, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x52, 0x08, 0x2d, + 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x05, 0x2d, + 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x15, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x65, 0x6d, + 0x61, 0x69, 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x16, 0x2d, 0x70, 0x72, + 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x52, 0x06, 0x2d, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x52, 0x05, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x52, 0x06, 0x2d, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x52, 0x0b, 0x2d, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x52, 0x05, 0x6f, 0x72, 0x64, 0x65, + 0x72, 0x12, 0x1e, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, + 0x42, 0x08, 0xfa, 0x42, 0x05, 0x2a, 0x03, 0x18, 0xe8, 0x07, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, + 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x04, 0x70, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x3a, + 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x22, 0x72, 0x0a, 0x11, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x32, + 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, - 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, - 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, - 0x22, 0xc5, 0x01, 0x0a, 0x19, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, - 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, - 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, - 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, - 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x07, 0x75, 0x73, 0x65, - 0x72, 0x49, 0x64, 0x73, 0x12, 0x1a, 0x0a, 0x03, 0x6e, 0x65, 0x77, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0xe8, 0x07, 0x52, 0x03, 0x6e, 0x65, 0x77, - 0x12, 0x1a, 0x0a, 0x03, 0x6f, 0x6c, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, - 0x42, 0x05, 0x72, 0x03, 0x18, 0xe8, 0x07, 0x52, 0x03, 0x6f, 0x6c, 0x64, 0x12, 0x2a, 0x0a, 0x11, - 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x5f, 0x61, 0x6c, 0x6c, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x41, - 0x6c, 0x6c, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x93, 0x02, 0x0a, 0x16, 0x4c, 0x69, 0x73, - 0x74, 0x55, 0x73, 0x65, 0x72, 0x41, 0x50, 0x49, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, - 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, - 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x75, 0x0a, 0x05, 0x6f, 0x72, 0x64, - 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x5f, 0xfa, 0x42, 0x5c, 0x72, 0x5a, 0x52, - 0x00, 0x52, 0x0a, 0x61, 0x70, 0x69, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x52, 0x0b, 0x2d, - 0x61, 0x70, 0x69, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x52, 0x05, 0x2d, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, - 0x5f, 0x61, 0x74, 0x52, 0x0b, 0x2d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, - 0x52, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x61, 0x74, 0x52, 0x0b, 0x2d, 0x65, - 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x61, 0x74, 0x52, 0x05, 0x6f, 0x72, 0x64, 0x65, 0x72, - 0x12, 0x1e, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x42, - 0x08, 0xfa, 0x42, 0x05, 0x2a, 0x03, 0x18, 0xe8, 0x07, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, - 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, - 0x70, 0x61, 0x67, 0x65, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x00, 0x10, 0x01, 0x22, 0x73, - 0x0a, 0x14, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x41, 0x50, 0x49, 0x4b, 0x65, 0x79, 0x52, + 0x65, 0x72, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x04, 0x75, 0x73, + 0x65, 0x72, 0x12, 0x29, 0x0a, 0x10, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x69, 0x6e, + 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x82, 0x01, + 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x32, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, + 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, + 0x01, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x39, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, + 0x5f, 0x6d, 0x61, 0x73, 0x6b, 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, 0x46, 0x69, + 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, + 0x73, 0x6b, 0x22, 0x66, 0x0a, 0x1e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x65, 0x6d, 0x70, + 0x6f, 0x72, 0x61, 0x72, 0x79, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, + 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, + 0x01, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x22, 0xc5, 0x01, 0x0a, 0x19, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, + 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, + 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, + 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, + 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, + 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x1a, + 0x0a, 0x03, 0x6e, 0x65, 0x77, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, + 0x72, 0x03, 0x18, 0xe8, 0x07, 0x52, 0x03, 0x6e, 0x65, 0x77, 0x12, 0x1a, 0x0a, 0x03, 0x6f, 0x6c, + 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0xe8, + 0x07, 0x52, 0x03, 0x6f, 0x6c, 0x64, 0x12, 0x2a, 0x0a, 0x11, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, + 0x5f, 0x61, 0x6c, 0x6c, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x0f, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x41, 0x6c, 0x6c, 0x41, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x22, 0x93, 0x02, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x41, + 0x50, 0x49, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, + 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, + 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, + 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, + 0x49, 0x64, 0x73, 0x12, 0x75, 0x0a, 0x05, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x5f, 0xfa, 0x42, 0x5c, 0x72, 0x5a, 0x52, 0x00, 0x52, 0x0a, 0x61, 0x70, 0x69, + 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x52, 0x0b, 0x2d, 0x61, 0x70, 0x69, 0x5f, 0x6b, 0x65, + 0x79, 0x5f, 0x69, 0x64, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x05, 0x2d, 0x6e, 0x61, 0x6d, + 0x65, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x52, 0x0b, 0x2d, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x70, 0x69, + 0x72, 0x65, 0x73, 0x5f, 0x61, 0x74, 0x52, 0x0b, 0x2d, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, + 0x5f, 0x61, 0x74, 0x52, 0x05, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x05, 0x6c, 0x69, + 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x2a, 0x03, + 0x18, 0xe8, 0x07, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, + 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, 0x3a, 0x08, + 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x00, 0x10, 0x01, 0x22, 0x73, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x55, + 0x73, 0x65, 0x72, 0x41, 0x50, 0x49, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, + 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, + 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x07, 0x75, + 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x15, 0x0a, 0x06, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6b, 0x65, 0x79, 0x49, 0x64, 0x22, 0x83, 0x02, + 0x0a, 0x17, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x41, 0x50, 0x49, 0x4b, + 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, + 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, + 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, + 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, + 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, + 0x1b, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, + 0x42, 0x04, 0x72, 0x02, 0x18, 0x32, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x40, 0x0a, 0x06, + 0x72, 0x69, 0x67, 0x68, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x74, + 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x69, + 0x67, 0x68, 0x74, 0x42, 0x11, 0xfa, 0x42, 0x0e, 0x92, 0x01, 0x0b, 0x08, 0x01, 0x18, 0x01, 0x22, + 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x06, 0x72, 0x69, 0x67, 0x68, 0x74, 0x73, 0x12, 0x43, + 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x61, 0x74, 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, 0x42, 0x08, + 0xfa, 0x42, 0x05, 0xb2, 0x01, 0x02, 0x40, 0x01, 0x52, 0x09, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, + 0x73, 0x41, 0x74, 0x22, 0xd5, 0x01, 0x0a, 0x17, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, + 0x65, 0x72, 0x41, 0x50, 0x49, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, + 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, + 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x07, 0x75, 0x73, + 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x39, 0x0a, 0x07, 0x61, 0x70, 0x69, 0x5f, 0x6b, 0x65, 0x79, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, + 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x50, 0x49, 0x4b, 0x65, 0x79, 0x42, 0x08, + 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x06, 0x61, 0x70, 0x69, 0x4b, 0x65, 0x79, + 0x12, 0x39, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 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, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, + 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0x76, 0x0a, 0x17, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x41, 0x50, 0x49, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x15, 0x0a, 0x06, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6b, 0x65, - 0x79, 0x49, 0x64, 0x22, 0x83, 0x02, 0x0a, 0x17, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, - 0x65, 0x72, 0x41, 0x50, 0x49, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x79, 0x49, 0x64, 0x22, 0xf1, 0x02, 0x0a, 0x0a, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x60, 0x01, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, + 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x39, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, + 0x65, 0x73, 0x5f, 0x61, 0x74, 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, 0x09, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, + 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, + 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, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, + 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x05, 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, 0x75, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x3b, 0x0a, 0x0b, 0x61, 0x63, 0x63, 0x65, + 0x70, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x06, 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, 0x0a, 0x61, 0x63, 0x63, 0x65, 0x70, + 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x40, 0x0a, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, + 0x64, 0x5f, 0x62, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, + 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, + 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x52, 0x0a, 0x61, 0x63, 0x63, + 0x65, 0x70, 0x74, 0x65, 0x64, 0x42, 0x79, 0x22, 0x4c, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x49, + 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1e, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, + 0x42, 0x08, 0xfa, 0x42, 0x05, 0x2a, 0x03, 0x18, 0xe8, 0x07, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, + 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x04, 0x70, 0x61, 0x67, 0x65, 0x22, 0x4b, 0x0a, 0x0b, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x3c, 0x0a, 0x0b, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, + 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x49, 0x6e, 0x76, 0x69, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x22, 0x36, 0x0a, 0x15, 0x53, 0x65, 0x6e, 0x64, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x05, 0x65, + 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, + 0x02, 0x60, 0x01, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x38, 0x0a, 0x17, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x60, 0x01, 0x52, 0x05, 0x65, + 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x86, 0x01, 0x0a, 0x16, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x12, 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x07, 0x75, 0x73, - 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x1b, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x18, 0x32, 0x52, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x12, 0x40, 0x0a, 0x06, 0x72, 0x69, 0x67, 0x68, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, - 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, - 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x69, 0x67, 0x68, 0x74, 0x42, 0x11, 0xfa, 0x42, 0x0e, 0x92, 0x01, - 0x0b, 0x08, 0x01, 0x18, 0x01, 0x22, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x06, 0x72, 0x69, - 0x67, 0x68, 0x74, 0x73, 0x12, 0x43, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x5f, - 0x61, 0x74, 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, 0x42, 0x08, 0xfa, 0x42, 0x05, 0xb2, 0x01, 0x02, 0x40, 0x01, 0x52, 0x09, - 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x22, 0xd5, 0x01, 0x0a, 0x17, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x41, 0x50, 0x49, 0x4b, 0x65, 0x79, 0x52, 0x65, + 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x26, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, + 0x18, 0x40, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0xd3, 0x02, + 0x0a, 0x0b, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x44, 0x0a, + 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, + 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, + 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, + 0x49, 0x64, 0x73, 0x12, 0x26, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, + 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x18, 0x40, + 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x39, 0x0a, 0x0a, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 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, 0x09, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x64, 0x5f, 0x61, 0x74, 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, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, + 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x61, 0x74, 0x18, + 0x05, 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, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x12, 0x25, 0x0a, 0x0e, + 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x63, + 0x72, 0x65, 0x74, 0x22, 0x47, 0x0a, 0x0c, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x12, 0x37, 0x0a, 0x08, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, + 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x52, 0x08, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xcb, 0x01, 0x0a, + 0x17, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, + 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, + 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, + 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, + 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x36, + 0x0a, 0x05, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x20, 0xfa, + 0x42, 0x1d, 0x72, 0x1b, 0x52, 0x00, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, + 0x61, 0x74, 0x52, 0x0b, 0x2d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x52, + 0x05, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x2a, 0x03, 0x18, 0xe8, 0x07, 0x52, + 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x67, 0x65, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, 0x22, 0xad, 0x02, 0x0a, 0x0a, 0x4c, + 0x6f, 0x67, 0x69, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, + 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, + 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, + 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, + 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, + 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 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, + 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 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, 0x09, 0x75, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, + 0x5f, 0x61, 0x74, 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, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, + 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x64, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x75, 0x73, 0x65, 0x64, 0x22, 0x7e, 0x0a, 0x17, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, - 0x10, 0x01, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x39, 0x0a, 0x07, 0x61, - 0x70, 0x69, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x74, - 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x50, - 0x49, 0x4b, 0x65, 0x79, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x06, - 0x61, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x12, 0x39, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, - 0x6d, 0x61, 0x73, 0x6b, 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, 0x46, 0x69, 0x65, - 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, - 0x6b, 0x22, 0x76, 0x0a, 0x17, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x41, - 0x50, 0x49, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x08, - 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, - 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, - 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, - 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, - 0x64, 0x73, 0x12, 0x15, 0x0a, 0x06, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x6b, 0x65, 0x79, 0x49, 0x64, 0x22, 0xf1, 0x02, 0x0a, 0x0a, 0x49, 0x6e, - 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, - 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x60, 0x01, - 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x39, 0x0a, - 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x61, 0x74, 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, 0x09, 0x65, - 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 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, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, - 0x74, 0x18, 0x05, 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, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x3b, - 0x0a, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x06, 0x20, + 0x10, 0x01, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x73, + 0x6b, 0x69, 0x70, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x09, 0x73, 0x6b, 0x69, 0x70, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x30, 0x0a, 0x18, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xdb, 0x01, 0x0a, + 0x0c, 0x55, 0x73, 0x65, 0x72, 0x42, 0x6f, 0x6f, 0x6b, 0x6d, 0x61, 0x72, 0x6b, 0x12, 0x44, 0x0a, + 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, + 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, + 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, + 0x49, 0x64, 0x73, 0x12, 0x4a, 0x0a, 0x0a, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, + 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, + 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, + 0x01, 0x02, 0x10, 0x01, 0x52, 0x09, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x64, 0x73, 0x12, + 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 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, - 0x0a, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x40, 0x0a, 0x0b, 0x61, - 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, - 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, - 0x73, 0x52, 0x0a, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x42, 0x79, 0x22, 0x4c, 0x0a, - 0x16, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x2a, 0x03, 0x18, 0xe8, 0x07, - 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x67, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, 0x22, 0x4b, 0x0a, 0x0b, 0x49, - 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x3c, 0x0a, 0x0b, 0x69, 0x6e, - 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x1a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, - 0x2e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x69, 0x6e, 0x76, - 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x36, 0x0a, 0x15, 0x53, 0x65, 0x6e, 0x64, - 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x1d, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x60, 0x01, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, - 0x22, 0x38, 0x0a, 0x17, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x05, 0x65, - 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, - 0x02, 0x60, 0x01, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x86, 0x01, 0x0a, 0x16, 0x55, - 0x73, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x66, 0x69, 0x65, 0x72, 0x73, 0x12, 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, + 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x4b, 0x0a, 0x0d, 0x55, 0x73, + 0x65, 0x72, 0x42, 0x6f, 0x6f, 0x6b, 0x6d, 0x61, 0x72, 0x6b, 0x73, 0x12, 0x3a, 0x0a, 0x09, 0x62, + 0x6f, 0x6f, 0x6b, 0x6d, 0x61, 0x72, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, + 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, + 0x55, 0x73, 0x65, 0x72, 0x42, 0x6f, 0x6f, 0x6b, 0x6d, 0x61, 0x72, 0x6b, 0x52, 0x09, 0x62, 0x6f, + 0x6f, 0x6b, 0x6d, 0x61, 0x72, 0x6b, 0x73, 0x22, 0xad, 0x01, 0x0a, 0x19, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x42, 0x6f, 0x6f, 0x6b, 0x6d, 0x61, 0x72, 0x6b, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, - 0x10, 0x01, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x26, 0x0a, 0x0a, 0x73, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, - 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x18, 0x40, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x49, 0x64, 0x22, 0xd3, 0x02, 0x0a, 0x0b, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x12, 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, - 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, - 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x26, 0x0a, 0x0a, 0x73, 0x65, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, - 0x42, 0x04, 0x72, 0x02, 0x18, 0x40, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, - 0x64, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 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, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, - 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 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, 0x75, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, - 0x65, 0x73, 0x5f, 0x61, 0x74, 0x18, 0x05, 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, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, - 0x41, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x65, - 0x63, 0x72, 0x65, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x65, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x22, 0x47, 0x0a, 0x0c, 0x55, 0x73, 0x65, - 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x37, 0x0a, 0x08, 0x73, 0x65, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x74, - 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, - 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x73, 0x22, 0xcb, 0x01, 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x53, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, - 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, - 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, - 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x07, 0x75, 0x73, 0x65, - 0x72, 0x49, 0x64, 0x73, 0x12, 0x36, 0x0a, 0x05, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x42, 0x20, 0xfa, 0x42, 0x1d, 0x72, 0x1b, 0x52, 0x00, 0x52, 0x0a, 0x63, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x52, 0x0b, 0x2d, 0x63, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x64, 0x5f, 0x61, 0x74, 0x52, 0x05, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x05, - 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x08, 0xfa, 0x42, 0x05, - 0x2a, 0x03, 0x18, 0xe8, 0x07, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x12, 0x0a, 0x04, - 0x70, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, - 0x22, 0xad, 0x02, 0x0a, 0x0a, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, - 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, - 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, - 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x07, 0x75, 0x73, - 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, - 0x5f, 0x61, 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, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, - 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 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, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x65, - 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x61, 0x74, 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, 0x65, 0x78, 0x70, - 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x12, 0x0a, 0x04, - 0x75, 0x73, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x75, 0x73, 0x65, 0x64, - 0x22, 0x7e, 0x0a, 0x17, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x54, - 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x08, 0x75, - 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, - 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, - 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, - 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, - 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x6b, 0x69, 0x70, 0x45, 0x6d, 0x61, 0x69, 0x6c, - 0x22, 0x30, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x54, - 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, - 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, - 0x65, 0x6e, 0x22, 0xdb, 0x01, 0x0a, 0x0c, 0x55, 0x73, 0x65, 0x72, 0x42, 0x6f, 0x6f, 0x6b, 0x6d, - 0x61, 0x72, 0x6b, 0x12, 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, - 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, - 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x4a, 0x0a, 0x0a, 0x65, 0x6e, 0x74, - 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, - 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x45, - 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, - 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x09, 0x65, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x49, 0x64, 0x73, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, - 0x5f, 0x61, 0x74, 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, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, - 0x22, 0x4b, 0x0a, 0x0d, 0x55, 0x73, 0x65, 0x72, 0x42, 0x6f, 0x6f, 0x6b, 0x6d, 0x61, 0x72, 0x6b, - 0x73, 0x12, 0x3a, 0x0a, 0x09, 0x62, 0x6f, 0x6f, 0x6b, 0x6d, 0x61, 0x72, 0x6b, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, - 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x42, 0x6f, 0x6f, 0x6b, 0x6d, 0x61, - 0x72, 0x6b, 0x52, 0x09, 0x62, 0x6f, 0x6f, 0x6b, 0x6d, 0x61, 0x72, 0x6b, 0x73, 0x22, 0xad, 0x01, - 0x0a, 0x19, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x42, 0x6f, 0x6f, 0x6b, - 0x6d, 0x61, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x08, 0x75, - 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, - 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, - 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, - 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, - 0x73, 0x12, 0x4a, 0x0a, 0x0a, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, 0x73, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, - 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, - 0x10, 0x01, 0x52, 0x09, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x64, 0x73, 0x22, 0xa4, 0x03, - 0x0a, 0x18, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x42, 0x6f, 0x6f, 0x6b, 0x6d, 0x61, - 0x72, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x08, 0x75, 0x73, - 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, - 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, - 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, - 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, - 0x12, 0x1e, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x42, - 0x08, 0xfa, 0x42, 0x05, 0x2a, 0x03, 0x18, 0xe8, 0x07, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, - 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, - 0x70, 0x61, 0x67, 0x65, 0x12, 0x7b, 0x0a, 0x05, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x09, 0x42, 0x65, 0xfa, 0x42, 0x62, 0x72, 0x60, 0x52, 0x00, 0x52, 0x07, 0x75, 0x73, - 0x65, 0x72, 0x5f, 0x69, 0x64, 0x52, 0x08, 0x2d, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x52, - 0x0b, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x52, 0x0c, 0x2d, 0x65, - 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x52, 0x09, 0x65, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x5f, 0x69, 0x64, 0x52, 0x0a, 0x2d, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x69, - 0x64, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x52, 0x0b, 0x2d, - 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x52, 0x05, 0x6f, 0x72, 0x64, 0x65, - 0x72, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x6d, 0x0a, 0x0c, 0x65, - 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, - 0x09, 0x42, 0x4a, 0xfa, 0x42, 0x47, 0x92, 0x01, 0x44, 0x18, 0x01, 0x22, 0x40, 0x72, 0x3e, 0x52, - 0x0b, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x63, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x52, 0x0a, 0x65, 0x6e, 0x64, 0x20, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, - 0x52, 0x07, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x52, 0x0c, 0x6f, 0x72, 0x67, 0x61, 0x6e, - 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x52, 0x0b, 0x65, - 0x6e, 0x74, 0x69, 0x74, 0x79, 0x54, 0x79, 0x70, 0x65, 0x73, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, - 0x08, 0x00, 0x10, 0x01, 0x22, 0xad, 0x01, 0x0a, 0x19, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, - 0x73, 0x65, 0x72, 0x42, 0x6f, 0x6f, 0x6b, 0x6d, 0x61, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x10, 0x01, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x4a, 0x0a, 0x0a, 0x65, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x21, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, + 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, + 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x09, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x49, 0x64, 0x73, 0x22, 0xa4, 0x03, 0x0a, 0x18, 0x4c, 0x69, 0x73, 0x74, + 0x55, 0x73, 0x65, 0x72, 0x42, 0x6f, 0x6f, 0x6b, 0x6d, 0x61, 0x72, 0x6b, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, + 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, + 0x01, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x1e, 0x0a, 0x05, 0x6c, 0x69, + 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x2a, 0x03, + 0x18, 0xe8, 0x07, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, + 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, 0x12, 0x7b, + 0x0a, 0x05, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x65, 0xfa, + 0x42, 0x62, 0x72, 0x60, 0x52, 0x00, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x52, + 0x08, 0x2d, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x52, 0x0b, 0x65, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x52, 0x0c, 0x2d, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, + 0x74, 0x79, 0x70, 0x65, 0x52, 0x09, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, 0x52, + 0x0a, 0x2d, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, 0x52, 0x0a, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x52, 0x0b, 0x2d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x64, 0x5f, 0x61, 0x74, 0x52, 0x05, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x64, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x6d, 0x0a, 0x0c, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, + 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x42, 0x4a, 0xfa, 0x42, 0x47, + 0x92, 0x01, 0x44, 0x18, 0x01, 0x22, 0x40, 0x72, 0x3e, 0x52, 0x0b, 0x61, 0x70, 0x70, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x0a, + 0x65, 0x6e, 0x64, 0x20, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x07, 0x67, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x52, 0x0c, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x52, 0x0b, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x54, + 0x79, 0x70, 0x65, 0x73, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x00, 0x10, 0x01, 0x22, 0xad, + 0x01, 0x0a, 0x19, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x42, 0x6f, 0x6f, + 0x6b, 0x6d, 0x61, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x08, + 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, + 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, + 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, + 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, + 0x64, 0x73, 0x12, 0x4a, 0x0a, 0x0a, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, 0x73, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, + 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, + 0x02, 0x10, 0x01, 0x52, 0x09, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x64, 0x73, 0x22, 0xb5, + 0x01, 0x0a, 0x1f, 0x42, 0x61, 0x74, 0x63, 0x68, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, + 0x65, 0x72, 0x42, 0x6f, 0x6f, 0x6b, 0x6d, 0x61, 0x72, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, - 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x4a, 0x0a, 0x0a, 0x65, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, + 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x4c, 0x0a, 0x0a, 0x65, 0x6e, 0x74, 0x69, + 0x74, 0x79, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, - 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x09, 0x65, 0x6e, 0x74, 0x69, 0x74, - 0x79, 0x49, 0x64, 0x73, 0x22, 0xb5, 0x01, 0x0a, 0x1f, 0x42, 0x61, 0x74, 0x63, 0x68, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x42, 0x6f, 0x6f, 0x6b, 0x6d, 0x61, 0x72, 0x6b, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, - 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, - 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, - 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, - 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x4c, - 0x0a, 0x0a, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, - 0x2e, 0x76, 0x33, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x0a, 0xfa, 0x42, 0x07, 0x92, 0x01, 0x04, 0x08, 0x01, 0x10, - 0x14, 0x52, 0x09, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x64, 0x73, 0x2a, 0x70, 0x0a, 0x0c, - 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x54, 0x68, 0x65, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x14, - 0x43, 0x4f, 0x4e, 0x53, 0x4f, 0x4c, 0x45, 0x5f, 0x54, 0x48, 0x45, 0x4d, 0x45, 0x5f, 0x53, 0x59, - 0x53, 0x54, 0x45, 0x4d, 0x10, 0x00, 0x12, 0x17, 0x0a, 0x13, 0x43, 0x4f, 0x4e, 0x53, 0x4f, 0x4c, - 0x45, 0x5f, 0x54, 0x48, 0x45, 0x4d, 0x45, 0x5f, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x10, 0x01, 0x12, - 0x16, 0x0a, 0x12, 0x43, 0x4f, 0x4e, 0x53, 0x4f, 0x4c, 0x45, 0x5f, 0x54, 0x48, 0x45, 0x4d, 0x45, - 0x5f, 0x44, 0x41, 0x52, 0x4b, 0x10, 0x02, 0x1a, 0x15, 0xea, 0xaa, 0x19, 0x11, 0x18, 0x01, 0x2a, - 0x0d, 0x43, 0x4f, 0x4e, 0x53, 0x4f, 0x4c, 0x45, 0x5f, 0x54, 0x48, 0x45, 0x4d, 0x45, 0x2a, 0x4b, - 0x0a, 0x08, 0x54, 0x75, 0x74, 0x6f, 0x72, 0x69, 0x61, 0x6c, 0x12, 0x14, 0x0a, 0x10, 0x54, 0x55, - 0x54, 0x4f, 0x52, 0x49, 0x41, 0x4c, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, - 0x12, 0x21, 0x0a, 0x1d, 0x54, 0x55, 0x54, 0x4f, 0x52, 0x49, 0x41, 0x4c, 0x5f, 0x4c, 0x49, 0x56, - 0x45, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x53, 0x50, 0x4c, 0x49, 0x54, 0x5f, 0x56, 0x49, 0x45, - 0x57, 0x10, 0x01, 0x1a, 0x06, 0xea, 0xaa, 0x19, 0x02, 0x18, 0x01, 0x2a, 0x7d, 0x0a, 0x0f, 0x44, - 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x12, 0x1a, - 0x0a, 0x16, 0x44, 0x41, 0x53, 0x48, 0x42, 0x4f, 0x41, 0x52, 0x44, 0x5f, 0x4c, 0x41, 0x59, 0x4f, - 0x55, 0x54, 0x5f, 0x54, 0x41, 0x42, 0x4c, 0x45, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x44, 0x41, - 0x53, 0x48, 0x42, 0x4f, 0x41, 0x52, 0x44, 0x5f, 0x4c, 0x41, 0x59, 0x4f, 0x55, 0x54, 0x5f, 0x4c, - 0x49, 0x53, 0x54, 0x10, 0x01, 0x12, 0x19, 0x0a, 0x15, 0x44, 0x41, 0x53, 0x48, 0x42, 0x4f, 0x41, - 0x52, 0x44, 0x5f, 0x4c, 0x41, 0x59, 0x4f, 0x55, 0x54, 0x5f, 0x47, 0x52, 0x49, 0x44, 0x10, 0x02, - 0x1a, 0x18, 0xea, 0xaa, 0x19, 0x14, 0x18, 0x01, 0x2a, 0x10, 0x44, 0x41, 0x53, 0x48, 0x42, 0x4f, - 0x41, 0x52, 0x44, 0x5f, 0x4c, 0x41, 0x59, 0x4f, 0x55, 0x54, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x6f, - 0x2e, 0x74, 0x68, 0x65, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x2f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2d, 0x73, 0x74, 0x61, 0x63, 0x6b, - 0x2f, 0x76, 0x33, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x74, 0x74, 0x6e, 0x70, 0x62, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x0a, 0xfa, 0x42, 0x07, 0x92, 0x01, 0x04, 0x08, 0x01, 0x10, 0x14, 0x52, 0x09, 0x65, 0x6e, 0x74, + 0x69, 0x74, 0x79, 0x49, 0x64, 0x73, 0x2a, 0x70, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, + 0x65, 0x54, 0x68, 0x65, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x14, 0x43, 0x4f, 0x4e, 0x53, 0x4f, 0x4c, + 0x45, 0x5f, 0x54, 0x48, 0x45, 0x4d, 0x45, 0x5f, 0x53, 0x59, 0x53, 0x54, 0x45, 0x4d, 0x10, 0x00, + 0x12, 0x17, 0x0a, 0x13, 0x43, 0x4f, 0x4e, 0x53, 0x4f, 0x4c, 0x45, 0x5f, 0x54, 0x48, 0x45, 0x4d, + 0x45, 0x5f, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x10, 0x01, 0x12, 0x16, 0x0a, 0x12, 0x43, 0x4f, 0x4e, + 0x53, 0x4f, 0x4c, 0x45, 0x5f, 0x54, 0x48, 0x45, 0x4d, 0x45, 0x5f, 0x44, 0x41, 0x52, 0x4b, 0x10, + 0x02, 0x1a, 0x15, 0xea, 0xaa, 0x19, 0x11, 0x18, 0x01, 0x2a, 0x0d, 0x43, 0x4f, 0x4e, 0x53, 0x4f, + 0x4c, 0x45, 0x5f, 0x54, 0x48, 0x45, 0x4d, 0x45, 0x2a, 0x4b, 0x0a, 0x08, 0x54, 0x75, 0x74, 0x6f, + 0x72, 0x69, 0x61, 0x6c, 0x12, 0x14, 0x0a, 0x10, 0x54, 0x55, 0x54, 0x4f, 0x52, 0x49, 0x41, 0x4c, + 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x21, 0x0a, 0x1d, 0x54, 0x55, + 0x54, 0x4f, 0x52, 0x49, 0x41, 0x4c, 0x5f, 0x4c, 0x49, 0x56, 0x45, 0x5f, 0x44, 0x41, 0x54, 0x41, + 0x5f, 0x53, 0x50, 0x4c, 0x49, 0x54, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x10, 0x01, 0x1a, 0x06, 0xea, + 0xaa, 0x19, 0x02, 0x18, 0x01, 0x2a, 0x7d, 0x0a, 0x0f, 0x44, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, + 0x72, 0x64, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x12, 0x1a, 0x0a, 0x16, 0x44, 0x41, 0x53, 0x48, + 0x42, 0x4f, 0x41, 0x52, 0x44, 0x5f, 0x4c, 0x41, 0x59, 0x4f, 0x55, 0x54, 0x5f, 0x54, 0x41, 0x42, + 0x4c, 0x45, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x44, 0x41, 0x53, 0x48, 0x42, 0x4f, 0x41, 0x52, + 0x44, 0x5f, 0x4c, 0x41, 0x59, 0x4f, 0x55, 0x54, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x10, 0x01, 0x12, + 0x19, 0x0a, 0x15, 0x44, 0x41, 0x53, 0x48, 0x42, 0x4f, 0x41, 0x52, 0x44, 0x5f, 0x4c, 0x41, 0x59, + 0x4f, 0x55, 0x54, 0x5f, 0x47, 0x52, 0x49, 0x44, 0x10, 0x02, 0x1a, 0x18, 0xea, 0xaa, 0x19, 0x14, + 0x18, 0x01, 0x2a, 0x10, 0x44, 0x41, 0x53, 0x48, 0x42, 0x4f, 0x41, 0x52, 0x44, 0x5f, 0x4c, 0x41, + 0x59, 0x4f, 0x55, 0x54, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x6f, 0x2e, 0x74, 0x68, 0x65, 0x74, 0x68, + 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x6c, 0x6f, 0x72, + 0x61, 0x77, 0x61, 0x6e, 0x2d, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2f, 0x76, 0x33, 0x2f, 0x70, 0x6b, + 0x67, 0x2f, 0x74, 0x74, 0x6e, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/pkg/ttnpb/user_flags.pb.go b/pkg/ttnpb/user_flags.pb.go index dde3aa9ce5..3d8653adfc 100644 --- a/pkg/ttnpb/user_flags.pb.go +++ b/pkg/ttnpb/user_flags.pb.go @@ -12,6 +12,44 @@ import ( pflag "github.com/spf13/pflag" ) +// AddSelectFlagsForUserConsolePreferences_Tutorials adds flags to select fields in UserConsolePreferences_Tutorials. +func AddSelectFlagsForUserConsolePreferences_Tutorials(flags *pflag.FlagSet, prefix string, hidden bool) { + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("seen", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("seen", prefix), false), flagsplugin.WithHidden(hidden))) +} + +// SelectFromFlags outputs the fieldmask paths forUserConsolePreferences_Tutorials message from select flags. +func PathsFromSelectFlagsForUserConsolePreferences_Tutorials(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("seen", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("seen", prefix)) + } + return paths, nil +} + +// AddSetFlagsForUserConsolePreferences_Tutorials adds flags to select fields in UserConsolePreferences_Tutorials. +func AddSetFlagsForUserConsolePreferences_Tutorials(flags *pflag.FlagSet, prefix string, hidden bool) { + flags.AddFlag(flagsplugin.NewStringSliceFlag(flagsplugin.Prefix("seen", prefix), flagsplugin.EnumValueDesc(Tutorial_value), flagsplugin.WithHidden(hidden))) +} + +// SetFromFlags sets the UserConsolePreferences_Tutorials message from flags. +func (m *UserConsolePreferences_Tutorials) SetFromFlags(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if val, changed, err := flagsplugin.GetStringSlice(flags, flagsplugin.Prefix("seen", prefix)); err != nil { + return nil, err + } else if changed { + m.Seen = make([]Tutorial, len(val)) + for i, v := range val { + enumValue, err := flagsplugin.SetEnumString(v, Tutorial_value) + if err != nil { + return nil, err + } + m.Seen[i] = Tutorial(enumValue) + } + paths = append(paths, flagsplugin.Prefix("seen", prefix)) + } + return paths, nil +} + // AddSelectFlagsForUserConsolePreferences adds flags to select fields in UserConsolePreferences. func AddSelectFlagsForUserConsolePreferences(flags *pflag.FlagSet, prefix string, hidden bool) { flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("console-theme", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("console-theme", prefix), false), flagsplugin.WithHidden(hidden))) @@ -20,7 +58,7 @@ func AddSelectFlagsForUserConsolePreferences(flags *pflag.FlagSet, prefix string flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("sort-by", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("sort-by", prefix), true), flagsplugin.WithHidden(hidden))) // NOTE: sort_by (UserConsolePreferences_SortBy) does not seem to have select flags. flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("tutorials", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("tutorials", prefix), true), flagsplugin.WithHidden(hidden))) - // NOTE: tutorials (UserConsolePreferences_Tutorials) does not seem to have select flags. + AddSelectFlagsForUserConsolePreferences_Tutorials(flags, flagsplugin.Prefix("tutorials", prefix), hidden) } // SelectFromFlags outputs the fieldmask paths forUserConsolePreferences message from select flags. @@ -47,7 +85,11 @@ func PathsFromSelectFlagsForUserConsolePreferences(flags *pflag.FlagSet, prefix } else if selected && val { paths = append(paths, flagsplugin.Prefix("tutorials", prefix)) } - // NOTE: tutorials (UserConsolePreferences_Tutorials) does not seem to have select flags. + if selectPaths, err := PathsFromSelectFlagsForUserConsolePreferences_Tutorials(flags, flagsplugin.Prefix("tutorials", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, selectPaths...) + } return paths, nil } @@ -56,7 +98,7 @@ func AddSetFlagsForUserConsolePreferences(flags *pflag.FlagSet, prefix string, h flags.AddFlag(flagsplugin.NewStringFlag(flagsplugin.Prefix("console-theme", prefix), flagsplugin.EnumValueDesc(ConsoleTheme_value), flagsplugin.WithHidden(hidden))) // FIXME: Skipping DashboardLayouts because it does not seem to implement AddSetFlags. // FIXME: Skipping SortBy because it does not seem to implement AddSetFlags. - // FIXME: Skipping Tutorials because it does not seem to implement AddSetFlags. + AddSetFlagsForUserConsolePreferences_Tutorials(flags, flagsplugin.Prefix("tutorials", prefix), hidden) } // SetFromFlags sets the UserConsolePreferences message from flags. @@ -73,7 +115,16 @@ func (m *UserConsolePreferences) SetFromFlags(flags *pflag.FlagSet, prefix strin } // FIXME: Skipping DashboardLayouts because it does not seem to implement AddSetFlags. // FIXME: Skipping SortBy because it does not seem to implement AddSetFlags. - // FIXME: Skipping Tutorials because it does not seem to implement AddSetFlags. + if changed := flagsplugin.IsAnyPrefixSet(flags, flagsplugin.Prefix("tutorials", prefix)); changed { + if m.Tutorials == nil { + m.Tutorials = &UserConsolePreferences_Tutorials{} + } + if setPaths, err := m.Tutorials.SetFromFlags(flags, flagsplugin.Prefix("tutorials", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, setPaths...) + } + } return paths, nil } diff --git a/pkg/webui/assets/misc/split-view-illustration.png b/pkg/webui/assets/misc/split-view-illustration.png new file mode 100644 index 0000000000..ce7438d592 Binary files /dev/null and b/pkg/webui/assets/misc/split-view-illustration.png differ diff --git a/pkg/webui/components/button/button.styl b/pkg/webui/components/button/button.styl index f5057163d9..fade683c19 100644 --- a/pkg/webui/components/button/button.styl +++ b/pkg/webui/components/button/button.styl @@ -120,6 +120,9 @@ &:disabled background-color: var(--c-bg-error-normal-disabled) + .expand-icon + color: var(--c-text-neutral-min) + &.secondary color: var(--c-text-neutral-heavy) background-color: var(--c-bg-neutral-min) diff --git a/pkg/webui/components/header/index.js b/pkg/webui/components/header/index.js index 73624e3783..f07e1c2d1b 100644 --- a/pkg/webui/components/header/index.js +++ b/pkg/webui/components/header/index.js @@ -95,7 +95,8 @@ const Header = ({
+ + ) + ) +} + +LiveDataTutorial.propTypes = { + seen: PropTypes.bool.isRequired, + setIsOpen: PropTypes.func.isRequired, + setTutorialSeen: PropTypes.func.isRequired, +} +LiveDataTutorial.defaultProps = {} + +export default LiveDataTutorial diff --git a/pkg/webui/console/components/live-data-tutorial/live-data-tutorial.styl b/pkg/webui/console/components/live-data-tutorial/live-data-tutorial.styl new file mode 100644 index 0000000000..e803c23ae6 --- /dev/null +++ b/pkg/webui/console/components/live-data-tutorial/live-data-tutorial.styl @@ -0,0 +1,47 @@ +// Copyright © 2025 The Things Network Foundation, The Things Industries B.V. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +.container + background-color: var(--c-bg-neutral-heavy) + color: var(--c-text-neutral-min) + padding: $cs.m $cs.l $cs.l $cs.l + border-radius: $br.xxl + margin: 0 0 $cs.s 0 + width: 21rem + box-shadow: var(--shadow-box-modal-normal) + +.title + margin: 0 + font-size: $fs.m + +.subtitle + font-size: $fs.s + margin: $cs.xs 0 $cs.m 0 + +.image + width: 100% + +.buttonGroup + display: flex + justify-content: space-between + gap: $cs.m + margin-top: $cs.m + + .button + flex: 1 + +.closeButton + position: absolute + top: $cs.m + right: $cs.m diff --git a/pkg/webui/console/components/total-end-devices-upseller-panel/index.js b/pkg/webui/console/components/total-end-devices-upseller-panel/index.js index 109e147a36..b898315593 100644 --- a/pkg/webui/console/components/total-end-devices-upseller-panel/index.js +++ b/pkg/webui/console/components/total-end-devices-upseller-panel/index.js @@ -13,6 +13,7 @@ // limitations under the License. import React from 'react' +import classNames from 'classnames' import { IconBolt, IconDevice } from '@ttn-lw/components/icon' import Panel from '@ttn-lw/components/panel' @@ -21,10 +22,11 @@ import Button from '@ttn-lw/components/button' import Message from '@ttn-lw/lib/components/message' import sharedMessages from '@ttn-lw/lib/shared-messages' +import PropTypes from '@ttn-lw/lib/prop-types' import style from './total-end-devices-upseller-panel.styl' -const TotalEndDevicesUpsellerPanel = () => { +const TotalEndDevicesUpsellerPanel = ({ className }) => { const upgradeUrl = 'https://www.thethingsindustries.com/stack/plans/' return ( @@ -34,7 +36,7 @@ const TotalEndDevicesUpsellerPanel = () => { shortCutLinkButton shortCutLinkPath="#" shortCutLinkDisabled - className={style.panel} + className={classNames(className, style.panel)} compact >
@@ -58,4 +60,12 @@ const TotalEndDevicesUpsellerPanel = () => { ) } +TotalEndDevicesUpsellerPanel.propTypes = { + className: PropTypes.string, +} + +TotalEndDevicesUpsellerPanel.defaultProps = { + className: undefined, +} + export default TotalEndDevicesUpsellerPanel diff --git a/pkg/webui/console/components/total-end-devices-upseller-panel/total-end-devices-upseller-panel.styl b/pkg/webui/console/components/total-end-devices-upseller-panel/total-end-devices-upseller-panel.styl index c29652ebb9..c686778cf0 100644 --- a/pkg/webui/console/components/total-end-devices-upseller-panel/total-end-devices-upseller-panel.styl +++ b/pkg/webui/console/components/total-end-devices-upseller-panel/total-end-devices-upseller-panel.styl @@ -13,7 +13,6 @@ // limitations under the License. .panel - height: 100% display: flex flex-direction: column position: relative diff --git a/pkg/webui/console/containers/event-split-frame/event-split-frame.styl b/pkg/webui/console/containers/event-split-frame/event-split-frame.styl index dbc744903c..df78ab1cfb 100644 --- a/pkg/webui/console/containers/event-split-frame/event-split-frame.styl +++ b/pkg/webui/console/containers/event-split-frame/event-split-frame.styl @@ -51,8 +51,31 @@ .open-button position: fixed - right: 0 - bottom: 0 + right: $cs.s + bottom: $cs.s padding: $cs.xxs width: fit-content + display: flex + flex-direction: column + align-items: flex-end + +.live-data-button + position: relative + display: inline-flex + transition: 80ms background ease-in-out, 80ms color ease-in-out, 80ms border-color ease-in-out, 80ms box-shadow ease-in-out + outline: 0 + cursor: pointer + justify-content: center + align-items: center + gap: $cs.xxs + height: $ls.m + text-decoration: none + padding: 0 $cs.l 0 $cs.m + border-radius: $br.xl3 + color: var(--c-text-neutral-min) + background-color: var(--c-bg-neutral-heavy) + border: 1px solid transparent + box-shadow: var(--shadow-box-button-bold) + &:hover + background-color: var(--c-bg-neutral-heavy-hover) diff --git a/pkg/webui/console/containers/event-split-frame/index.js b/pkg/webui/console/containers/event-split-frame/index.js index 8722e423ad..50db5c4676 100644 --- a/pkg/webui/console/containers/event-split-frame/index.js +++ b/pkg/webui/console/containers/event-split-frame/index.js @@ -14,31 +14,58 @@ import React, { useContext, useCallback, useRef, useEffect } from 'react' import DOM from 'react-dom' -import { IconLayoutBottombarExpand } from '@tabler/icons-react' -import { defineMessages } from 'react-intl' +import { useDispatch, useSelector } from 'react-redux' import Button from '@ttn-lw/components/button' +import { IconChevronUp } from '@ttn-lw/components/icon' + +import RequireRequest from '@ttn-lw/lib/components/require-request' + +import LiveDataTutorial from '@console/components/live-data-tutorial' import PropTypes from '@ttn-lw/lib/prop-types' +import attachPromise from '@ttn-lw/lib/store/actions/attach-promise' +import sharedMessages from '@ttn-lw/lib/shared-messages' + +import { getUser } from '@console/store/actions/users' +import { updateUser } from '@console/store/actions/user' + +import { selectUserId } from '@console/store/selectors/logout' +import { selectUserById } from '@console/store/selectors/users' +import { selectConsolePreferences } from '@console/store/selectors/user-preferences' import EventSplitFrameContext from './context' import style from './event-split-frame.styl' -const m = defineMessages({ - expandEventPanel: 'Expand live data overlay', -}) - const EventSplitFrameInner = ({ children }) => { const { isOpen, height, isActive, setHeight, setIsMounted, setIsOpen } = useContext(EventSplitFrameContext) const ref = useRef() + const dispatch = useDispatch() + const userId = useSelector(selectUserId) + const user = useSelector(state => selectUserById(state, userId)) + const consolePreferences = useSelector(state => selectConsolePreferences(state)) + const tutorialsSeen = consolePreferences.tutorials?.seen || [] + const seen = tutorialsSeen.includes('TUTORIAL_LIVE_DATA_SPLIT_VIEW') useEffect(() => { setIsMounted(true) return () => setIsMounted(false) }, [setIsMounted]) + const setTutorialSeen = useCallback(async () => { + const patch = { + console_preferences: { + tutorials: { + seen: [...tutorialsSeen, 'TUTORIAL_LIVE_DATA_SPLIT_VIEW'], + }, + }, + } + + await dispatch(attachPromise(updateUser({ id: user.ids.user_id, patch }))) + }, [dispatch, tutorialsSeen, user.ids.user_id]) + // Handle the dragging of the handler to resize the frame. const handleDragStart = useCallback( e => { @@ -79,13 +106,12 @@ const EventSplitFrameInner = ({ children }) => { )} {isActive && !isOpen && (
+
)} @@ -97,7 +123,15 @@ EventSplitFrameInner.propTypes = { children: PropTypes.node.isRequired, } -const EventSplitFrame = props => - DOM.createPortal(, document.getElementById('split-frame')) +const EventSplitFrame = props => { + const userId = useSelector(selectUserId) + + return DOM.createPortal( + + + , + document.getElementById('split-frame'), + ) +} export default EventSplitFrame diff --git a/pkg/webui/console/containers/shortcut-panel/index.js b/pkg/webui/console/containers/shortcut-panel/index.js index b50b6edccf..868127c111 100644 --- a/pkg/webui/console/containers/shortcut-panel/index.js +++ b/pkg/webui/console/containers/shortcut-panel/index.js @@ -15,6 +15,7 @@ import React from 'react' import { defineMessages } from 'react-intl' import { useDispatch } from 'react-redux' +import classNames from 'classnames' import { APPLICATION } from '@console/constants/entities' @@ -28,6 +29,7 @@ import { } from '@ttn-lw/components/icon' import sharedMessages from '@ttn-lw/lib/shared-messages' +import PropTypes from '@ttn-lw/lib/prop-types' import { setSearchOpen, setSearchScope } from '@console/store/actions/search' @@ -37,55 +39,94 @@ import ShortcutItem from './shortcut-item' const m = defineMessages({ shortcuts: 'Quick actions', - addApplication: 'New application', - addGateway: 'New gateway', - addNewOrganization: 'New organization', - addPersonalApiKey: 'New personal API key', + addEndDevice: 'Add end device', }) -const ShortcutPanel = () => { +const ShortcutPanel = ({ panelClassName, mobile }) => { const dispatch = useDispatch() const handleRegisterDeviceClick = React.useCallback(() => { dispatch(setSearchScope(APPLICATION)) dispatch(setSearchOpen(true)) }, [dispatch]) + if (mobile) { + return ( +
+ + + + + +
+ ) + } + return ( - -
+ +
) } +ShortcutPanel.propTypes = { + mobile: PropTypes.bool, + panelClassName: PropTypes.string, +} + +ShortcutPanel.defaultProps = { + panelClassName: undefined, + mobile: false, +} + export default ShortcutPanel diff --git a/pkg/webui/console/containers/shortcut-panel/shortcut-item/index.js b/pkg/webui/console/containers/shortcut-panel/shortcut-item/index.js index 657ef36fcd..41243095e0 100644 --- a/pkg/webui/console/containers/shortcut-panel/shortcut-item/index.js +++ b/pkg/webui/console/containers/shortcut-panel/shortcut-item/index.js @@ -17,6 +17,7 @@ import classnames from 'classnames' import Icon from '@ttn-lw/components/icon' import Link from '@ttn-lw/components/link' +import Tooltip from '@ttn-lw/components/tooltip' import Message from '@ttn-lw/lib/components/message' @@ -24,25 +25,27 @@ import PropTypes from '@ttn-lw/lib/prop-types' import style from './shortcut-item.styl' -const ShortcutItem = ({ icon, title, link, action, className }) => +const ShortcutItem = ({ icon, link, action, title, className, mobile }) => action ? ( - + } delay={0}> + + ) : ( - -
-
- - -
-
- + } delay={0}> + + + {mobile && } + + ) ShortcutItem.propTypes = { @@ -50,6 +53,7 @@ ShortcutItem.propTypes = { className: PropTypes.string, icon: PropTypes.icon.isRequired, link: PropTypes.string, + mobile: PropTypes.bool, title: PropTypes.message.isRequired, } @@ -57,6 +61,7 @@ ShortcutItem.defaultProps = { className: undefined, action: undefined, link: undefined, + mobile: false, } export default ShortcutItem diff --git a/pkg/webui/console/containers/shortcut-panel/shortcut-item/shortcut-item.styl b/pkg/webui/console/containers/shortcut-panel/shortcut-item/shortcut-item.styl index a6d8c1b390..29a62ee5eb 100644 --- a/pkg/webui/console/containers/shortcut-panel/shortcut-item/shortcut-item.styl +++ b/pkg/webui/console/containers/shortcut-panel/shortcut-item/shortcut-item.styl @@ -13,44 +13,30 @@ // limitations under the License. .shortcut + padding: $cs.s $cs.m + color: var(--c-text-brand-normal) + background-color: var(--c-bg-brand-light) + border-radius: $br.l + height: 4.5rem + width: 100% display: flex - gap: $cs.m - flex-direction: column align-items: center justify-content: center - padding: $cs.s $cs.m - text-decoration: none - height: 9rem - border-radius: $br.l - background: var(--c-bg-brand-normal) - color: var(--c-text-neutral-min) - font-size: $fs.m + gap: $cs.xs font-weight: $fw.bold - transition: $ad.s background ease-in-out - -webkit-appearance: none border: 0 - &-title-wrapper - width: 100% - height: 100% - display: flex - justify-content: center - align-items: center - flex-direction: column - text-wrap: wrap - text-align: center - gap: $cs.m - transition: $ad.s opacity ease-in-out - - span - line-height: normal + +media-query(1304px) + padding: $cs.xxs $cs.xs - span.icon - font-size: 2rem + .icon + color: var(--c-icon-brand-normal) &:hover cursor: pointer - background: var(--c-bg-brand-normal-hover) + background-color: var(--c-bg-brand-semilight) - span.icon - font-size: 2rem + &-panel + height: unset + aspect-ratio: 1 / 1 + box-sizing: border-box diff --git a/pkg/webui/console/containers/sidebar/navigation/app-side-navigation.js b/pkg/webui/console/containers/sidebar/navigation/app-side-navigation.js index 3bb59a0328..717e376eee 100644 --- a/pkg/webui/console/containers/sidebar/navigation/app-side-navigation.js +++ b/pkg/webui/console/containers/sidebar/navigation/app-side-navigation.js @@ -73,7 +73,13 @@ const AppSideNavigation = () => { const rights = useSelector(selectApplicationRights) const natsDisabled = useSelector(selectNatsProviderDisabled) const mqttDisabled = useSelector(selectMqttProviderDisabled) - const topEntityFilter = useCallback(e => e.id.startsWith(appId), [appId]) + const topEntityFilter = useCallback( + e => { + const separatedAppId = e.id.split('/')[0] + return separatedAppId === appId + }, + [appId], + ) const topEntities = useSelector(state => selectEndDeviceTopEntities(state, topEntityFilter)) if (!app) { diff --git a/pkg/webui/console/containers/user-data-form/add.js b/pkg/webui/console/containers/user-data-form/add.js index 63c6ba1a9f..03928700ef 100644 --- a/pkg/webui/console/containers/user-data-form/add.js +++ b/pkg/webui/console/containers/user-data-form/add.js @@ -30,6 +30,7 @@ import Yup from '@ttn-lw/lib/yup' import createPasswordValidationSchema from '@ttn-lw/lib/create-password-validation-schema' import { userId as userIdRegexp } from '@ttn-lw/lib/regexp' import capitalizeMessage from '@ttn-lw/lib/capitalize-message' +import attachPromise from '@ttn-lw/lib/store/actions/attach-promise' import { createUser } from '@console/store/actions/users' @@ -73,7 +74,10 @@ const UserDataFormAdd = () => { const validationSchema = baseValidationSchema.concat( createPasswordValidationSchema(passwordRequirements), ) - const createUserAction = useCallback(values => dispatch(createUser(values)), [dispatch]) + const createUserAction = useCallback( + values => dispatch(attachPromise(createUser(values))), + [dispatch], + ) const { formatMessage } = intl diff --git a/pkg/webui/console/containers/users-table/index.js b/pkg/webui/console/containers/users-table/index.js index 9d38d88ce9..81e24bc2cd 100644 --- a/pkg/webui/console/containers/users-table/index.js +++ b/pkg/webui/console/containers/users-table/index.js @@ -34,7 +34,13 @@ import PropTypes from '@ttn-lw/lib/prop-types' import { getUserId } from '@ttn-lw/lib/selectors/id' import attachPromise from '@ttn-lw/lib/store/actions/attach-promise' -import { checkFromState, mayManageUsers, maySendInvites } from '@console/lib/feature-checks' +import { + checkFromState, + mayCreateUsers, + mayManageUsers, + mayPerformAllUserActions, + maySendInvites, +} from '@console/lib/feature-checks' import { getUsersList, @@ -329,7 +335,7 @@ const UsersTable = props => { (users, totalCount) => ({ users, totalCount, - mayAdd: mayManageUsers, + mayAdd: mayManageUsers && (mayPerformAllUserActions || mayCreateUsers), }), ) diff --git a/pkg/webui/console/lib/attributes.js b/pkg/webui/console/lib/attributes.js index d22da72f3c..bb581abe1c 100644 --- a/pkg/webui/console/lib/attributes.js +++ b/pkg/webui/console/lib/attributes.js @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +import { isEmpty } from 'lodash' + import { id as idRegexp } from '@ttn-lw/lib/regexp' export const encodeAttributes = formValue => @@ -60,5 +62,6 @@ export const attributeValueTooLongCheck = object => object === undefined || object === null || (object instanceof Object && - Object.values(object).some(value => value !== undefined) && - Object.values(object).every(value => value.length <= 200)) + (isEmpty(object) || + (Object.values(object).some(value => value !== undefined) && + Object.values(object).every(value => value.length <= 200)))) diff --git a/pkg/webui/console/lib/feature-checks.js b/pkg/webui/console/lib/feature-checks.js index 163be25c40..f9a69b6089 100644 --- a/pkg/webui/console/lib/feature-checks.js +++ b/pkg/webui/console/lib/feature-checks.js @@ -34,6 +34,10 @@ export const checkFromState = (featureCheck, state) => featureCheck.check(featureCheck.rightsSelector(state)) // User related feature checks. +export const mayPerformAllUserActions = { + rightsSelector: selectUserRights, + check: rights => rights.includes('RIGHT_USER_ALL'), +} export const mayViewApplicationsOfUser = { rightsSelector: selectUserRights, check: rights => rights.includes('RIGHT_USER_APPLICATIONS_LIST'), @@ -92,6 +96,11 @@ export const mayViewOrEditUserApiKeys = { check: rights => rights.includes('RIGHT_USER_SETTINGS_API_KEYS'), } +export const mayCreateUsers = { + rightsSelector: selectUserRights, + check: rights => rights.includes('RIGHT_USER_CREATE'), +} + // Application related feature checks. export const mayViewApplicationInfo = { rightsSelector: selectApplicationRights, diff --git a/pkg/webui/console/store/reducers/user-preferences.js b/pkg/webui/console/store/reducers/user-preferences.js index 3bbcd99dd5..91c0e9fc75 100644 --- a/pkg/webui/console/store/reducers/user-preferences.js +++ b/pkg/webui/console/store/reducers/user-preferences.js @@ -22,6 +22,8 @@ import { } from '@console/store/actions/user-preferences' import { APPLY_PERSISTED_STATE_SUCCESS, GET_USER_ME_SUCCESS } from '@console/store/actions/user' +import { UPDATE_USER_SUCCESS } from '../actions/users' + const initialState = { bookmarks: { bookmarks: [], @@ -109,6 +111,7 @@ const userPreferences = (state = initialState, { type, payload }) => { }, } case GET_USER_ME_SUCCESS: + case UPDATE_USER_SUCCESS: return { ...state, consolePreferences: { diff --git a/pkg/webui/console/store/selectors/top-entities.js b/pkg/webui/console/store/selectors/top-entities.js index 4ce5d197b7..b043e063f7 100644 --- a/pkg/webui/console/store/selectors/top-entities.js +++ b/pkg/webui/console/store/selectors/top-entities.js @@ -178,17 +178,20 @@ export const selectTopEntities = createSelector( ) const createTopEntityByTypeSelector = entityType => - createSelector([selectTopEntities, (_, filter) => filter], (topEntities, filter) => { - if (!topEntities[entityType]) { - return [] - } + createSelector( + [selectTopEntities, (_, topEntityFilter) => topEntityFilter], + (topEntities, topEntityFilter) => { + if (!topEntities[entityType]) { + return [] + } - const filteredEntities = filter - ? topEntities[entityType].filter(filter) - : topEntities[entityType] + const filteredEntities = topEntityFilter + ? topEntities[entityType].filter(topEntityFilter) + : topEntities[entityType] - return filteredEntities - }) + return filteredEntities + }, + ) export const selectTopEntitiesAll = state => selectTopEntities(state)[ALL] diff --git a/pkg/webui/console/views/gateway-api-key-edit/index.js b/pkg/webui/console/views/gateway-api-key-edit/index.js index 4c19419c6e..bec68d8908 100644 --- a/pkg/webui/console/views/gateway-api-key-edit/index.js +++ b/pkg/webui/console/views/gateway-api-key-edit/index.js @@ -41,7 +41,7 @@ const GatewayApiKeyEditInner = () => { ) return ( -
+
diff --git a/pkg/webui/console/views/overview/overview.js b/pkg/webui/console/views/overview/overview.js index ac4bfaeee9..671c2ee52a 100644 --- a/pkg/webui/console/views/overview/overview.js +++ b/pkg/webui/console/views/overview/overview.js @@ -13,6 +13,7 @@ // limitations under the License. import React from 'react' +import classNames from 'classnames' import { APPLICATION, GATEWAY } from '@console/constants/entities' @@ -30,11 +31,20 @@ import TopEntitiesDashboardPanel from '@console/containers/top-entities-dashboar import sharedMessages from '@ttn-lw/lib/shared-messages' +import style from './overview.styl' + const Overview = () => { useBreadcrumbs('overview.dashboard', ) return (
+
+ +
+
+ + +
{ entityPath="/gateways" />
-
- -
@@ -63,9 +70,6 @@ const Overview = () => {
-
- -
) } diff --git a/pkg/webui/console/views/overview/overview.styl b/pkg/webui/console/views/overview/overview.styl new file mode 100644 index 0000000000..0f79804a6a --- /dev/null +++ b/pkg/webui/console/views/overview/overview.styl @@ -0,0 +1,20 @@ +// Copyright © 2025 The Things Network Foundation, The Things Industries B.V. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +.shortcut-overview-panel + display: none + +media-query($bp.xl) + display: block + +media-query($bp.md-lg) + display: none \ No newline at end of file diff --git a/pkg/webui/locales/en.json b/pkg/webui/locales/en.json index 213db09db9..2cba82c25c 100644 --- a/pkg/webui/locales/en.json +++ b/pkg/webui/locales/en.json @@ -163,6 +163,10 @@ "console.components.gateway-api-keys-modal.index.downloadLns": "Download LNS key", "console.components.gateway-api-keys-modal.index.downloadCups": "Download CUPS key", "console.components.gateway-visibility-form.index.saveDefaultGatewayVisibility": "Save default gateway visibility", + "console.components.live-data-tutorial.index.liveDataSplitView": "Live data split view", + "console.components.live-data-tutorial.index.liveDataSplitViewDescription": "Debug, make changes while keeping an eye on live data from everywhere with split view.", + "console.components.live-data-tutorial.index.gotIt": "Got it", + "console.components.live-data-tutorial.index.tryIt": "Try it", "console.components.location-form.index.deleteAllLocations": "Delete all location data", "console.components.location-form.index.deleteFailure": "An error occurred and the location could not be deleted", "console.components.location-form.index.deleteLocation": "Remove location data", @@ -539,7 +543,6 @@ "console.containers.email-notifications-form.index.unsubscribeDescription": "You will continue to receive notifications in the console.", "console.containers.email-notifications-form.index.discardChanges": "Discard changes", "console.containers.email-notifications-form.index.updateEmailPreferences": "Updated email preferences", - "console.containers.event-split-frame.index.expandEventPanel": "Expand live data overlay", "console.containers.freq-plans-select.utils.warning": "Frequency plans unavailable", "console.containers.freq-plans-select.utils.none": "Do not set a frequency plan", "console.containers.freq-plans-select.utils.selectFrequencyPlan": "Select a frequency plan...", @@ -793,10 +796,7 @@ "console.containers.sessions-table.index.endSession": "Logout to end this session", "console.containers.sessions-table.index.currentSession": "(This is the current session)", "console.containers.shortcut-panel.index.shortcuts": "Quick actions", - "console.containers.shortcut-panel.index.addApplication": "New application", - "console.containers.shortcut-panel.index.addGateway": "New gateway", - "console.containers.shortcut-panel.index.addNewOrganization": "New organization", - "console.containers.shortcut-panel.index.addPersonalApiKey": "New personal API key", + "console.containers.shortcut-panel.index.addEndDevice": "Add end device", "console.containers.sidebar.navigation.app-side-navigation.buttonMessage": "Back to Applications list", "console.containers.sidebar.navigation.gtw-side-navigation.buttonMessage": "Back to Gateways list", "console.containers.sidebar.navigation.top-entities-section.topGateways": "Top gateways", diff --git a/pkg/webui/locales/ja.json b/pkg/webui/locales/ja.json index 9ddfabb8ab..cfa1b85339 100644 --- a/pkg/webui/locales/ja.json +++ b/pkg/webui/locales/ja.json @@ -163,6 +163,10 @@ "console.components.gateway-api-keys-modal.index.downloadLns": "LNSキーをダウンロード", "console.components.gateway-api-keys-modal.index.downloadCups": "CUPSキーをダウンロード", "console.components.gateway-visibility-form.index.saveDefaultGatewayVisibility": "デフォルトゲートウェイの可視性を保存", + "console.components.live-data-tutorial.index.liveDataSplitView": "", + "console.components.live-data-tutorial.index.liveDataSplitViewDescription": "", + "console.components.live-data-tutorial.index.gotIt": "", + "console.components.live-data-tutorial.index.tryIt": "", "console.components.location-form.index.deleteAllLocations": "", "console.components.location-form.index.deleteFailure": "", "console.components.location-form.index.deleteLocation": "", @@ -539,7 +543,6 @@ "console.containers.email-notifications-form.index.unsubscribeDescription": "", "console.containers.email-notifications-form.index.discardChanges": "", "console.containers.email-notifications-form.index.updateEmailPreferences": "", - "console.containers.event-split-frame.index.expandEventPanel": "", "console.containers.freq-plans-select.utils.warning": "", "console.containers.freq-plans-select.utils.none": "", "console.containers.freq-plans-select.utils.selectFrequencyPlan": "", @@ -793,10 +796,7 @@ "console.containers.sessions-table.index.endSession": "", "console.containers.sessions-table.index.currentSession": "", "console.containers.shortcut-panel.index.shortcuts": "", - "console.containers.shortcut-panel.index.addApplication": "", - "console.containers.shortcut-panel.index.addGateway": "", - "console.containers.shortcut-panel.index.addNewOrganization": "", - "console.containers.shortcut-panel.index.addPersonalApiKey": "", + "console.containers.shortcut-panel.index.addEndDevice": "", "console.containers.sidebar.navigation.app-side-navigation.buttonMessage": "", "console.containers.sidebar.navigation.gtw-side-navigation.buttonMessage": "", "console.containers.sidebar.navigation.top-entities-section.topGateways": "", @@ -2143,7 +2143,7 @@ "error:pkg/applicationserver/io/web:validate_body": "本文を検証する", "error:pkg/applicationserver/io/web:webhook_not_found": "Webhookが見つかりません", "error:pkg/applicationserver/io:buffer_full": "バッファがいっぱいです", - "error:pkg/applicationserver/metadata/redis:cache_miss": "キャッシュミス", + "error:pkg/applicationserver/metadata:field_mask_path_not_supported": "", "error:pkg/applicationserver/redis:application_uid": "無効なアプリケーションUID `{application_uid}`", "error:pkg/applicationserver/redis:invalid_fieldmask": "無効なフィールドマスク", "error:pkg/applicationserver/redis:invalid_identifiers": "無効な識別子", @@ -2156,7 +2156,6 @@ "error:pkg/applicationserver:field_value": "無効なフィールド `{field}` の値", "error:pkg/applicationserver:formatter_script_too_large": "フォーマッタースクリプトのサイズが許可された最大サイズを超えています", "error:pkg/applicationserver:invalid_timeout": "無効なタイムアウト`{timeout}`", - "error:pkg/applicationserver:invalid_ttl": "無効なTTL `{ttl}`", "error:pkg/applicationserver:join_server_unavailable": "JoinEUI `{join_eui}` ではジョインサーバが利用できません", "error:pkg/applicationserver:linking_not_implemented": "リンキングが実装されていません", "error:pkg/applicationserver:listen_frontend": "アドレス `{address}` でフロントエンドリスナ `{protocol}` を起動失敗", diff --git a/pkg/webui/styles/variables/tokens.styl b/pkg/webui/styles/variables/tokens.styl index 6ade3ea34e..f3c08ebf8f 100644 --- a/pkg/webui/styles/variables/tokens.styl +++ b/pkg/webui/styles/variables/tokens.styl @@ -40,6 +40,7 @@ $tokens = { 'bg-neutral-semibold': $c.neutral-700, 'bg-neutral-bold': $c.neutral-800, 'bg-neutral-heavy': $c.neutral-900, // Background for navigation element items when active. + 'bg-neutral-heavy-hover': $c.neutral-1050, // Background for navigation element items when active on hover. // Brand @@ -181,6 +182,7 @@ $tokens = { 'box-warning-normal': 0 0 3px 2px rgba(219, 118, 0,.2), // Shadow for focused inputs and other elements that have errors. 'box-panel-normal': 0px 1px 5px 0px rgba(0, 0, 0, .09), 'box-button-normal': 0 1px 2px 0 rgba(0, 0, 0, .05), + 'box-button-bold': 0px 5px 10px 0px rgba(0, 0, 0, .2), 'box-modal-normal': 0px 4px 35px 0px rgba(0, 0, 0, .25), }, diff --git a/sdk/js/generated/api-definition.json b/sdk/js/generated/api-definition.json index 27bf4962ff..4de765ea3b 100644 --- a/sdk/js/generated/api-definition.json +++ b/sdk/js/generated/api-definition.json @@ -745,6 +745,7 @@ "simulated", "up", "up.downlink_ack", + "up.downlink_ack.attributes", "up.downlink_ack.class_b_c", "up.downlink_ack.class_b_c.absolute_time", "up.downlink_ack.class_b_c.gateways", @@ -758,10 +759,26 @@ "up.downlink_ack.f_cnt", "up.downlink_ack.f_port", "up.downlink_ack.frm_payload", + "up.downlink_ack.locations", + "up.downlink_ack.network_ids", + "up.downlink_ack.network_ids.cluster_address", + "up.downlink_ack.network_ids.cluster_id", + "up.downlink_ack.network_ids.net_id", + "up.downlink_ack.network_ids.ns_id", + "up.downlink_ack.network_ids.tenant_address", + "up.downlink_ack.network_ids.tenant_id", "up.downlink_ack.priority", "up.downlink_ack.session_key_id", + "up.downlink_ack.version_ids", + "up.downlink_ack.version_ids.band_id", + "up.downlink_ack.version_ids.brand_id", + "up.downlink_ack.version_ids.firmware_version", + "up.downlink_ack.version_ids.hardware_version", + "up.downlink_ack.version_ids.model_id", "up.downlink_failed", + "up.downlink_failed.attributes", "up.downlink_failed.downlink", + "up.downlink_failed.downlink.attributes", "up.downlink_failed.downlink.class_b_c", "up.downlink_failed.downlink.class_b_c.absolute_time", "up.downlink_failed.downlink.class_b_c.gateways", @@ -775,8 +792,22 @@ "up.downlink_failed.downlink.f_cnt", "up.downlink_failed.downlink.f_port", "up.downlink_failed.downlink.frm_payload", + "up.downlink_failed.downlink.locations", + "up.downlink_failed.downlink.network_ids", + "up.downlink_failed.downlink.network_ids.cluster_address", + "up.downlink_failed.downlink.network_ids.cluster_id", + "up.downlink_failed.downlink.network_ids.net_id", + "up.downlink_failed.downlink.network_ids.ns_id", + "up.downlink_failed.downlink.network_ids.tenant_address", + "up.downlink_failed.downlink.network_ids.tenant_id", "up.downlink_failed.downlink.priority", "up.downlink_failed.downlink.session_key_id", + "up.downlink_failed.downlink.version_ids", + "up.downlink_failed.downlink.version_ids.band_id", + "up.downlink_failed.downlink.version_ids.brand_id", + "up.downlink_failed.downlink.version_ids.firmware_version", + "up.downlink_failed.downlink.version_ids.hardware_version", + "up.downlink_failed.downlink.version_ids.model_id", "up.downlink_failed.error", "up.downlink_failed.error.attributes", "up.downlink_failed.error.cause", @@ -791,7 +822,22 @@ "up.downlink_failed.error.message_format", "up.downlink_failed.error.name", "up.downlink_failed.error.namespace", + "up.downlink_failed.locations", + "up.downlink_failed.network_ids", + "up.downlink_failed.network_ids.cluster_address", + "up.downlink_failed.network_ids.cluster_id", + "up.downlink_failed.network_ids.net_id", + "up.downlink_failed.network_ids.ns_id", + "up.downlink_failed.network_ids.tenant_address", + "up.downlink_failed.network_ids.tenant_id", + "up.downlink_failed.version_ids", + "up.downlink_failed.version_ids.band_id", + "up.downlink_failed.version_ids.brand_id", + "up.downlink_failed.version_ids.firmware_version", + "up.downlink_failed.version_ids.hardware_version", + "up.downlink_failed.version_ids.model_id", "up.downlink_nack", + "up.downlink_nack.attributes", "up.downlink_nack.class_b_c", "up.downlink_nack.class_b_c.absolute_time", "up.downlink_nack.class_b_c.gateways", @@ -805,13 +851,43 @@ "up.downlink_nack.f_cnt", "up.downlink_nack.f_port", "up.downlink_nack.frm_payload", + "up.downlink_nack.locations", + "up.downlink_nack.network_ids", + "up.downlink_nack.network_ids.cluster_address", + "up.downlink_nack.network_ids.cluster_id", + "up.downlink_nack.network_ids.net_id", + "up.downlink_nack.network_ids.ns_id", + "up.downlink_nack.network_ids.tenant_address", + "up.downlink_nack.network_ids.tenant_id", "up.downlink_nack.priority", "up.downlink_nack.session_key_id", + "up.downlink_nack.version_ids", + "up.downlink_nack.version_ids.band_id", + "up.downlink_nack.version_ids.brand_id", + "up.downlink_nack.version_ids.firmware_version", + "up.downlink_nack.version_ids.hardware_version", + "up.downlink_nack.version_ids.model_id", "up.downlink_queue_invalidated", + "up.downlink_queue_invalidated.attributes", "up.downlink_queue_invalidated.downlinks", "up.downlink_queue_invalidated.last_f_cnt_down", + "up.downlink_queue_invalidated.locations", + "up.downlink_queue_invalidated.network_ids", + "up.downlink_queue_invalidated.network_ids.cluster_address", + "up.downlink_queue_invalidated.network_ids.cluster_id", + "up.downlink_queue_invalidated.network_ids.net_id", + "up.downlink_queue_invalidated.network_ids.ns_id", + "up.downlink_queue_invalidated.network_ids.tenant_address", + "up.downlink_queue_invalidated.network_ids.tenant_id", "up.downlink_queue_invalidated.session_key_id", + "up.downlink_queue_invalidated.version_ids", + "up.downlink_queue_invalidated.version_ids.band_id", + "up.downlink_queue_invalidated.version_ids.brand_id", + "up.downlink_queue_invalidated.version_ids.firmware_version", + "up.downlink_queue_invalidated.version_ids.hardware_version", + "up.downlink_queue_invalidated.version_ids.model_id", "up.downlink_queued", + "up.downlink_queued.attributes", "up.downlink_queued.class_b_c", "up.downlink_queued.class_b_c.absolute_time", "up.downlink_queued.class_b_c.gateways", @@ -825,9 +901,24 @@ "up.downlink_queued.f_cnt", "up.downlink_queued.f_port", "up.downlink_queued.frm_payload", + "up.downlink_queued.locations", + "up.downlink_queued.network_ids", + "up.downlink_queued.network_ids.cluster_address", + "up.downlink_queued.network_ids.cluster_id", + "up.downlink_queued.network_ids.net_id", + "up.downlink_queued.network_ids.ns_id", + "up.downlink_queued.network_ids.tenant_address", + "up.downlink_queued.network_ids.tenant_id", "up.downlink_queued.priority", "up.downlink_queued.session_key_id", + "up.downlink_queued.version_ids", + "up.downlink_queued.version_ids.band_id", + "up.downlink_queued.version_ids.brand_id", + "up.downlink_queued.version_ids.firmware_version", + "up.downlink_queued.version_ids.hardware_version", + "up.downlink_queued.version_ids.model_id", "up.downlink_sent", + "up.downlink_sent.attributes", "up.downlink_sent.class_b_c", "up.downlink_sent.class_b_c.absolute_time", "up.downlink_sent.class_b_c.gateways", @@ -841,17 +932,46 @@ "up.downlink_sent.f_cnt", "up.downlink_sent.f_port", "up.downlink_sent.frm_payload", + "up.downlink_sent.locations", + "up.downlink_sent.network_ids", + "up.downlink_sent.network_ids.cluster_address", + "up.downlink_sent.network_ids.cluster_id", + "up.downlink_sent.network_ids.net_id", + "up.downlink_sent.network_ids.ns_id", + "up.downlink_sent.network_ids.tenant_address", + "up.downlink_sent.network_ids.tenant_id", "up.downlink_sent.priority", "up.downlink_sent.session_key_id", + "up.downlink_sent.version_ids", + "up.downlink_sent.version_ids.band_id", + "up.downlink_sent.version_ids.brand_id", + "up.downlink_sent.version_ids.firmware_version", + "up.downlink_sent.version_ids.hardware_version", + "up.downlink_sent.version_ids.model_id", "up.join_accept", "up.join_accept.app_s_key", "up.join_accept.app_s_key.encrypted_key", "up.join_accept.app_s_key.kek_label", "up.join_accept.app_s_key.key", + "up.join_accept.attributes", "up.join_accept.invalidated_downlinks", + "up.join_accept.locations", + "up.join_accept.network_ids", + "up.join_accept.network_ids.cluster_address", + "up.join_accept.network_ids.cluster_id", + "up.join_accept.network_ids.net_id", + "up.join_accept.network_ids.ns_id", + "up.join_accept.network_ids.tenant_address", + "up.join_accept.network_ids.tenant_id", "up.join_accept.pending_session", "up.join_accept.received_at", "up.join_accept.session_key_id", + "up.join_accept.version_ids", + "up.join_accept.version_ids.band_id", + "up.join_accept.version_ids.brand_id", + "up.join_accept.version_ids.firmware_version", + "up.join_accept.version_ids.hardware_version", + "up.join_accept.version_ids.model_id", "up.location_solved", "up.location_solved.attributes", "up.location_solved.location", @@ -862,13 +982,29 @@ "up.location_solved.location.source", "up.location_solved.service", "up.service_data", + "up.service_data.attributes", "up.service_data.data", + "up.service_data.locations", + "up.service_data.network_ids", + "up.service_data.network_ids.cluster_address", + "up.service_data.network_ids.cluster_id", + "up.service_data.network_ids.net_id", + "up.service_data.network_ids.ns_id", + "up.service_data.network_ids.tenant_address", + "up.service_data.network_ids.tenant_id", "up.service_data.service", + "up.service_data.version_ids", + "up.service_data.version_ids.band_id", + "up.service_data.version_ids.brand_id", + "up.service_data.version_ids.firmware_version", + "up.service_data.version_ids.hardware_version", + "up.service_data.version_ids.model_id", "up.uplink_message", "up.uplink_message.app_s_key", "up.uplink_message.app_s_key.encrypted_key", "up.uplink_message.app_s_key.kek_label", "up.uplink_message.app_s_key.key", + "up.uplink_message.attributes", "up.uplink_message.confirmed", "up.uplink_message.consumed_airtime", "up.uplink_message.decoded_payload", @@ -877,6 +1013,10 @@ "up.uplink_message.f_port", "up.uplink_message.frm_payload", "up.uplink_message.last_a_f_cnt_down", + "up.uplink_message.last_battery_percentage", + "up.uplink_message.last_battery_percentage.f_cnt", + "up.uplink_message.last_battery_percentage.received_at", + "up.uplink_message.last_battery_percentage.value", "up.uplink_message.locations", "up.uplink_message.network_ids", "up.uplink_message.network_ids.cluster_address", @@ -920,6 +1060,7 @@ "up.uplink_message.version_ids.hardware_version", "up.uplink_message.version_ids.model_id", "up.uplink_normalized", + "up.uplink_normalized.attributes", "up.uplink_normalized.confirmed", "up.uplink_normalized.consumed_airtime", "up.uplink_normalized.f_cnt", @@ -4750,6 +4891,7 @@ "mac_state.last_network_initiated_downlink_at", "mac_state.lorawan_version", "mac_state.pending_application_downlink", + "mac_state.pending_application_downlink.attributes", "mac_state.pending_application_downlink.class_b_c", "mac_state.pending_application_downlink.class_b_c.absolute_time", "mac_state.pending_application_downlink.class_b_c.gateways", @@ -4758,8 +4900,22 @@ "mac_state.pending_application_downlink.f_cnt", "mac_state.pending_application_downlink.f_port", "mac_state.pending_application_downlink.frm_payload", + "mac_state.pending_application_downlink.locations", + "mac_state.pending_application_downlink.network_ids", + "mac_state.pending_application_downlink.network_ids.cluster_address", + "mac_state.pending_application_downlink.network_ids.cluster_id", + "mac_state.pending_application_downlink.network_ids.net_id", + "mac_state.pending_application_downlink.network_ids.ns_id", + "mac_state.pending_application_downlink.network_ids.tenant_address", + "mac_state.pending_application_downlink.network_ids.tenant_id", "mac_state.pending_application_downlink.priority", "mac_state.pending_application_downlink.session_key_id", + "mac_state.pending_application_downlink.version_ids", + "mac_state.pending_application_downlink.version_ids.band_id", + "mac_state.pending_application_downlink.version_ids.brand_id", + "mac_state.pending_application_downlink.version_ids.firmware_version", + "mac_state.pending_application_downlink.version_ids.hardware_version", + "mac_state.pending_application_downlink.version_ids.model_id", "mac_state.pending_relay_downlink", "mac_state.pending_relay_downlink.raw_payload", "mac_state.pending_requests", @@ -5366,6 +5522,13 @@ "mac_state.pending_application_downlink.f_cnt", "mac_state.pending_application_downlink.f_port", "mac_state.pending_application_downlink.frm_payload", + "mac_state.pending_application_downlink.network_ids", + "mac_state.pending_application_downlink.network_ids.cluster_address", + "mac_state.pending_application_downlink.network_ids.cluster_id", + "mac_state.pending_application_downlink.network_ids.net_id", + "mac_state.pending_application_downlink.network_ids.ns_id", + "mac_state.pending_application_downlink.network_ids.tenant_address", + "mac_state.pending_application_downlink.network_ids.tenant_id", "mac_state.pending_application_downlink.priority", "mac_state.pending_application_downlink.session_key_id", "mac_state.pending_relay_downlink", @@ -5962,6 +6125,7 @@ "mac_state.last_network_initiated_downlink_at", "mac_state.lorawan_version", "mac_state.pending_application_downlink", + "mac_state.pending_application_downlink.attributes", "mac_state.pending_application_downlink.class_b_c", "mac_state.pending_application_downlink.class_b_c.absolute_time", "mac_state.pending_application_downlink.class_b_c.gateways", @@ -5970,8 +6134,22 @@ "mac_state.pending_application_downlink.f_cnt", "mac_state.pending_application_downlink.f_port", "mac_state.pending_application_downlink.frm_payload", + "mac_state.pending_application_downlink.locations", + "mac_state.pending_application_downlink.network_ids", + "mac_state.pending_application_downlink.network_ids.cluster_address", + "mac_state.pending_application_downlink.network_ids.cluster_id", + "mac_state.pending_application_downlink.network_ids.net_id", + "mac_state.pending_application_downlink.network_ids.ns_id", + "mac_state.pending_application_downlink.network_ids.tenant_address", + "mac_state.pending_application_downlink.network_ids.tenant_id", "mac_state.pending_application_downlink.priority", "mac_state.pending_application_downlink.session_key_id", + "mac_state.pending_application_downlink.version_ids", + "mac_state.pending_application_downlink.version_ids.band_id", + "mac_state.pending_application_downlink.version_ids.brand_id", + "mac_state.pending_application_downlink.version_ids.firmware_version", + "mac_state.pending_application_downlink.version_ids.hardware_version", + "mac_state.pending_application_downlink.version_ids.model_id", "mac_state.pending_relay_downlink", "mac_state.pending_relay_downlink.raw_payload", "mac_state.pending_requests", diff --git a/sdk/js/generated/api.json b/sdk/js/generated/api.json index 5ceb4fcecf..5c4c2aae19 100644 --- a/sdk/js/generated/api.json +++ b/sdk/js/generated/api.json @@ -38661,6 +38661,110 @@ "isoneof": false, "oneofdecl": "", "defaultValue": "" + }, + { + "name": "locations", + "description": "End device location metadata, set by the Application Server while handling the message.", + "label": "repeated", + "type": "LocationsEntry", + "longType": "ApplicationDownlink.LocationsEntry", + "fullType": "ttn.lorawan.v3.ApplicationDownlink.LocationsEntry", + "ismap": true, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + }, + { + "name": "version_ids", + "description": "End device version identifiers, set by the Application Server while handling the message.", + "label": "", + "type": "EndDeviceVersionIdentifiers", + "longType": "EndDeviceVersionIdentifiers", + "fullType": "ttn.lorawan.v3.EndDeviceVersionIdentifiers", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + }, + { + "name": "network_ids", + "description": "Network identifiers, set by the Network Server that handles the message.", + "label": "", + "type": "NetworkIdentifiers", + "longType": "NetworkIdentifiers", + "fullType": "ttn.lorawan.v3.NetworkIdentifiers", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + }, + { + "name": "attributes", + "description": "Attributes for devices, set by the Application Server while handling the message.", + "label": "repeated", + "type": "AttributesEntry", + "longType": "ApplicationDownlink.AttributesEntry", + "fullType": "ttn.lorawan.v3.ApplicationDownlink.AttributesEntry", + "ismap": true, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "", + "options": { + "validate.rules": [ + { + "name": "map.max_pairs", + "value": 10 + }, + { + "name": "map.keys.string.max_len", + "value": 36 + }, + { + "name": "map.keys.string.pattern", + "value": "^[a-z0-9](?:[-]?[a-z0-9]){2,}$" + }, + { + "name": "map.values.string.max_len", + "value": 200 + } + ] + } + } + ] + }, + { + "name": "AttributesEntry", + "longName": "ApplicationDownlink.AttributesEntry", + "fullName": "ttn.lorawan.v3.ApplicationDownlink.AttributesEntry", + "description": "", + "hasExtensions": false, + "hasFields": true, + "hasOneofs": false, + "extensions": [], + "fields": [ + { + "name": "key", + "description": "", + "label": "", + "type": "string", + "longType": "string", + "fullType": "string", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + }, + { + "name": "value", + "description": "", + "label": "", + "type": "string", + "longType": "string", + "fullType": "string", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" } ] }, @@ -38748,6 +38852,42 @@ } ] }, + { + "name": "LocationsEntry", + "longName": "ApplicationDownlink.LocationsEntry", + "fullName": "ttn.lorawan.v3.ApplicationDownlink.LocationsEntry", + "description": "", + "hasExtensions": false, + "hasFields": true, + "hasOneofs": false, + "extensions": [], + "fields": [ + { + "name": "key", + "description": "", + "label": "", + "type": "string", + "longType": "string", + "fullType": "string", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + }, + { + "name": "value", + "description": "", + "label": "", + "type": "Location", + "longType": "Location", + "fullType": "ttn.lorawan.v3.Location", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + } + ] + }, { "name": "ApplicationDownlinkFailed", "longName": "ApplicationDownlinkFailed", @@ -38797,83 +38937,71 @@ } ] } - } - ] - }, - { - "name": "ApplicationDownlinks", - "longName": "ApplicationDownlinks", - "fullName": "ttn.lorawan.v3.ApplicationDownlinks", - "description": "", - "hasExtensions": false, - "hasFields": true, - "hasOneofs": false, - "extensions": [], - "fields": [ + }, { - "name": "downlinks", - "description": "", + "name": "locations", + "description": "End device location metadata, set by the Application Server while handling the message.", "label": "repeated", - "type": "ApplicationDownlink", - "longType": "ApplicationDownlink", - "fullType": "ttn.lorawan.v3.ApplicationDownlink", - "ismap": false, + "type": "LocationsEntry", + "longType": "ApplicationDownlinkFailed.LocationsEntry", + "fullType": "ttn.lorawan.v3.ApplicationDownlinkFailed.LocationsEntry", + "ismap": true, "isoneof": false, "oneofdecl": "", "defaultValue": "" - } - ] - }, - { - "name": "ApplicationInvalidatedDownlinks", - "longName": "ApplicationInvalidatedDownlinks", - "fullName": "ttn.lorawan.v3.ApplicationInvalidatedDownlinks", - "description": "", - "hasExtensions": false, - "hasFields": true, - "hasOneofs": false, - "extensions": [], - "fields": [ + }, { - "name": "downlinks", - "description": "", - "label": "repeated", - "type": "ApplicationDownlink", - "longType": "ApplicationDownlink", - "fullType": "ttn.lorawan.v3.ApplicationDownlink", + "name": "version_ids", + "description": "End device version identifiers, set by the Application Server while handling the message.", + "label": "", + "type": "EndDeviceVersionIdentifiers", + "longType": "EndDeviceVersionIdentifiers", + "fullType": "ttn.lorawan.v3.EndDeviceVersionIdentifiers", "ismap": false, "isoneof": false, "oneofdecl": "", "defaultValue": "" }, { - "name": "last_f_cnt_down", - "description": "", + "name": "network_ids", + "description": "Network identifiers, set by the Network Server that handles the message.", "label": "", - "type": "uint32", - "longType": "uint32", - "fullType": "uint32", + "type": "NetworkIdentifiers", + "longType": "NetworkIdentifiers", + "fullType": "ttn.lorawan.v3.NetworkIdentifiers", "ismap": false, "isoneof": false, "oneofdecl": "", "defaultValue": "" }, { - "name": "session_key_id", - "description": "", - "label": "", - "type": "bytes", - "longType": "bytes", - "fullType": "bytes", - "ismap": false, + "name": "attributes", + "description": "Attributes for devices, set by the Application Server while handling the message.", + "label": "repeated", + "type": "AttributesEntry", + "longType": "ApplicationDownlinkFailed.AttributesEntry", + "fullType": "ttn.lorawan.v3.ApplicationDownlinkFailed.AttributesEntry", + "ismap": true, "isoneof": false, "oneofdecl": "", "defaultValue": "", "options": { "validate.rules": [ { - "name": "bytes.max_len", - "value": 2048 + "name": "map.max_pairs", + "value": 10 + }, + { + "name": "map.keys.string.max_len", + "value": 36 + }, + { + "name": "map.keys.string.pattern", + "value": "^[a-z0-9](?:[-]?[a-z0-9]){2,}$" + }, + { + "name": "map.values.string.max_len", + "value": 200 } ] } @@ -38881,9 +39009,9 @@ ] }, { - "name": "ApplicationJoinAccept", - "longName": "ApplicationJoinAccept", - "fullName": "ttn.lorawan.v3.ApplicationJoinAccept", + "name": "AttributesEntry", + "longName": "ApplicationDownlinkFailed.AttributesEntry", + "fullName": "ttn.lorawan.v3.ApplicationDownlinkFailed.AttributesEntry", "description": "", "hasExtensions": false, "hasFields": true, @@ -38891,40 +39019,332 @@ "extensions": [], "fields": [ { - "name": "session_key_id", - "description": "Join Server issued identifier for the session keys negotiated in this join.", + "name": "key", + "description": "", "label": "", - "type": "bytes", - "longType": "bytes", - "fullType": "bytes", + "type": "string", + "longType": "string", + "fullType": "string", "ismap": false, "isoneof": false, "oneofdecl": "", - "defaultValue": "", - "options": { - "validate.rules": [ - { - "name": "bytes.max_len", - "value": 2048 - } - ] - } + "defaultValue": "" }, { - "name": "app_s_key", - "description": "Encrypted Application Session Key (if Join Server sent it to Network Server).", + "name": "value", + "description": "", "label": "", - "type": "KeyEnvelope", - "longType": "KeyEnvelope", - "fullType": "ttn.lorawan.v3.KeyEnvelope", + "type": "string", + "longType": "string", + "fullType": "string", "ismap": false, "isoneof": false, "oneofdecl": "", "defaultValue": "" - }, - { - "name": "invalidated_downlinks", - "description": "Downlink messages in the queue that got invalidated because of the session change.", + } + ] + }, + { + "name": "LocationsEntry", + "longName": "ApplicationDownlinkFailed.LocationsEntry", + "fullName": "ttn.lorawan.v3.ApplicationDownlinkFailed.LocationsEntry", + "description": "", + "hasExtensions": false, + "hasFields": true, + "hasOneofs": false, + "extensions": [], + "fields": [ + { + "name": "key", + "description": "", + "label": "", + "type": "string", + "longType": "string", + "fullType": "string", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + }, + { + "name": "value", + "description": "", + "label": "", + "type": "Location", + "longType": "Location", + "fullType": "ttn.lorawan.v3.Location", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + } + ] + }, + { + "name": "ApplicationDownlinks", + "longName": "ApplicationDownlinks", + "fullName": "ttn.lorawan.v3.ApplicationDownlinks", + "description": "", + "hasExtensions": false, + "hasFields": true, + "hasOneofs": false, + "extensions": [], + "fields": [ + { + "name": "downlinks", + "description": "", + "label": "repeated", + "type": "ApplicationDownlink", + "longType": "ApplicationDownlink", + "fullType": "ttn.lorawan.v3.ApplicationDownlink", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + } + ] + }, + { + "name": "ApplicationInvalidatedDownlinks", + "longName": "ApplicationInvalidatedDownlinks", + "fullName": "ttn.lorawan.v3.ApplicationInvalidatedDownlinks", + "description": "", + "hasExtensions": false, + "hasFields": true, + "hasOneofs": false, + "extensions": [], + "fields": [ + { + "name": "downlinks", + "description": "", + "label": "repeated", + "type": "ApplicationDownlink", + "longType": "ApplicationDownlink", + "fullType": "ttn.lorawan.v3.ApplicationDownlink", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + }, + { + "name": "last_f_cnt_down", + "description": "", + "label": "", + "type": "uint32", + "longType": "uint32", + "fullType": "uint32", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + }, + { + "name": "session_key_id", + "description": "", + "label": "", + "type": "bytes", + "longType": "bytes", + "fullType": "bytes", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "", + "options": { + "validate.rules": [ + { + "name": "bytes.max_len", + "value": 2048 + } + ] + } + }, + { + "name": "locations", + "description": "End device location metadata, set by the Application Server while handling the message.", + "label": "repeated", + "type": "LocationsEntry", + "longType": "ApplicationInvalidatedDownlinks.LocationsEntry", + "fullType": "ttn.lorawan.v3.ApplicationInvalidatedDownlinks.LocationsEntry", + "ismap": true, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + }, + { + "name": "version_ids", + "description": "End device version identifiers, set by the Application Server while handling the message.", + "label": "", + "type": "EndDeviceVersionIdentifiers", + "longType": "EndDeviceVersionIdentifiers", + "fullType": "ttn.lorawan.v3.EndDeviceVersionIdentifiers", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + }, + { + "name": "network_ids", + "description": "Network identifiers, set by the Network Server that handles the message.", + "label": "", + "type": "NetworkIdentifiers", + "longType": "NetworkIdentifiers", + "fullType": "ttn.lorawan.v3.NetworkIdentifiers", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + }, + { + "name": "attributes", + "description": "Attributes for devices, set by the Application Server while handling the message.", + "label": "repeated", + "type": "AttributesEntry", + "longType": "ApplicationInvalidatedDownlinks.AttributesEntry", + "fullType": "ttn.lorawan.v3.ApplicationInvalidatedDownlinks.AttributesEntry", + "ismap": true, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "", + "options": { + "validate.rules": [ + { + "name": "map.max_pairs", + "value": 10 + }, + { + "name": "map.keys.string.max_len", + "value": 36 + }, + { + "name": "map.keys.string.pattern", + "value": "^[a-z0-9](?:[-]?[a-z0-9]){2,}$" + }, + { + "name": "map.values.string.max_len", + "value": 200 + } + ] + } + } + ] + }, + { + "name": "AttributesEntry", + "longName": "ApplicationInvalidatedDownlinks.AttributesEntry", + "fullName": "ttn.lorawan.v3.ApplicationInvalidatedDownlinks.AttributesEntry", + "description": "", + "hasExtensions": false, + "hasFields": true, + "hasOneofs": false, + "extensions": [], + "fields": [ + { + "name": "key", + "description": "", + "label": "", + "type": "string", + "longType": "string", + "fullType": "string", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + }, + { + "name": "value", + "description": "", + "label": "", + "type": "string", + "longType": "string", + "fullType": "string", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + } + ] + }, + { + "name": "LocationsEntry", + "longName": "ApplicationInvalidatedDownlinks.LocationsEntry", + "fullName": "ttn.lorawan.v3.ApplicationInvalidatedDownlinks.LocationsEntry", + "description": "", + "hasExtensions": false, + "hasFields": true, + "hasOneofs": false, + "extensions": [], + "fields": [ + { + "name": "key", + "description": "", + "label": "", + "type": "string", + "longType": "string", + "fullType": "string", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + }, + { + "name": "value", + "description": "", + "label": "", + "type": "Location", + "longType": "Location", + "fullType": "ttn.lorawan.v3.Location", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + } + ] + }, + { + "name": "ApplicationJoinAccept", + "longName": "ApplicationJoinAccept", + "fullName": "ttn.lorawan.v3.ApplicationJoinAccept", + "description": "", + "hasExtensions": false, + "hasFields": true, + "hasOneofs": false, + "extensions": [], + "fields": [ + { + "name": "session_key_id", + "description": "Join Server issued identifier for the session keys negotiated in this join.", + "label": "", + "type": "bytes", + "longType": "bytes", + "fullType": "bytes", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "", + "options": { + "validate.rules": [ + { + "name": "bytes.max_len", + "value": 2048 + } + ] + } + }, + { + "name": "app_s_key", + "description": "Encrypted Application Session Key (if Join Server sent it to Network Server).", + "label": "", + "type": "KeyEnvelope", + "longType": "KeyEnvelope", + "fullType": "ttn.lorawan.v3.KeyEnvelope", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + }, + { + "name": "invalidated_downlinks", + "description": "Downlink messages in the queue that got invalidated because of the session change.", "label": "repeated", "type": "ApplicationDownlink", "longType": "ApplicationDownlink", @@ -38965,6 +39385,146 @@ } ] } + }, + { + "name": "locations", + "description": "End device location metadata, set by the Application Server while handling the message.", + "label": "repeated", + "type": "LocationsEntry", + "longType": "ApplicationJoinAccept.LocationsEntry", + "fullType": "ttn.lorawan.v3.ApplicationJoinAccept.LocationsEntry", + "ismap": true, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + }, + { + "name": "version_ids", + "description": "End device version identifiers, set by the Application Server while handling the message.", + "label": "", + "type": "EndDeviceVersionIdentifiers", + "longType": "EndDeviceVersionIdentifiers", + "fullType": "ttn.lorawan.v3.EndDeviceVersionIdentifiers", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + }, + { + "name": "network_ids", + "description": "Network identifiers, set by the Network Server that handles the message.", + "label": "", + "type": "NetworkIdentifiers", + "longType": "NetworkIdentifiers", + "fullType": "ttn.lorawan.v3.NetworkIdentifiers", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + }, + { + "name": "attributes", + "description": "Attributes for devices, set by the Application Server while handling the message.", + "label": "repeated", + "type": "AttributesEntry", + "longType": "ApplicationJoinAccept.AttributesEntry", + "fullType": "ttn.lorawan.v3.ApplicationJoinAccept.AttributesEntry", + "ismap": true, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "", + "options": { + "validate.rules": [ + { + "name": "map.max_pairs", + "value": 10 + }, + { + "name": "map.keys.string.max_len", + "value": 36 + }, + { + "name": "map.keys.string.pattern", + "value": "^[a-z0-9](?:[-]?[a-z0-9]){2,}$" + }, + { + "name": "map.values.string.max_len", + "value": 200 + } + ] + } + } + ] + }, + { + "name": "AttributesEntry", + "longName": "ApplicationJoinAccept.AttributesEntry", + "fullName": "ttn.lorawan.v3.ApplicationJoinAccept.AttributesEntry", + "description": "", + "hasExtensions": false, + "hasFields": true, + "hasOneofs": false, + "extensions": [], + "fields": [ + { + "name": "key", + "description": "", + "label": "", + "type": "string", + "longType": "string", + "fullType": "string", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + }, + { + "name": "value", + "description": "", + "label": "", + "type": "string", + "longType": "string", + "fullType": "string", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + } + ] + }, + { + "name": "LocationsEntry", + "longName": "ApplicationJoinAccept.LocationsEntry", + "fullName": "ttn.lorawan.v3.ApplicationJoinAccept.LocationsEntry", + "description": "", + "hasExtensions": false, + "hasFields": true, + "hasOneofs": false, + "extensions": [], + "fields": [ + { + "name": "key", + "description": "", + "label": "", + "type": "string", + "longType": "string", + "fullType": "string", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + }, + { + "name": "value", + "description": "", + "label": "", + "type": "Location", + "longType": "Location", + "fullType": "ttn.lorawan.v3.Location", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" } ] }, @@ -38982,41 +39542,181 @@ "name": "service", "description": "", "label": "", - "type": "string", - "longType": "string", - "fullType": "string", + "type": "string", + "longType": "string", + "fullType": "string", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + }, + { + "name": "location", + "description": "", + "label": "", + "type": "Location", + "longType": "Location", + "fullType": "ttn.lorawan.v3.Location", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "", + "options": { + "validate.rules": [ + { + "name": "message.required", + "value": true + } + ] + } + }, + { + "name": "attributes", + "description": "", + "label": "repeated", + "type": "AttributesEntry", + "longType": "ApplicationLocation.AttributesEntry", + "fullType": "ttn.lorawan.v3.ApplicationLocation.AttributesEntry", + "ismap": true, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "", + "options": { + "validate.rules": [ + { + "name": "map.max_pairs", + "value": 10 + }, + { + "name": "map.keys.string.max_len", + "value": 36 + }, + { + "name": "map.keys.string.pattern", + "value": "^[a-z0-9](?:[-]?[a-z0-9]){2,}$" + }, + { + "name": "map.values.string.max_len", + "value": 200 + } + ] + } + } + ] + }, + { + "name": "AttributesEntry", + "longName": "ApplicationLocation.AttributesEntry", + "fullName": "ttn.lorawan.v3.ApplicationLocation.AttributesEntry", + "description": "", + "hasExtensions": false, + "hasFields": true, + "hasOneofs": false, + "extensions": [], + "fields": [ + { + "name": "key", + "description": "", + "label": "", + "type": "string", + "longType": "string", + "fullType": "string", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + }, + { + "name": "value", + "description": "", + "label": "", + "type": "string", + "longType": "string", + "fullType": "string", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + } + ] + }, + { + "name": "ApplicationServiceData", + "longName": "ApplicationServiceData", + "fullName": "ttn.lorawan.v3.ApplicationServiceData", + "description": "", + "hasExtensions": false, + "hasFields": true, + "hasOneofs": false, + "extensions": [], + "fields": [ + { + "name": "service", + "description": "", + "label": "", + "type": "string", + "longType": "string", + "fullType": "string", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + }, + { + "name": "data", + "description": "", + "label": "", + "type": "Struct", + "longType": "google.protobuf.Struct", + "fullType": "google.protobuf.Struct", "ismap": false, "isoneof": false, "oneofdecl": "", "defaultValue": "" }, { - "name": "location", - "description": "", + "name": "locations", + "description": "End device location metadata, set by the Application Server while handling the message.", + "label": "repeated", + "type": "LocationsEntry", + "longType": "ApplicationServiceData.LocationsEntry", + "fullType": "ttn.lorawan.v3.ApplicationServiceData.LocationsEntry", + "ismap": true, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + }, + { + "name": "version_ids", + "description": "End device version identifiers, set by the Application Server while handling the message.", "label": "", - "type": "Location", - "longType": "Location", - "fullType": "ttn.lorawan.v3.Location", + "type": "EndDeviceVersionIdentifiers", + "longType": "EndDeviceVersionIdentifiers", + "fullType": "ttn.lorawan.v3.EndDeviceVersionIdentifiers", "ismap": false, "isoneof": false, "oneofdecl": "", - "defaultValue": "", - "options": { - "validate.rules": [ - { - "name": "message.required", - "value": true - } - ] - } + "defaultValue": "" + }, + { + "name": "network_ids", + "description": "Network identifiers, set by the Network Server that handles the message.", + "label": "", + "type": "NetworkIdentifiers", + "longType": "NetworkIdentifiers", + "fullType": "ttn.lorawan.v3.NetworkIdentifiers", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" }, { "name": "attributes", - "description": "", + "description": "Attributes for devices, set by the Application Server while handling the message.", "label": "repeated", "type": "AttributesEntry", - "longType": "ApplicationLocation.AttributesEntry", - "fullType": "ttn.lorawan.v3.ApplicationLocation.AttributesEntry", + "longType": "ApplicationServiceData.AttributesEntry", + "fullType": "ttn.lorawan.v3.ApplicationServiceData.AttributesEntry", "ismap": true, "isoneof": false, "oneofdecl": "", @@ -39046,8 +39746,8 @@ }, { "name": "AttributesEntry", - "longName": "ApplicationLocation.AttributesEntry", - "fullName": "ttn.lorawan.v3.ApplicationLocation.AttributesEntry", + "longName": "ApplicationServiceData.AttributesEntry", + "fullName": "ttn.lorawan.v3.ApplicationServiceData.AttributesEntry", "description": "", "hasExtensions": false, "hasFields": true, @@ -39081,9 +39781,9 @@ ] }, { - "name": "ApplicationServiceData", - "longName": "ApplicationServiceData", - "fullName": "ttn.lorawan.v3.ApplicationServiceData", + "name": "LocationsEntry", + "longName": "ApplicationServiceData.LocationsEntry", + "fullName": "ttn.lorawan.v3.ApplicationServiceData.LocationsEntry", "description": "", "hasExtensions": false, "hasFields": true, @@ -39091,7 +39791,7 @@ "extensions": [], "fields": [ { - "name": "service", + "name": "key", "description": "", "label": "", "type": "string", @@ -39103,12 +39803,12 @@ "defaultValue": "" }, { - "name": "data", + "name": "value", "description": "", "label": "", - "type": "Struct", - "longType": "google.protobuf.Struct", - "fullType": "google.protobuf.Struct", + "type": "Location", + "longType": "Location", + "fullType": "ttn.lorawan.v3.Location", "ismap": false, "isoneof": false, "oneofdecl": "", @@ -39591,6 +40291,86 @@ "isoneof": false, "oneofdecl": "", "defaultValue": "" + }, + { + "name": "last_battery_percentage", + "description": "Last battery percentage of the end device.\nReceived via the DevStatus MAC command at last_dev_status_received_at or earlier.\nSet by the Network Server while handling the message.", + "label": "", + "type": "LastBatteryPercentage", + "longType": "LastBatteryPercentage", + "fullType": "ttn.lorawan.v3.LastBatteryPercentage", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + }, + { + "name": "attributes", + "description": "Attributes for devices, set by the Application Server while handling the message.", + "label": "repeated", + "type": "AttributesEntry", + "longType": "ApplicationUplink.AttributesEntry", + "fullType": "ttn.lorawan.v3.ApplicationUplink.AttributesEntry", + "ismap": true, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "", + "options": { + "validate.rules": [ + { + "name": "map.max_pairs", + "value": 10 + }, + { + "name": "map.keys.string.max_len", + "value": 36 + }, + { + "name": "map.keys.string.pattern", + "value": "^[a-z0-9](?:[-]?[a-z0-9]){2,}$" + }, + { + "name": "map.values.string.max_len", + "value": 200 + } + ] + } + } + ] + }, + { + "name": "AttributesEntry", + "longName": "ApplicationUplink.AttributesEntry", + "fullName": "ttn.lorawan.v3.ApplicationUplink.AttributesEntry", + "description": "", + "hasExtensions": false, + "hasFields": true, + "hasOneofs": false, + "extensions": [], + "fields": [ + { + "name": "key", + "description": "", + "label": "", + "type": "string", + "longType": "string", + "fullType": "string", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + }, + { + "name": "value", + "description": "", + "label": "", + "type": "string", + "longType": "string", + "fullType": "string", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" } ] }, @@ -39857,6 +40637,74 @@ "isoneof": false, "oneofdecl": "", "defaultValue": "" + }, + { + "name": "attributes", + "description": "Attributes for devices, set by the Application Server while handling the message.", + "label": "repeated", + "type": "AttributesEntry", + "longType": "ApplicationUplinkNormalized.AttributesEntry", + "fullType": "ttn.lorawan.v3.ApplicationUplinkNormalized.AttributesEntry", + "ismap": true, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "", + "options": { + "validate.rules": [ + { + "name": "map.max_pairs", + "value": 10 + }, + { + "name": "map.keys.string.max_len", + "value": 36 + }, + { + "name": "map.keys.string.pattern", + "value": "^[a-z0-9](?:[-]?[a-z0-9]){2,}$" + }, + { + "name": "map.values.string.max_len", + "value": 200 + } + ] + } + } + ] + }, + { + "name": "AttributesEntry", + "longName": "ApplicationUplinkNormalized.AttributesEntry", + "fullName": "ttn.lorawan.v3.ApplicationUplinkNormalized.AttributesEntry", + "description": "", + "hasExtensions": false, + "hasFields": true, + "hasOneofs": false, + "extensions": [], + "fields": [ + { + "name": "key", + "description": "", + "label": "", + "type": "string", + "longType": "string", + "fullType": "string", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + }, + { + "name": "value", + "description": "", + "label": "", + "type": "string", + "longType": "string", + "fullType": "string", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" } ] }, @@ -40256,6 +41104,66 @@ } ] }, + { + "name": "LastBatteryPercentage", + "longName": "LastBatteryPercentage", + "fullName": "ttn.lorawan.v3.LastBatteryPercentage", + "description": "", + "hasExtensions": false, + "hasFields": true, + "hasOneofs": false, + "extensions": [], + "fields": [ + { + "name": "f_cnt", + "description": "Frame counter value of last uplink containing DevStatusAns.", + "label": "", + "type": "uint32", + "longType": "uint32", + "fullType": "uint32", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + }, + { + "name": "value", + "description": "The battery percentage of the end device.\nThe value is defined in the [0, 100] interval.", + "label": "", + "type": "FloatValue", + "longType": "google.protobuf.FloatValue", + "fullType": "google.protobuf.FloatValue", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "", + "options": { + "validate.rules": [ + { + "name": "float.lte", + "value": 100 + }, + { + "name": "float.gte", + "value": 0 + } + ] + } + }, + { + "name": "received_at", + "description": "Time when last DevStatus MAC command was received.", + "label": "", + "type": "Timestamp", + "longType": "google.protobuf.Timestamp", + "fullType": "google.protobuf.Timestamp", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + } + ] + }, { "name": "MessagePayloadFormatters", "longName": "MessagePayloadFormatters", diff --git a/sdk/js/generated/device-entity-map.json b/sdk/js/generated/device-entity-map.json index 0d65c728ec..62da12da47 100644 --- a/sdk/js/generated/device-entity-map.json +++ b/sdk/js/generated/device-entity-map.json @@ -2091,6 +2091,10 @@ "ns", "ns" ], + "attributes": [ + "ns", + "read_only" + ], "class_b_c": { "_root": [ "ns", @@ -2125,6 +2129,40 @@ "ns", "ns" ], + "locations": [ + "ns", + "read_only" + ], + "network_ids": { + "_root": [ + "ns", + "ns" + ], + "cluster_address": [ + "ns", + "ns" + ], + "cluster_id": [ + "ns", + "ns" + ], + "net_id": [ + "ns", + "ns" + ], + "ns_id": [ + "ns", + "ns" + ], + "tenant_address": [ + "ns", + "ns" + ], + "tenant_id": [ + "ns", + "ns" + ] + }, "priority": [ "ns", "ns" @@ -2132,7 +2170,33 @@ "session_key_id": [ "ns", "ns" - ] + ], + "version_ids": { + "_root": [ + "ns", + "read_only" + ], + "band_id": [ + "ns", + "read_only" + ], + "brand_id": [ + "ns", + "read_only" + ], + "firmware_version": [ + "ns", + "read_only" + ], + "hardware_version": [ + "ns", + "read_only" + ], + "model_id": [ + "ns", + "read_only" + ] + } }, "pending_relay_downlink": { "_root": [ diff --git a/sdk/js/yarn.lock b/sdk/js/yarn.lock index 10e93ece53..36e93787db 100644 --- a/sdk/js/yarn.lock +++ b/sdk/js/yarn.lock @@ -646,9 +646,9 @@ unbox-primitive@^1.0.2: which-boxed-primitive "^1.0.2" web-streams-polyfill@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-4.0.0.tgz#74cedf168339ee6e709532f76c49313a8c7acdac" - integrity sha512-0zJXHRAYEjM2tUfZ2DiSOHAa2aw1tisnnhU3ufD57R8iefL+DcdJyRBRyJpG+NUimDgbTI/lH+gAE1PAvV3Cgw== + version "4.1.0" + resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-4.1.0.tgz#3ba095d0eb3ef6377cd126e8354b2cdba286e0d3" + integrity sha512-A7Jxrg7+eV+eZR/CIdESDnRGFb6/bcKukGvJBB5snI6cw3is1c2qamkYstC1bY1p08TyMRlN9eTMkxmnKJBPBw== which-boxed-primitive@^1.0.2: version "1.0.2" diff --git a/tools/go.mod b/tools/go.mod index 40ce83ad12..9988d4c019 100644 --- a/tools/go.mod +++ b/tools/go.mod @@ -37,7 +37,7 @@ require ( github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.49.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.49.0 // indirect - github.com/KimMachineGun/automemlimit v0.6.1 // indirect + github.com/KimMachineGun/automemlimit v0.7.0 // indirect github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver/v3 v3.3.1 // indirect github.com/Masterminds/sprig/v3 v3.3.0 // indirect @@ -68,7 +68,6 @@ require ( github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.5 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.33.1 // indirect github.com/aws/smithy-go v1.22.1 // indirect - github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.17.0 // indirect github.com/blevesearch/bleve v1.0.14 // indirect @@ -82,22 +81,16 @@ require ( github.com/blevesearch/zap/v14 v14.0.5 // indirect github.com/blevesearch/zap/v15 v15.0.3 // indirect github.com/bluele/gcache v0.0.2 // indirect - github.com/buger/jsonparser v1.1.1 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/cilium/ebpf v0.16.0 // indirect github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 // indirect github.com/coder/websocket v1.8.12 // indirect - github.com/containerd/cgroups/v3 v3.0.4 // indirect - github.com/containerd/log v0.1.0 // indirect - github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/couchbase/vellum v1.0.2 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/disintegration/imaging v1.6.2 // indirect github.com/dlclark/regexp2 v1.11.4 // indirect - github.com/docker/go-units v0.5.0 // indirect github.com/dop251/goja v0.0.0-20241024094426-79f3a7efcdbd // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/eclipse/paho.mqtt.golang v1.5.0 // indirect @@ -105,11 +98,10 @@ require ( github.com/envoyproxy/protoc-gen-validate v1.1.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.8.0 // indirect - github.com/getsentry/sentry-go v0.30.0 // indirect + github.com/getsentry/sentry-go v0.31.1 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-sourcemap/sourcemap v2.1.4+incompatible // indirect - github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/golang-jwt/jwt/v5 v5.2.1 // indirect github.com/golang/gddo v0.0.0-20210115222349-20d68f94ee1f // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect @@ -157,13 +149,11 @@ require ( github.com/kylelemons/godebug v1.1.0 // indirect github.com/lib/pq v1.10.9 // indirect github.com/magiconair/properties v1.8.7 // indirect - github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect github.com/mileusna/useragent v1.3.5 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect - github.com/moby/sys/userns v0.1.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mschoch/smat v0.2.0 // indirect @@ -173,7 +163,6 @@ require ( github.com/nats-io/nuid v1.0.1 // indirect github.com/oklog/ulid/v2 v2.1.0 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect - github.com/opencontainers/runtime-spec v1.2.0 // indirect github.com/openshift/osin v1.0.2-0.20220317075346-0f4d38c6e53f // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/pborman/uuid v1.2.1 // indirect @@ -195,7 +184,6 @@ require ( github.com/sendgrid/rest v2.6.9+incompatible // indirect github.com/sendgrid/sendgrid-go v3.16.0+incompatible // indirect github.com/shopspring/decimal v1.4.0 // indirect - github.com/sirupsen/logrus v1.9.3 // indirect github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect @@ -208,14 +196,13 @@ require ( github.com/subosito/gotenv v1.6.0 // indirect github.com/throttled/throttled/v2 v2.12.0 // indirect github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect - github.com/uptrace/bun v1.2.6 // indirect - github.com/uptrace/bun/dialect/pgdialect v1.2.6 // indirect - github.com/uptrace/bun/driver/pgdriver v1.2.6 // indirect + github.com/uptrace/bun v1.2.8 // indirect + github.com/uptrace/bun/dialect/pgdialect v1.2.8 // indirect + github.com/uptrace/bun/driver/pgdriver v1.2.8 // indirect github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/weppos/publicsuffix-go v0.30.0 // indirect github.com/willf/bitset v1.1.11 // indirect - github.com/wk8/go-ordered-map/v2 v2.1.9-0.20240816141633-0a40785b4f41 // indirect github.com/zmap/zcrypto v0.0.0-20230310154051-c8b263fd8300 // indirect github.com/zmap/zlint/v3 v3.5.0 // indirect go.etcd.io/bbolt v1.3.11 // indirect @@ -248,15 +235,15 @@ require ( go.uber.org/zap v1.27.0 // indirect gocloud.dev v0.40.0 // indirect gocloud.dev/pubsub/natspubsub v0.40.0 // indirect - golang.org/x/crypto v0.31.0 // indirect + golang.org/x/crypto v0.32.0 // indirect golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect golang.org/x/image v0.22.0 // indirect golang.org/x/mod v0.22.0 // indirect - golang.org/x/net v0.33.0 // indirect - golang.org/x/oauth2 v0.24.0 // indirect + golang.org/x/net v0.34.0 // indirect + golang.org/x/oauth2 v0.25.0 // indirect golang.org/x/sync v0.10.0 // indirect - golang.org/x/sys v0.28.0 // indirect - golang.org/x/term v0.27.0 // indirect + golang.org/x/sys v0.29.0 // indirect + golang.org/x/term v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect golang.org/x/time v0.8.0 // indirect golang.org/x/tools v0.27.0 // indirect @@ -265,8 +252,8 @@ require ( google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20241219192143-6b3ec007d9bb // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20241219192143-6b3ec007d9bb // indirect - google.golang.org/grpc v1.69.2 // indirect - google.golang.org/protobuf v1.36.1 // indirect + google.golang.org/grpc v1.69.4 // indirect + google.golang.org/protobuf v1.36.2 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/mail.v2 v2.3.1 // indirect diff --git a/tools/go.sum b/tools/go.sum index 8645f3a127..7eecff75c4 100644 --- a/tools/go.sum +++ b/tools/go.sum @@ -58,8 +58,8 @@ github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0 github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.49.0/go.mod h1:l2fIqmwB+FKSfvn3bAD/0i+AXAxhIZjTK2svT/mgUXs= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.49.0 h1:GYUJLfvd++4DMuMhCFLgLXvFwofIxh/qOwoGuS/LTew= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.49.0/go.mod h1:wRbFgBQUVm1YXrvWKofAEmq9HNJTDphbAaJSSX01KUI= -github.com/KimMachineGun/automemlimit v0.6.1 h1:ILa9j1onAAMadBsyyUJv5cack8Y1WT26yLj/V+ulKp8= -github.com/KimMachineGun/automemlimit v0.6.1/go.mod h1:T7xYht7B8r6AG/AqFcUdc7fzd2bIdBKmepfP2S1svPY= +github.com/KimMachineGun/automemlimit v0.7.0 h1:7G06p/dMSf7G8E6oq+f2uOPuVncFyIlDI/pBWK49u88= +github.com/KimMachineGun/automemlimit v0.7.0/go.mod h1:QZxpHaGOQoYvFhv/r4u3U0JTC2ZcOwbSr11UZF46UBM= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4= @@ -124,8 +124,6 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.33.1 h1:6SZUVRQNvExYlMLbHdlKB48x0fLb github.com/aws/aws-sdk-go-v2/service/sts v1.33.1/go.mod h1:GqWyYCwLXnlUB1lOAXQyNSPqPLQJvmo8J0DWBzp9mtg= github.com/aws/smithy-go v1.22.1 h1:/HPHZQ0g7f4eUeK6HKglFz8uwVfZKgoI25rb/J+dnro= github.com/aws/smithy-go v1.22.1/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= -github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= -github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= @@ -168,8 +166,6 @@ github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdb github.com/bsm/gomega v1.26.0/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= -github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= -github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -179,8 +175,6 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cilium/ebpf v0.16.0 h1:+BiEnHL6Z7lXnlGUsXQPPAE7+kenAd4ES8MQ5min0Ok= -github.com/cilium/ebpf v0.16.0/go.mod h1:L7u2Blt2jMM/vLAVgjxluxtBKlz3/GWjB0dMOEngfwE= github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cfssl v1.6.5 h1:46zpNkm6dlNkMZH/wMW22ejih6gIaJbzL2du6vD7ZeI= @@ -190,15 +184,9 @@ github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 h1:QVw89YDxXxEe+l8gU8E github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo= github.com/coder/websocket v1.8.12/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs= -github.com/containerd/cgroups/v3 v3.0.4 h1:2fs7l3P0Qxb1nKWuJNFiwhp2CqiKzho71DQkDrHJIo4= -github.com/containerd/cgroups/v3 v3.0.4/go.mod h1:SA5DLYnXO8pTGYiAHXz94qvLQTKfVM5GEVisn4jpins= -github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= -github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= -github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/couchbase/ghistogram v0.1.0/go.mod h1:s1Jhy76zqfEecpNWJfWUiKZookAFaiGOEoyzgHt9i7k= github.com/couchbase/moss v0.1.0/go.mod h1:9MaHIaRuy9pvLPUJxB8sh8OrLfyDczECVL37grCIubs= github.com/couchbase/vellum v1.0.2 h1:BrbP0NKiyDdndMPec8Jjhy0U47CZ0Lgx3xUC2r9rZqw= @@ -222,8 +210,6 @@ github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1 github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo= github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= -github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= -github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dop251/goja v0.0.0-20241024094426-79f3a7efcdbd h1:QMSNEh9uQkDjyPwu/J541GgSH+4hw+0skJDIj9HJ3mE= github.com/dop251/goja v0.0.0-20241024094426-79f3a7efcdbd/go.mod h1:MxLav0peU43GgvwVgNbLAj1s/bSGboKkhuULvq/7hx4= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= @@ -255,8 +241,8 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4 github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/garyburd/redigo v1.1.1-0.20170914051019-70e1b1943d4f/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= -github.com/getsentry/sentry-go v0.30.0 h1:lWUwDnY7sKHaVIoZ9wYqRHJ5iEmoc0pqcRqFkosKzBo= -github.com/getsentry/sentry-go v0.30.0/go.mod h1:WU9B9/1/sHDqeV8T+3VwwbjeR5MSXs/6aqG3mqZrezA= +github.com/getsentry/sentry-go v0.31.1 h1:ELVc0h7gwyhnXHDouXkhqTFSO5oslsRDk0++eyE0KJ4= +github.com/getsentry/sentry-go v0.31.1/go.mod h1:CYNcMMz73YigoHljQRG+qPF+eMq8gG72XcGN/p71BAY= github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= @@ -269,8 +255,6 @@ github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= -github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= github.com/go-redis/redis v6.15.8+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-redis/redis/v8 v8.4.2/go.mod h1:A1tbYoHSa1fXwN+//ljcCYYJeLmVrwL9hbQN45Jdy0M= github.com/go-sourcemap/sourcemap v2.1.4+incompatible h1:a+iTbH5auLKxaNwQFg0B+TCYl6lbukKPc7b5x0n1s6Q= @@ -278,9 +262,6 @@ github.com/go-sourcemap/sourcemap v2.1.4+incompatible/go.mod h1:F8jJfvm2KbVjc5Nq github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.6.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= -github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= @@ -434,11 +415,6 @@ github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= -github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= -github.com/jsimonetti/rtnetlink/v2 v2.0.1 h1:xda7qaHDSVOsADNouv7ukSuicKZO7GgVUCXxpaIEIlM= -github.com/jsimonetti/rtnetlink/v2 v2.0.1/go.mod h1:7MoNYNbb3UaDHtF8udiJo/RH6VsTKP1pqKLUTVCvToE= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jtacoma/uritemplates v1.0.0 h1:xwx5sBF7pPAb0Uj8lDC1Q/aBPpOFyQza7OC705ZlLCo= @@ -473,8 +449,6 @@ github.com/magiconair/properties v1.7.4-0.20170902060319-8d7837e64d3c/go.mod h1: github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.0.10-0.20170816031813-ad5389df28cd/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.2/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= @@ -483,10 +457,6 @@ github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/goveralls v0.0.12 h1:PEEeF0k1SsTjOBQ8FOmrOAoCu4ytuMaWCnWe94zxbCg= github.com/mattn/goveralls v0.0.12/go.mod h1:44ImGEUfmqH8bBtaMrYKsM65LXfNLWmwaxFGjZwgMSQ= -github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g= -github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= -github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= -github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= github.com/mileusna/useragent v1.3.5 h1:SJM5NzBmh/hO+4LGeATKpaEX9+b4vcGg2qXGLiNGDws= github.com/mileusna/useragent v1.3.5/go.mod h1:3d8TOmwL/5I8pJjyVDteHtgDGcefrFUX4ccGOMKNYYc= github.com/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD6Q= @@ -500,8 +470,6 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= -github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -540,8 +508,6 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= -github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk= -github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/openshift/build-machinery-go v0.0.0-20200917070002-f171684f77ab/go.mod h1:b1BuldmJlbA/xYtdZvKi+7j5YGB44qJUJDZ9zwiNCfE= github.com/openshift/osin v1.0.2-0.20220317075346-0f4d38c6e53f h1:4da9vH8eDlJo58703cADj3FlsdnFRgsnfuwj/4lYXfY= github.com/openshift/osin v1.0.2-0.20220317075346-0f4d38c6e53f/go.mod h1:DoYehsADYGKlXTIvqyZVnopfJbWgT6UsQYf8ETt1vjw= @@ -612,8 +578,6 @@ github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M= github.com/smarty/assertions v1.16.0 h1:EvHNkdRA4QHMrn75NZSoUQ/mAUXAYWfatfB01yTCzfY= @@ -676,12 +640,12 @@ github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDW github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo= github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/uptrace/bun v1.2.6 h1:lyGBQAhNiClchb97HA2cBnDeRxwTRLhSIgiFPXVisV8= -github.com/uptrace/bun v1.2.6/go.mod h1:xMgnVFf+/5xsrFBU34HjDJmzZnXbVuNEt/Ih56I8qBU= -github.com/uptrace/bun/dialect/pgdialect v1.2.6 h1:iNd1YLx619K+sZK+dRcWPzluurXYK1QwIkp9FEfNB/8= -github.com/uptrace/bun/dialect/pgdialect v1.2.6/go.mod h1:OL7d3qZLxKYP8kxNhMg3IheN1pDR3UScGjoUP+ivxJQ= -github.com/uptrace/bun/driver/pgdriver v1.2.6 h1:dD7ckqIhVDayfYTwMKZ0dJM9AZfNJNBu5Cg/8g0EMOk= -github.com/uptrace/bun/driver/pgdriver v1.2.6/go.mod h1:ChrVrMZlRzPQHTP4QCm/p1FfQqgnYXWlES0GS9qjWEY= +github.com/uptrace/bun v1.2.8 h1:HEiLvy9wc7ehU5S02+O6NdV5BLz48lL4REPhTkMX3Dg= +github.com/uptrace/bun v1.2.8/go.mod h1:JBq0uBKsKqNT0Ccce1IAFZY337Wkf08c6F6qlmfOHE8= +github.com/uptrace/bun/dialect/pgdialect v1.2.8 h1:9n3qVh6yc+u7F3lpXzsWrAFJG1yLHUC2thjCCVEDpM8= +github.com/uptrace/bun/dialect/pgdialect v1.2.8/go.mod h1:plksD43MjAlPGYLD9/SzsLUpGH5poXE9IB1+ka/sEzE= +github.com/uptrace/bun/driver/pgdriver v1.2.8 h1:5XrNn/9enSrWhhrUpz+6PY9S1vcg/jhCQPJu+ZmsKX4= +github.com/uptrace/bun/driver/pgdriver v1.2.8/go.mod h1:cwRRwqabgePwYBiLlXtbeNmPD7LGJnqP21J2ZKP4ah8= github.com/vitorsalgado/mocha/v2 v2.0.2 h1:wb1QCRzVkp8uhRcUYmb9jJfbMj/qbiqcDyD8rD+Ldfw= github.com/vitorsalgado/mocha/v2 v2.0.2/go.mod h1:l7jRVm7KTL4VAxxazH99UVo+KzwztjrYpFTksTmL1DE= github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= @@ -696,8 +660,6 @@ github.com/weppos/publicsuffix-go/publicsuffix/generator v0.0.0-20220927085643-d github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= github.com/willf/bitset v1.1.11 h1:N7Z7E9UvjW+sGsEl7k/SJrvY2reP1A07MrGuCjIOjRE= github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI= -github.com/wk8/go-ordered-map/v2 v2.1.9-0.20240816141633-0a40785b4f41 h1:rnB8ZLMeAr3VcqjfRkAm27qb8y6zFKNfuHvy1Gfe7KI= -github.com/wk8/go-ordered-map/v2 v2.1.9-0.20240816141633-0a40785b4f41/go.mod h1:DbzwytT4g/odXquuOCqroKvtxxldI4nb3nuesHF/Exo= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -794,8 +756,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= -golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= +golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo= golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak= @@ -840,13 +802,13 @@ golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= -golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= +golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= golang.org/x/oauth2 v0.0.0-20170912212905-13449ad91cb2/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= -golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.25.0 h1:CY4y7XT9v0cRI9oupztF8AgiIu99L/ksR/Xp/6jrZ70= +golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20170517211232-f52d1811a629/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -891,8 +853,8 @@ golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -902,8 +864,8 @@ golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= -golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= -golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= +golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -966,8 +928,8 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU= -google.golang.org/grpc v1.69.2/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= +google.golang.org/grpc v1.69.4 h1:MF5TftSMkd8GLw/m0KM6V8CMOCY6NZ1NQDPGFgbTt4A= +google.golang.org/grpc v1.69.4/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -977,8 +939,8 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= -google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.2 h1:R8FeyR1/eLmkutZOM5CWghmo5itiG9z0ktFlTVLuTmU= +google.golang.org/protobuf v1.36.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/tools/js/serve-dev-webui.js b/tools/js/serve-dev-webui.js index 5197ae41cf..8f01648dd0 100644 --- a/tools/js/serve-dev-webui.js +++ b/tools/js/serve-dev-webui.js @@ -29,6 +29,8 @@ export TTN_LW_LOG_LEVEL="debug" export TTN_LW_NOC_ACCESS_EXTENDED="true" export TTN_LW_PLUGINS_SOURCE="directory" export TTN_LW_CONSOLE_UI_CANONICAL_URL="http://localhost:8080/console" +export TTN_LW_TRACING_ENABLE="false" +export TTN_LW_TELEMETRY_ENABLE="false" ` // Local configuration environment variables @@ -136,6 +138,9 @@ if (relevantSetEnvs.length > 0) { } envConfig += stagingConfig } + } else { + // Cypress setup + envConfig = `${baseConfig + localConfig}export CYPRESS_BASE_URL="http://localhost:8080"\n` } const envVars = envConfig diff --git a/tools/mage/dev.go b/tools/mage/dev.go index cd0e903cb3..7158329622 100644 --- a/tools/mage/dev.go +++ b/tools/mage/dev.go @@ -135,21 +135,39 @@ func (Dev) SQLRestore() error { ) } -// RedisFlush deletes all keys from redis. +// RedisFlush deletes all keys from redis except specific task queues. func (Dev) RedisFlush() error { if mg.Verbose() { - fmt.Println("Deleting all keys from redis") + fmt.Println("Deleting keys from redis (preserving task queues)") } keys, err := sh.Output("docker", dockerComposeFlags("exec", "-T", "redis", "redis-cli", "keys", "ttn:v3:*")...) if err != nil { return err } + ks := strings.Split(keys, "\n") if len(ks) == 0 { return nil } - flags := dockerComposeFlags(append([]string{"exec", "-T", "redis", "redis-cli", "del"}, ks...)...) + + // Delete all keys except preserved ones + baseArgs := []string{"exec", "-T", "redis", "redis-cli", "del"} + keysToDelete := make([]string, 0, len(ks)) + + for _, k := range ks { + if k != "ttn:v3:ns:tasks:downlink:ready" && + k != "ttn:v3:ns:tasks:downlink:input" && + k != "ttn:v3:ns:application-uplinks:uplinks" { + keysToDelete = append(keysToDelete, k) + } + } + // No keys to delete + if len(keysToDelete) == len(baseArgs) { + return nil + } + + flags := dockerComposeFlags(append(baseArgs, keysToDelete...)...) _, err = sh.Exec(nil, nil, os.Stderr, "docker", flags...) return err } diff --git a/yarn.lock b/yarn.lock index c0d60a6db2..8f7c0a9ae2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -71,10 +71,10 @@ json5 "^2.2.3" semver "^6.3.1" -"@babel/eslint-parser@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.25.9.tgz#603c68a63078796527bc9d0833f5e52dd5f9224c" - integrity sha512-5UXfgpK0j0Xr/xIdgdLEhOFxaDZ0bRPWJJchRpqOSur/3rZoPbqqki5mm0p4NE2cs28krBEiSM2MB7//afRSQQ== +"@babel/eslint-parser@^7.26.5": + version "7.26.5" + resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.26.5.tgz#aa669f4d873f9cd617050cf3c40c19cd96307efb" + integrity sha512-Kkm8C8uxI842AwQADxl0GbcG1rupELYLShazYEZO/2DYjhyWXJIOUVOE3tBYm6JXzUCNJOZEzqc4rCW/jsEQYQ== dependencies: "@nicolo-ribaudo/eslint-scope-5-internals" "5.1.1-v1" eslint-visitor-keys "^2.1.0" @@ -1202,10 +1202,10 @@ debug "^3.1.0" lodash.once "^4.1.1" -"@discoveryjs/json-ext@^0.5.0": - version "0.5.7" - resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" - integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== +"@discoveryjs/json-ext@^0.6.1": + version "0.6.3" + resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.6.3.tgz#f13c7c205915eb91ae54c557f5e92bddd8be0e83" + integrity sha512-4B4OijXeVNOPZlYA2oEwWOTkzyltLao+xbotHQeqN++Rv27Y6s818+n2Qkp8q+Fxhn0t/5lA5X1Mxktud8eayQ== "@dual-bundle/import-meta-resolve@^4.1.0": version "4.1.0" @@ -1496,64 +1496,65 @@ resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.1.tgz#16308cea045f0fc777b6ff20a9f25474dd8293d2" integrity sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q== -"@formatjs/ecma402-abstract@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-2.3.1.tgz#cdeb3ffe1aeea9c4284b85b7e37e8e8615314c39" - integrity sha512-Ip9uV+/MpLXWRk03U/GzeJMuPeOXpJBSB5V1tjA6kJhvqssye5J5LoYLc7Z5IAHb7nR62sRoguzrFiVCP/hnzw== +"@formatjs/ecma402-abstract@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-2.3.2.tgz#0ee291effe7ee2c340742a6c95d92eacb5e6c00a" + integrity sha512-6sE5nyvDloULiyOMbOTJEEgWL32w+VHkZQs8S02Lnn8Y/O5aQhjOEXwWzvR7SsBE/exxlSpY2EsWZgqHbtLatg== dependencies: - "@formatjs/fast-memoize" "2.2.5" - "@formatjs/intl-localematcher" "0.5.9" + "@formatjs/fast-memoize" "2.2.6" + "@formatjs/intl-localematcher" "0.5.10" decimal.js "10" tslib "2" -"@formatjs/fast-memoize@2.2.5": - version "2.2.5" - resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-2.2.5.tgz#54a4a1793d773b72c372d3dcab3595149aee7880" - integrity sha512-6PoewUMrrcqxSoBXAOJDiW1m+AmkrAj0RiXnOMD59GRaswjXhm3MDhgepXPBgonc09oSirAJTsAggzAGQf6A6g== +"@formatjs/fast-memoize@2.2.6": + version "2.2.6" + resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-2.2.6.tgz#fac0a84207a1396be1f1aa4ee2805b179e9343d1" + integrity sha512-luIXeE2LJbQnnzotY1f2U2m7xuQNj2DA8Vq4ce1BY9ebRZaoPB1+8eZ6nXpLzsxuW5spQxr7LdCg+CApZwkqkw== dependencies: tslib "2" -"@formatjs/icu-messageformat-parser@2.9.7": - version "2.9.7" - resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.9.7.tgz#84abd5c86ef2ad7cb82da63b3380c33808efb6da" - integrity sha512-cuEHyRM5VqLQobANOjtjlgU7+qmk9Q3fDQuBiRRJ3+Wp3ZoZhpUPtUfuimZXsir6SaI2TaAJ+SLo9vLnV5QcbA== +"@formatjs/icu-messageformat-parser@2.9.8": + version "2.9.8" + resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.9.8.tgz#118e7156f8a8db6b27b650f09334db21456c681f" + integrity sha512-hZlLNI3+Lev8IAXuwehLoN7QTKqbx3XXwFW1jh0AdIA9XJdzn9Uzr+2LLBspPm/PX0+NLIfykj/8IKxQqHUcUQ== dependencies: - "@formatjs/ecma402-abstract" "2.3.1" - "@formatjs/icu-skeleton-parser" "1.8.11" + "@formatjs/ecma402-abstract" "2.3.2" + "@formatjs/icu-skeleton-parser" "1.8.12" tslib "2" -"@formatjs/icu-skeleton-parser@1.8.11": - version "1.8.11" - resolved "https://registry.yarnpkg.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.11.tgz#e7c9918274dfa0c1c2bca1ab6e15ef49b10cf0bb" - integrity sha512-8LlHHE/yL/zVJZHAX3pbKaCjZKmBIO6aJY1mkVh4RMSEu/2WRZ4Ysvv3kKXJ9M8RJLBHdnk1/dUQFdod1Dt7Dw== +"@formatjs/icu-skeleton-parser@1.8.12": + version "1.8.12" + resolved "https://registry.yarnpkg.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.12.tgz#43076747cdbe0f23bfac2b2a956bd8219716680d" + integrity sha512-QRAY2jC1BomFQHYDMcZtClqHR55EEnB96V7Xbk/UiBodsuFc5kujybzt87+qj1KqmJozFhk6n4KiT1HKwAkcfg== dependencies: - "@formatjs/ecma402-abstract" "2.3.1" + "@formatjs/ecma402-abstract" "2.3.2" tslib "2" -"@formatjs/intl-datetimeformat@^6.17.1": - version "6.17.1" - resolved "https://registry.yarnpkg.com/@formatjs/intl-datetimeformat/-/intl-datetimeformat-6.17.1.tgz#d5e800891f9d79c8f1af1999f51db51f1384eca1" - integrity sha512-a18NqRo6R73xpREuMZo8FqjO+LnYFDHoeoviTh5de4ebI46wqLSDgbAIKoceuWblTQt8bvCpJIwvKgLItea88Q== +"@formatjs/intl-datetimeformat@^6.17.2": + version "6.17.2" + resolved "https://registry.yarnpkg.com/@formatjs/intl-datetimeformat/-/intl-datetimeformat-6.17.2.tgz#37e571dfb6ce8a2a9e29e1519b50720c7cb0ff3c" + integrity sha512-8Y3qViHTDg4W8mhe68Ido5wPtjF9nlQZUzYJ0QoM9xDJGr6L5WOBBCGOV8wN/TuYHrTPlJi3EzC4TZxXFFGq4g== dependencies: - "@formatjs/ecma402-abstract" "2.3.1" - "@formatjs/intl-localematcher" "0.5.9" + "@formatjs/ecma402-abstract" "2.3.2" + "@formatjs/intl-localematcher" "0.5.10" + decimal.js "10" tslib "2" -"@formatjs/intl-displaynames@^6.8.8": - version "6.8.8" - resolved "https://registry.yarnpkg.com/@formatjs/intl-displaynames/-/intl-displaynames-6.8.8.tgz#ce90876b37f761ed945e7b0e77b6e8e48c63d8ce" - integrity sha512-adxyxMt7cw1SGth87e3QjbtDH2aKWtczbjibMdp04rxSroh2S4jtkaBdva3gL9pKDU0FxRyp7I+lUu/8aGMbsQ== +"@formatjs/intl-displaynames@^6.8.9": + version "6.8.9" + resolved "https://registry.yarnpkg.com/@formatjs/intl-displaynames/-/intl-displaynames-6.8.9.tgz#69a873272c46754f4cfd9c954512d3f925a54be5" + integrity sha512-HBbh6A4o7XGYjO2icJmlN05xoQyneUStX3bl0JUcs0TFGpVjXISj+8ZfXq91SbB7UQ5vxl2fTX9oMrUWU9+bug== dependencies: - "@formatjs/ecma402-abstract" "2.3.1" - "@formatjs/intl-localematcher" "0.5.9" + "@formatjs/ecma402-abstract" "2.3.2" + "@formatjs/intl-localematcher" "0.5.10" tslib "2" -"@formatjs/intl-enumerator@1.8.7": - version "1.8.7" - resolved "https://registry.yarnpkg.com/@formatjs/intl-enumerator/-/intl-enumerator-1.8.7.tgz#3f004753333f80cc468ae34046bd8416772a0412" - integrity sha512-qd7UlWUivKRJ073btssUqMSqzWW9yN3Ki6EqfCZ6uvIv19mONelE5q3GMmdPWBEjgqZikBzBE2qPTqfrgJ4TCA== +"@formatjs/intl-enumerator@1.8.8": + version "1.8.8" + resolved "https://registry.yarnpkg.com/@formatjs/intl-enumerator/-/intl-enumerator-1.8.8.tgz#e04642a695fa48edbc5b8068bc241149ef18e8f0" + integrity sha512-U/1FGFNObuWWy0N+DwRiDDZvH8cjKixjDDbgr1I1RJ66jOLSVDUApdOsGd8hSmFFAiNXT5s4tM9WfL4QT5VoSw== dependencies: - "@formatjs/ecma402-abstract" "2.3.1" + "@formatjs/ecma402-abstract" "2.3.2" tslib "2" "@formatjs/intl-getcanonicallocales@2.5.4": @@ -1563,70 +1564,70 @@ dependencies: tslib "2" -"@formatjs/intl-listformat@^7.7.8": - version "7.7.8" - resolved "https://registry.yarnpkg.com/@formatjs/intl-listformat/-/intl-listformat-7.7.8.tgz#9aba13a1a360a167903667b444e0bfc2ba09c35f" - integrity sha512-ezlfqfyegMbepGVcf3rTApVGIbZQvJwx1PZsXjMe2xAqEU1jSBZ/2efLE8u3sUBHGrrsdWER98W85zCg4N7rmQ== +"@formatjs/intl-listformat@^7.7.9": + version "7.7.9" + resolved "https://registry.yarnpkg.com/@formatjs/intl-listformat/-/intl-listformat-7.7.9.tgz#c0cde2b83d11c18ff531f4362740430819e51ea1" + integrity sha512-VGbGrngcjwrlPvstc6ysCwGlbxaq3PKXSkC9P5DYyfLI+C6I+PIog9UW8rPwH1xLXMfmyZblrkvkRboGn3E8qA== dependencies: - "@formatjs/ecma402-abstract" "2.3.1" - "@formatjs/intl-localematcher" "0.5.9" + "@formatjs/ecma402-abstract" "2.3.2" + "@formatjs/intl-localematcher" "0.5.10" tslib "2" -"@formatjs/intl-locale@^4.2.8": - version "4.2.8" - resolved "https://registry.yarnpkg.com/@formatjs/intl-locale/-/intl-locale-4.2.8.tgz#571d44e92b6eb43b7410b37f25e280ec384a32cf" - integrity sha512-6RY/npeA0kyoZ8QW0JRAT+VBAFBT6+4ZVeGkKCNIDjbLX2LPuU73emGR35Mbwcc6pquVFrxyo6mXxKNzib0kEA== +"@formatjs/intl-locale@^4.2.9": + version "4.2.9" + resolved "https://registry.yarnpkg.com/@formatjs/intl-locale/-/intl-locale-4.2.9.tgz#3fc9b1bc46dcc12de3906a993547211a8fd64d8e" + integrity sha512-zX3Y06SmZ3sAGymzTFNTpWCx4yfdHmuODpGBPbyMfA5Z7Frc17VKEW+D7FIJOVdBZD1918d97vKxu7UAlAxwaw== dependencies: - "@formatjs/ecma402-abstract" "2.3.1" - "@formatjs/intl-enumerator" "1.8.7" + "@formatjs/ecma402-abstract" "2.3.2" + "@formatjs/intl-enumerator" "1.8.8" "@formatjs/intl-getcanonicallocales" "2.5.4" tslib "2" -"@formatjs/intl-localematcher@0.5.9": - version "0.5.9" - resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.5.9.tgz#43c6ee22be85b83340bcb09bdfed53657a2720db" - integrity sha512-8zkGu/sv5euxbjfZ/xmklqLyDGQSxsLqg8XOq88JW3cmJtzhCP8EtSJXlaKZnVO4beEaoiT9wj4eIoCQ9smwxA== +"@formatjs/intl-localematcher@0.5.10": + version "0.5.10" + resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.5.10.tgz#1e0bd3fc1332c1fe4540cfa28f07e9227b659a58" + integrity sha512-af3qATX+m4Rnd9+wHcjJ4w2ijq+rAVP3CCinJQvFv1kgSu1W6jypUmvleJxcewdxmutM8dmIRZFxO/IQBZmP2Q== dependencies: tslib "2" -"@formatjs/intl-numberformat@^8.15.1": - version "8.15.1" - resolved "https://registry.yarnpkg.com/@formatjs/intl-numberformat/-/intl-numberformat-8.15.1.tgz#b2a5b00889ed31dbef9d4e5aeee1dea3d040b068" - integrity sha512-NIouSY50xpH/SMJrRbX1Q3hMsGyQmT5MQrta/bOYhpZda1bztOlEYZAKLytk8VGs10wkGz875602mCMhtg4/LA== +"@formatjs/intl-numberformat@^8.15.2": + version "8.15.2" + resolved "https://registry.yarnpkg.com/@formatjs/intl-numberformat/-/intl-numberformat-8.15.2.tgz#dd131d15b0e22351ffcf6523b9421852fa1268f1" + integrity sha512-8rdXSBKXb0nyfEX98/Sh3+ML4JXK2vm7Slnrjikx1svXoBKhiw8kZKwQMpAcGIKtEiQA0conUW3LMPXzv/YlSg== dependencies: - "@formatjs/ecma402-abstract" "2.3.1" - "@formatjs/intl-localematcher" "0.5.9" + "@formatjs/ecma402-abstract" "2.3.2" + "@formatjs/intl-localematcher" "0.5.10" decimal.js "10" tslib "2" -"@formatjs/intl-pluralrules@^5.4.1": - version "5.4.1" - resolved "https://registry.yarnpkg.com/@formatjs/intl-pluralrules/-/intl-pluralrules-5.4.1.tgz#1c03cd2da449e1871bb7c54ea36fec1de68b7e7e" - integrity sha512-kKK4ixTsfKAzyJIVRiJGuw4zd18nEHXiKloYBO9VmLpxrwJTgLQHv2+1hcbxQcwbbo2uc8moUFQuyvxeGEFOfw== +"@formatjs/intl-pluralrules@^5.4.2": + version "5.4.2" + resolved "https://registry.yarnpkg.com/@formatjs/intl-pluralrules/-/intl-pluralrules-5.4.2.tgz#59413d61fcf873a5fb7ea738626891082d5a9c18" + integrity sha512-iPjo+F3q7W7KPQrIwJ7Hm72viKtvJeqcpyCHOWcx4haw04gnHksmd1qqfLgXj8l0w66kfG5f1ECwNfToYtseUA== dependencies: - "@formatjs/ecma402-abstract" "2.3.1" - "@formatjs/intl-localematcher" "0.5.9" + "@formatjs/ecma402-abstract" "2.3.2" + "@formatjs/intl-localematcher" "0.5.10" decimal.js "10" tslib "2" -"@formatjs/intl-relativetimeformat@^11.4.8": - version "11.4.8" - resolved "https://registry.yarnpkg.com/@formatjs/intl-relativetimeformat/-/intl-relativetimeformat-11.4.8.tgz#c9ad072b7c866e78ee359b188e3599bd994328f7" - integrity sha512-HOyTJaxMLpurJXAwRyYsElxiLKXJnbczghxZNe4Rqlstet8dZxwBonGkAnkd1sKgmVp2W2454nr40dlvlMRqnA== +"@formatjs/intl-relativetimeformat@^11.4.9": + version "11.4.9" + resolved "https://registry.yarnpkg.com/@formatjs/intl-relativetimeformat/-/intl-relativetimeformat-11.4.9.tgz#81f3fd8bf2bf2d132cb3cb06b1f943967e89990b" + integrity sha512-nhDpZkDcAoW7hfqy6kLwY/Zb41rRKzkyWp7kbTZHmIsIjUfKlqekoBuwZ7xfOOKz82wsJkkJWASB60gkLWt9Ng== dependencies: - "@formatjs/ecma402-abstract" "2.3.1" - "@formatjs/intl-localematcher" "0.5.9" + "@formatjs/ecma402-abstract" "2.3.2" + "@formatjs/intl-localematcher" "0.5.10" tslib "2" -"@formatjs/intl@3.0.4": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@formatjs/intl/-/intl-3.0.4.tgz#b257d8c472b8f439d5e901fd74ea47b97d3cebb5" - integrity sha512-pnetak6R7Xp/ET96O5kx9zRYoQQqr6sbRXWkJHKw0Hr/jr3ls4CddZKq+suwCDuW6p/ior2BhpOSh/WLLcJM6w== +"@formatjs/intl@3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@formatjs/intl/-/intl-3.1.0.tgz#5fd40b593d412e25ff86ae5a6de0bbda4774fd52" + integrity sha512-1TIJAPMs8e0O2L/kbIyC0PKmnujO199dhHxCeJ5Loi0FT8K4HAJzcnc/f5buj/OAQZ7m9bw29VjV5uQS0L3Mtw== dependencies: - "@formatjs/ecma402-abstract" "2.3.1" - "@formatjs/fast-memoize" "2.2.5" - "@formatjs/icu-messageformat-parser" "2.9.7" - intl-messageformat "10.7.10" + "@formatjs/ecma402-abstract" "2.3.2" + "@formatjs/fast-memoize" "2.2.6" + "@formatjs/icu-messageformat-parser" "2.9.8" + intl-messageformat "10.7.11" tslib "2" "@hapi/hoek@^9.0.0", "@hapi/hoek@^9.3.0": @@ -1660,29 +1661,29 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz#d9fae00a2d5cb40f92cfe64b47ad749fbc38f917" integrity sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw== -"@inquirer/checkbox@^4.0.4": - version "4.0.4" - resolved "https://registry.yarnpkg.com/@inquirer/checkbox/-/checkbox-4.0.4.tgz#e7335f9c23f4100f789a8fceb26417c9a74a6dee" - integrity sha512-fYAKCAcGNMdfjL6hZTRUwkIByQ8EIZCXKrIQZH7XjADnN/xvRUhj8UdBbpC4zoUzvChhkSC/zRKaP/tDs3dZpg== +"@inquirer/checkbox@^4.0.5": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@inquirer/checkbox/-/checkbox-4.0.5.tgz#901b1cb135b322f43e50a1a9d004ad31613ff70e" + integrity sha512-H//QP3E8Vy0oYX5lw6WSFnOTiRUNm4+LYRby1/1r6y3doRurnqekAj4pJoUbdL5ESEgLqJFJ5HhNDWTp5Qyz5A== dependencies: - "@inquirer/core" "^10.1.2" + "@inquirer/core" "^10.1.3" "@inquirer/figures" "^1.0.9" "@inquirer/type" "^3.0.2" ansi-escapes "^4.3.2" yoctocolors-cjs "^2.1.2" -"@inquirer/confirm@^5.1.1": - version "5.1.1" - resolved "https://registry.yarnpkg.com/@inquirer/confirm/-/confirm-5.1.1.tgz#18385064b8275eb79fdba505ce527801804eea04" - integrity sha512-vVLSbGci+IKQvDOtzpPTCOiEJCNidHcAq9JYVoWTW0svb5FiwSLotkM+JXNXejfjnzVYV9n0DTBythl9+XgTxg== +"@inquirer/confirm@^5.1.2": + version "5.1.2" + resolved "https://registry.yarnpkg.com/@inquirer/confirm/-/confirm-5.1.2.tgz#af43448417204b87a67036521ab6f675a906438f" + integrity sha512-VKgaKxw2I3cu2smedeMFyxuYyI+HABlFY1Px4j8NueA7xDskKAo9hxEQemTpp1Fu4OiTtOCgU4eK91BVuBKH3g== dependencies: - "@inquirer/core" "^10.1.2" + "@inquirer/core" "^10.1.3" "@inquirer/type" "^3.0.2" -"@inquirer/core@^10.1.2": - version "10.1.2" - resolved "https://registry.yarnpkg.com/@inquirer/core/-/core-10.1.2.tgz#a9c5b9ed814a636e99b5c0a8ca4f1626d99fd75d" - integrity sha512-bHd96F3ezHg1mf/J0Rb4CV8ndCN0v28kUlrHqP7+ECm1C/A+paB7Xh2lbMk6x+kweQC+rZOxM/YeKikzxco8bQ== +"@inquirer/core@^10.1.3": + version "10.1.3" + resolved "https://registry.yarnpkg.com/@inquirer/core/-/core-10.1.3.tgz#c52101b3f3ceb1b5591c8bed49424726336dc02a" + integrity sha512-+7/dCYwDku2xfcWJWX6Urxb8aRz6d0K+4lRgIBM08ktE84dm++RPROgnVfWq4hLK5FVu/O4rbO9HnJtaz3pt2w== dependencies: "@inquirer/figures" "^1.0.9" "@inquirer/type" "^3.0.2" @@ -1694,21 +1695,21 @@ wrap-ansi "^6.2.0" yoctocolors-cjs "^2.1.2" -"@inquirer/editor@^4.2.1": - version "4.2.1" - resolved "https://registry.yarnpkg.com/@inquirer/editor/-/editor-4.2.1.tgz#9887e95aa28a52eb20e9e08d85cb3698ef404601" - integrity sha512-xn9aDaiP6nFa432i68JCaL302FyL6y/6EG97nAtfIPnWZ+mWPgCMLGc4XZ2QQMsZtu9q3Jd5AzBPjXh10aX9kA== +"@inquirer/editor@^4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@inquirer/editor/-/editor-4.2.2.tgz#1a6d63eb3dcacb54f20c499d7e67544d5a125b07" + integrity sha512-BPLJsWxLO6r47wU2qtGG+akQuoSCotDlOu8GTIkJVxJpNNVYnA60xKHkSGbEAALO+D3DFeRXE0JFvFJ53sVbjA== dependencies: - "@inquirer/core" "^10.1.2" + "@inquirer/core" "^10.1.3" "@inquirer/type" "^3.0.2" external-editor "^3.1.0" -"@inquirer/expand@^4.0.4": - version "4.0.4" - resolved "https://registry.yarnpkg.com/@inquirer/expand/-/expand-4.0.4.tgz#e3b052835e48fd4ebcf71813b7eae8b03c729d1b" - integrity sha512-GYocr+BPyxKPxQ4UZyNMqZFSGKScSUc0Vk17II3J+0bDcgGsQm0KYQNooN1Q5iBfXsy3x/VWmHGh20QnzsaHwg== +"@inquirer/expand@^4.0.5": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@inquirer/expand/-/expand-4.0.5.tgz#af22e94be68d9ca89976ddd08ae9526a0365eb39" + integrity sha512-Ff3CqHmc8MuUu9A0LKgftzIdp+D5k/kTYHGmjY7iouO37OuP6Np4UqL0clkjQ2UHph7ORwvi0RMfSNnH3PF0PQ== dependencies: - "@inquirer/core" "^10.1.2" + "@inquirer/core" "^10.1.3" "@inquirer/type" "^3.0.2" yoctocolors-cjs "^2.1.2" @@ -1717,72 +1718,72 @@ resolved "https://registry.yarnpkg.com/@inquirer/figures/-/figures-1.0.9.tgz#9d8128f8274cde4ca009ca8547337cab3f37a4a3" integrity sha512-BXvGj0ehzrngHTPTDqUoDT3NXL8U0RxUk2zJm2A66RhCEIWdtU1v6GuUqNAgArW4PQ9CinqIWyHdQgdwOj06zQ== -"@inquirer/input@^4.1.1": - version "4.1.1" - resolved "https://registry.yarnpkg.com/@inquirer/input/-/input-4.1.1.tgz#aea2e463087c6aae57b9801e1ae5648f50d0d22e" - integrity sha512-nAXAHQndZcXB+7CyjIW3XuQZZHbQQ0q8LX6miY6bqAWwDzNa9JUioDBYrFmOUNIsuF08o1WT/m2gbBXvBhYVxg== +"@inquirer/input@^4.1.2": + version "4.1.2" + resolved "https://registry.yarnpkg.com/@inquirer/input/-/input-4.1.2.tgz#01d50e435c02c168ec2b9f0273618710fb3cc3c5" + integrity sha512-YnnskI/AX92KVU6gjNxdeLNqdJPBEOkL3I6EzZjfByKskjZtJuAX1CBev8AAHJsLaB3X9JCQoB/ag2dyzRPdSg== dependencies: - "@inquirer/core" "^10.1.2" + "@inquirer/core" "^10.1.3" "@inquirer/type" "^3.0.2" -"@inquirer/number@^3.0.4": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@inquirer/number/-/number-3.0.4.tgz#090dcac6886d0cddc255f6624b61fb4461747fee" - integrity sha512-DX7a6IXRPU0j8kr2ovf+QaaDiIf+zEKaZVzCWdLOTk7XigqSXvoh4cul7x68xp54WTQrgSnW7P1WBJDbyY3GhA== +"@inquirer/number@^3.0.5": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@inquirer/number/-/number-3.0.5.tgz#603dc92b23ba1fc0c0c14f8ece0db6e785b37a72" + integrity sha512-O/gcUwhS0TzBdBszYues3B4PTwyOLo51RctvXPRGtDfwIftuTTdPnm3K7oiK2OC2CDc7eG4UNa+QtdLlaJxIOA== dependencies: - "@inquirer/core" "^10.1.2" + "@inquirer/core" "^10.1.3" "@inquirer/type" "^3.0.2" -"@inquirer/password@^4.0.4": - version "4.0.4" - resolved "https://registry.yarnpkg.com/@inquirer/password/-/password-4.0.4.tgz#77891ae3ed5736607e6e942993ac40ca00411a2c" - integrity sha512-wiliQOWdjM8FnBmdIHtQV2Ca3S1+tMBUerhyjkRCv1g+4jSvEweGu9GCcvVEgKDhTBT15nrxvk5/bVrGUqSs1w== +"@inquirer/password@^4.0.5": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@inquirer/password/-/password-4.0.5.tgz#8937e548f3f500962c3f1a885258f1155b6b3b1a" + integrity sha512-/Undb8fTDSo6LX79OtAsdaaW08x6Xx9zr4z9Xd1VV/N4kDnJ9fWyUHJ287V0XTqMYgH/5SnZBU2e8VzgpGWO8g== dependencies: - "@inquirer/core" "^10.1.2" + "@inquirer/core" "^10.1.3" "@inquirer/type" "^3.0.2" ansi-escapes "^4.3.2" -"@inquirer/prompts@^7.2.1": - version "7.2.1" - resolved "https://registry.yarnpkg.com/@inquirer/prompts/-/prompts-7.2.1.tgz#f00fbcf06998a07faebc10741efa289384529950" - integrity sha512-v2JSGri6/HXSfoGIwuKEn8sNCQK6nsB2BNpy2lSX6QH9bsECrMv93QHnj5+f+1ZWpF/VNioIV2B/PDox8EvGuQ== - dependencies: - "@inquirer/checkbox" "^4.0.4" - "@inquirer/confirm" "^5.1.1" - "@inquirer/editor" "^4.2.1" - "@inquirer/expand" "^4.0.4" - "@inquirer/input" "^4.1.1" - "@inquirer/number" "^3.0.4" - "@inquirer/password" "^4.0.4" - "@inquirer/rawlist" "^4.0.4" - "@inquirer/search" "^3.0.4" - "@inquirer/select" "^4.0.4" - -"@inquirer/rawlist@^4.0.4": - version "4.0.4" - resolved "https://registry.yarnpkg.com/@inquirer/rawlist/-/rawlist-4.0.4.tgz#d10bbd6c529cd468d3d764c19de21334a01fa6d9" - integrity sha512-IsVN2EZdNHsmFdKWx9HaXb8T/s3FlR/U1QPt9dwbSyPtjFbMTlW9CRFvnn0bm/QIsrMRD2oMZqrQpSWPQVbXXg== +"@inquirer/prompts@^7.2.2": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@inquirer/prompts/-/prompts-7.2.2.tgz#351d1b3893d5ed562c7811dcd5c8dce86cc50044" + integrity sha512-kUd4L1S8huk+2FbIl0UbBqZ6g8mYFtag9Pb8IqzeefIYgRXyS4Oc29ikuSlhfSkEYjG+gBAA5Ip0JvuvSqtfWA== + dependencies: + "@inquirer/checkbox" "^4.0.5" + "@inquirer/confirm" "^5.1.2" + "@inquirer/editor" "^4.2.2" + "@inquirer/expand" "^4.0.5" + "@inquirer/input" "^4.1.2" + "@inquirer/number" "^3.0.5" + "@inquirer/password" "^4.0.5" + "@inquirer/rawlist" "^4.0.5" + "@inquirer/search" "^3.0.5" + "@inquirer/select" "^4.0.5" + +"@inquirer/rawlist@^4.0.5": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@inquirer/rawlist/-/rawlist-4.0.5.tgz#f62c0cfa5fd3ca3d74d3dff41f9c9991d01a2e70" + integrity sha512-38g3v5/cX3NUv+jcr4sU6phKAthQKv36NYRgahsZIGNIVy8ewtSnolCJ1N64nGwi/sTUz5AE6PV1ZF+NaIThxg== dependencies: - "@inquirer/core" "^10.1.2" + "@inquirer/core" "^10.1.3" "@inquirer/type" "^3.0.2" yoctocolors-cjs "^2.1.2" -"@inquirer/search@^3.0.4": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@inquirer/search/-/search-3.0.4.tgz#fcf51a853536add37491920634a182ecc9f5524b" - integrity sha512-tSkJk2SDmC2MEdTIjknXWmCnmPr5owTs9/xjfa14ol1Oh95n6xW7SYn5fiPk4/vrJPys0ggSWiISdPze4LTa7A== +"@inquirer/search@^3.0.5": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@inquirer/search/-/search-3.0.5.tgz#798b926a79faaa33ccd9522c455abb050cb05901" + integrity sha512-INqlGeK85gOmlVY8aosAdOMWgOmpcA7+eDlq5WBdbh8aZbAXX0HItf1GIdDj8zQnh+8Pv0DXU7OvdaLVcV4bWA== dependencies: - "@inquirer/core" "^10.1.2" + "@inquirer/core" "^10.1.3" "@inquirer/figures" "^1.0.9" "@inquirer/type" "^3.0.2" yoctocolors-cjs "^2.1.2" -"@inquirer/select@^4.0.4": - version "4.0.4" - resolved "https://registry.yarnpkg.com/@inquirer/select/-/select-4.0.4.tgz#026ada15754def1cd3fbc01efc56eae45ccc7de4" - integrity sha512-ZzYLuLoUzTIW9EJm++jBpRiTshGqS3Q1o5qOEQqgzaBlmdsjQr6pA4TUNkwu6OBYgM2mIRbCz6mUhFDfl/GF+w== +"@inquirer/select@^4.0.5": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@inquirer/select/-/select-4.0.5.tgz#f7f59e19f085d9b0b62e659b54a81d54b5740cdb" + integrity sha512-5UAnpWqs0G316MwJdSdgaRcWPIuUPllHa8pdHVi/w9KE/Ff/GzWhPwUn9ETtq/n8GEiWDUrP/LdJN8FJxf7JbA== dependencies: - "@inquirer/core" "^10.1.2" + "@inquirer/core" "^10.1.3" "@inquirer/figures" "^1.0.9" "@inquirer/type" "^3.0.2" ansi-escapes "^4.3.2" @@ -2067,6 +2068,13 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" +"@keyv/serialize@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@keyv/serialize/-/serialize-1.0.2.tgz#72507c4be94d8914434a4aa80661f8ac6131967f" + integrity sha512-+E/LyaAeuABniD/RvUezWVXKpeuvwLEA9//nE9952zBaOdBd2mQ3pPoM8cUe2X6IcMByfuSLzmYqnYshG60+HQ== + dependencies: + buffer "^6.0.3" + "@leichtgewicht/ip-codec@^2.0.1": version "2.0.4" resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz#b2ac626d6cb9c8718ab459166d4bb405b8ffa78b" @@ -2187,46 +2195,46 @@ resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g== -"@sentry-internal/browser-utils@8.47.0": - version "8.47.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/browser-utils/-/browser-utils-8.47.0.tgz#39f2766a1bbdffc2d211e2f61f8ed8c258245b3d" - integrity sha512-vOXzYzHTKkahTLDzWWIA4EiVCQ+Gk+7xGWUlNcR2ZiEPBqYZVb5MjsUozAcc7syrSUy6WicyFjcomZ3rlCVQhg== +"@sentry-internal/browser-utils@8.48.0": + version "8.48.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/browser-utils/-/browser-utils-8.48.0.tgz#320713e29566929894de42d54152064ec19cc9b3" + integrity sha512-pLtu0Fa1Ou0v3M1OEO1MB1EONJVmXEGtoTwFRCO1RPQI2ulmkG6BikINClFG5IBpoYKZ33WkEXuM6U5xh+pdZg== dependencies: - "@sentry/core" "8.47.0" + "@sentry/core" "8.48.0" -"@sentry-internal/feedback@8.47.0": - version "8.47.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/feedback/-/feedback-8.47.0.tgz#22bceac03b61ab8509e79c0875fb140f214b7c4f" - integrity sha512-IAiIemTQIalxAOYhUENs9bZ8pMNgJnX3uQSuY7v0gknEqClOGpGkG04X/cxCmtJUj1acZ9ShTGDxoh55a+ggAQ== +"@sentry-internal/feedback@8.48.0": + version "8.48.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/feedback/-/feedback-8.48.0.tgz#92d2301b0e7379716efae6c05bc4a4740687921a" + integrity sha512-6PwcJNHVPg0EfZxmN+XxVOClfQpv7MBAweV8t9i5l7VFr8sM/7wPNSeU/cG7iK19Ug9ZEkBpzMOe3G4GXJ5bpw== dependencies: - "@sentry/core" "8.47.0" + "@sentry/core" "8.48.0" -"@sentry-internal/replay-canvas@8.47.0": - version "8.47.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/replay-canvas/-/replay-canvas-8.47.0.tgz#5bbd04c81235b2bf627aa216185ae1993d2102c4" - integrity sha512-M4W9UGouEeELbGbP3QsXLDVtGiQSZoWJlKwqMWyqdQgZuLoKw0S33+60t6teLVMhuQZR0UI9VJTF5coiXysnnA== +"@sentry-internal/replay-canvas@8.48.0": + version "8.48.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/replay-canvas/-/replay-canvas-8.48.0.tgz#f88282b0594751407ca3016d0a63b133c2e37ac3" + integrity sha512-LdivLfBXXB9us1aAc6XaL7/L2Ob4vi3C/fEOXElehg3qHjX6q6pewiv5wBvVXGX1NfZTRvu+X11k6TZoxKsezw== dependencies: - "@sentry-internal/replay" "8.47.0" - "@sentry/core" "8.47.0" + "@sentry-internal/replay" "8.48.0" + "@sentry/core" "8.48.0" -"@sentry-internal/replay@8.47.0": - version "8.47.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/replay/-/replay-8.47.0.tgz#4f7bd359df2de25d919a378295cab67dfa05a406" - integrity sha512-G/S40ZBORj0HSMLw/uVC6YDEPN/dqVk901vf4VYfml686DEhJrZesfAfp5SydJumQ0NKZQrdtvny+BWnlI5H1w== +"@sentry-internal/replay@8.48.0": + version "8.48.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/replay/-/replay-8.48.0.tgz#2cc802178f6b0185581b61058f2541b9f3384a8b" + integrity sha512-csILVupc5RkrsTrncuUTGmlB56FQSFjXPYWG8I8yBTGlXEJ+o8oTuF6+55R4vbw3EIzBveXWi4kEBbnQlXW/eg== dependencies: - "@sentry-internal/browser-utils" "8.47.0" - "@sentry/core" "8.47.0" + "@sentry-internal/browser-utils" "8.48.0" + "@sentry/core" "8.48.0" -"@sentry/browser@8.47.0": - version "8.47.0" - resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-8.47.0.tgz#fe0b6b65c0394f54438d6704039adeaec214ce18" - integrity sha512-K6BzHisykmbFy/wORtGyfsAlw7ShevLALzu3ReZZZ18dVubO1bjSNjkZQU9MJD5Jcb9oLwkq89n3N9XIBfvdRA== +"@sentry/browser@8.48.0": + version "8.48.0" + resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-8.48.0.tgz#bdd7793ddd3ae7a65d595066bde93fbb63ce8b9d" + integrity sha512-fuuVULB5/1vI8NoIwXwR3xwhJJqk+y4RdSdajExGF7nnUDBpwUJyXsmYJnOkBO+oLeEs58xaCpotCKiPUNnE3g== dependencies: - "@sentry-internal/browser-utils" "8.47.0" - "@sentry-internal/feedback" "8.47.0" - "@sentry-internal/replay" "8.47.0" - "@sentry-internal/replay-canvas" "8.47.0" - "@sentry/core" "8.47.0" + "@sentry-internal/browser-utils" "8.48.0" + "@sentry-internal/feedback" "8.48.0" + "@sentry-internal/replay" "8.48.0" + "@sentry-internal/replay-canvas" "8.48.0" + "@sentry/core" "8.48.0" "@sentry/core@7.114.0": version "7.114.0" @@ -2236,10 +2244,10 @@ "@sentry/types" "7.114.0" "@sentry/utils" "7.114.0" -"@sentry/core@8.47.0": - version "8.47.0" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-8.47.0.tgz#e811444552f7a91b5de573875a318a6cd4e802f8" - integrity sha512-iSEJZMe3DOcqBFZQAqgA3NB2lCWBc4Gv5x/SCri/TVg96wAlss4VrUunSI2Mp0J4jJ5nJcJ2ChqHSBAU48k3FA== +"@sentry/core@8.48.0": + version "8.48.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-8.48.0.tgz#3bb8d06305f0ec7c873453844687deafdeab168b" + integrity sha512-VGwYgTfLpvJ5LRO5A+qWo1gpo6SfqaGXL9TOzVgBucAdpzbrYHpZ87sEarDVq/4275uk1b0S293/mfsskFczyw== "@sentry/integrations@^7.114.0": version "7.114.0" @@ -2251,13 +2259,13 @@ "@sentry/utils" "7.114.0" localforage "^1.8.1" -"@sentry/react@^8.47.0": - version "8.47.0" - resolved "https://registry.yarnpkg.com/@sentry/react/-/react-8.47.0.tgz#0d9c120b0d4a2efd6d8e8fb9acff332c63afd50d" - integrity sha512-SRk2Up+qBTow4rQGiRXViC2i4M5w/tae5w8I/rmX+IxFoPyh8wXERcLAj/8xbbRm8aR+A4i5gNgfFtrYsyFJFA== +"@sentry/react@^8.48.0": + version "8.48.0" + resolved "https://registry.yarnpkg.com/@sentry/react/-/react-8.48.0.tgz#0550a9a4d123d20c680d94bdaa8a8dbeb3b2661e" + integrity sha512-J8XAUOJYbsjXnowTEXE+zWJWLWUzQGP8kMb+smoGdRzFJwwXKrbE709Kr/Boz6rK48EbbRT4UUINoTbHgL3RHQ== dependencies: - "@sentry/browser" "8.47.0" - "@sentry/core" "8.47.0" + "@sentry/browser" "8.48.0" + "@sentry/core" "8.48.0" hoist-non-react-statics "^3.3.2" "@sentry/types@7.114.0": @@ -2660,17 +2668,17 @@ resolved "https://registry.yarnpkg.com/@svgdotjs/svg.select.js/-/svg.select.js-4.0.2.tgz#80a10409e6c73206218690eac5c9f94f8c8909b5" integrity sha512-5gWdrvoQX3keo03SCmgaBbD+kFftq0F/f2bzCbNnpkkvW6tk4rl4MakORzFuNjvXPWwB4az9GwuvVxQVnjaK2g== -"@tabler/icons-react@^3.26.0": - version "3.26.0" - resolved "https://registry.yarnpkg.com/@tabler/icons-react/-/icons-react-3.26.0.tgz#5db95a886f3766aefea6d94b729438dd0a8dd784" - integrity sha512-t18Zmu1ROktB7M8hWQ6vJw+mNpI/LPk5PPxLuE+kNB+4Zzf38GfETL8VF98inhzcfHohsggdROzMzwSAfjcAxw== +"@tabler/icons-react@^3.28.1": + version "3.28.1" + resolved "https://registry.yarnpkg.com/@tabler/icons-react/-/icons-react-3.28.1.tgz#6bcd85f3fb924ceeb3caf2ce5be7523e41008266" + integrity sha512-KNBpA2kbxr3/2YK5swt7b/kd/xpDP1FHYZCxDFIw54tX8slELRFEf95VMxsccQHZeIcUbdoojmUUuYSbt/sM5Q== dependencies: - "@tabler/icons" "3.26.0" + "@tabler/icons" "3.28.1" -"@tabler/icons@3.26.0": - version "3.26.0" - resolved "https://registry.yarnpkg.com/@tabler/icons/-/icons-3.26.0.tgz#7a23b2a99abda32e3b4cf00ce46dddaa5daa1923" - integrity sha512-oO3D4ss+DxzxqU1aDy0f1HmToyrO0gcQWIMpzHAfV1quPUx0BZYvNm5xz1DQb4DxNm/+xNvbBGLJy4pzTLYWag== +"@tabler/icons@3.28.1": + version "3.28.1" + resolved "https://registry.yarnpkg.com/@tabler/icons/-/icons-3.28.1.tgz#271e6d4107525dbb8622a36a9414487e734606aa" + integrity sha512-h7nqKEvFooLtFxhMOC1/2eiV+KRXhBUuDUUJrJlt6Ft6tuMw2eU/9GLQgrTk41DNmIEzp/LI83K9J9UUU8YBYQ== "@testing-library/cypress@^10.0.2": version "10.0.2" @@ -2963,6 +2971,11 @@ resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.2.tgz#5950e50960793055845e956c427fc2b0d70c5239" integrity sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw== +"@types/prop-types@*": + version "15.7.14" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.14.tgz#1433419d73b2a7ebfc6918dcefd2ec0d5cd698f2" + integrity sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ== + "@types/qs@*": version "6.9.11" resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.11.tgz#208d8a30bc507bd82e03ada29e4732ea46a6bbda" @@ -2980,13 +2993,21 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@16 || 17 || 18 || 19": +"@types/react@*": version "19.0.2" resolved "https://registry.yarnpkg.com/@types/react/-/react-19.0.2.tgz#9363e6b3ef898c471cb182dd269decc4afc1b4f6" integrity sha512-USU8ZI/xyKJwFTpjSVIrSeHBVAGagkHQKPNbxeWwql/vDmnTIBgx+TJnhFnj1NXgz8XfprU0egV2dROLGpsBEg== dependencies: csstype "^3.0.2" +"@types/react@16 || 17 || 18": + version "18.3.18" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.18.tgz#9b382c4cd32e13e463f97df07c2ee3bbcd26904b" + integrity sha512-t4yC+vtgnkYjNSKlFx1jkAhH8LgTo2N/7Qvi83kdEaUtMDiwpbLAktKDaAMlRcJ5eSxZkH74eEGt1ky31d7kfQ== + dependencies: + "@types/prop-types" "*" + csstype "^3.0.2" + "@types/resolve@^1.20.2": version "1.20.6" resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.20.6.tgz#e6e60dad29c2c8c206c026e6dd8d6d1bdda850b8" @@ -3270,20 +3291,20 @@ "@webassemblyjs/ast" "1.14.1" "@xtuc/long" "4.2.2" -"@webpack-cli/configtest@^2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-2.1.1.tgz#3b2f852e91dac6e3b85fb2a314fb8bef46d94646" - integrity sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw== +"@webpack-cli/configtest@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-3.0.1.tgz#76ac285b9658fa642ce238c276264589aa2b6b57" + integrity sha512-u8d0pJ5YFgneF/GuvEiDA61Tf1VDomHHYMjv/wc9XzYj7nopltpG96nXN5dJRstxZhcNpV1g+nT6CydO7pHbjA== -"@webpack-cli/info@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-2.0.2.tgz#cc3fbf22efeb88ff62310cf885c5b09f44ae0fdd" - integrity sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A== +"@webpack-cli/info@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-3.0.1.tgz#3cff37fabb7d4ecaab6a8a4757d3826cf5888c63" + integrity sha512-coEmDzc2u/ffMvuW9aCjoRzNSPDl/XLuhPdlFRpT9tZHmJ/039az33CE7uH+8s0uL1j5ZNtfdv0HkfaKRBGJsQ== -"@webpack-cli/serve@^2.0.5": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-2.0.5.tgz#325db42395cd49fe6c14057f9a900e427df8810e" - integrity sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ== +"@webpack-cli/serve@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-3.0.1.tgz#bd8b1f824d57e30faa19eb78e4c0951056f72f00" + integrity sha512-sbgw03xQaCLiT6gcY/6u3qBDn01CWw/nbaXl3gTdTFuJJ75Gffv3E3DBpgvY2fkkrdS1fpjaXNOmJlnbtKauKg== "@xtuc/ieee754@^1.2.0": version "1.2.0" @@ -3747,10 +3768,10 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.12.0.tgz#ce1c9d143389679e253b314241ea9aa5cec980d3" integrity sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg== -axios@^1.4.0, axios@^1.5.1, axios@^1.7.7: - version "1.7.7" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.7.tgz#2f554296f9892a72ac8d8e4c5b79c14a91d0a47f" - integrity sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q== +axios@^1.4.0, axios@^1.5.1, axios@^1.7.9: + version "1.7.9" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.9.tgz#d7d071380c132a24accda1b2cfc1535b79ec650a" + integrity sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw== dependencies: follow-redirects "^1.15.6" form-data "^4.0.0" @@ -4072,6 +4093,14 @@ buffer@^5.5.0, buffer@^5.7.1: base64-js "^1.3.1" ieee754 "^1.1.13" +buffer@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + bundle-name@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/bundle-name/-/bundle-name-4.1.0.tgz#f3b96b34160d6431a19d7688135af7cfb8797889" @@ -4089,6 +4118,14 @@ bytes@3.1.2: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== +cacheable@^1.8.7: + version "1.8.7" + resolved "https://registry.yarnpkg.com/cacheable/-/cacheable-1.8.7.tgz#a4e2c99de531539cb26db7003f1ac9287b6d9f15" + integrity sha512-AbfG7dAuYNjYxFUtL1lAqmlWdxczCJ47w7cFjhGcnGnUdwSo6VgmSojfoW3tUI12HUkgTJ5kqj78yyq6TsFtlg== + dependencies: + hookified "^1.6.0" + keyv "^5.2.3" + cachedir@^2.3.0: version "2.4.0" resolved "https://registry.yarnpkg.com/cachedir/-/cachedir-2.4.0.tgz#7fef9cf7367233d7c88068fe6e34ed0d355a610d" @@ -4477,7 +4514,7 @@ commander@2.11.x: resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" integrity sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ== -commander@^10.0.0, commander@^10.0.1: +commander@^10.0.0: version "10.0.1" resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== @@ -4636,10 +4673,10 @@ core-js@^2.6.12, core-js@^2.6.5: resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== -core-js@^3.33.2: - version "3.35.1" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.35.1.tgz#9c28f8b7ccee482796f8590cc8d15739eaaf980c" - integrity sha512-IgdsbxNyMskrTFxa9lWHyMwAJU5gXOPP+1yO+K59d50VLVAIDAbs7gIv705KzALModfK3ZrSZTPNpC0PQgIZuw== +core-js@^3.40.0: + version "3.40.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.40.0.tgz#2773f6b06877d8eda102fc42f828176437062476" + integrity sha512-7vsMc/Lty6AGnn7uFpYT56QesI5D2Y/UkgKounk87OP9Z2H9Z8kj6jzcSGAxFmUtDOS0ntK6lbQz+Nsa0Jj6mQ== core-util-is@1.0.2: version "1.0.2" @@ -4758,7 +4795,7 @@ css-select@^5.1.0: domutils "^3.0.1" nth-check "^2.0.1" -css-tree@^3.0.1: +css-tree@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-3.1.0.tgz#7aabc035f4e66b5c86f54570d55e05b1346eb0fd" integrity sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w== @@ -5405,10 +5442,10 @@ env-paths@^2.2.1: resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== -envinfo@^7.7.3: - version "7.11.1" - resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.11.1.tgz#2ffef77591057081b0129a8fd8cf6118da1b94e1" - integrity sha512-8PiZgZNIB4q/Lw4AhOvAfB/ityHAd2bli3lESSWmWSzSsl5dKpy5N1d1Rfkd2teq/g9xN90lc6o98DOjMeYHpg== +envinfo@^7.14.0, envinfo@^7.7.3: + version "7.14.0" + resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.14.0.tgz#26dac5db54418f2a4c1159153a0b2ae980838aae" + integrity sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg== error-ex@^1.3.1: version "1.3.2" @@ -5890,10 +5927,10 @@ eslint-plugin-react-hooks@^1.7.0: resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.7.0.tgz#6210b6d5a37205f0b92858f895a4e827020a7d04" integrity sha512-iXTCFcOmlWvw4+TOE8CLWj6yX1GwzT0Y6cUfHHZqWnSk144VmVIRcVGtUAzrLES7C798lmvnt02C7rxaOX1HNA== -eslint-plugin-react@^7.14.3, eslint-plugin-react@^7.37.3: - version "7.37.3" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.37.3.tgz#567549e9251533975c4ea9706f986c3a64832031" - integrity sha512-DomWuTQPFYZwF/7c9W2fkKkStqZmBd3uugfqBYLdkZ3Hii23WzZuOLUskGxB8qkSKqftxEeGL1TB2kMhrce0jA== +eslint-plugin-react@^7.14.3, eslint-plugin-react@^7.37.4: + version "7.37.4" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.37.4.tgz#1b6c80b6175b6ae4b26055ae4d55d04c414c7181" + integrity sha512-BGP0jRmfYyvOyvMoRX/uoUeW+GqNj9y16bPQzqAHf3AYII/tDs+jMN0dBVkl88/OZwNGwrVFxE7riHsXVfy/LQ== dependencies: array-includes "^3.1.8" array.prototype.findlast "^1.2.5" @@ -6221,16 +6258,16 @@ fast-diff@^1.1.2, fast-diff@^1.2.0: resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== -fast-glob@^3.2.9, fast-glob@^3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" - integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== +fast-glob@^3.2.9, fast-glob@^3.3.2, fast-glob@^3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818" + integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" glob-parent "^5.1.2" merge2 "^1.3.0" - micromatch "^4.0.4" + micromatch "^4.0.8" fast-json-parse@^1.0.3: version "1.0.3" @@ -6294,6 +6331,13 @@ figures@^3.2.0: dependencies: escape-string-regexp "^1.0.5" +file-entry-cache@^10.0.5: + version "10.0.5" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-10.0.5.tgz#0255cd065769ef930005073883389e432a16a9a7" + integrity sha512-umpQsJrBNsdMDgreSryMEXvJh66XeLtZUwA8Gj7rHGearGufUFv6rB/bcXRFsiGWw/VeSUgUofF4Rf2UKEOrTA== + dependencies: + flat-cache "^6.1.5" + file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" @@ -6301,13 +6345,6 @@ file-entry-cache@^6.0.1: dependencies: flat-cache "^3.0.4" -file-entry-cache@^9.1.0: - version "9.1.0" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-9.1.0.tgz#2e66ad98ce93f49aed1b178c57b0b5741591e075" - integrity sha512-/pqPFG+FdxWQj+/WSuzXSDaNzxgTLr/OrR1QuqfEZzDakpdYE70PwUxL7BPUa8hpjbvY1+qvCl8k+8Tq34xJgg== - dependencies: - flat-cache "^5.0.0" - file-loader@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-6.2.0.tgz#baef7cf8e1840df325e4390b4484879480eebe4d" @@ -6412,13 +6449,14 @@ flat-cache@^3.0.4: keyv "^4.5.3" rimraf "^3.0.2" -flat-cache@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-5.0.0.tgz#26c4da7b0f288b408bb2b506b2cb66c240ddf062" - integrity sha512-JrqFmyUl2PnPi1OvLyTVHnQvwQ0S+e6lGSwu8OkAZlSaNIZciTY2H/cOOROxsBA1m/LZNHDsqAgDZt6akWcjsQ== +flat-cache@^6.1.5: + version "6.1.5" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-6.1.5.tgz#a3e0077571aa340c85c011aa6b9150b4606e2b0d" + integrity sha512-QR+2kN38f8nMfiIQ1LHYjuDEmZNZVjxuxY+HufbS3BW0EX01Q5OnH7iduOYRutmgiXb797HAKcXUeXrvRjjgSQ== dependencies: - flatted "^3.3.1" - keyv "^4.5.4" + cacheable "^1.8.7" + flatted "^3.3.2" + hookified "^1.6.0" flat@^5.0.2: version "5.0.2" @@ -6430,10 +6468,10 @@ flatted@^3.2.9: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.9.tgz#7eb4c67ca1ba34232ca9d2d93e9886e611ad7daf" integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ== -flatted@^3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" - integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== +flatted@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.2.tgz#adba1448a9841bec72b42c532ea23dbbedef1a27" + integrity sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA== flow-parser@0.*: version "0.228.0" @@ -6994,6 +7032,11 @@ hoist-non-react-statics@3, hoist-non-react-statics@^3.3.0, hoist-non-react-stati dependencies: react-is "^16.7.0" +hookified@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/hookified/-/hookified-1.6.0.tgz#161315ed4525a21f74d710dd9cec71e73951bed2" + integrity sha512-se7cpwTA+iA/eY548Bu03JJqBiEZAqU2jnyKdj5B5qurtBg64CZGHTgqCv4Yh7NWu6FGI09W61MCq+NoPj9GXA== + hpack.js@^2.1.6: version "2.1.6" resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" @@ -7231,7 +7274,7 @@ icss-utils@^5.0.0, icss-utils@^5.1.0: resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA== -ieee754@^1.1.13: +ieee754@^1.1.13, ieee754@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== @@ -7241,10 +7284,10 @@ ignore@^5.2.0, ignore@^5.2.4: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== -ignore@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-6.0.2.tgz#77cccb72a55796af1b6d2f9eb14fa326d24f4283" - integrity sha512-InwqeHHN2XpumIkMvpl/DCJVrAHgCsG5+cn1XlnLWGwtZBm8QJfSusItfrwx81CTp5agNZqpKU2J/ccC5nGT4A== +ignore@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-7.0.1.tgz#e0aca8bd28ed81f45bfbc042c57f24eb682aa2b9" + integrity sha512-D1gVletsbVOoiXF963rgZnfobGAbq7Lb+dz3fcBmlOmZg6hHkpbycLqL8PLNB8f4GVv6dOVYwhPL/r7hwiH0Fw== immediate@~3.0.5: version "3.0.6" @@ -7343,14 +7386,14 @@ intl-messageformat-parser@^1.8.1: resolved "https://registry.yarnpkg.com/intl-messageformat-parser/-/intl-messageformat-parser-1.8.1.tgz#0eb14c5618333be4c95c409457b66c8c33ddcc01" integrity sha512-IMSCKVf0USrM/959vj3xac7s8f87sc+80Y/ipBzdKy4ifBv5Gsj2tZ41EAaURVg01QU71fYr77uA8Meh6kELbg== -intl-messageformat@10.7.10: - version "10.7.10" - resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-10.7.10.tgz#fc8fc8c13b0a4104ba08dc2f5f9225f14945bcb7" - integrity sha512-hp7iejCBiJdW3zmOe18FdlJu8U/JsADSDiBPQhfdSeI8B9POtvPRvPh3nMlvhYayGMKLv6maldhR7y3Pf1vkpw== +intl-messageformat@10.7.11: + version "10.7.11" + resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-10.7.11.tgz#f24893b2a64e7b5ec29f9eceb4f1a58bde1346e0" + integrity sha512-IB2N1tmI24k2EFH3PWjU7ivJsnWyLwOWOva0jnXFa29WzB6fb0JZ5EMQGu+XN5lDtjHYFo0/UooP67zBwUg7rQ== dependencies: - "@formatjs/ecma402-abstract" "2.3.1" - "@formatjs/fast-memoize" "2.2.5" - "@formatjs/icu-messageformat-parser" "2.9.7" + "@formatjs/ecma402-abstract" "2.3.2" + "@formatjs/fast-memoize" "2.2.6" + "@formatjs/icu-messageformat-parser" "2.9.8" tslib "2" invariant@^2.2.4: @@ -8526,13 +8569,20 @@ just-curry-it@^3.1.0: resolved "https://registry.yarnpkg.com/just-curry-it/-/just-curry-it-3.2.1.tgz#7bb18284c8678ed816bfc5c19e44400605fbe461" integrity sha512-Q8206k8pTY7krW32cdmPsP+DqqLgWx/hYPSj9/+7SYqSqz7UuwPbfSe07lQtvuuaVyiSJveXk0E5RydOuWwsEg== -keyv@^4.5.3, keyv@^4.5.4: +keyv@^4.5.3: version "4.5.4" resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== dependencies: json-buffer "3.0.1" +keyv@^5.2.3: + version "5.2.3" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-5.2.3.tgz#32db1a4aa8d05e2b8ab82688a57ddc5d2184a25c" + integrity sha512-AGKecUfzrowabUv0bH1RIR5Vf7w+l4S3xtQAypKaUpTdIR1EbrAcTxHCrpo9Q+IWeUlFE2palRtgIQcgm+PQJw== + dependencies: + "@keyv/serialize" "^1.0.2" + kind-of@^6.0.2: version "6.0.3" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" @@ -10905,18 +10955,18 @@ react-helmet@^6.1.0: react-fast-compare "^3.1.1" react-side-effect "^2.1.0" -react-intl@^7.0.4: - version "7.0.4" - resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-7.0.4.tgz#9bb491fc686ed2e8bba9fd859375e9464a4fab5a" - integrity sha512-WGNfCPNcRQhNAZBN+amz2hfR8Kd7jngScJ4WaRZcsaOWsvva1ciStnUIGj9MvOAxPqTf1D78J5OdRdc3l0wgKQ== +react-intl@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-7.1.0.tgz#31e03315c24b73e7c24c83a0abee18e5f06c33e6" + integrity sha512-fILi/lC06IlYR8FFI39TBjHsSA3yKKC4ndl5hKx5MJWv571vdkhZWW3FJF8Z5/5H46WTy8UvRYnIFtw7Dt6kmw== dependencies: - "@formatjs/ecma402-abstract" "2.3.1" - "@formatjs/icu-messageformat-parser" "2.9.7" - "@formatjs/intl" "3.0.4" + "@formatjs/ecma402-abstract" "2.3.2" + "@formatjs/icu-messageformat-parser" "2.9.8" + "@formatjs/intl" "3.1.0" "@types/hoist-non-react-statics" "3" - "@types/react" "16 || 17 || 18 || 19" + "@types/react" "16 || 17 || 18" hoist-non-react-statics "3" - intl-messageformat "10.7.10" + intl-messageformat "10.7.11" tslib "2" react-is@^16.13.1, react-is@^16.7.0: @@ -11170,12 +11220,12 @@ redux-actions@^2.6.5: reduce-reducers "^0.4.3" to-camel-case "^1.0.0" -redux-logic@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/redux-logic/-/redux-logic-5.0.1.tgz#19821105592098061ea8ad047e4b7ba156041a9c" - integrity sha512-GoIOf/VokF01yDSGCjmozGTTAtZpFvePa67i5mFJS4fZ4fgYX/+zY5AIMT8R37TuWmfxKUb9wo7/MIEBUBSa8w== +redux-logic@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/redux-logic/-/redux-logic-5.0.2.tgz#4de0e638ad811583de40a255420900c3d433e22a" + integrity sha512-pQGmSazH1/NXQFXWeBY7CC0rDcD6jKVxSZbbdLG/gPV11ORw8oQM1ICDehZhN7epHV3ljUPtxZ2GlpUXB0Y66Q== dependencies: - core-js "^3.33.2" + core-js "^3.40.0" is-promise "^4.0.0" loose-envify "^1.4.0" rxjs "^7.8.1" @@ -12285,10 +12335,10 @@ stylelint-stylus@^1.0.0: stylelint-config-html "^1.0.0" svg-tags "^1.0.0" -stylelint@^16.12.0: - version "16.12.0" - resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-16.12.0.tgz#13532dcbaed21348da0e9e0fb9a4e1e7f6dab2b8" - integrity sha512-F8zZ3L/rBpuoBZRvI4JVT20ZanPLXfQLzMOZg1tzPflRVh9mKpOZ8qcSIhh1my3FjAjZWG4T2POwGnmn6a6hbg== +stylelint@^16.13.1: + version "16.13.1" + resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-16.13.1.tgz#bc1bb8a01052c60a1b7c1038aa54773b14fea5b7" + integrity sha512-691JjSIIcP6f9QJFz0J0/AMG3lupE9RqYAgYCON3wiqp5nQiKqDYIsz321GeTOYNznoRPNh0Mf6VjzP1eBVz/Q== dependencies: "@csstools/css-parser-algorithms" "^3.0.4" "@csstools/css-tokenizer" "^3.0.3" @@ -12299,16 +12349,16 @@ stylelint@^16.12.0: colord "^2.9.3" cosmiconfig "^9.0.0" css-functions-list "^3.2.3" - css-tree "^3.0.1" + css-tree "^3.1.0" debug "^4.3.7" - fast-glob "^3.3.2" + fast-glob "^3.3.3" fastest-levenshtein "^1.0.16" - file-entry-cache "^9.1.0" + file-entry-cache "^10.0.5" global-modules "^2.0.0" globby "^11.1.0" globjoin "^0.1.4" html-tags "^3.3.1" - ignore "^6.0.2" + ignore "^7.0.1" imurmurhash "^0.1.4" is-plain-object "^5.0.0" known-css-properties "^0.35.0" @@ -13184,12 +13234,12 @@ w3c-xmlserializer@^4.0.0: dependencies: xml-name-validator "^4.0.0" -wait-on@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/wait-on/-/wait-on-8.0.1.tgz#13c8ec77115517f8fbc2d670521a444201f03f53" - integrity sha512-1wWQOyR2LVVtaqrcIL2+OM+x7bkpmzVROa0Nf6FryXkS+er5Sa1kzFGjzZRqLnHa3n1rACFLeTwUqE1ETL9Mig== +wait-on@^8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/wait-on/-/wait-on-8.0.2.tgz#0c7929abf7c5e625b733e992a9c0bd8b7691afe3" + integrity sha512-qHlU6AawrgAIHlueGQHQ+ETcPLAauXbnoTKl3RKq20W0T8x0DKVAo5xWIYjHSyvHxQlcYbFdR0jp4T9bDVITFA== dependencies: - axios "^1.7.7" + axios "^1.7.9" joi "^17.13.3" lodash "^4.17.21" minimist "^1.2.8" @@ -13256,24 +13306,24 @@ webidl-conversions@^7.0.0: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== -webpack-cli@^5.1.4: - version "5.1.4" - resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-5.1.4.tgz#c8e046ba7eaae4911d7e71e2b25b776fcc35759b" - integrity sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg== +webpack-cli@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-6.0.1.tgz#a1ce25da5ba077151afd73adfa12e208e5089207" + integrity sha512-MfwFQ6SfwinsUVi0rNJm7rHZ31GyTcpVE5pgVA3hwFRb7COD4TzjUUwhGWKfO50+xdc2MQPuEBBJoqIMGt3JDw== dependencies: - "@discoveryjs/json-ext" "^0.5.0" - "@webpack-cli/configtest" "^2.1.1" - "@webpack-cli/info" "^2.0.2" - "@webpack-cli/serve" "^2.0.5" + "@discoveryjs/json-ext" "^0.6.1" + "@webpack-cli/configtest" "^3.0.1" + "@webpack-cli/info" "^3.0.1" + "@webpack-cli/serve" "^3.0.1" colorette "^2.0.14" - commander "^10.0.1" + commander "^12.1.0" cross-spawn "^7.0.3" - envinfo "^7.7.3" + envinfo "^7.14.0" fastest-levenshtein "^1.0.12" import-local "^3.0.2" interpret "^3.1.1" rechoir "^0.8.0" - webpack-merge "^5.7.3" + webpack-merge "^6.0.1" webpack-dev-middleware@^6.1.2: version "6.1.3" @@ -13340,14 +13390,14 @@ webpack-hot-middleware@^2.25.1: html-entities "^2.1.0" strip-ansi "^6.0.0" -webpack-merge@^5.7.3: - version "5.10.0" - resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.10.0.tgz#a3ad5d773241e9c682803abf628d4cd62b8a4177" - integrity sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA== +webpack-merge@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-6.0.1.tgz#50c776868e080574725abc5869bd6e4ef0a16c6a" + integrity sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg== dependencies: clone-deep "^4.0.1" flat "^5.0.2" - wildcard "^2.0.0" + wildcard "^2.0.1" "webpack-shell-plugin@https://github.com/cdeutsch/webpack-shell-plugin.git#bee537d": version "0.5.0" @@ -13538,7 +13588,7 @@ which@^2.0.1: dependencies: isexe "^2.0.0" -wildcard@^2.0.0: +wildcard@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.1.tgz#5ab10d02487198954836b6349f74fff961e10f67" integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==